From 54641798833071da9686f3c65310dcd829afe11e Mon Sep 17 00:00:00 2001 From: Andrew Segavac Date: Sat, 12 Jun 2021 12:26:53 -0600 Subject: [PATCH] added struct getters --- boring/parse.py | 20 +++++++++++++++++--- boring/type_checking.py | 34 +++++++++++++++++++++++++++++++--- examples/math/main.bl | 11 ++++++++--- notes.txt | 6 +++--- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/boring/parse.py b/boring/parse.py index 12673e9..4bcbf10 100644 --- a/boring/parse.py +++ b/boring/parse.py @@ -31,9 +31,7 @@ NEVER_TYPE = "!" @dataclass class FunctionTypeUsage: - arguments: List[ - "TypeUsage" - ] + arguments: List["TypeUsage"] return_type: "TypeUsage" @@ -68,6 +66,7 @@ class LiteralFloat: value: float type: TypeUsage + @dataclass class LiteralStruct: name: str @@ -82,6 +81,13 @@ class FunctionCall: type: TypeUsage +@dataclass +class StructGetter: + source: "Expression" + attribute: str + type: TypeUsage + + @dataclass class Operation: left: "Expression" @@ -109,6 +115,7 @@ class Expression: LiteralFloat, LiteralStruct, FunctionCall, + StructGetter, "Block", ReturnStatement, VariableUsage, @@ -190,6 +197,8 @@ boring_grammar = r""" function_call : expression "(" [expression ("," expression)*] ")" + struct_getter : expression "." identifier + add_expression : expression plus factor sub_expression : expression minus factor mult_expression : expression mult term @@ -212,6 +221,7 @@ boring_grammar = r""" | literal_struct | variable_usage | function_call + | struct_getter | "(" expression ")" | block @@ -317,6 +327,10 @@ class TreeToBoring(Transformer): def function_call(self, call) -> FunctionCall: return FunctionCall(source=call[0], arguments=call[1:], type=UnknownTypeUsage()) + def struct_getter(self, getter) -> StructGetter: + expression, attribute = getter + return StructGetter(expression, attribute, UnknownTypeUsage()) + def add_expression(self, ae) -> Operation: return Operation(left=ae[0], op=ae[1], right=ae[2], type=UnknownTypeUsage()) diff --git a/boring/type_checking.py b/boring/type_checking.py index 70c6dcf..9925a91 100644 --- a/boring/type_checking.py +++ b/boring/type_checking.py @@ -28,7 +28,9 @@ def unify(ctx: Context, first, second) -> bool: return changed -def type_compare(ctx: Context, first: parse.TypeUsage, second: parse.TypeUsage) -> Tuple[parse.TypeUsage, bool]: +def type_compare( + ctx: Context, first: parse.TypeUsage, second: parse.TypeUsage +) -> Tuple[parse.TypeUsage, bool]: print(first, second) if isinstance(first, parse.UnknownTypeUsage): if not isinstance(second, parse.UnknownTypeUsage): @@ -84,6 +86,7 @@ def assert_exists(ctx: Context, type: parse.TypeUsage): for argument in type.arguments: assert_exists(ctx, argument) + class TypeChecker: def with_module(self, ctx: Context, module: parse.Module) -> bool: for type_declaration in module.types: @@ -234,6 +237,11 @@ class TypeChecker: if unify(ctx, subexpression, expression): changed = True return changed + if isinstance(subexpression, parse.StructGetter): + changed = self.with_struct_getter(ctx, subexpression) + if unify(ctx, subexpression, expression): + changed = True + return changed if isinstance(subexpression, parse.Block): changed = self.with_block(ctx, subexpression) if unify(ctx, subexpression, expression): @@ -305,6 +313,22 @@ class TypeChecker: changed = True return changed + def with_struct_getter( + self, ctx: Context, struct_getter: parse.StructGetter + ) -> bool: + changed = self.with_expression(ctx, struct_getter.source) + assert isinstance(struct_getter.source.type, parse.DataTypeUsage) + struct_declaration = ctx.environment[struct_getter.source.type.name] + assert isinstance(struct_declaration, parse.StructTypeDeclaration) + assert struct_getter.attribute in struct_declaration.fields + result_type, changed_getter = type_compare( + ctx, struct_getter.type, struct_declaration.fields[struct_getter.attribute] + ) + if changed_getter: + changed = True + struct_getter.type = result_type + return changed + def with_literal_float( self, ctx: Context, literal_float: parse.LiteralFloat ) -> bool: @@ -321,7 +345,9 @@ class TypeChecker: assert literal_int.type.name in ints, f"{literal_int.type}" return False - def with_literal_struct(self, ctx: Context, literal_struct: parse.LiteralStruct) -> bool: + def with_literal_struct( + self, ctx: Context, literal_struct: parse.LiteralStruct + ) -> bool: assert literal_struct.name in ctx.environment struct_declaration = ctx.environment[literal_struct.name] assert isinstance(struct_declaration, parse.StructTypeDeclaration) @@ -330,7 +356,9 @@ class TypeChecker: assert name in literal_struct.fields if self.with_expression(ctx, literal_struct.fields[name]): changed = True - result_type, field_changed = type_compare(ctx, field_type, literal_struct.fields[name].type) + result_type, field_changed = type_compare( + ctx, field_type, literal_struct.fields[name].type + ) if field_changed: literal_struct.fields[name].type = result_type changed = True diff --git a/examples/math/main.bl b/examples/math/main.bl index 760d008..eda8937 100644 --- a/examples/math/main.bl +++ b/examples/math/main.bl @@ -28,17 +28,22 @@ fn unit_function() { let a: I32 = 4; } +fn main(): I32 { + add(4, subtract(5, 2)) +} + + fn returns_user(): User { return User{ id: 4, }; } -fn main(): I32 { - add(4, subtract(5, 2)) +fn get_user_id(): U64 { + let user = returns_user(); + return user.id; } - type User struct { id: U64, } diff --git a/notes.txt b/notes.txt index 35577a6..de5ca01 100644 --- a/notes.txt +++ b/notes.txt @@ -40,12 +40,12 @@ TODO: * Structs * ~Define~ * ~Literal~ - * Getter + * ~Getter~ * Setter -* Generics -* Enums * Methods * Traits +* Generics +* Enums * Arrays * Strings * Lambdas