From 421a5160fd38248a4d5a337741586f48b6f255d6 Mon Sep 17 00:00:00 2001 From: Andrew Segavac Date: Sat, 12 Jun 2021 10:59:58 -0600 Subject: [PATCH] added struct literals --- boring/parse.py | 22 +++++++++++++++++++++- boring/type_checking.py | 20 ++++++++++++++++++++ examples/math/main.bl | 6 ++++++ notes.txt | 2 +- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/boring/parse.py b/boring/parse.py index 96f41ee..12673e9 100644 --- a/boring/parse.py +++ b/boring/parse.py @@ -68,6 +68,12 @@ class LiteralFloat: value: float type: TypeUsage +@dataclass +class LiteralStruct: + name: str + fields: Dict[str, "Expression"] + type: TypeUsage + @dataclass class FunctionCall: @@ -101,6 +107,7 @@ class Expression: expression: Union[ LiteralInt, LiteralFloat, + LiteralStruct, FunctionCall, "Block", ReturnStatement, @@ -174,9 +181,12 @@ boring_grammar = r""" mult : "*" div : "/" + identifier : CNAME literal_float : SIGNED_FLOAT literal_int : SIGNED_INT - identifier : CNAME + + literal_struct_field : identifier ":" expression + literal_struct : identifier "{" (literal_struct_field ",")* "}" function_call : expression "(" [expression ("," expression)*] ")" @@ -199,6 +209,7 @@ boring_grammar = r""" term : literal_int | literal_float + | literal_struct | variable_usage | function_call | "(" expression ")" @@ -280,6 +291,15 @@ class TreeToBoring(Transformer): (f,) = f return LiteralFloat(value=float(f), type=UnknownTypeUsage()) + def literal_struct_field(self, lsf): + (name, expression) = lsf + return name, expression + + def literal_struct(self, literal_struct) -> LiteralStruct: + name = literal_struct[0] + fields = {key: value for (key, value) in literal_struct[1:]} + return LiteralStruct(name=name, fields=fields, type=DataTypeUsage(name=name)) + def identifier(self, i) -> str: (i,) = i return str(i) diff --git a/boring/type_checking.py b/boring/type_checking.py index ce2f1d1..70c6dcf 100644 --- a/boring/type_checking.py +++ b/boring/type_checking.py @@ -224,6 +224,11 @@ class TypeChecker: if unify(ctx, subexpression, expression): changed = True return changed + if isinstance(subexpression, parse.LiteralStruct): + changed = self.with_literal_struct(ctx, subexpression) + if unify(ctx, subexpression, expression): + changed = True + return changed if isinstance(subexpression, parse.FunctionCall): changed = self.with_function_call(ctx, subexpression) if unify(ctx, subexpression, expression): @@ -315,3 +320,18 @@ class TypeChecker: assert isinstance(literal_int.type, parse.DataTypeUsage) 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: + assert literal_struct.name in ctx.environment + struct_declaration = ctx.environment[literal_struct.name] + assert isinstance(struct_declaration, parse.StructTypeDeclaration) + changed = False + for name, field_type in struct_declaration.fields.items(): + 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) + if field_changed: + literal_struct.fields[name].type = result_type + changed = True + return changed diff --git a/examples/math/main.bl b/examples/math/main.bl index 294f0fa..760d008 100644 --- a/examples/math/main.bl +++ b/examples/math/main.bl @@ -28,6 +28,12 @@ fn unit_function() { let a: I32 = 4; } +fn returns_user(): User { + return User{ + id: 4, + }; +} + fn main(): I32 { add(4, subtract(5, 2)) } diff --git a/notes.txt b/notes.txt index e46db68..35577a6 100644 --- a/notes.txt +++ b/notes.txt @@ -39,7 +39,7 @@ TODO: * ~Normal assignment~ * Structs * ~Define~ - * Literal + * ~Literal~ * Getter * Setter * Generics