From 3884422afbd227f708493dcc1e7704f0089c0584 Mon Sep 17 00:00:00 2001 From: Gwendolyn Date: Sat, 12 Feb 2022 18:30:04 +0100 Subject: [PATCH] parser mostly done I hope --- README.md | 85 ++-- compiler/example.mew | 37 +- parser/ArrayAccessExpressionModel.cs | 4 + parser/ArrayConstructorExpressionModel.cs | 4 + parser/ArrayTypeModel.cs | 3 + parser/AssignmentExpressionModel.cs | 4 + parser/AssignmentOperator.cs | 16 + parser/AssignmentOperatorExtensions.cs | 34 ++ parser/AttributeModel.cs | 3 + parser/AttributeValueModel.cs | 3 + parser/AttributeValueVisitorNya.cs | 17 + parser/AttributeVisitorNya.cs | 13 + parser/BinaryOperationExpressionModel.cs | 4 + parser/BinaryOperator.cs | 24 ++ parser/BinaryOperatorExtensions.cs | 50 +++ parser/BlockExpressionModel.cs | 3 + parser/BoolLiteralModel.cs | 3 + parser/BreakStatementModel.cs | 3 + parser/CharacterLiteralModel.cs | 3 + parser/ConstantDeclarationStatementModel.cs | 4 + parser/ConstraintModel.cs | 3 + parser/ConstraintRuleModel.cs | 3 + parser/ConstraintRuleVisitorNya.cs | 24 ++ parser/ConstraintTopLevelConstructModel.cs | 4 + parser/ContinueStatementModel.cs | 3 + parser/DeclarationVisitorNya.cs | 101 +++++ parser/EmbedConstraintRuleModel.cs | 4 + parser/EnumConstructorExpressionModel.cs | 3 + parser/EnumMemberModel.cs | 3 + parser/EnumMemberVisitorNya.cs | 20 + parser/EnumTopLevelConstructModel.cs | 4 + parser/EnumTypeModel.cs | 3 + parser/ExpressionModel.cs | 3 + parser/ExpressionStatementModel.cs | 3 + parser/ExpressionVisitorNya.cs | 255 ++++++++++++ parser/ForLoopStatementModel.cs | 5 + parser/FunctionCallExpressionModel.cs | 4 + parser/FunctionConstraintRuleModel.cs | 4 + parser/FunctionConstraintVisitorNya.cs | 13 + parser/FunctionModel.cs | 5 + parser/FunctionParameterModel.cs | 3 + parser/FunctionParameterVisitorNya.cs | 13 + parser/IdentifierAttributeValueModel.cs | 3 + parser/IdentifierNameModel.cs | 3 + parser/IdentifierNameVisitorNya.cs | 13 + parser/IfExpressionModel.cs | 5 + parser/ImportModel.cs | 3 + parser/ImportVisitorNya.cs | 50 +++ parser/InfiniteLoopStatementModel.cs | 3 + parser/InvalidEscapeSequenceException.cs | 8 + parser/InvalidImportPathException.cs | 10 + parser/InvalidStructAccessorException.cs | 10 + parser/LiteralAttributeValueModel.cs | 3 + parser/LiteralExpressionModel.cs | 3 + parser/LiteralModel.cs | 3 + parser/LiteralVisitorNya.cs | 30 ++ parser/LoopStatementModel.cs | 3 + parser/Meow.g4 | 292 ++++++++++---- parser/MeowVisitorException.cs | 13 + parser/Model.cs | 3 + parser/ModelBase.cs | 2 +- parser/NameExpressionModel.cs | 3 + parser/NumericLiteralModel.cs | 3 + parser/ParenthesisExpressionModel.cs | 3 + parser/Parser.cs | 5 +- parser/PatternModel.cs | 3 + parser/PointerDereferenceExpressionModel.cs | 3 + parser/PointerReferenceExpressionModel.cs | 3 + parser/PointerTypeReferenceModel.cs | 3 + parser/ReturnStatementModel.cs | 3 + parser/SliceTypeModel.cs | 3 + parser/StatementModel.cs | 3 + parser/StatementVisitorNya.cs | 83 ++++ parser/StringLiteralModel.cs | 3 + parser/StructAccessExpressionModel.cs | 3 + parser/StructConstructorExpressionModel.cs | 4 + parser/StructConstructorMemberModel.cs | 3 + parser/StructMemberModel.cs | 3 + parser/StructMemberVisitorNya.cs | 13 + parser/StructTopLevelConstructModel.cs | 4 + parser/StructTypeModel.cs | 3 + parser/SwitchExpressionModel.cs | 4 + parser/TopLevelConstructModel.cs | 3 + parser/TopLevelStatementModel.cs | 3 + parser/TupleConstructorExpressionModel.cs | 3 + parser/TupleTopLevelConstructModel.cs | 4 + parser/TupleTypeModel.cs | 3 + parser/TypeAliasModel.cs | 5 + parser/TypeNameModel.cs | 4 + parser/TypeParameterModel.cs | 3 + parser/TypeReferenceModel.cs | 3 + parser/TypeReferenceVisitorNya.cs | 54 +++ parser/UnaryOperationExpressionModel.cs | 4 + parser/UnaryOperator.cs | 8 + parser/UnaryOperatorExtensions.cs | 18 + parser/Utils.cs | 7 + parser/VariableDeclarationStatementModel.cs | 4 + parser/Visitor.cs | 412 -------------------- parser/VisitorNya.cs | 17 + parser/WhileLoopStatementModel.cs | 4 + 100 files changed, 1448 insertions(+), 529 deletions(-) create mode 100644 parser/ArrayAccessExpressionModel.cs create mode 100644 parser/ArrayConstructorExpressionModel.cs create mode 100644 parser/ArrayTypeModel.cs create mode 100644 parser/AssignmentExpressionModel.cs create mode 100644 parser/AssignmentOperator.cs create mode 100644 parser/AssignmentOperatorExtensions.cs create mode 100644 parser/AttributeModel.cs create mode 100644 parser/AttributeValueModel.cs create mode 100644 parser/AttributeValueVisitorNya.cs create mode 100644 parser/AttributeVisitorNya.cs create mode 100644 parser/BinaryOperationExpressionModel.cs create mode 100644 parser/BinaryOperator.cs create mode 100644 parser/BinaryOperatorExtensions.cs create mode 100644 parser/BlockExpressionModel.cs create mode 100644 parser/BoolLiteralModel.cs create mode 100644 parser/BreakStatementModel.cs create mode 100644 parser/CharacterLiteralModel.cs create mode 100644 parser/ConstantDeclarationStatementModel.cs create mode 100644 parser/ConstraintModel.cs create mode 100644 parser/ConstraintRuleModel.cs create mode 100644 parser/ConstraintRuleVisitorNya.cs create mode 100644 parser/ConstraintTopLevelConstructModel.cs create mode 100644 parser/ContinueStatementModel.cs create mode 100644 parser/DeclarationVisitorNya.cs create mode 100644 parser/EmbedConstraintRuleModel.cs create mode 100644 parser/EnumConstructorExpressionModel.cs create mode 100644 parser/EnumMemberModel.cs create mode 100644 parser/EnumMemberVisitorNya.cs create mode 100644 parser/EnumTopLevelConstructModel.cs create mode 100644 parser/EnumTypeModel.cs create mode 100644 parser/ExpressionModel.cs create mode 100644 parser/ExpressionStatementModel.cs create mode 100644 parser/ExpressionVisitorNya.cs create mode 100644 parser/ForLoopStatementModel.cs create mode 100644 parser/FunctionCallExpressionModel.cs create mode 100644 parser/FunctionConstraintRuleModel.cs create mode 100644 parser/FunctionConstraintVisitorNya.cs create mode 100644 parser/FunctionModel.cs create mode 100644 parser/FunctionParameterModel.cs create mode 100644 parser/FunctionParameterVisitorNya.cs create mode 100644 parser/IdentifierAttributeValueModel.cs create mode 100644 parser/IdentifierNameModel.cs create mode 100644 parser/IdentifierNameVisitorNya.cs create mode 100644 parser/IfExpressionModel.cs create mode 100644 parser/ImportModel.cs create mode 100644 parser/ImportVisitorNya.cs create mode 100644 parser/InfiniteLoopStatementModel.cs create mode 100644 parser/InvalidEscapeSequenceException.cs create mode 100644 parser/InvalidImportPathException.cs create mode 100644 parser/InvalidStructAccessorException.cs create mode 100644 parser/LiteralAttributeValueModel.cs create mode 100644 parser/LiteralExpressionModel.cs create mode 100644 parser/LiteralModel.cs create mode 100644 parser/LiteralVisitorNya.cs create mode 100644 parser/LoopStatementModel.cs create mode 100644 parser/MeowVisitorException.cs create mode 100644 parser/Model.cs create mode 100644 parser/NameExpressionModel.cs create mode 100644 parser/NumericLiteralModel.cs create mode 100644 parser/ParenthesisExpressionModel.cs create mode 100644 parser/PatternModel.cs create mode 100644 parser/PointerDereferenceExpressionModel.cs create mode 100644 parser/PointerReferenceExpressionModel.cs create mode 100644 parser/PointerTypeReferenceModel.cs create mode 100644 parser/ReturnStatementModel.cs create mode 100644 parser/SliceTypeModel.cs create mode 100644 parser/StatementModel.cs create mode 100644 parser/StatementVisitorNya.cs create mode 100644 parser/StringLiteralModel.cs create mode 100644 parser/StructAccessExpressionModel.cs create mode 100644 parser/StructConstructorExpressionModel.cs create mode 100644 parser/StructConstructorMemberModel.cs create mode 100644 parser/StructMemberModel.cs create mode 100644 parser/StructMemberVisitorNya.cs create mode 100644 parser/StructTopLevelConstructModel.cs create mode 100644 parser/StructTypeModel.cs create mode 100644 parser/SwitchExpressionModel.cs create mode 100644 parser/TopLevelConstructModel.cs create mode 100644 parser/TopLevelStatementModel.cs create mode 100644 parser/TupleConstructorExpressionModel.cs create mode 100644 parser/TupleTopLevelConstructModel.cs create mode 100644 parser/TupleTypeModel.cs create mode 100644 parser/TypeAliasModel.cs create mode 100644 parser/TypeNameModel.cs create mode 100644 parser/TypeParameterModel.cs create mode 100644 parser/TypeReferenceModel.cs create mode 100644 parser/TypeReferenceVisitorNya.cs create mode 100644 parser/UnaryOperationExpressionModel.cs create mode 100644 parser/UnaryOperator.cs create mode 100644 parser/UnaryOperatorExtensions.cs create mode 100644 parser/VariableDeclarationStatementModel.cs delete mode 100644 parser/Visitor.cs create mode 100644 parser/VisitorNya.cs create mode 100644 parser/WhileLoopStatementModel.cs diff --git a/README.md b/README.md index 77ab5e1..8dab8f4 100644 --- a/README.md +++ b/README.md @@ -54,29 +54,29 @@ pub fn y() {} Functions can take the `[c_export]` attribute to make them callable when compiled as a static library, and to generate C headers for them. ``` -[c_export] pub fn foo(int a, Foo b, Bar c) -> int { +[c_export] pub fn foo(a: int, b: Foo, c: Bar): int { } -[c_export("renamed_foo2")] pub fn foo2(int a, Foo b, Bar c) -> int, int { +[c_export("renamed_foo2")] pub fn foo2(a: int, b: Foo, c: Bar): int, int { } ``` Functions can be overloaded on parameter and return types ``` -fn a() -> s32 { +fn a(): s32 { return -1; } -fn a() -> u32 { +fn a(): u32 { return 1; } -fn a(i32 x, i32 y) -> (i32, i32) { +fn a(x: i32, y: i32): (i32, i32) { return y, x; } -fn a(u32 x) -> u32 { +fn a(x: u32): u32 { return x + 1; } ``` @@ -92,13 +92,13 @@ constraints are kind of weird because they // this one can be used only as a constraint for generic type parameters constraint Foo on A B { some_func(A, B); - some_other_func(A) -> B; + some_other_func(A): B; } // this one can be used both as a constraint for generic type parameters or as an interface type constraint Bar on A { - f1(A) -> A; - f2(A) -> i32; + f1(A): A; + f2(A): i32; } ``` @@ -111,7 +111,7 @@ fn foo(T1 x) some_func(x, y); } -fn bar(T a) -> i32 +fn bar(T a): i32 where Bar T { T b = f1(a); @@ -141,15 +141,6 @@ constraint Foo on A { ``` -``` -int a = 1; -mut int b = 2; - -let a = 1; -mut let b = 2; - -``` - ### literals #### numeric Numeric literals are untyped but literals with a decimal point can not be used as integers. @@ -190,27 +181,31 @@ Their type is an `u8` array with length of the string in bytes. ``` let a: [u8] = "foo"; let b: u8 = a[1]; -let d: [s32; 4] = {1,2,3,4}; +let d: [s32; 4] = []{1,2,3,4}; let e = [u8]{1,2,3,4}; + +type Arr = [u8]; +let f = Arr[]{1,2,3}; + ``` ##### struct ###### declaration ``` struct Point { - s32 x; - s32 y; - s32 z; + x: s32; + y: s32; + z: s32; } type Point = struct { - s32 x; - s32 y; - s32 z; + x: s32; + y: s32; + z: s32; } type Options = struct { - struct { + api: struct { int foo; - } api; + }; } ``` ##### use @@ -314,3 +309,37 @@ let e: u8 = *c; // 1 *(&a[0]+1) = 2; // a is now {0,2} ``` + + +## operator precedence + +``` +. (struct member access), [] array subscripting + + unaries: + - ! ~, pointer dereference *, pointer reference &, + binary operators: + * / % + + - + << >> + > >= < <= + == != + & + ^ + | + && + ^^ + || + lowest precedence, assignment: + = + += + -= + /= + *= + %= + &= + |= + ^= + <<= + >>= + +``` \ No newline at end of file diff --git a/compiler/example.mew b/compiler/example.mew index 74705fb..84c5c4e 100644 --- a/compiler/example.mew +++ b/compiler/example.mew @@ -49,17 +49,16 @@ constraint Bar B { */ + +/* struct Foo { - int something; - struct { - int foo; - } bar; + something: int; + bar: struct { + foo: int; + }; } -Foo f; -f.something - enum X { A, B, @@ -79,7 +78,7 @@ enum X where Constraint T1 T2 where Constraint T2 T3 { } struct X { - T a; + a: T; } tuple Point(int,int,int) @@ -89,3 +88,25 @@ tuple Point where Arithmetic T (T,T,T) type A = Foo; type F = Foo>; + + + +type X = [Y; 10]; + +*/ + + +fn foo() { + meoooow let x-nyaaaa = []{1-nya, meow 2}; + + outer: loop let x = 1; x < 10; x += 1 { + switch 1 { + case 1: { + foobar(); + }, + case 2: fallthrough, + case 3: x, + default: bar(), + } + } +} \ No newline at end of file diff --git a/parser/ArrayAccessExpressionModel.cs b/parser/ArrayAccessExpressionModel.cs new file mode 100644 index 0000000..7e0c58f --- /dev/null +++ b/parser/ArrayAccessExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record ArrayAccessExpressionModel + (Span Span, ExpressionModel Expression, ExpressionModel Indexer) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/ArrayConstructorExpressionModel.cs b/parser/ArrayConstructorExpressionModel.cs new file mode 100644 index 0000000..c5239ba --- /dev/null +++ b/parser/ArrayConstructorExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record ArrayConstructorExpressionModel(Span Span, TypeReferenceModel? Type, + List Members) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/ArrayTypeModel.cs b/parser/ArrayTypeModel.cs new file mode 100644 index 0000000..63c7465 --- /dev/null +++ b/parser/ArrayTypeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ArrayTypeModel(Span Span, TypeReferenceModel Type, string Length) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/AssignmentExpressionModel.cs b/parser/AssignmentExpressionModel.cs new file mode 100644 index 0000000..b8430b3 --- /dev/null +++ b/parser/AssignmentExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record AssignmentExpressionModel(Span Span, PatternModel Pattern, AssignmentOperator Operator, + ExpressionModel Initializer) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/AssignmentOperator.cs b/parser/AssignmentOperator.cs new file mode 100644 index 0000000..1ae9405 --- /dev/null +++ b/parser/AssignmentOperator.cs @@ -0,0 +1,16 @@ +namespace meowlang.parser; + +public enum AssignmentOperator +{ + Assign, + PlusAssign, + MinusAssign, + MultAssign, + DivAssign, + ModAssign, + BitwiseOrAssign, + BitwiseAndAssign, + BitwiseXorAssign, + ShiftRightAssign, + ShiftLeftAssign +} \ No newline at end of file diff --git a/parser/AssignmentOperatorExtensions.cs b/parser/AssignmentOperatorExtensions.cs new file mode 100644 index 0000000..5386cf3 --- /dev/null +++ b/parser/AssignmentOperatorExtensions.cs @@ -0,0 +1,34 @@ +namespace meowlang.parser; + +public static class AssignmentOperatorExtensions +{ + public static AssignmentOperator ToAssignmentOperator(this string str) => str switch + { + "=" => AssignmentOperator.Assign, + "+=" => AssignmentOperator.PlusAssign, + "-=" => AssignmentOperator.MinusAssign, + "*=" => AssignmentOperator.MultAssign, + "/=" => AssignmentOperator.DivAssign, + "%=" => AssignmentOperator.ModAssign, + "|=" => AssignmentOperator.BitwiseOrAssign, + "&=" => AssignmentOperator.BitwiseAndAssign, + "^=" => AssignmentOperator.BitwiseXorAssign, + ">>=" => AssignmentOperator.ShiftRightAssign, + "<<=" => AssignmentOperator.ShiftLeftAssign, + }; + + public static string ToString(this AssignmentOperator op) => op switch + { + AssignmentOperator.Assign => "=", + AssignmentOperator.PlusAssign => "+=", + AssignmentOperator.MinusAssign => "-=", + AssignmentOperator.MultAssign => "*=", + AssignmentOperator.DivAssign => "/=", + AssignmentOperator.ModAssign => "%=", + AssignmentOperator.BitwiseOrAssign => "|=", + AssignmentOperator.BitwiseAndAssign => "&=", + AssignmentOperator.BitwiseXorAssign => "^=", + AssignmentOperator.ShiftRightAssign => ">>=", + AssignmentOperator.ShiftLeftAssign => "<<=", + }; +} \ No newline at end of file diff --git a/parser/AttributeModel.cs b/parser/AttributeModel.cs new file mode 100644 index 0000000..f4d7051 --- /dev/null +++ b/parser/AttributeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record AttributeModel(Span Span, string Name, List Values) : ModelBase(Span); \ No newline at end of file diff --git a/parser/AttributeValueModel.cs b/parser/AttributeValueModel.cs new file mode 100644 index 0000000..5256a9c --- /dev/null +++ b/parser/AttributeValueModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record AttributeValueModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/AttributeValueVisitorNya.cs b/parser/AttributeValueVisitorNya.cs new file mode 100644 index 0000000..a4cdc90 --- /dev/null +++ b/parser/AttributeValueVisitorNya.cs @@ -0,0 +1,17 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class AttributeValueVisitorNya : MeowBaseVisitorNya +{ + public override AttributeValueModel VisitAttributeValue(MeowParser.AttributeValueContext context) + { + if (context.id != null) + { + return new IdentifierAttributeValueModel(context.GetSpan(), context.id.Text); + } + + var literal = new LiteralVisitorNya().Visit(context.literal()); + return new LiteralAttributeValueModel(context.GetSpan(), literal); + } +} \ No newline at end of file diff --git a/parser/AttributeVisitorNya.cs b/parser/AttributeVisitorNya.cs new file mode 100644 index 0000000..ae349fb --- /dev/null +++ b/parser/AttributeVisitorNya.cs @@ -0,0 +1,13 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class AttributeVisitorNya : MeowBaseVisitorNya +{ + public override AttributeModel VisitAttribute(MeowParser.AttributeContext context) + { + var name = context.name.Text; + var values = context.attributeValue().Select(x => new AttributeValueVisitorNya().Visit(x)).ToList(); + return new AttributeModel(context.GetSpan(), name, values); + } +} \ No newline at end of file diff --git a/parser/BinaryOperationExpressionModel.cs b/parser/BinaryOperationExpressionModel.cs new file mode 100644 index 0000000..6b46d7b --- /dev/null +++ b/parser/BinaryOperationExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record BinaryOperationExpressionModel(Span Span, ExpressionModel Left, BinaryOperator Operator, + ExpressionModel Right) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/BinaryOperator.cs b/parser/BinaryOperator.cs new file mode 100644 index 0000000..61292db --- /dev/null +++ b/parser/BinaryOperator.cs @@ -0,0 +1,24 @@ +namespace meowlang.parser; + +public enum BinaryOperator +{ + LogicalOr, + LogicalAnd, + LogicalXor, + BitwiseOr, + BitwiseAnd, + BitwiseXor, + Equal, + NotEqual, + GreaterThan, + GreaterThanOrEqual, + LessThan, + LessThanOrEqual, + ShiftLeft, + ShiftRight, + Addition, + Subtraction, + Multiplication, + Division, + Modulo, +} \ No newline at end of file diff --git a/parser/BinaryOperatorExtensions.cs b/parser/BinaryOperatorExtensions.cs new file mode 100644 index 0000000..41b095f --- /dev/null +++ b/parser/BinaryOperatorExtensions.cs @@ -0,0 +1,50 @@ +namespace meowlang.parser; + +public static class BinaryOperatorExtensions +{ + public static BinaryOperator ToBinaryOperator(this string str) => str switch + { + "||" => BinaryOperator.LogicalOr, + "&&" => BinaryOperator.LogicalAnd, + "^^" => BinaryOperator.LogicalXor, + "|" => BinaryOperator.BitwiseOr, + "&" => BinaryOperator.BitwiseAnd, + "^" => BinaryOperator.BitwiseXor, + "==" => BinaryOperator.Equal, + "!=" => BinaryOperator.NotEqual, + ">" => BinaryOperator.GreaterThan, + ">=" => BinaryOperator.GreaterThanOrEqual, + "<" => BinaryOperator.LessThan, + "<=" => BinaryOperator.LessThanOrEqual, + "<<" => BinaryOperator.ShiftLeft, + ">>" => BinaryOperator.ShiftRight, + "+" => BinaryOperator.Addition, + "-" => BinaryOperator.Subtraction, + "*" => BinaryOperator.Multiplication, + "/" => BinaryOperator.Division, + "%" => BinaryOperator.Modulo, + }; + + public static string ToString(this BinaryOperator op) => op switch + { + BinaryOperator.LogicalOr => "||", + BinaryOperator.LogicalAnd => "&&", + BinaryOperator.LogicalXor => "^^", + BinaryOperator.BitwiseOr => "|", + BinaryOperator.BitwiseAnd => "&", + BinaryOperator.BitwiseXor => "^", + BinaryOperator.Equal => "==", + BinaryOperator.NotEqual => "!=", + BinaryOperator.GreaterThan => ">", + BinaryOperator.GreaterThanOrEqual => ">=", + BinaryOperator.LessThan => "<", + BinaryOperator.LessThanOrEqual => "<=", + BinaryOperator.ShiftLeft => "<<", + BinaryOperator.ShiftRight => ">>", + BinaryOperator.Addition => "+", + BinaryOperator.Subtraction => "-", + BinaryOperator.Multiplication => "*", + BinaryOperator.Division => "/", + BinaryOperator.Modulo => "%", + }; +} \ No newline at end of file diff --git a/parser/BlockExpressionModel.cs b/parser/BlockExpressionModel.cs new file mode 100644 index 0000000..7fee99d --- /dev/null +++ b/parser/BlockExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record BlockExpressionModel(Span Span, List Statements, ExpressionModel? Value) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/BoolLiteralModel.cs b/parser/BoolLiteralModel.cs new file mode 100644 index 0000000..5d14ef0 --- /dev/null +++ b/parser/BoolLiteralModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record BoolLiteralModel(Span Span, bool Value) : LiteralModel(Span); \ No newline at end of file diff --git a/parser/BreakStatementModel.cs b/parser/BreakStatementModel.cs new file mode 100644 index 0000000..c328c3e --- /dev/null +++ b/parser/BreakStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record BreakStatementModel(Span Span, string? Label) : StatementModel(Span); \ No newline at end of file diff --git a/parser/CharacterLiteralModel.cs b/parser/CharacterLiteralModel.cs new file mode 100644 index 0000000..fbf3c4f --- /dev/null +++ b/parser/CharacterLiteralModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record CharacterLiteralModel(Span Span, string Value) : LiteralModel(Span); \ No newline at end of file diff --git a/parser/ConstantDeclarationStatementModel.cs b/parser/ConstantDeclarationStatementModel.cs new file mode 100644 index 0000000..00e9c7f --- /dev/null +++ b/parser/ConstantDeclarationStatementModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record ConstantDeclarationStatementModel + (Span Span, List Names, ExpressionModel Initializer) : StatementModel(Span); \ No newline at end of file diff --git a/parser/ConstraintModel.cs b/parser/ConstraintModel.cs new file mode 100644 index 0000000..2b7cec6 --- /dev/null +++ b/parser/ConstraintModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ConstraintModel(Span Span, string Name, List TypeNames) : ModelBase(Span); \ No newline at end of file diff --git a/parser/ConstraintRuleModel.cs b/parser/ConstraintRuleModel.cs new file mode 100644 index 0000000..0f4b749 --- /dev/null +++ b/parser/ConstraintRuleModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record ConstraintRuleModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/ConstraintRuleVisitorNya.cs b/parser/ConstraintRuleVisitorNya.cs new file mode 100644 index 0000000..37eddaf --- /dev/null +++ b/parser/ConstraintRuleVisitorNya.cs @@ -0,0 +1,24 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class ConstraintRuleVisitorNya : MeowBaseVisitorNya +{ + public override ConstraintRuleModel VisitEmbedConstraintRule(MeowParser.EmbedConstraintRuleContext context) + { + var name = context.name.Text; + var types = context._types.Select(x => new TypeReferenceVisitorNya().Visit(x)).ToList(); + return new EmbedConstraintRuleModel(context.GetSpan(), name, types); + } + + public override ConstraintRuleModel VisitFunctionConstraintRule(MeowParser.FunctionConstraintRuleContext context) + { + var name = context.name.Text; + var parameters = context.constraintFunctionParameters().typeReference() + .Select(x => new TypeReferenceVisitorNya().Visit(x)).ToList(); + var returns = + context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitorNya().Visit(x)).ToList() ?? + new List(); + return new FunctionConstraintRuleModel(context.GetSpan(), name, parameters, returns); + } +} \ No newline at end of file diff --git a/parser/ConstraintTopLevelConstructModel.cs b/parser/ConstraintTopLevelConstructModel.cs new file mode 100644 index 0000000..f43f65c --- /dev/null +++ b/parser/ConstraintTopLevelConstructModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record ConstraintTopLevelConstructModel + (Span Span, List Attributes, bool Pub, string Name, List TypeNames, List Rules) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/ContinueStatementModel.cs b/parser/ContinueStatementModel.cs new file mode 100644 index 0000000..bc37ccb --- /dev/null +++ b/parser/ContinueStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ContinueStatementModel(Span Span, string? Label) : StatementModel(Span); \ No newline at end of file diff --git a/parser/DeclarationVisitorNya.cs b/parser/DeclarationVisitorNya.cs new file mode 100644 index 0000000..1118255 --- /dev/null +++ b/parser/DeclarationVisitorNya.cs @@ -0,0 +1,101 @@ +using Antlr4.Runtime.Tree; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class DeclarationVisitorNya : MeowBaseVisitorNya +{ + public override TopLevelConstructModel VisitTopLevelStatement(MeowParser.TopLevelStatementContext context) + { + var statement = new StatementVisitorNya().Visit(context); + return new TopLevelStatementModel(context.GetSpan(), statement); + } + + public override TopLevelConstructModel VisitFunction(MeowParser.FunctionContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + + var typeParameters = + context.genericParameters()?._name.Select(x => new TypeParameterModel(x.GetSpan(), x.Text)).ToList() ?? + new List(); + var functionParameters = context.functionParameters().functionParameter() + .Select(x => new FunctionParameterVisitorNya().Visit(x)).ToList(); + var functionReturns = context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitorNya().Visit(x)) + .ToList() ?? new List(); + var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitorNya().Visit(x)).ToList() ?? + new List(); + + var body = new ExpressionVisitorNya().Visit(context.body); + + return new FunctionModel(context.GetSpan(), attributes, pub, name, typeParameters, functionParameters, + functionReturns, constraints, body); + } + + public override ConstraintTopLevelConstructModel VisitConstraintDeclaration( + MeowParser.ConstraintDeclarationContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + var typeNames = context._types.Select(x => x.Text).ToList(); + var rules = context.constraintRule().Select(x => new ConstraintRuleVisitorNya().Visit(x)).ToList(); + return new ConstraintTopLevelConstructModel(context.GetSpan(), attributes, pub, name, typeNames, rules); + } + + public override TopLevelConstructModel VisitStructDeclaration(MeowParser.StructDeclarationContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); + var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitorNya().Visit(x)).ToList() ?? + new List(); + var structModel = new TypeReferenceVisitorNya().Visit(context.structType()) as StructTypeModel; + return new StructTopLevelConstructModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, structModel!); + } + + public override TopLevelConstructModel VisitEnumDeclaration(MeowParser.EnumDeclarationContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); + var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitorNya().Visit(x)).ToList() ?? + new List(); + + var enumModel = new TypeReferenceVisitorNya().Visit(context.enumType()) as EnumTypeModel; + return new EnumTopLevelConstructModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, enumModel!); + } + + public override TopLevelConstructModel VisitTupleDeclaration(MeowParser.TupleDeclarationContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); + var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitorNya().Visit(x)).ToList() ?? + new List(); + var tupleModel = new TypeReferenceVisitorNya().Visit(context.tupleType()) as TupleTypeModel; + return new TupleTopLevelConstructModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, tupleModel!); + } + + public override TopLevelConstructModel VisitTypeAlias(MeowParser.TypeAliasContext context) + { + var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); + var pub = context.pub != null; + var name = context.name.Text; + var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); + var type = new TypeReferenceVisitorNya().Visit(context.typeReference()); + return new TypeAliasModel(context.GetSpan(), attributes, pub, name, typeParameters, type); + } +} + +public class MeowBaseVisitorNya : MeowBaseVisitor +{ + public T? TryVisit(IParseTree? tree) + { + return tree == null ? default : Visit(tree); + } +} \ No newline at end of file diff --git a/parser/EmbedConstraintRuleModel.cs b/parser/EmbedConstraintRuleModel.cs new file mode 100644 index 0000000..0b68710 --- /dev/null +++ b/parser/EmbedConstraintRuleModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record EmbedConstraintRuleModel + (Span Span, string Name, List Types) : ConstraintRuleModel(Span); \ No newline at end of file diff --git a/parser/EnumConstructorExpressionModel.cs b/parser/EnumConstructorExpressionModel.cs new file mode 100644 index 0000000..cfd6e46 --- /dev/null +++ b/parser/EnumConstructorExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record EnumConstructorExpressionModel(Span Span, TypeNameModel Type, string Name) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/EnumMemberModel.cs b/parser/EnumMemberModel.cs new file mode 100644 index 0000000..cac18bc --- /dev/null +++ b/parser/EnumMemberModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record EnumMemberModel(Span Span, string Name, TypeReferenceModel? Type) : ModelBase(Span); \ No newline at end of file diff --git a/parser/EnumMemberVisitorNya.cs b/parser/EnumMemberVisitorNya.cs new file mode 100644 index 0000000..bade6cb --- /dev/null +++ b/parser/EnumMemberVisitorNya.cs @@ -0,0 +1,20 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class EnumMemberVisitorNya : MeowBaseVisitorNya +{ + public override EnumMemberModel VisitEnumMember(MeowParser.EnumMemberContext context) + { + var name = context.name.Text; + + TypeReferenceModel? type = null; + var typeRef = context.typeReference(); + if (typeRef != null) + { + type = new TypeReferenceVisitorNya().Visit(typeRef); + } + + return new EnumMemberModel(context.GetSpan(), name, type); + } +} \ No newline at end of file diff --git a/parser/EnumTopLevelConstructModel.cs b/parser/EnumTopLevelConstructModel.cs new file mode 100644 index 0000000..18acbf3 --- /dev/null +++ b/parser/EnumTopLevelConstructModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record EnumTopLevelConstructModel(Span Span, List Attributes, bool Pub, string Name, List TypeParameters, + List Constraints, EnumTypeModel Enum) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/EnumTypeModel.cs b/parser/EnumTypeModel.cs new file mode 100644 index 0000000..197b013 --- /dev/null +++ b/parser/EnumTypeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record EnumTypeModel(Span Span, List Members) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/ExpressionModel.cs b/parser/ExpressionModel.cs new file mode 100644 index 0000000..fe13677 --- /dev/null +++ b/parser/ExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record ExpressionModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/ExpressionStatementModel.cs b/parser/ExpressionStatementModel.cs new file mode 100644 index 0000000..8aa8897 --- /dev/null +++ b/parser/ExpressionStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ExpressionStatementModel(Span Span, ExpressionModel Expression) : StatementModel(Span); \ No newline at end of file diff --git a/parser/ExpressionVisitorNya.cs b/parser/ExpressionVisitorNya.cs new file mode 100644 index 0000000..71d0660 --- /dev/null +++ b/parser/ExpressionVisitorNya.cs @@ -0,0 +1,255 @@ +using Antlr4.Runtime; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class ExpressionVisitorNya : MeowBaseVisitorNya +{ + public override ExpressionModel VisitAssignmentExpression(MeowParser.AssignmentExpressionContext context) + { + var expression = Visit(context.logicalOrExpression()); + if (context.op == null) + { + return expression; + } + + var op = context.op.Text.ToAssignmentOperator(); + var pattern = new PatternModel(context.pattern().GetSpan(), + new List(context.pattern().pointerDereferenceExpression() + .Select(Visit).ToList())); + return new AssignmentExpressionModel(context.GetSpan(), pattern, op, expression); + } + + private ExpressionModel MakeBinOpTree(List expressions, BinaryOperator op) + { + if (expressions.Count == 1) return expressions[0]; + var left = MakeBinOpTree(expressions.Take(expressions.Count - 1).ToList(), op); + var right = expressions[^1]; + var span = new Span(left.Span.Filename, left.Span.From, right.Span.To); + return new BinaryOperationExpressionModel(span, left, op, right); + } + + private ExpressionModel MakeBinOpTree(List expressions, List ops) + { + if (expressions.Count == 1) return expressions[0]; + var op = ops[^1]; + var right = expressions[^1]; + var remainingExpressions = expressions.Take(expressions.Count - 1).ToList(); + var remainingOps = ops.Take(ops.Count - 1).ToList(); + var left = MakeBinOpTree(remainingExpressions, remainingOps); + var span = new Span(left.Span.Filename, left.Span.From, right.Span.To); + return new BinaryOperationExpressionModel(span, left, op, right); + } + + public override ExpressionModel VisitLogicalOrExpression(MeowParser.LogicalOrExpressionContext context) + { + var expressions = context.logicalXorExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.LogicalOr); + } + + public override ExpressionModel VisitLogicalXorExpression(MeowParser.LogicalXorExpressionContext context) + { + var expressions = context.logicalAndExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.LogicalXor); + } + + public override ExpressionModel VisitLogicalAndExpression(MeowParser.LogicalAndExpressionContext context) + { + var expressions = context.bitwiseOrExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.LogicalAnd); + } + + public override ExpressionModel VisitBitwiseOrExpression(MeowParser.BitwiseOrExpressionContext context) + { + var expressions = context.bitwiseXorExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.BitwiseOr); + } + + public override ExpressionModel VisitBitwiseXorExpression(MeowParser.BitwiseXorExpressionContext context) + { + var expressions = context.bitwiseAndExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.BitwiseXor); + } + + public override ExpressionModel VisitBitwiseAndExpression(MeowParser.BitwiseAndExpressionContext context) + { + var expressions = context.equalityExpression().Select(Visit).ToList(); + return MakeBinOpTree(expressions, BinaryOperator.BitwiseAnd); + } + + public override ExpressionModel VisitEqualityExpression(MeowParser.EqualityExpressionContext context) + { + var expressions = context.relationalExpression().Select(Visit).ToList(); + var operators = context._op.Select(x => x.Text.ToBinaryOperator()).ToList(); + return MakeBinOpTree(expressions, operators); + } + + public override ExpressionModel VisitRelationalExpression(MeowParser.RelationalExpressionContext context) + { + var expressions = context.shiftExpression().Select(Visit).ToList(); + var operators = context._op.Select(x => x.Text.ToBinaryOperator()).ToList(); + return MakeBinOpTree(expressions, operators); + } + + public override ExpressionModel VisitShiftExpression(MeowParser.ShiftExpressionContext context) + { + var expressions = context.addExpression().Select(Visit).ToList(); + var operators = context._op.Select(x => x.Text.Replace(">", ">>").ToBinaryOperator()).ToList(); + return MakeBinOpTree(expressions, operators); + } + + public override ExpressionModel VisitAddExpression(MeowParser.AddExpressionContext context) + { + var expressions = context.multExpression().Select(Visit).ToList(); + var operators = context._op.Select(x => x.Text.ToBinaryOperator()).ToList(); + return MakeBinOpTree(expressions, operators); + } + + public override ExpressionModel VisitMultExpression(MeowParser.MultExpressionContext context) + { + var expressions = context.unaryExpression().Select(Visit).ToList(); + var operators = context._op.Select(x => x.Text.ToBinaryOperator()).ToList(); + return MakeBinOpTree(expressions, operators); + } + + public override ExpressionModel VisitUnaryExpression(MeowParser.UnaryExpressionContext context) + { + var expression = Visit(context.pointerDereferenceExpression()); + foreach (var unaryOperator in context._op.Reverse()) + { + var span = new Span(expression.Span.Filename, unaryOperator.StartIndex, expression.Span.To); + if (unaryOperator.Text == "&") + { + expression = new PointerReferenceExpressionModel(span, expression); + } + else + { + expression = new UnaryOperationExpressionModel(span, unaryOperator.Text.ToUnaryOperator(), expression); + } + } + + return expression; + } + + public override ExpressionModel VisitPointerDereferenceExpression( + MeowParser.PointerDereferenceExpressionContext context) + { + var expression = Visit(context.accessExpression()); + foreach (var op in context._op.Reverse()) + { + var span = new Span(expression.Span.Filename, op.StartIndex, expression.Span.To); + expression = new PointerDereferenceExpressionModel(span, expression); + } + + return expression; + } + + public override ExpressionModel VisitAccessExpression(MeowParser.AccessExpressionContext context) + { + var expression = Visit(context.terminalExpression()); + var current = context.accessExpression1(); + while (current != null) + { + if (current.subscript != null) // array access + { + var span = new Span(expression.Span.Filename, expression.Span.From, current.end.StopIndex); + var indexer = Visit(current.subscript); + expression = new ArrayAccessExpressionModel(span, expression, indexer); + } + else // struct access + { + var span = new Span(expression.Span.Filename, expression.Span.From, current.name.StopIndex); + var name = current.name.Text; + if (name.Contains('.') || !Char.IsDigit(name.TrimStart('0')[0])) + { + throw new InvalidStructAccessorException(current.name, ""); + } + + expression = new StructAccessExpressionModel(span, expression, name); + } + + current = current.accessExpression1(); + } + + return expression; + } + + public override ExpressionModel VisitLiteralExpression(MeowParser.LiteralExpressionContext context) + { + var literal = new LiteralVisitorNya().Visit(context.literal()); + return new LiteralExpressionModel(context.GetSpan(), literal); + } + + + public override ExpressionModel VisitNameExpression(MeowParser.NameExpressionContext context) + { + var name = new IdentifierNameVisitorNya().Visit(context.identifierName()); + return new NameExpressionModel(context.GetSpan(), name); + } + + public override ExpressionModel VisitStructConstructor(MeowParser.StructConstructorContext context) + { + var typeName = new TypeReferenceVisitorNya().TryVisit(context.typeName()) as TypeNameModel; + var members = context.structConstructorMember().Select(x => + new StructConstructorMemberModel(x.GetSpan(), x.name.Text, Visit(x.expression()))).ToList(); + return new StructConstructorExpressionModel(context.GetSpan(), typeName, members); + } + + public override ExpressionModel VisitArrayConstructor(MeowParser.ArrayConstructorContext context) + { + var type = new TypeReferenceVisitorNya().TryVisit(context.arrayType() ?? context.typeName() as ParserRuleContext); + var members = context.expression().Select(Visit).ToList(); + return new ArrayConstructorExpressionModel(context.GetSpan(), type, members); + } + + public override ExpressionModel VisitEnumConstructor(MeowParser.EnumConstructorContext context) + { + var typeName = new TypeReferenceVisitorNya().TryVisit(context.typeName()) as TypeNameModel; + var name = context.name.Text; + return new EnumConstructorExpressionModel(context.GetSpan(), typeName!, name); + } + + public override ExpressionModel VisitTupleConstructor(MeowParser.TupleConstructorContext context) + { + var values = context.expression().Select(Visit).ToList(); + return new TupleConstructorExpressionModel(context.GetSpan(), values); + } + + public override ExpressionModel VisitFunctionCall(MeowParser.FunctionCallContext context) + { + var name = new IdentifierNameVisitorNya().Visit(context.identifierName()); + var arguments = context.expression().Select(Visit).ToList(); + return new FunctionCallExpressionModel(context.GetSpan(), name, arguments); + } + + public override ExpressionModel VisitIfExpression(MeowParser.IfExpressionContext context) + { + var cond = Visit(context.cond); + var then = Visit(context.then) as BlockExpressionModel; + var @else = TryVisit(context.@else) as BlockExpressionModel; + var ifElses = context.elseIfExpression().Select(x => (Visit(x.cond), (Visit(x.then) as BlockExpressionModel)!)) + .ToList(); + return new IfExpressionModel(context.GetSpan(), cond, then!, ifElses, @else); + } + + public override ExpressionModel VisitSwitchExpression(MeowParser.SwitchExpressionContext context) + { + var expression = Visit(context.expression()); + var cases = context.switchCase().Select(x => (new LiteralVisitorNya().Visit(x.literal()), TryVisit(x.expression()))).ToList(); + var defaultCase = TryVisit(context.switchDefault()?.expression()); + return new SwitchExpressionModel(context.GetSpan(), expression, cases, defaultCase); + } + + public override ExpressionModel VisitBlockExpression(MeowParser.BlockExpressionContext context) + { + var statements = context.terminatedStatement().Select(x => new StatementVisitorNya().Visit(x)).ToList(); + var value = TryVisit(context.expression()); + return new BlockExpressionModel(context.GetSpan(), statements, value); + } + + public override ExpressionModel VisitParenthesisExpression(MeowParser.ParenthesisExpressionContext context) + { + var expression = Visit(context.expression()); + return new ParenthesisExpressionModel(context.GetSpan(), expression); + } +} \ No newline at end of file diff --git a/parser/ForLoopStatementModel.cs b/parser/ForLoopStatementModel.cs new file mode 100644 index 0000000..0598ea6 --- /dev/null +++ b/parser/ForLoopStatementModel.cs @@ -0,0 +1,5 @@ +namespace meowlang.parser; + +public record ForLoopStatementModel(Span Span, List Body, + VariableDeclarationStatementModel? InitStatement, ExpressionModel? InitExpression, ExpressionModel? Condition, + ExpressionModel? Increment) : LoopStatementModel(Span, Body); \ No newline at end of file diff --git a/parser/FunctionCallExpressionModel.cs b/parser/FunctionCallExpressionModel.cs new file mode 100644 index 0000000..f010f14 --- /dev/null +++ b/parser/FunctionCallExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record FunctionCallExpressionModel + (Span Span, IdentifierNameModel Name, List Arguments) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/FunctionConstraintRuleModel.cs b/parser/FunctionConstraintRuleModel.cs new file mode 100644 index 0000000..4b01533 --- /dev/null +++ b/parser/FunctionConstraintRuleModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record FunctionConstraintRuleModel(Span Span, string Name, List Parameters, + List Returns) : ConstraintRuleModel(Span); \ No newline at end of file diff --git a/parser/FunctionConstraintVisitorNya.cs b/parser/FunctionConstraintVisitorNya.cs new file mode 100644 index 0000000..8deaf1e --- /dev/null +++ b/parser/FunctionConstraintVisitorNya.cs @@ -0,0 +1,13 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class FunctionConstraintVisitorNya : MeowBaseVisitorNya +{ + public override ConstraintModel VisitConstraint(MeowParser.ConstraintContext context) + { + var name = context.name.Text; + var typeNames = context._typenames.Select(x => x.Text).ToList(); + return new ConstraintModel(context.GetSpan(), name, typeNames); + } +} \ No newline at end of file diff --git a/parser/FunctionModel.cs b/parser/FunctionModel.cs new file mode 100644 index 0000000..70e8c5d --- /dev/null +++ b/parser/FunctionModel.cs @@ -0,0 +1,5 @@ +namespace meowlang.parser; + +public record FunctionModel(Span Span, List Attributes, bool Pub, string Name, + List TypeParameters, List Parameters, List Returns, + List Constraints, ExpressionModel Body) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/FunctionParameterModel.cs b/parser/FunctionParameterModel.cs new file mode 100644 index 0000000..b4702dd --- /dev/null +++ b/parser/FunctionParameterModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record FunctionParameterModel(Span Span, TypeReferenceModel Type, string Name) : ModelBase(Span); \ No newline at end of file diff --git a/parser/FunctionParameterVisitorNya.cs b/parser/FunctionParameterVisitorNya.cs new file mode 100644 index 0000000..c06bc0d --- /dev/null +++ b/parser/FunctionParameterVisitorNya.cs @@ -0,0 +1,13 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class FunctionParameterVisitorNya : MeowBaseVisitorNya +{ + public override FunctionParameterModel VisitFunctionParameter(MeowParser.FunctionParameterContext context) + { + var type = new TypeReferenceVisitorNya().Visit(context.typeReference()); + var name = context.name.Text; + return new FunctionParameterModel(context.GetSpan(), type, name); + } +} \ No newline at end of file diff --git a/parser/IdentifierAttributeValueModel.cs b/parser/IdentifierAttributeValueModel.cs new file mode 100644 index 0000000..68d2ba1 --- /dev/null +++ b/parser/IdentifierAttributeValueModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record IdentifierAttributeValueModel(Span Span, string Name) : AttributeValueModel(Span); \ No newline at end of file diff --git a/parser/IdentifierNameModel.cs b/parser/IdentifierNameModel.cs new file mode 100644 index 0000000..d0c57d3 --- /dev/null +++ b/parser/IdentifierNameModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record IdentifierNameModel(Span Span, string? ImportName, string Name) : ModelBase(Span); \ No newline at end of file diff --git a/parser/IdentifierNameVisitorNya.cs b/parser/IdentifierNameVisitorNya.cs new file mode 100644 index 0000000..3835c13 --- /dev/null +++ b/parser/IdentifierNameVisitorNya.cs @@ -0,0 +1,13 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class IdentifierNameVisitorNya : MeowBaseVisitorNya +{ + public override IdentifierNameModel VisitIdentifierName(MeowParser.IdentifierNameContext context) + { + var import = context.importName?.Text; + var name = context.name.Text; + return new IdentifierNameModel(context.GetSpan(), import, name); + } +} \ No newline at end of file diff --git a/parser/IfExpressionModel.cs b/parser/IfExpressionModel.cs new file mode 100644 index 0000000..0f7457e --- /dev/null +++ b/parser/IfExpressionModel.cs @@ -0,0 +1,5 @@ +namespace meowlang.parser; + +public record IfExpressionModel(Span Span, ExpressionModel Condition, BlockExpressionModel Block, + List<(ExpressionModel Condition, BlockExpressionModel Block)> IfElses, + BlockExpressionModel? Else) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/ImportModel.cs b/parser/ImportModel.cs new file mode 100644 index 0000000..017f481 --- /dev/null +++ b/parser/ImportModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ImportModel(Span Span, string? Project, string Path, string? Alias) : ModelBase(Span); \ No newline at end of file diff --git a/parser/ImportVisitorNya.cs b/parser/ImportVisitorNya.cs new file mode 100644 index 0000000..9ce588b --- /dev/null +++ b/parser/ImportVisitorNya.cs @@ -0,0 +1,50 @@ +using System.Text.RegularExpressions; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class ImportVisitorNya : MeowBaseVisitorNya +{ + private static readonly string PathSegmentPattern = "[a-z][a-z0-9_]*"; + + private static readonly Regex ProjectRegex = new Regex("^[a-z][a-z0-9_]*$"); + + private static readonly Regex PathRegexNoProject = + new Regex($"^({PathSegmentPattern}|\\.|\\.\\.)(/{PathSegmentPattern})*$"); + + private static readonly Regex PathRegex = new Regex($"^{PathSegmentPattern}(/{PathSegmentPattern})*$"); + + public override ImportModel VisitImportStatement(MeowParser.ImportStatementContext context) + { + var path = context.importpath.Text[1..^1].Unescape(); + + string? project = null; + + if (path.Contains(':')) + { + var parts = path.Split(':'); + project = parts[0]; + if (!ProjectRegex.IsMatch(project)) + { + throw new InvalidImportPathException(context.importpath, "malformed project name"); + } + + path = parts[1]; + if (!PathRegex.IsMatch(path)) + { + throw new InvalidImportPathException(context.importpath, "malformed path"); + } + } + else + { + if (!PathRegexNoProject.IsMatch(path)) + { + throw new InvalidImportPathException(context.importpath, "malformed path"); + } + } + + var alias = context.importname?.Text; + + return new ImportModel(context.GetSpan(), project, path, alias); + } +} \ No newline at end of file diff --git a/parser/InfiniteLoopStatementModel.cs b/parser/InfiniteLoopStatementModel.cs new file mode 100644 index 0000000..3f5b21b --- /dev/null +++ b/parser/InfiniteLoopStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record InfiniteLoopStatementModel(Span Span, List Body) : LoopStatementModel(Span, Body); \ No newline at end of file diff --git a/parser/InvalidEscapeSequenceException.cs b/parser/InvalidEscapeSequenceException.cs new file mode 100644 index 0000000..007a55a --- /dev/null +++ b/parser/InvalidEscapeSequenceException.cs @@ -0,0 +1,8 @@ +namespace meowlang.parser; + +public class InvalidEscapeSequenceException : Exception +{ + public InvalidEscapeSequenceException(string escapeSequence) : base($"invalid escape sequence `{escapeSequence}`") + { + } +} \ No newline at end of file diff --git a/parser/InvalidImportPathException.cs b/parser/InvalidImportPathException.cs new file mode 100644 index 0000000..2c206de --- /dev/null +++ b/parser/InvalidImportPathException.cs @@ -0,0 +1,10 @@ +using Antlr4.Runtime; + +namespace meowlang.parser; + +public class InvalidImportPathException : MeowVisitorException +{ + public InvalidImportPathException(IToken context, string message) : base(context, message) + { + } +} \ No newline at end of file diff --git a/parser/InvalidStructAccessorException.cs b/parser/InvalidStructAccessorException.cs new file mode 100644 index 0000000..44625a3 --- /dev/null +++ b/parser/InvalidStructAccessorException.cs @@ -0,0 +1,10 @@ +using Antlr4.Runtime; + +namespace meowlang.parser; + +public class InvalidStructAccessorException : MeowVisitorException +{ + public InvalidStructAccessorException(IToken token, string message) : base(token, message) + { + } +} \ No newline at end of file diff --git a/parser/LiteralAttributeValueModel.cs b/parser/LiteralAttributeValueModel.cs new file mode 100644 index 0000000..1839917 --- /dev/null +++ b/parser/LiteralAttributeValueModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record LiteralAttributeValueModel(Span Span, LiteralModel Literal) : AttributeValueModel(Span); \ No newline at end of file diff --git a/parser/LiteralExpressionModel.cs b/parser/LiteralExpressionModel.cs new file mode 100644 index 0000000..826e730 --- /dev/null +++ b/parser/LiteralExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record LiteralExpressionModel(Span Span, LiteralModel Literal) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/LiteralModel.cs b/parser/LiteralModel.cs new file mode 100644 index 0000000..80b26a6 --- /dev/null +++ b/parser/LiteralModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record LiteralModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/LiteralVisitorNya.cs b/parser/LiteralVisitorNya.cs new file mode 100644 index 0000000..cdecb50 --- /dev/null +++ b/parser/LiteralVisitorNya.cs @@ -0,0 +1,30 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class LiteralVisitorNya : MeowBaseVisitorNya +{ + public override LiteralModel VisitStringLiteral(MeowParser.StringLiteralContext context) + { + var value = context.val.Text[1..^1].Unescape(); + return new StringLiteralModel(context.GetSpan(), value); + } + + public override LiteralModel VisitBoolLiteral(MeowParser.BoolLiteralContext context) + { + var text = context.val.Text; + var value = text == "true"; + return new BoolLiteralModel(context.GetSpan(), value); + } + + public override LiteralModel VisitNumericLiteral(MeowParser.NumericLiteralContext context) + { + return new NumericLiteralModel(context.GetSpan(), context.val.Text); + } + + public override LiteralModel VisitCharacterLiteral(MeowParser.CharacterLiteralContext context) + { + var value = context.val.Text[1..^1].Unescape(); + return new CharacterLiteralModel(context.GetSpan(), value); + } +} \ No newline at end of file diff --git a/parser/LoopStatementModel.cs b/parser/LoopStatementModel.cs new file mode 100644 index 0000000..6555bde --- /dev/null +++ b/parser/LoopStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record LoopStatementModel(Span Span, List Body) : StatementModel(Span); \ No newline at end of file diff --git a/parser/Meow.g4 b/parser/Meow.g4 index 57f43a9..9a336cd 100644 --- a/parser/Meow.g4 +++ b/parser/Meow.g4 @@ -1,41 +1,50 @@ grammar Meow; file - : importStatement* declaration* EOF + : importStatement* topLevelDeclaration* EOF ; importStatement : ImportKeyword importpath=StringLiteral (AsKeyword importname=Identifier)? ';' ; -declaration - : function ';'? - | constraintDeclaration ';'? - | structDeclaration ';'? - | enumDeclaration ';'? - | tupleDeclaration ';'? - | typeAlias ';'? - ; + +topLevelDeclaration + : unterminatedTopLevelDeclaration ';'? + ; + +unterminatedTopLevelDeclaration + : function + | constraintDeclaration + | structDeclaration + | enumDeclaration + | tupleDeclaration + | typeAlias + | topLevelStatement + ; + +topLevelStatement + : constantDeclarationStatement + ; structDeclaration - : StructKeyword name=Identifier (genericParameters constraint*)? structType + : attribute* pub=PubKeyword? StructKeyword name=Identifier (genericParameters constraint*)? structType ; enumDeclaration - : EnumKeyword name=Identifier (genericParameters constraint*)? enumType + : attribute* pub=PubKeyword? EnumKeyword name=Identifier (genericParameters constraint*)? enumType ; tupleDeclaration - : TupleKeyword name=Identifier (genericParameters constraint*)? tupleType + : attribute* pub=PubKeyword? TupleKeyword name=Identifier (genericParameters constraint*)? tupleType ; typeAlias - : TypeKeyword name=Identifier genericParameters? '=' typeReference + : attribute* pub=PubKeyword? TypeKeyword name=Identifier genericParameters? '=' typeReference ; - constraintDeclaration - : ConstraintKeyword name=Identifier types+=Identifier+ '{' constraintRule* '}' + : attribute* pub=PubKeyword? ConstraintKeyword name=Identifier types+=Identifier+ '{' constraintRule* '}' ; constraintRule @@ -56,8 +65,8 @@ constraintFunctionParameters ; function - : attribute* pub=PubKeyword? FnKeyword name=Identifier functionParameters functionReturn? functionBody - | attribute* pub=PubKeyword? FnKeyword name=Identifier genericParameters functionParameters functionReturn? constraint* functionBody + : attribute* pub=PubKeyword? FnKeyword name=Identifier functionParameters functionReturn? body=blockExpression + | attribute* pub=PubKeyword? FnKeyword name=Identifier genericParameters functionParameters functionReturn? constraint* body=blockExpression ; @@ -91,22 +100,17 @@ functionParameters ; functionParameter - : typeReference name=Identifier + : name=Identifier ':' typeReference ; functionReturn - : '->' (typeReference (',' typeReference)*) + : ':' (typeReference (',' typeReference)*) ; constraint : WhereKeyword name=Identifier typenames+=Identifier+ ; -functionBody - : '{' statement* expression? '}' - ; - - typeReference : nonPointerTypeReference pointer='*'? ; @@ -119,8 +123,13 @@ nonPointerTypeReference | EnumKeyword enumType ; + typeName - : (importName=Identifier ':')? name+=Identifier ('<' genericType+=typeName (',' genericType+=typeName)* '>')? ('@' name+=Identifier)* + : identifierName ('<' genericType+=typeName (',' genericType+=typeName)* '>')? ('@' name+=Identifier)* + ; + +identifierName + : (importName=Identifier ':')? name=Identifier ; arrayType @@ -132,11 +141,11 @@ tupleType ; structType - : '{' structMember* '}' + : '{' structMember+ '}' ; structMember - : typeReference name=Identifier ';' + : name=Identifier ':' typeReference ';' ; enumType @@ -148,97 +157,214 @@ enumMember ; +terminatedStatement + : statement ';' + | blockStatement + ; + statement : breakStatement | continueStatement | returnStatement - | loopStatement | expressionStatement + | variableDeclarationStatement + | constantDeclarationStatement + ; + +blockStatement + : ifExpression + | switchExpression + | blockExpression + | loopStatement ; breakStatement - : BreakKeyword label=Identifier? ';' + : BreakKeyword label=Identifier? ; + +variableDeclarationStatement + : 'let' name+=Identifier (',' name+= Identifier)* '=' expression + ; +constantDeclarationStatement + : 'const' Identifier (',' name+= Identifier)* '=' expression + ; + continueStatement - : ContinueKeyword label=Identifier? ';' + : ContinueKeyword label=Identifier? ; returnStatement - : ReturnKeyword expression? ';' + : ReturnKeyword expression? ; loopStatement - : LoopKeyword '{' statement* '}' - | LoopKeyword condition=expression '{' statement* '}' - | LoopKeyword init=expression? ';' condition=expression? ';' increment=expression? '{' statement* '}' + : (label=Identifier ':')? LoopKeyword '{' terminatedStatement* '}' + | (label=Identifier ':')? LoopKeyword condition=expression '{' terminatedStatement* '}' + | (label=Identifier ':')? LoopKeyword (initExpression=expression|initDeclaration=variableDeclarationStatement)? forIndicator=';' condition=expression? ';' increment=expression? '{' terminatedStatement* '}' ; expressionStatement - : expression ';' + : expression ; - -/* -todo: use C operator precedence: https://en.cppreference.com/w/c/language/operator_precedence - - binary operators: - == != > >= < <= - || - && - + - - * / % - & - | - ^ - << - >> - - unary operators: - + - - - ~ - ! - - - assignment: - = - += - -= - /= - *= - %= - &= - |= - ^= - <<= - >>= - - - */ expression - : addExpression + : assignmentExpression + ; + +assignmentExpression + : pattern op=AssignmentOperator logicalOrExpression + | logicalOrExpression ; +pattern + : pointerDereferenceExpression (',' pointerDereferenceExpression)* + ; + +logicalOrExpression + : logicalXorExpression ('||' logicalXorExpression)* + ; + +logicalXorExpression + : logicalAndExpression ('^^' logicalAndExpression)* + ; + +logicalAndExpression + : bitwiseOrExpression ('&&' bitwiseOrExpression)* + ; + +bitwiseOrExpression + : bitwiseXorExpression ('|' bitwiseXorExpression)* + ; + +bitwiseXorExpression + : bitwiseAndExpression ('^' bitwiseAndExpression)* + ; + +bitwiseAndExpression + : equalityExpression ('&' equalityExpression)* + ; + +equalityExpression + : relationalExpression ((op+='=='|op+='!=') relationalExpression)* + ; + +relationalExpression + : shiftExpression ((op+='<'|op+='>'|op+='<='|op+='>=') shiftExpression)* + ; + +shiftExpression + : addExpression ((op+='<<'|op+='>' '>') addExpression)* + ; + addExpression - : multExpression ((op='+'|op='-') multExpression)* + : multExpression ((op+='+'|op+='-') multExpression)* ; multExpression - : terminalExpression ((op='*'|op='/'|op='%') terminalExpression)* + : unaryExpression ((op+='*'|op+='/'|op+='%') unaryExpression)* + ; + +unaryExpression + : (op+='!'|op+='~'|op+='-'|op+='&')* pointerDereferenceExpression ; +pointerDereferenceExpression + : op+='*'* accessExpression + ; + +accessExpression + : terminalExpression accessExpression1? + ; + +accessExpression1 + : '[' subscript=expression end=']' accessExpression1? + | '.' (name=Identifier|name=NumericLiteral) accessExpression1? + ; + + terminalExpression - : literal + : literalExpression + | nameExpression | structConstructor | arrayConstructor | enumConstructor + | tupleConstructor | functionCall | ifExpression | switchExpression | blockExpression | parenthesisExpression ; + +literalExpression + : literal + ; + +nameExpression + : identifierName + ; + +structConstructor + : typeName? '{' structConstructorMember (',' structConstructorMember)* ','? '}' + ; + +structConstructorMember + : name=Identifier ':' expression + ; + +arrayConstructor + : (arrayType | typeName? '[' ']') '{' (expression (',' expression)* ','?)? '}' + ; + +enumConstructor + : typeName? '\'' name=Identifier + ; + +tupleConstructor + : '(' ')' + | '(' expression ',' ')' + | '(' expression (',' expression)+ ','? ')' + ; + + +functionCall + : identifierName '(' (expression (',' expression)*)? ')' + ; + +ifExpression + : IfKeyword cond=expression then=blockExpression elseIfExpression* (ElseKeyword else=blockExpression)? + ; + +elseIfExpression + : ElseKeyword IfKeyword cond=expression then=blockExpression + ; + + +switchExpression + : SwitchKeyword expression '{' (switchDefault ','?)? '}' + | SwitchKeyword expression '{' switchCase (',' switchCase)* (',' switchDefault ','?)? '}' + ; + +switchCase + : CaseKeyword literal ':' (expression|FallthroughKeyword) + ; + +switchDefault + : DefaultKeyword ':' expression + ; + +blockExpression + : '{' terminatedStatement* expression? '}' + ; + +parenthesisExpression + : '(' expression ')' + ; + /////////////////////////// - + +MeowKeyword: 'm' 'e'+ 'o'* 'w' -> channel(HIDDEN); // ignores all me+o*ws in the code +NyaKeyword: '-ny' 'a'+ -> channel(HIDDEN); // ignores all -nya+s in the code + ImportKeyword: 'import'; AsKeyword: 'as'; PubKeyword: 'pub'; @@ -253,6 +379,16 @@ BreakKeyword: 'break'; ContinueKeyword: 'continue'; ReturnKeyword: 'return'; LoopKeyword: 'loop'; +IfKeyword: 'if'; +ElseKeyword: 'else'; +SwitchKeyword: 'switch'; +CaseKeyword: 'case'; +FallthroughKeyword: 'fallthrough'; +DefaultKeyword: 'default'; + + +AssignmentOperator: '='|'+='|'-='|'*='|'/='|'%='|'&='|'|='|'^='|'<<='|'>>='; + diff --git a/parser/MeowVisitorException.cs b/parser/MeowVisitorException.cs new file mode 100644 index 0000000..76de573 --- /dev/null +++ b/parser/MeowVisitorException.cs @@ -0,0 +1,13 @@ +using Antlr4.Runtime; + +namespace meowlang.parser; + +public class MeowVisitorException : Exception +{ + public IToken Token { get; } + + public MeowVisitorException(IToken token, string message) : base(message) + { + Token = token; + } +} \ No newline at end of file diff --git a/parser/Model.cs b/parser/Model.cs new file mode 100644 index 0000000..58bc5f8 --- /dev/null +++ b/parser/Model.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record Model(Span Span, List Imports, List Declarations) : ModelBase(Span); \ No newline at end of file diff --git a/parser/ModelBase.cs b/parser/ModelBase.cs index 59aee58..2cb10a8 100644 --- a/parser/ModelBase.cs +++ b/parser/ModelBase.cs @@ -1,3 +1,3 @@ namespace meowlang.parser; -public record ModelBase([property:Ignore] Span span); \ No newline at end of file +public record ModelBase([property:Ignore] Span Span); \ No newline at end of file diff --git a/parser/NameExpressionModel.cs b/parser/NameExpressionModel.cs new file mode 100644 index 0000000..e912b27 --- /dev/null +++ b/parser/NameExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record NameExpressionModel(Span Span, IdentifierNameModel Name): ExpressionModel(Span); \ No newline at end of file diff --git a/parser/NumericLiteralModel.cs b/parser/NumericLiteralModel.cs new file mode 100644 index 0000000..6365bd4 --- /dev/null +++ b/parser/NumericLiteralModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record NumericLiteralModel(Span Span, string StringValue) : LiteralModel(Span); \ No newline at end of file diff --git a/parser/ParenthesisExpressionModel.cs b/parser/ParenthesisExpressionModel.cs new file mode 100644 index 0000000..8723e99 --- /dev/null +++ b/parser/ParenthesisExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ParenthesisExpressionModel(Span Span, ExpressionModel Expression) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/Parser.cs b/parser/Parser.cs index 92fe72b..1f32587 100644 --- a/parser/Parser.cs +++ b/parser/Parser.cs @@ -8,8 +8,9 @@ public class Parser public static Model? Parse(string path) { var lexer = new MeowLexer(new AntlrFileStream(path)); - var parser = new MeowParser(new CommonTokenStream(lexer)); - var visitor = new Visitor(); + var tokenStream = new CommonTokenStream(lexer); + var parser = new MeowParser(tokenStream); + var visitor = new VisitorNya(); var file = parser.file(); if (parser.NumberOfSyntaxErrors > 0) { diff --git a/parser/PatternModel.cs b/parser/PatternModel.cs new file mode 100644 index 0000000..cdf9df4 --- /dev/null +++ b/parser/PatternModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record PatternModel(Span Span, List Expressions) : ModelBase(Span); \ No newline at end of file diff --git a/parser/PointerDereferenceExpressionModel.cs b/parser/PointerDereferenceExpressionModel.cs new file mode 100644 index 0000000..d85e2b5 --- /dev/null +++ b/parser/PointerDereferenceExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record PointerDereferenceExpressionModel(Span Span, ExpressionModel Expression) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/PointerReferenceExpressionModel.cs b/parser/PointerReferenceExpressionModel.cs new file mode 100644 index 0000000..f66e052 --- /dev/null +++ b/parser/PointerReferenceExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record PointerReferenceExpressionModel(Span Span, ExpressionModel Expression) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/PointerTypeReferenceModel.cs b/parser/PointerTypeReferenceModel.cs new file mode 100644 index 0000000..73716b0 --- /dev/null +++ b/parser/PointerTypeReferenceModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record PointerTypeReferenceModel(Span Span, TypeReferenceModel Type) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/ReturnStatementModel.cs b/parser/ReturnStatementModel.cs new file mode 100644 index 0000000..d61e7c0 --- /dev/null +++ b/parser/ReturnStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record ReturnStatementModel(Span Span, ExpressionModel? Expression) : StatementModel(Span); \ No newline at end of file diff --git a/parser/SliceTypeModel.cs b/parser/SliceTypeModel.cs new file mode 100644 index 0000000..216429c --- /dev/null +++ b/parser/SliceTypeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record SliceTypeModel(Span Span, TypeReferenceModel Type) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/StatementModel.cs b/parser/StatementModel.cs new file mode 100644 index 0000000..72f30d5 --- /dev/null +++ b/parser/StatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record StatementModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/StatementVisitorNya.cs b/parser/StatementVisitorNya.cs new file mode 100644 index 0000000..d1855ab --- /dev/null +++ b/parser/StatementVisitorNya.cs @@ -0,0 +1,83 @@ +using Antlr4.Runtime; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class StatementVisitorNya : MeowBaseVisitorNya +{ + public override StatementModel VisitTerminatedStatement(MeowParser.TerminatedStatementContext context) + { + return Visit(context.statement() ?? context.blockStatement() as ParserRuleContext); + } + + public override StatementModel VisitBlockStatement(MeowParser.BlockStatementContext context) + { + if (context.loopStatement() != null) + { + return Visit(context.loopStatement()); + } + + var expression = new ExpressionVisitorNya().Visit(context); + return new ExpressionStatementModel(context.GetSpan(), expression); + } + + public override StatementModel VisitLoopStatement(MeowParser.LoopStatementContext context) + { + var body = context.terminatedStatement().Select(Visit).ToList(); + if (context.condition == null) + { + return new InfiniteLoopStatementModel(context.GetSpan(), body); + } + + var condition = new ExpressionVisitorNya().Visit(context.condition); + if (context.forIndicator == null) + { + return new WhileLoopStatementModel(context.GetSpan(), body, condition); + } + + var increment = new ExpressionVisitorNya().TryVisit(context.increment); + var initStatement = TryVisit(context.initDeclaration) as VariableDeclarationStatementModel; + var initExpression = new ExpressionVisitorNya().TryVisit(context.initExpression); + return new ForLoopStatementModel(context.GetSpan(), body, initStatement, initExpression, condition, increment); + } + + public override StatementModel VisitBreakStatement(MeowParser.BreakStatementContext context) + { + var label = context.label?.Text; + return new BreakStatementModel(context.GetSpan(), label); + } + + public override StatementModel VisitContinueStatement(MeowParser.ContinueStatementContext context) + { + var label = context.label?.Text; + return new ContinueStatementModel(context.GetSpan(), label); + } + + public override StatementModel VisitReturnStatement(MeowParser.ReturnStatementContext context) + { + var expression = new ExpressionVisitorNya().TryVisit(context.expression()); + return new ReturnStatementModel(context.GetSpan(), expression); + } + + public override StatementModel VisitExpressionStatement(MeowParser.ExpressionStatementContext context) + { + var expression = new ExpressionVisitorNya().Visit(context.expression()); + return new ExpressionStatementModel(context.GetSpan(), expression); + } + + public override StatementModel VisitVariableDeclarationStatement( + MeowParser.VariableDeclarationStatementContext context) + { + var names = context._name.Select(x => x.Text).ToList(); + var initializer = new ExpressionVisitorNya().Visit(context.expression()); + return new VariableDeclarationStatementModel(context.GetSpan(), names, initializer); + } + + public override StatementModel VisitConstantDeclarationStatement( + MeowParser.ConstantDeclarationStatementContext context) + { + var names = context._name.Select(x => x.Text).ToList(); + var initializer = new ExpressionVisitorNya().Visit(context.expression()); + return new ConstantDeclarationStatementModel(context.GetSpan(), names, initializer); + } +} \ No newline at end of file diff --git a/parser/StringLiteralModel.cs b/parser/StringLiteralModel.cs new file mode 100644 index 0000000..ac31c74 --- /dev/null +++ b/parser/StringLiteralModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record StringLiteralModel(Span Span, string Value) : LiteralModel(Span); \ No newline at end of file diff --git a/parser/StructAccessExpressionModel.cs b/parser/StructAccessExpressionModel.cs new file mode 100644 index 0000000..238d7e5 --- /dev/null +++ b/parser/StructAccessExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record StructAccessExpressionModel(Span Span, ExpressionModel Expression, string Name) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/StructConstructorExpressionModel.cs b/parser/StructConstructorExpressionModel.cs new file mode 100644 index 0000000..73c21af --- /dev/null +++ b/parser/StructConstructorExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record StructConstructorExpressionModel(Span Span, TypeNameModel? Type, + List Members) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/StructConstructorMemberModel.cs b/parser/StructConstructorMemberModel.cs new file mode 100644 index 0000000..1a97a3c --- /dev/null +++ b/parser/StructConstructorMemberModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record StructConstructorMemberModel(Span Span, string Name, ExpressionModel Value) : ModelBase(Span); \ No newline at end of file diff --git a/parser/StructMemberModel.cs b/parser/StructMemberModel.cs new file mode 100644 index 0000000..fdf1473 --- /dev/null +++ b/parser/StructMemberModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record StructMemberModel(Span Span, TypeReferenceModel Type, string Name) : ModelBase(Span); \ No newline at end of file diff --git a/parser/StructMemberVisitorNya.cs b/parser/StructMemberVisitorNya.cs new file mode 100644 index 0000000..24a9ac7 --- /dev/null +++ b/parser/StructMemberVisitorNya.cs @@ -0,0 +1,13 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class StructMemberVisitorNya : MeowBaseVisitorNya +{ + public override StructMemberModel VisitStructMember(MeowParser.StructMemberContext context) + { + var type = new TypeReferenceVisitorNya().Visit(context.typeReference()); + var name = context.name.Text; + return new StructMemberModel(context.GetSpan(), type, name); + } +} \ No newline at end of file diff --git a/parser/StructTopLevelConstructModel.cs b/parser/StructTopLevelConstructModel.cs new file mode 100644 index 0000000..9aa92da --- /dev/null +++ b/parser/StructTopLevelConstructModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record StructTopLevelConstructModel(Span Span, List Attributes, bool Pub, string Name, List TypeParameters, + List Constraints, StructTypeModel Struct) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/StructTypeModel.cs b/parser/StructTypeModel.cs new file mode 100644 index 0000000..7415c0d --- /dev/null +++ b/parser/StructTypeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record StructTypeModel(Span Span, List Members) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/SwitchExpressionModel.cs b/parser/SwitchExpressionModel.cs new file mode 100644 index 0000000..2c87a19 --- /dev/null +++ b/parser/SwitchExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record SwitchExpressionModel(Span Span, ExpressionModel Expression, + List<(LiteralModel Value, ExpressionModel? Body)> Cases, ExpressionModel? Default) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/TopLevelConstructModel.cs b/parser/TopLevelConstructModel.cs new file mode 100644 index 0000000..4e848b4 --- /dev/null +++ b/parser/TopLevelConstructModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record TopLevelConstructModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/TopLevelStatementModel.cs b/parser/TopLevelStatementModel.cs new file mode 100644 index 0000000..9b165ed --- /dev/null +++ b/parser/TopLevelStatementModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record TopLevelStatementModel(Span Span, StatementModel Statement): TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/TupleConstructorExpressionModel.cs b/parser/TupleConstructorExpressionModel.cs new file mode 100644 index 0000000..a35c42b --- /dev/null +++ b/parser/TupleConstructorExpressionModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record TupleConstructorExpressionModel(Span Span, List Values) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/TupleTopLevelConstructModel.cs b/parser/TupleTopLevelConstructModel.cs new file mode 100644 index 0000000..b093318 --- /dev/null +++ b/parser/TupleTopLevelConstructModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record TupleTopLevelConstructModel(Span Span, List Attributes, bool Pub, string Name, List TypeParameters, + List Constraints, TupleTypeModel Tuple) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/TupleTypeModel.cs b/parser/TupleTypeModel.cs new file mode 100644 index 0000000..dc612c4 --- /dev/null +++ b/parser/TupleTypeModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record TupleTypeModel(Span Span, List Types) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/TypeAliasModel.cs b/parser/TypeAliasModel.cs new file mode 100644 index 0000000..b6e6fb7 --- /dev/null +++ b/parser/TypeAliasModel.cs @@ -0,0 +1,5 @@ +namespace meowlang.parser; + +public record TypeAliasModel + (Span Span, List Attributes, bool Pub, string Name, List TypeParameters, TypeReferenceModel Type) : TopLevelConstructModel(Span); + diff --git a/parser/TypeNameModel.cs b/parser/TypeNameModel.cs new file mode 100644 index 0000000..a44dfb3 --- /dev/null +++ b/parser/TypeNameModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record TypeNameModel(Span Span, IdentifierNameModel Name, List TypeParameters, + List Nested) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/TypeParameterModel.cs b/parser/TypeParameterModel.cs new file mode 100644 index 0000000..8887965 --- /dev/null +++ b/parser/TypeParameterModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public record TypeParameterModel(Span Span, string Name) : ModelBase(Span); \ No newline at end of file diff --git a/parser/TypeReferenceModel.cs b/parser/TypeReferenceModel.cs new file mode 100644 index 0000000..1ec8534 --- /dev/null +++ b/parser/TypeReferenceModel.cs @@ -0,0 +1,3 @@ +namespace meowlang.parser; + +public abstract record TypeReferenceModel(Span Span) : ModelBase(Span); \ No newline at end of file diff --git a/parser/TypeReferenceVisitorNya.cs b/parser/TypeReferenceVisitorNya.cs new file mode 100644 index 0000000..788d250 --- /dev/null +++ b/parser/TypeReferenceVisitorNya.cs @@ -0,0 +1,54 @@ +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class TypeReferenceVisitorNya : MeowBaseVisitorNya +{ + public override TypeReferenceModel VisitTypeReference(MeowParser.TypeReferenceContext context) + { + var type = Visit(context.nonPointerTypeReference()); + if (context.pointer != null) + { + return new PointerTypeReferenceModel(context.GetSpan(), type); + } + + return type; + } + + public override TypeReferenceModel VisitTypeName(MeowParser.TypeNameContext context) + { + var name = new IdentifierNameVisitorNya().Visit(context.identifierName()); + var typeParameters = context._genericType.Select(Visit).ToList(); + var nestedName = context._name.Select(x => x.Text).ToList(); + return new TypeNameModel(context.GetSpan(), name, typeParameters, nestedName); + } + + public override TypeReferenceModel VisitArrayType(MeowParser.ArrayTypeContext context) + { + var type = Visit(context.typeReference()); + if (context.length == null) + { + return new SliceTypeModel(context.GetSpan(), type); + } + + return new ArrayTypeModel(context.GetSpan(), type, context.length.Text); + } + + public override TypeReferenceModel VisitTupleType(MeowParser.TupleTypeContext context) + { + var types = context.typeReference().Select(Visit).ToList(); + return new TupleTypeModel(context.GetSpan(), types); + } + + public override TypeReferenceModel VisitStructType(MeowParser.StructTypeContext context) + { + var members = context.structMember().Select(x => new StructMemberVisitorNya().Visit(x)).ToList(); + return new StructTypeModel(context.GetSpan(), members); + } + + public override TypeReferenceModel VisitEnumType(MeowParser.EnumTypeContext context) + { + var members = context.enumMember().Select(x => new EnumMemberVisitorNya().Visit(x)).ToList(); + return new EnumTypeModel(context.GetSpan(), members); + } +} \ No newline at end of file diff --git a/parser/UnaryOperationExpressionModel.cs b/parser/UnaryOperationExpressionModel.cs new file mode 100644 index 0000000..5103df6 --- /dev/null +++ b/parser/UnaryOperationExpressionModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record UnaryOperationExpressionModel + (Span Span, UnaryOperator Operator, ExpressionModel Expression) : ExpressionModel(Span); \ No newline at end of file diff --git a/parser/UnaryOperator.cs b/parser/UnaryOperator.cs new file mode 100644 index 0000000..e813646 --- /dev/null +++ b/parser/UnaryOperator.cs @@ -0,0 +1,8 @@ +namespace meowlang.parser; + +public enum UnaryOperator +{ + LogicalNot, + BitwiseNot, + Negative, +} \ No newline at end of file diff --git a/parser/UnaryOperatorExtensions.cs b/parser/UnaryOperatorExtensions.cs new file mode 100644 index 0000000..3b689c2 --- /dev/null +++ b/parser/UnaryOperatorExtensions.cs @@ -0,0 +1,18 @@ +namespace meowlang.parser; + +public static class UnaryOperatorExtensions +{ + public static UnaryOperator ToUnaryOperator(this string str) => str switch + { + "!" => UnaryOperator.LogicalNot, + "~" => UnaryOperator.BitwiseNot, + "-" => UnaryOperator.Negative, + }; + + public static string ToString(this UnaryOperator op) => op switch + { + UnaryOperator.LogicalNot => "!", + UnaryOperator.BitwiseNot => "~", + UnaryOperator.Negative => "-", + }; +} \ No newline at end of file diff --git a/parser/Utils.cs b/parser/Utils.cs index c70e241..8a9e933 100644 --- a/parser/Utils.cs +++ b/parser/Utils.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; using Antlr4.Runtime; using Newtonsoft.Json; @@ -41,6 +42,12 @@ public static class ObjectExtensions string json; + if (o is ITuple t) + { + var values = Enumerable.Range(0, t.Length).Select(i => t[i]).ToList(); + return values.AutoToString(); + } + if (type.IsAssignableTo(typeof(IEnumerable))) { var enumerable = (o as IEnumerable)!.Cast(); diff --git a/parser/VariableDeclarationStatementModel.cs b/parser/VariableDeclarationStatementModel.cs new file mode 100644 index 0000000..0abdc01 --- /dev/null +++ b/parser/VariableDeclarationStatementModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record VariableDeclarationStatementModel + (Span Span, List Names, ExpressionModel Initializer) : StatementModel(Span); \ No newline at end of file diff --git a/parser/Visitor.cs b/parser/Visitor.cs deleted file mode 100644 index 6a15bb9..0000000 --- a/parser/Visitor.cs +++ /dev/null @@ -1,412 +0,0 @@ -using System.Reflection.Metadata; -using System.Text; -using System.Text.RegularExpressions; -using Antlr4.Runtime; -using meowlang.parser.antlr; - -namespace meowlang.parser; - -public class InvalidEscapeSequenceException : Exception -{ - public InvalidEscapeSequenceException(string escapeSequence) : base($"invalid escape sequence `{escapeSequence}`") - { - } -} - -public class MeowVisitorException : Exception -{ - public IToken Token { get; } - - public MeowVisitorException(IToken token, string message) : base(message) - { - Token = token; - } -} - -public class InvalidImportPathException : MeowVisitorException -{ - public InvalidImportPathException(IToken context, string message) : base(context, message) - { - } -} - -public class Visitor : MeowBaseVisitor -{ - public override Model VisitFile(MeowParser.FileContext context) - { - var imports = context.importStatement().Select(x => new ImportVisitor().Visit(x)).ToList(); - var declarations = context.declaration().Select(x => new DeclarationVisitor().Visit(x)).ToList(); - - return new Model(context.GetSpan(), imports, declarations); - } -} - -public class ImportVisitor : MeowBaseVisitor -{ - private static readonly string PathSegmentPattern = "[a-z][a-z0-9_]*"; - - private static readonly Regex ProjectRegex = new Regex("^[a-z][a-z0-9_]*$"); - - private static readonly Regex PathRegexNoProject = - new Regex($"^({PathSegmentPattern}|\\.|\\.\\.)(/{PathSegmentPattern})*$"); - - private static readonly Regex PathRegex = new Regex($"^{PathSegmentPattern}(/{PathSegmentPattern})*$"); - - public override ImportModel VisitImportStatement(MeowParser.ImportStatementContext context) - { - var path = context.importpath.Text[1..^1].Unescape(); - - string? project = null; - - if (path.Contains(':')) - { - var parts = path.Split(':'); - project = parts[0]; - if (!ProjectRegex.IsMatch(project)) - { - throw new InvalidImportPathException(context.importpath, "malformed project name"); - } - - path = parts[1]; - if (!PathRegex.IsMatch(path)) - { - throw new InvalidImportPathException(context.importpath, "malformed path"); - } - } - else - { - if (!PathRegexNoProject.IsMatch(path)) - { - throw new InvalidImportPathException(context.importpath, "malformed path"); - } - } - - var alias = context.importname?.Text; - - return new ImportModel(context.GetSpan(), project, path, alias); - } -} - -public class DeclarationVisitor : MeowBaseVisitor -{ - public override DeclarationModel VisitFunction(MeowParser.FunctionContext context) - { - var attributes = context.attribute().Select(x => new AttributeVisitor().Visit(x)).ToList(); - var pub = context.pub != null; - var name = context.name.Text; - - var typeParameters = - context.genericParameters()?._name.Select(x => new TypeParameterModel(x.GetSpan(), x.Text)).ToList() ?? - new List(); - var functionParameters = context.functionParameters().functionParameter() - .Select(x => new FunctionParameterVisitor().Visit(x)).ToList(); - var functionReturns = context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitor().Visit(x)) - .ToList() ?? new List(); - var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ?? - new List(); - - return new FunctionModel(context.GetSpan(), attributes, pub, name, typeParameters, functionParameters, - functionReturns, constraints, - new FunctionBodyModel(context.functionBody().GetSpan())); // TODO: visit function body - } - - public override ConstraintDeclarationModel VisitConstraintDeclaration( - MeowParser.ConstraintDeclarationContext context) - { - var name = context.name.Text; - var typeNames = context._types.Select(x => x.Text).ToList(); - var rules = context.constraintRule().Select(x => new ConstraintRuleVisitor().Visit(x)).ToList(); - return new ConstraintDeclarationModel(context.GetSpan(), name, typeNames, rules); - } - - public override DeclarationModel VisitStructDeclaration(MeowParser.StructDeclarationContext context) - { - var name = context.name.Text; - var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); - var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ?? - new List(); - var structModel = new TypeReferenceVisitor().Visit(context.structType()) as StructTypeModel; - return new StructDeclarationModel(context.GetSpan(), name, typeParameters, constraints, structModel!); - } - - public override DeclarationModel VisitEnumDeclaration(MeowParser.EnumDeclarationContext context) - { - var name = context.name.Text; - var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); - var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ?? - new List(); - - var enumModel = new TypeReferenceVisitor().Visit(context.enumType()) as EnumTypeModel; - return new EnumDeclarationModel(context.GetSpan(), name, typeParameters, constraints, enumModel!); - } - - public override DeclarationModel VisitTupleDeclaration(MeowParser.TupleDeclarationContext context) - { - var name = context.name.Text; - var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); - var constraints = context.constraint()?.Select(x => new FunctionConstraintVisitor().Visit(x)).ToList() ?? - new List(); - var tupleModel = new TypeReferenceVisitor().Visit(context.tupleType()) as TupleTypeModel; - return new TupleDeclarationModel(context.GetSpan(), name, typeParameters, constraints, tupleModel!); - } - - public override DeclarationModel VisitTypeAlias(MeowParser.TypeAliasContext context) - { - var name = context.name.Text; - var typeParameters = context.genericParameters()?._name.Select(x => x.Text).ToList() ?? new List(); - var type = new TypeReferenceVisitor().Visit(context.typeReference()); - return new TypeAliasModel(context.GetSpan(), name, typeParameters, type); - } -} - -public class AttributeVisitor : MeowBaseVisitor -{ - public override AttributeModel VisitAttribute(MeowParser.AttributeContext context) - { - var name = context.name.Text; - var values = context.attributeValue().Select(x => new AttributeValueVisitor().Visit(x)).ToList(); - return new AttributeModel(context.GetSpan(), name, values); - } -} - -public class AttributeValueVisitor : MeowBaseVisitor -{ - public override AttributeValueModel VisitAttributeValue(MeowParser.AttributeValueContext context) - { - if (context.id != null) - { - return new IdentifierAttributeValueModel(context.GetSpan(), context.id.Text); - } - - var literal = new LiteralVisitor().Visit(context.literal()); - return new LiteralAttributeValueModel(context.GetSpan(), literal); - } -} - -public class FunctionParameterVisitor : MeowBaseVisitor -{ - public override FunctionParameterModel VisitFunctionParameter(MeowParser.FunctionParameterContext context) - { - var type = new TypeReferenceVisitor().Visit(context.typeReference()); - var name = context.name.Text; - return new FunctionParameterModel(context.GetSpan(), type, name); - } -} - -public class TypeReferenceVisitor : MeowBaseVisitor -{ - public override TypeReferenceModel VisitTypeReference(MeowParser.TypeReferenceContext context) - { - var type = Visit(context.nonPointerTypeReference()); - if (context.pointer != null) - { - return new PointerTypeReferenceModel(context.GetSpan(), type); - } - - return type; - } - - public override TypeReferenceModel VisitTypeName(MeowParser.TypeNameContext context) - { - var import = context.importName?.Text; - var nestedName = context._name.Select(x => x.Text).ToList(); - - var typeParameters = context._genericType.Select(Visit).ToList(); - - return new TypeNameModel(context.GetSpan(), import, nestedName[0], typeParameters, nestedName.Skip(1).ToList()); - } - - public override TypeReferenceModel VisitArrayType(MeowParser.ArrayTypeContext context) - { - var type = Visit(context.typeReference()); - if (context.length == null) - { - return new SliceTypeModel(context.GetSpan(), type); - } - - return new ArrayTypeModel(context.GetSpan(), type, context.length.Text); - } - - public override TypeReferenceModel VisitTupleType(MeowParser.TupleTypeContext context) - { - var types = context.typeReference().Select(Visit).ToList(); - return new TupleTypeModel(context.GetSpan(), types); - } - - public override TypeReferenceModel VisitStructType(MeowParser.StructTypeContext context) - { - var members = context.structMember().Select(x => new StructMemberVisitor().Visit(x)).ToList(); - return new StructTypeModel(context.GetSpan(), members); - } - - public override TypeReferenceModel VisitEnumType(MeowParser.EnumTypeContext context) - { - var members = context.enumMember().Select(x => new EnumMemberVisitor().Visit(x)).ToList(); - return new EnumTypeModel(context.GetSpan(), members); - } -} - -public class StructMemberVisitor : MeowBaseVisitor -{ - public override StructMemberModel VisitStructMember(MeowParser.StructMemberContext context) - { - var type = new TypeReferenceVisitor().Visit(context.typeReference()); - var name = context.name.Text; - return new StructMemberModel(context.GetSpan(), type, name); - } -} - -public class EnumMemberVisitor : MeowBaseVisitor -{ - public override EnumMemberModel VisitEnumMember(MeowParser.EnumMemberContext context) - { - var name = context.name.Text; - - TypeReferenceModel? type = null; - var typeRef = context.typeReference(); - if (typeRef != null) - { - type = new TypeReferenceVisitor().Visit(typeRef); - } - - return new EnumMemberModel(context.GetSpan(), name, type); - } -} - -public class FunctionConstraintVisitor : MeowBaseVisitor -{ - public override ConstraintModel VisitConstraint(MeowParser.ConstraintContext context) - { - var name = context.name.Text; - var typeNames = context._typenames.Select(x => x.Text).ToList(); - return new ConstraintModel(context.GetSpan(), name, typeNames); - } -} - -public class LiteralVisitor : MeowBaseVisitor -{ - public override LiteralModel VisitStringLiteral(MeowParser.StringLiteralContext context) - { - var value = context.val.Text[1..^1].Unescape(); - return new StringLiteralModel(context.GetSpan(), value); - } - - public override LiteralModel VisitBoolLiteral(MeowParser.BoolLiteralContext context) - { - var text = context.val.Text; - var value = text == "true"; - return new BoolLiteralModel(context.GetSpan(), value); - } - - public override LiteralModel VisitNumericLiteral(MeowParser.NumericLiteralContext context) - { - return new NumericLiteralModel(context.GetSpan(), context.val.Text); - } - - public override LiteralModel VisitCharacterLiteral(MeowParser.CharacterLiteralContext context) - { - var value = context.val.Text[1..^1].Unescape(); - return new CharacterLiteralModel(context.GetSpan(), value); - } -} - -public class ConstraintRuleVisitor : MeowBaseVisitor -{ - public override ConstraintRuleModel VisitEmbedConstraintRule(MeowParser.EmbedConstraintRuleContext context) - { - var name = context.name.Text; - var types = context._types.Select(x => new TypeReferenceVisitor().Visit(x)).ToList(); - return new EmbedConstraintRuleModel(context.GetSpan(), name, types); - } - - public override ConstraintRuleModel VisitFunctionConstraintRule(MeowParser.FunctionConstraintRuleContext context) - { - var name = context.name.Text; - var parameters = context.constraintFunctionParameters().typeReference() - .Select(x => new TypeReferenceVisitor().Visit(x)).ToList(); - var returns = - context.functionReturn()?.typeReference().Select(x => new TypeReferenceVisitor().Visit(x)).ToList() ?? - new List(); - return new FunctionConstraintRuleModel(context.GetSpan(), name, parameters, returns); - } -} - -public record Model(Span span, List Imports, List Declarations) : ModelBase(span); - -public record ImportModel(Span span, string? Project, string Path, string? Alias) : ModelBase(span); - -public abstract record DeclarationModel(Span span) : ModelBase(span); - -public record FunctionModel(Span span, List Attributes, bool Pub, string Name, - List TypeParameters, List Parameters, List Returns, - List Constraints, FunctionBodyModel Body) : DeclarationModel(span); - -public record AttributeModel(Span span, string Name, List Values) : ModelBase(span); - -public abstract record AttributeValueModel(Span span) : ModelBase(span); - -public record IdentifierAttributeValueModel(Span span, string Name) : AttributeValueModel(span); - -public record LiteralAttributeValueModel(Span span, LiteralModel Literal) : AttributeValueModel(span); - -public record TypeParameterModel(Span span, string Name) : ModelBase(span); - -public record FunctionParameterModel(Span span, TypeReferenceModel Type, string Name) : ModelBase(span); - -public abstract record TypeReferenceModel(Span span) : ModelBase(span); - -public record PointerTypeReferenceModel(Span span, TypeReferenceModel Type) : TypeReferenceModel(span); - -public record TypeNameModel(Span span, string? ImportName, string Name, List TypeParameters, - List Nested) : TypeReferenceModel(span); - -public record ArrayTypeModel(Span span, TypeReferenceModel Type, string Length) : TypeReferenceModel(span); - -public record SliceTypeModel(Span span, TypeReferenceModel Type) : TypeReferenceModel(span); - -public record TupleTypeModel(Span span, List Types) : TypeReferenceModel(span); - -public record StructTypeModel(Span span, List Members) : TypeReferenceModel(span); - -public record StructMemberModel(Span span, TypeReferenceModel Type, string Name) : ModelBase(span); - -public record EnumTypeModel(Span span, List Members) : TypeReferenceModel(span); - -public record EnumMemberModel(Span span, string Name, TypeReferenceModel? Type) : ModelBase(span); - -public record ConstraintModel(Span span, string Name, List TypeNames) : ModelBase(span); - -public record FunctionBodyModel(Span span) : ModelBase(span); - -public abstract record LiteralModel(Span span) : ModelBase(span); - -public record StringLiteralModel(Span span, string Value) : LiteralModel(span); - -public record CharacterLiteralModel(Span span, string Value) : LiteralModel(span); - -public record NumericLiteralModel(Span span, string StringValue) : LiteralModel(span); - -public record BoolLiteralModel(Span span, bool Value) : LiteralModel(span); - -public record ConstraintDeclarationModel - (Span span, string Name, List TypeNames, List Rules) : DeclarationModel(span); - -public abstract record ConstraintRuleModel(Span span) : ModelBase(span); - -public record EmbedConstraintRuleModel - (Span span, string Name, List Types) : ConstraintRuleModel(span); - -public record FunctionConstraintRuleModel(Span span, string Name, List Parameters, - List Returns) : ConstraintRuleModel(span); - -public record StructDeclarationModel(Span span, string Name, List TypeParameters, - List Constraints, StructTypeModel Struct) : DeclarationModel(span); - -public record EnumDeclarationModel(Span span, string Name, List TypeParameters, - List Constraints, EnumTypeModel Enum) : DeclarationModel(span); - -public record TupleDeclarationModel(Span span, string Name, List TypeParameters, - List Constraints, TupleTypeModel Tuple) : DeclarationModel(span); - -public record TypeAliasModel - (Span span, string Name, List TypeParameters, TypeReferenceModel Type) : DeclarationModel(span); \ No newline at end of file diff --git a/parser/VisitorNya.cs b/parser/VisitorNya.cs new file mode 100644 index 0000000..52f1dd0 --- /dev/null +++ b/parser/VisitorNya.cs @@ -0,0 +1,17 @@ +using System.Linq.Expressions; +using System.Reflection.Metadata; +using System.Text; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +public class VisitorNya : MeowBaseVisitorNya +{ + public override Model VisitFile(MeowParser.FileContext context) + { + var imports = context.importStatement().Select(x => new ImportVisitorNya().Visit(x)).ToList(); + var declarations = context.topLevelDeclaration().Select(x => new DeclarationVisitorNya().Visit(x)).ToList(); + + return new Model(context.GetSpan(), imports, declarations); + } +} \ No newline at end of file diff --git a/parser/WhileLoopStatementModel.cs b/parser/WhileLoopStatementModel.cs new file mode 100644 index 0000000..4026f97 --- /dev/null +++ b/parser/WhileLoopStatementModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record WhileLoopStatementModel + (Span Span, List Body, ExpressionModel Condition) : LoopStatementModel(Span, Body); \ No newline at end of file