ideas
This commit is contained in:
parent
f6b4f7c20a
commit
90f5cf4c65
0
phasm/type4/__init__.py
Normal file
0
phasm/type4/__init__.py
Normal file
132
phasm/type4/classes.py
Normal file
132
phasm/type4/classes.py
Normal file
@ -0,0 +1,132 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TypeAlias
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
## Kind * (part 1)
|
||||
|
||||
@dataclass
|
||||
class Atomic:
|
||||
"""
|
||||
Atomic (or base or fundamental) type - it doesn't construct anything and wasn't constructed
|
||||
"""
|
||||
name: str
|
||||
|
||||
class Struct(Atomic):
|
||||
"""
|
||||
Structs are a fundamental type. But we need to store some extra info.
|
||||
"""
|
||||
fields: list[tuple[str, Type4]]
|
||||
|
||||
@dataclass
|
||||
class Variable:
|
||||
"""
|
||||
Type variable of kind *.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class Nat:
|
||||
"""
|
||||
Some type constructors take a natural number as argument, rather than a type.
|
||||
"""
|
||||
value: int
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return str(self.value)
|
||||
|
||||
## Kind * -> *
|
||||
|
||||
@dataclass
|
||||
class ConcreteConSS:
|
||||
"""
|
||||
An concrete type construtor of kind * -> *, like dynamic array.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class VariableConSS:
|
||||
"""
|
||||
A type variable of kind * -> *.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class AppliedConSS:
|
||||
"""
|
||||
An application of a type constructor of kind * -> *.
|
||||
|
||||
The result is a type of kind *.
|
||||
"""
|
||||
con: ConcreteConSS | VariableConSS | AppliedConSSS | AppliedConNSS
|
||||
arg: Type4
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return f'{self.con.name} {self.arg.name}'
|
||||
|
||||
## Kind * -> * -> *
|
||||
|
||||
@dataclass
|
||||
class ConcreteConSSS:
|
||||
"""
|
||||
An concrete type construtor of kind * -> * -> *, like function, tuple or Either.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class VariableConSSS:
|
||||
"""
|
||||
A type variable of kind * -> * -> *.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class AppliedConSSS:
|
||||
"""
|
||||
An application of a type constructor of kind * -> * -> *.
|
||||
|
||||
The result is a type construtor of kind * -> *.
|
||||
"""
|
||||
con: ConcreteConSSS | VariableConSSS
|
||||
arg: Type4
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return f'{self.con.name} {self.arg.name}'
|
||||
|
||||
## Kind Nat -> * -> *
|
||||
|
||||
@dataclass
|
||||
class ConcreteConNSS:
|
||||
"""
|
||||
An concrete type construtor of kind Nat -> * -> *, like static array.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class VariableConNSS:
|
||||
"""
|
||||
A type variable of kind Nat -> * -> *.
|
||||
"""
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class AppliedConNSS:
|
||||
"""
|
||||
An application of a type constructor of kind Nat -> * -> *.
|
||||
|
||||
The result is a type construtor of kind * -> *.
|
||||
"""
|
||||
con: ConcreteConNSS | VariableConNSS
|
||||
arg: Nat
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return f'{self.con.name} {self.arg.name}'
|
||||
|
||||
# Kind * (part 2)
|
||||
|
||||
Type4: TypeAlias = Atomic | Variable | AppliedConSS
|
||||
201
phasm/type4/unify.py
Normal file
201
phasm/type4/unify.py
Normal file
@ -0,0 +1,201 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from .classes import (
|
||||
AppliedConNSS,
|
||||
AppliedConSS,
|
||||
AppliedConSSS,
|
||||
Atomic,
|
||||
ConcreteConNSS,
|
||||
ConcreteConSS,
|
||||
ConcreteConSSS,
|
||||
Variable,
|
||||
VariableConNSS,
|
||||
VariableConSS,
|
||||
VariableConSSS,
|
||||
Type4
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Failure:
|
||||
"""
|
||||
Both types are already different - cannot be unified.
|
||||
"""
|
||||
msg: str
|
||||
|
||||
@dataclass
|
||||
class Action:
|
||||
pass
|
||||
|
||||
UnifyResult = Failure | list[Action]
|
||||
|
||||
@dataclass
|
||||
class SetTypeForVariable(Action):
|
||||
var: Variable
|
||||
type: Atomic | AppliedConSS
|
||||
|
||||
@dataclass
|
||||
class SetTypeForConSSVariable(Action):
|
||||
var: VariableConSS
|
||||
type: ConcreteConSS | AppliedConSSS | AppliedConNSS
|
||||
|
||||
@dataclass
|
||||
class SetTypeForConSSSVariable(Action):
|
||||
var: VariableConSSS
|
||||
type: ConcreteConSSS
|
||||
|
||||
@dataclass
|
||||
class ReplaceVariable(Action):
|
||||
before: Variable
|
||||
after: Variable
|
||||
|
||||
@dataclass
|
||||
class ReplaceConSSVariable(Action):
|
||||
before: VariableConSS
|
||||
after: VariableConSS
|
||||
|
||||
def unify(lft: Type4, rgt: Type4) -> UnifyResult:
|
||||
"""
|
||||
Tries to unify the given two types.
|
||||
"""
|
||||
if isinstance(lft, Atomic) and isinstance(rgt, Atomic):
|
||||
if lft == rgt:
|
||||
return []
|
||||
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, Atomic) and isinstance(rgt, Variable):
|
||||
return [SetTypeForVariable(rgt, lft)]
|
||||
|
||||
if isinstance(lft, Atomic) and isinstance(rgt, AppliedConSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, Variable) and isinstance(rgt, Atomic):
|
||||
return [SetTypeForVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, Variable) and isinstance(rgt, Variable):
|
||||
return [ReplaceVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, Variable) and isinstance(rgt, AppliedConSS):
|
||||
return [SetTypeForVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, AppliedConSS) and isinstance(rgt, Atomic):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, AppliedConSS) and isinstance(rgt, Variable):
|
||||
return [SetTypeForVariable(rgt, lft)]
|
||||
|
||||
if isinstance(lft, AppliedConSS) and isinstance(rgt, AppliedConSS):
|
||||
con_res = unify_con_ss(lft.con, rgt.con)
|
||||
if isinstance(con_res, Failure):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
arg_res = unify(lft.arg, rgt.arg)
|
||||
if isinstance(arg_res, Failure):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
return con_res + arg_res
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def unify_con_ss(
|
||||
lft: ConcreteConSS | VariableConSS | AppliedConSSS | AppliedConNSS,
|
||||
rgt: ConcreteConSS | VariableConSS | AppliedConSSS | AppliedConNSS,
|
||||
) -> UnifyResult:
|
||||
"""
|
||||
Tries to unify the given two constuctors of kind * -> *.
|
||||
"""
|
||||
if isinstance(lft, ConcreteConSS) and isinstance(rgt, ConcreteConSS):
|
||||
if lft == rgt:
|
||||
return []
|
||||
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, ConcreteConSS) and isinstance(rgt, VariableConSS):
|
||||
return [SetTypeForConSSVariable(rgt, lft)]
|
||||
|
||||
if isinstance(lft, ConcreteConSS) and isinstance(rgt, AppliedConSSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, ConcreteConSS) and isinstance(rgt, AppliedConNSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, VariableConSS) and isinstance(rgt, ConcreteConSS):
|
||||
return [SetTypeForConSSVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, VariableConSS) and isinstance(rgt, VariableConSS):
|
||||
return [ReplaceConSSVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, VariableConSS) and isinstance(rgt, AppliedConSSS):
|
||||
return [SetTypeForConSSVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, VariableConSS) and isinstance(rgt, AppliedConNSS):
|
||||
return [SetTypeForConSSVariable(lft, rgt)]
|
||||
|
||||
if isinstance(lft, AppliedConSSS) and isinstance(rgt, ConcreteConSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, AppliedConSSS) and isinstance(rgt, VariableConSS):
|
||||
return [SetTypeForConSSVariable(rgt, lft)]
|
||||
|
||||
if isinstance(lft, AppliedConSSS) and isinstance(rgt, AppliedConSSS):
|
||||
con_res = unify_con_sss(lft.con, rgt.con)
|
||||
if isinstance(con_res, Failure):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
arg_res = unify(lft.arg, rgt.arg)
|
||||
if isinstance(arg_res, Failure):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
return con_res + arg_res
|
||||
|
||||
if isinstance(lft, AppliedConSSS) and isinstance(rgt, AppliedConNSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, AppliedConNSS) and isinstance(rgt, ConcreteConSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, AppliedConNSS) and isinstance(rgt, VariableConSS):
|
||||
return [SetTypeForConSSVariable(rgt, lft)]
|
||||
|
||||
if isinstance(lft, AppliedConNSS) and isinstance(rgt, AppliedConSSS):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if isinstance(lft, AppliedConNSS) and isinstance(rgt, AppliedConNSS):
|
||||
con_res = unify_con_nss(lft.con, rgt.con)
|
||||
if isinstance(con_res, Failure):
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
if lft.arg.value != rgt.arg.value:
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
return con_res
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def unify_con_sss(
|
||||
lft: ConcreteConSSS | VariableConSSS,
|
||||
rgt: ConcreteConSSS | VariableConSSS,
|
||||
) -> UnifyResult:
|
||||
"""
|
||||
Tries to unify the given two constuctors of kind * -> * -> *.
|
||||
"""
|
||||
if isinstance(lft, ConcreteConSSS) and isinstance(rgt, ConcreteConSSS):
|
||||
if lft == rgt:
|
||||
return []
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def unify_con_nss(
|
||||
lft: ConcreteConNSS | VariableConNSS,
|
||||
rgt: ConcreteConNSS | VariableConNSS,
|
||||
) -> UnifyResult:
|
||||
"""
|
||||
Tries to unify the given two constuctors of kind * -> * -> *.
|
||||
"""
|
||||
if isinstance(lft, ConcreteConNSS) and isinstance(rgt, ConcreteConNSS):
|
||||
if lft == rgt:
|
||||
return []
|
||||
return Failure(f'Cannot unify {lft.name} and {rgt.name}')
|
||||
|
||||
raise NotImplementedError
|
||||
0
tests/integration/test_type4/__init__.py
Normal file
0
tests/integration/test_type4/__init__.py
Normal file
115
tests/integration/test_type4/test_unify.py
Normal file
115
tests/integration/test_type4/test_unify.py
Normal file
@ -0,0 +1,115 @@
|
||||
from typing import Sequence
|
||||
|
||||
import pytest
|
||||
|
||||
from phasm.type4 import classes
|
||||
|
||||
from phasm.type4 import unify as sut
|
||||
|
||||
class TestNamespace:
|
||||
## Kind * (part 1)
|
||||
u32 = classes.Atomic('u32')
|
||||
f64 = classes.Atomic('f64')
|
||||
|
||||
a = classes.Variable('a')
|
||||
b = classes.Variable('b')
|
||||
|
||||
## Kind * -> *
|
||||
dynamic_array = classes.ConcreteConSS('dynamic_array')
|
||||
maybe = classes.ConcreteConSS('maybe')
|
||||
f = classes.VariableConSS('f')
|
||||
t = classes.VariableConSS('t')
|
||||
|
||||
## Kind * -> * -> *
|
||||
function = classes.ConcreteConSSS('function')
|
||||
either = classes.ConcreteConSSS('either')
|
||||
|
||||
## Kind Nat -> * -> *
|
||||
static_array = classes.ConcreteConNSS('static_array')
|
||||
|
||||
## Kind * -> * (part 2)
|
||||
function_u32 = classes.AppliedConSSS(function, u32)
|
||||
function_f64 = classes.AppliedConSSS(function, f64)
|
||||
either_u32 = classes.AppliedConSSS(either, u32)
|
||||
either_f64 = classes.AppliedConSSS(either, f64)
|
||||
static_array_4 = classes.AppliedConNSS(static_array, classes.Nat(4))
|
||||
static_array_8 = classes.AppliedConNSS(static_array, classes.Nat(8))
|
||||
|
||||
## Kind * (part 2)
|
||||
dynamic_array_u32 = classes.AppliedConSS(dynamic_array, u32)
|
||||
dynamic_array_f64 = classes.AppliedConSS(dynamic_array, f64)
|
||||
maybe_u32 = classes.AppliedConSS(maybe, u32)
|
||||
maybe_f64 = classes.AppliedConSS(maybe, f64)
|
||||
t_u32 = classes.AppliedConSS(t, u32)
|
||||
t_f64 = classes.AppliedConSS(t, f64)
|
||||
f_u32 = classes.AppliedConSS(f, u32)
|
||||
f_f64 = classes.AppliedConSS(f, f64)
|
||||
function_f64_u32 = classes.AppliedConSS(function_f64, u32)
|
||||
either_f64_u32 = classes.AppliedConSS(either_f64, u32)
|
||||
static_array_4_u32 = classes.AppliedConSS(static_array_4, u32)
|
||||
static_array_8_u32 = classes.AppliedConSS(static_array_8, u32)
|
||||
|
||||
TEST_LIST: list[tuple[classes.Type4, classes.Type4, sut.UnifyResult]] = [
|
||||
# Atomic / Atomic
|
||||
(u32, u32, []),
|
||||
(u32, f64, sut.Failure('Cannot unify u32 and f64')),
|
||||
# Atomic / Variable
|
||||
(u32, a, [sut.SetTypeForVariable(a, u32)]),
|
||||
# Atomic / AppliedConSS
|
||||
(u32, t_f64, sut.Failure('Cannot unify u32 and t f64')),
|
||||
|
||||
# Variable / Atomic
|
||||
(a, u32, [sut.SetTypeForVariable(a, u32)]),
|
||||
# Variable / Variable
|
||||
(a, b, [sut.ReplaceVariable(a, b)]),
|
||||
# Variable / AppliedConSS
|
||||
(a, t_f64, [sut.SetTypeForVariable(a, t_f64)]),
|
||||
|
||||
# AppliedConSS / Atomic
|
||||
(t_f64, u32, sut.Failure('Cannot unify t f64 and u32')),
|
||||
# AppliedConSS / Variable
|
||||
(t_f64, a, [sut.SetTypeForVariable(a, t_f64)]),
|
||||
|
||||
# AppliedConSS ConcreteConSS / AppliedConSS ConcreteConSS
|
||||
(dynamic_array_u32, dynamic_array_u32, []),
|
||||
(dynamic_array_u32, maybe_u32, sut.Failure('Cannot unify dynamic_array u32 and maybe u32')),
|
||||
# AppliedConSS ConcreteConSS / AppliedConSS VariableConSS
|
||||
(dynamic_array_u32, t_u32, [sut.SetTypeForConSSVariable(t, dynamic_array)]),
|
||||
# AppliedConSS ConcreteConSS / AppliedConSS AppliedConSSS
|
||||
(dynamic_array_u32, function_f64_u32, sut.Failure('Cannot unify dynamic_array u32 and function f64 u32')),
|
||||
# AppliedConSS ConcreteConSS / AppliedConSS AppliedConNSS
|
||||
(dynamic_array_u32, static_array_4_u32, sut.Failure('Cannot unify dynamic_array u32 and static_array 4 u32')),
|
||||
|
||||
# AppliedConSS VariableConSS / AppliedConSS ConcreteConSS
|
||||
(t_u32, dynamic_array_u32, [sut.SetTypeForConSSVariable(t, dynamic_array)]),
|
||||
# AppliedConSS VariableConSS / AppliedConSS VariableConSS
|
||||
(t_u32, f_u32, [sut.ReplaceConSSVariable(t, f)]),
|
||||
# AppliedConSS VariableConSS / AppliedConSS AppliedConSSS
|
||||
(t_u32, function_f64_u32, [sut.SetTypeForConSSVariable(t, function_f64)]),
|
||||
# AppliedConSS VariableConSS / AppliedConSS AppliedConNSS
|
||||
(t_u32, static_array_4_u32, [sut.SetTypeForConSSVariable(t, static_array_4)]),
|
||||
|
||||
# AppliedConSS AppliedConSSS / AppliedConSS ConcreteConSS
|
||||
(function_f64_u32, dynamic_array_u32, sut.Failure('Cannot unify function f64 u32 and dynamic_array u32')),
|
||||
# AppliedConSS AppliedConSSS / AppliedConSS VariableConSS
|
||||
(function_f64_u32, t_u32, [sut.SetTypeForConSSVariable(t, function_f64)]),
|
||||
# AppliedConSS AppliedConSSS / AppliedConSS AppliedConSSS
|
||||
# (function_f64_u32, function_f64_u32, []),
|
||||
(function_f64_u32, either_f64_u32, sut.Failure('Cannot unify function f64 u32 and either f64 u32')),
|
||||
# AppliedConSS AppliedConSSS / AppliedConSS AppliedConNSS
|
||||
(function_f64_u32, static_array_4_u32, sut.Failure('Cannot unify function f64 u32 and static_array 4 u32')),
|
||||
|
||||
# AppliedConSS AppliedConNSS / AppliedConSS ConcreteConSS
|
||||
(static_array_4_u32, dynamic_array_u32, sut.Failure('Cannot unify static_array 4 u32 and dynamic_array u32')),
|
||||
# AppliedConSS AppliedConNSS / AppliedConSS VariableConSS
|
||||
(static_array_4_u32, t_u32, [sut.SetTypeForConSSVariable(t, static_array_4)]),
|
||||
# AppliedConSS AppliedConNSS / AppliedConSS AppliedConSSS
|
||||
(static_array_4_u32, function_f64_u32, sut.Failure('Cannot unify static_array 4 u32 and function f64 u32')),
|
||||
# AppliedConSS AppliedConNSS / AppliedConSS AppliedConNSS
|
||||
(static_array_4_u32, static_array_4_u32, []),
|
||||
(static_array_4_u32, static_array_8_u32, sut.Failure('Cannot unify static_array 4 u32 and static_array 8 u32')),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize('lft,rgt,exp_out', TestNamespace.TEST_LIST)
|
||||
def test_unify(lft: classes.Type4, rgt: classes.Type4, exp_out: sut.UnifyResult) -> None:
|
||||
assert exp_out == sut.unify(lft, rgt)
|
||||
Loading…
x
Reference in New Issue
Block a user