added typedefs and type_env
This commit is contained in:
@@ -2,6 +2,7 @@ import sys
|
|||||||
from typing import List
|
from typing import List
|
||||||
from boring.parse import boring_parser, TreeToBoring, pretty_print
|
from boring.parse import boring_parser, TreeToBoring, pretty_print
|
||||||
from boring.type_checking import TypeChecker
|
from boring.type_checking import TypeChecker
|
||||||
|
from boring import typedefs
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with open(sys.argv[1]) as f:
|
with open(sys.argv[1]) as f:
|
||||||
@@ -10,7 +11,7 @@ if __name__ == "__main__":
|
|||||||
result = TreeToBoring().transform(tree)
|
result = TreeToBoring().transform(tree)
|
||||||
# pretty_print(result)
|
# pretty_print(result)
|
||||||
type_checker = TypeChecker()
|
type_checker = TypeChecker()
|
||||||
while type_checker.with_module({}, result):
|
while type_checker.with_module({}, typedefs.builtins, result):
|
||||||
print("loop")
|
print("loop")
|
||||||
# type_checker.with_module({}, result)
|
# type_checker.with_module({}, result)
|
||||||
pretty_print(result)
|
pretty_print(result)
|
||||||
|
|||||||
@@ -2,21 +2,22 @@ from dataclasses import dataclass
|
|||||||
from typing import List, Dict, Optional, Union
|
from typing import List, Dict, Optional, Union
|
||||||
|
|
||||||
|
|
||||||
from boring import parse
|
from boring import parse, typedefs
|
||||||
|
|
||||||
|
|
||||||
Identified = Union[parse.LetStatement, parse.Function, parse.VariableDeclaration]
|
Identified = Union[parse.LetStatement, parse.Function, parse.VariableDeclaration]
|
||||||
Environment = Dict[str, Identified]
|
Environment = Dict[str, Identified]
|
||||||
|
TypeEnvironment = Dict[str, typedefs.TypeDef]
|
||||||
|
|
||||||
|
|
||||||
def unify(first, second) -> bool:
|
def unify(type_env: TypeEnvironment, first, second) -> bool:
|
||||||
result, changed = type_compare(first.type, second.type)
|
result, changed = type_compare(type_env, first.type, second.type)
|
||||||
first.type = result
|
first.type = result
|
||||||
second.type = result
|
second.type = result
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def type_compare(first, second) -> (parse.TypeUsage, bool):
|
def type_compare(type_env: TypeEnvironment, first, second) -> (parse.TypeUsage, bool):
|
||||||
print(first, second)
|
print(first, second)
|
||||||
if isinstance(first, parse.UnknownTypeUsage):
|
if isinstance(first, parse.UnknownTypeUsage):
|
||||||
if not isinstance(second, parse.UnknownTypeUsage):
|
if not isinstance(second, parse.UnknownTypeUsage):
|
||||||
@@ -31,18 +32,20 @@ def type_compare(first, second) -> (parse.TypeUsage, bool):
|
|||||||
second, parse.DataTypeUsage
|
second, parse.DataTypeUsage
|
||||||
):
|
):
|
||||||
assert second == first
|
assert second == first
|
||||||
|
assert first.name in type_env
|
||||||
|
assert second.name in type_env
|
||||||
return first, False
|
return first, False
|
||||||
elif isinstance(first, parse.FunctionTypeUsage) and isinstance(
|
elif isinstance(first, parse.FunctionTypeUsage) and isinstance(
|
||||||
second, parse.FunctionTypeUsage
|
second, parse.FunctionTypeUsage
|
||||||
):
|
):
|
||||||
return_type, changed = type_compare(
|
return_type, changed = type_compare(
|
||||||
first.return_type, second.return_type
|
type_env, first.return_type, second.return_type
|
||||||
)
|
)
|
||||||
arguments = []
|
arguments = []
|
||||||
assert len(first.arguments) == len(second.arguments)
|
assert len(first.arguments) == len(second.arguments)
|
||||||
for first_arg, second_arg in zip(first.arguments, second.arguments):
|
for first_arg, second_arg in zip(first.arguments, second.arguments):
|
||||||
argument_type, argument_changed = type_compare(
|
argument_type, argument_changed = type_compare(
|
||||||
first_arg, second_arg
|
type_env, first_arg, second_arg
|
||||||
)
|
)
|
||||||
arguments.append(argument_type)
|
arguments.append(argument_type)
|
||||||
if argument_changed:
|
if argument_changed:
|
||||||
@@ -53,31 +56,31 @@ def type_compare(first, second) -> (parse.TypeUsage, bool):
|
|||||||
|
|
||||||
|
|
||||||
class TypeChecker:
|
class TypeChecker:
|
||||||
def with_module(self, env: Environment, module: parse.Module) -> bool:
|
def with_module(self, env: Environment, type_env: TypeEnvironment, module: parse.Module) -> bool:
|
||||||
for function in module.functions:
|
for function in module.functions:
|
||||||
env[function.name] = function
|
env[function.name] = function
|
||||||
found = False
|
found = False
|
||||||
for function in module.functions:
|
for function in module.functions:
|
||||||
if self.with_function(env, function):
|
if self.with_function(env, type_env, function):
|
||||||
found = True
|
found = True
|
||||||
return found
|
return found
|
||||||
|
|
||||||
def with_function(self, env: Environment, function: parse.Function) -> bool:
|
def with_function(self, env: Environment, type_env: TypeEnvironment, function: parse.Function) -> bool:
|
||||||
function_env = env.copy()
|
function_env = env.copy()
|
||||||
for argument in function.arguments:
|
for argument in function.arguments:
|
||||||
function_env[argument.name] = argument
|
function_env[argument.name] = argument
|
||||||
assert isinstance(function.type, parse.FunctionTypeUsage)
|
assert isinstance(function.type, parse.FunctionTypeUsage)
|
||||||
|
|
||||||
type, changed = type_compare(function.block.type, function.type.return_type)
|
type, changed = type_compare(type_env, function.block.type, function.type.return_type)
|
||||||
function.block.type = type
|
function.block.type = type
|
||||||
function.type.return_type = type
|
function.type.return_type = type
|
||||||
if self.with_block(function_env, function.block):
|
if self.with_block(function_env, type_env, function.block):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
# Skip variable VariableDeclaration
|
# Skip variable VariableDeclaration
|
||||||
|
|
||||||
def with_block(self, env: Environment, block: parse.Block) -> bool:
|
def with_block(self, env: Environment, type_env: TypeEnvironment, block: parse.Block) -> bool:
|
||||||
block_env = env.copy()
|
block_env = env.copy()
|
||||||
# if parent is void, must be statement
|
# if parent is void, must be statement
|
||||||
# if parent is type, must be expression
|
# if parent is type, must be expression
|
||||||
@@ -94,74 +97,73 @@ class TypeChecker:
|
|||||||
name=parse.Identifier(name=parse.UNIT_TYPE)
|
name=parse.Identifier(name=parse.UNIT_TYPE)
|
||||||
)
|
)
|
||||||
elif isinstance(final, parse.Expression):
|
elif isinstance(final, parse.Expression):
|
||||||
if unify(final, block):
|
if unify(type_env, final, block):
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
for statement in block.statements:
|
for statement in block.statements:
|
||||||
if self.with_statement(block_env, statement):
|
if self.with_statement(block_env, type_env, statement):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def with_statement(self, env: Environment, statement: parse.Statement) -> bool:
|
def with_statement(self, env: Environment, type_env: TypeEnvironment, statement: parse.Statement) -> bool:
|
||||||
if isinstance(statement, parse.LetStatement):
|
if isinstance(statement, parse.LetStatement):
|
||||||
return self.with_let_statement(env, statement)
|
return self.with_let_statement(env, type_env, statement)
|
||||||
elif isinstance(statement, parse.Expression): # expression
|
elif isinstance(statement, parse.Expression): # expression
|
||||||
return self.with_expression(env, statement)
|
return self.with_expression(env, type_env, statement)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def with_let_statement(
|
def with_let_statement(
|
||||||
self, env: Environment, let_statement: parse.LetStatement
|
self, env: Environment, type_env: TypeEnvironment, let_statement: parse.LetStatement
|
||||||
) -> bool:
|
) -> bool:
|
||||||
found = False
|
found = False
|
||||||
env[let_statement.variable_name] = let_statement
|
env[let_statement.variable_name] = let_statement
|
||||||
changed = unify(let_statement, let_statement.expression)
|
changed = unify(type_env, let_statement, let_statement.expression)
|
||||||
if self.with_expression(env, let_statement.expression):
|
if self.with_expression(env, type_env, let_statement.expression):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def with_expression(self, env: Environment, expression: parse.Expression) -> bool:
|
def with_expression(self, env: Environment, type_env: TypeEnvironment, expression: parse.Expression) -> bool:
|
||||||
subexpression = expression.expression
|
subexpression = expression.expression
|
||||||
changed = unify(subexpression, expression)
|
changed = unify(type_env, subexpression, expression)
|
||||||
|
|
||||||
if isinstance(subexpression, parse.LiteralInt):
|
if isinstance(subexpression, parse.LiteralInt):
|
||||||
print(f"fooooo {expression.type}, {subexpression.type}")
|
if self.with_literal_int(env, type_env, subexpression):
|
||||||
if self.with_literal_int(env, subexpression):
|
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
if isinstance(subexpression, parse.FunctionCall):
|
if isinstance(subexpression, parse.FunctionCall):
|
||||||
if self.with_function_call(env, subexpression):
|
if self.with_function_call(env, type_env, subexpression):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
if isinstance(subexpression, parse.VariableUsage):
|
if isinstance(subexpression, parse.VariableUsage):
|
||||||
if self.with_variable_usage(env, subexpression):
|
if self.with_variable_usage(env, type_env, subexpression):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
if isinstance(subexpression, parse.Operation):
|
if isinstance(subexpression, parse.Operation):
|
||||||
if self.with_operation(env, subexpression):
|
if self.with_operation(env, type_env, subexpression):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def with_variable_usage(
|
def with_variable_usage(
|
||||||
self, env: Environment, variable_usage: parse.VariableUsage
|
self, env: Environment, type_env: TypeEnvironment, variable_usage: parse.VariableUsage
|
||||||
) -> bool:
|
) -> bool:
|
||||||
return unify(variable_usage, env[variable_usage.name])
|
return unify(type_env, variable_usage, env[variable_usage.name])
|
||||||
|
|
||||||
def with_operation(self, env: Environment, operation: parse.Operation) -> bool:
|
def with_operation(self, env: Environment, type_env: TypeEnvironment, operation: parse.Operation) -> bool:
|
||||||
changed = False
|
changed = False
|
||||||
if unify(operation, operation.left):
|
if unify(type_env, operation, operation.left):
|
||||||
changed = True
|
changed = True
|
||||||
if unify(operation, operation.right):
|
if unify(type_env, operation, operation.right):
|
||||||
changed = True
|
changed = True
|
||||||
if self.with_expression(env, operation.left):
|
if self.with_expression(env, type_env, operation.left):
|
||||||
changed = True
|
changed = True
|
||||||
if self.with_expression(env, operation.right):
|
if self.with_expression(env, type_env, operation.right):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def with_function_call(
|
def with_function_call(
|
||||||
self, env: Environment, function_call: parse.FunctionCall
|
self, env: Environment, type_env: TypeEnvironment, function_call: parse.FunctionCall
|
||||||
) -> bool:
|
) -> bool:
|
||||||
changed = False
|
changed = False
|
||||||
if isinstance(function_call.source.type, parse.UnknownTypeUsage):
|
if isinstance(function_call.source.type, parse.UnknownTypeUsage):
|
||||||
@@ -170,14 +172,14 @@ class TypeChecker:
|
|||||||
return_type=parse.UnknownTypeUsage(),
|
return_type=parse.UnknownTypeUsage(),
|
||||||
)
|
)
|
||||||
changed = True
|
changed = True
|
||||||
if self.with_expression(env, function_call.source):
|
if self.with_expression(env, type_env, function_call.source):
|
||||||
changed = True
|
changed = True
|
||||||
for argument in function_call.arguments:
|
for argument in function_call.arguments:
|
||||||
if self.with_expression(env, argument):
|
if self.with_expression(env, type_env, argument):
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
return_type, return_changed = type_compare(
|
return_type, return_changed = type_compare(
|
||||||
function_call.type, function_call.source.type.return_type
|
type_env, function_call.type, function_call.source.type.return_type
|
||||||
)
|
)
|
||||||
function_call.type = return_type
|
function_call.type = return_type
|
||||||
function_call.source.type.return_type = return_type
|
function_call.source.type.return_type = return_type
|
||||||
@@ -188,7 +190,7 @@ class TypeChecker:
|
|||||||
function_call.arguments, function_call.source.type.arguments
|
function_call.arguments, function_call.source.type.arguments
|
||||||
):
|
):
|
||||||
argument_out_type, argument_changed = type_compare(
|
argument_out_type, argument_changed = type_compare(
|
||||||
argument.type, function_call.source.type.return_type
|
type_env, argument.type, function_call.source.type.return_type
|
||||||
)
|
)
|
||||||
argument.type = argument_out_type
|
argument.type = argument_out_type
|
||||||
function_call.source.type.return_type = argument_out_type
|
function_call.source.type.return_type = argument_out_type
|
||||||
@@ -196,7 +198,7 @@ class TypeChecker:
|
|||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def with_literal_int(self, env: Environment, literal_int: parse.LiteralInt) -> bool:
|
def with_literal_int(self, env: Environment, type_env: TypeEnvironment, literal_int: parse.LiteralInt) -> bool:
|
||||||
ints = [
|
ints = [
|
||||||
parse.DataTypeUsage(name=name)
|
parse.DataTypeUsage(name=name)
|
||||||
for name in ["I8", "I16", "I32", "I64", "I128"]
|
for name in ["I8", "I16", "I32", "I64", "I128"]
|
||||||
|
|||||||
74
boring/typedefs.py
Normal file
74
boring/typedefs.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from dataclasses import dataclass, field
|
||||||
|
import enum
|
||||||
|
from typing import List, Dict, Optional, Union
|
||||||
|
|
||||||
|
|
||||||
|
class IntBitness(enum.Enum):
|
||||||
|
X8 = 'X8'
|
||||||
|
X16 = 'X16'
|
||||||
|
X32 = 'X32'
|
||||||
|
X64 = 'X64'
|
||||||
|
X128 = 'X128'
|
||||||
|
|
||||||
|
|
||||||
|
class Signedness(enum.Enum):
|
||||||
|
Signed = 'Signed'
|
||||||
|
Unsigned = 'Unsigned'
|
||||||
|
|
||||||
|
|
||||||
|
class FloatBitness(enum.Enum):
|
||||||
|
X32 = 'X32'
|
||||||
|
X64 = 'X64'
|
||||||
|
X128 = 'X128'
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class IntTypeDef:
|
||||||
|
signedness: Signedness
|
||||||
|
bitness: IntBitness
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FloatTypeDef:
|
||||||
|
bitness: FloatBitness
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FunctionTypeDef:
|
||||||
|
arguments: List["TypeDef"]
|
||||||
|
return_type: "TypeDef"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UnitTypeDef:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NeverTypeDef:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
TypeDef = Union[IntTypeDef, FloatTypeDef, FunctionTypeDef, UnitTypeDef, NeverTypeDef]
|
||||||
|
|
||||||
|
|
||||||
|
builtins: Dict[str, TypeDef] = {
|
||||||
|
'U8': IntTypeDef(Signedness.Unsigned, IntBitness.X8),
|
||||||
|
'U16': IntTypeDef(Signedness.Unsigned, IntBitness.X16),
|
||||||
|
'U32': IntTypeDef(Signedness.Unsigned, IntBitness.X32),
|
||||||
|
'U64': IntTypeDef(Signedness.Unsigned, IntBitness.X64),
|
||||||
|
'U128': IntTypeDef(Signedness.Unsigned, IntBitness.X128),
|
||||||
|
|
||||||
|
'I8': IntTypeDef(Signedness.Signed, IntBitness.X8),
|
||||||
|
'I16': IntTypeDef(Signedness.Signed, IntBitness.X16),
|
||||||
|
'I32': IntTypeDef(Signedness.Signed, IntBitness.X32),
|
||||||
|
'I64': IntTypeDef(Signedness.Signed, IntBitness.X64),
|
||||||
|
'I128': IntTypeDef(Signedness.Signed, IntBitness.X128),
|
||||||
|
|
||||||
|
'F32': FloatTypeDef(FloatBitness.X32),
|
||||||
|
'F64': FloatTypeDef(FloatBitness.X64),
|
||||||
|
'F128': FloatTypeDef(FloatBitness.X128),
|
||||||
|
|
||||||
|
'()': UnitTypeDef(),
|
||||||
|
'!': NeverTypeDef(),
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user