diff --git a/MeowLang.sln b/MeowLang.sln index 1f402ef..a0159b2 100644 --- a/MeowLang.sln +++ b/MeowLang.sln @@ -4,6 +4,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "compiler", "compiler\compil EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "parser", "parser\parser.csproj", "{240E1F81-DB04-46CE-AB7B-60616B6D868C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "typechecker", "typechecker\typechecker.csproj", "{C8E93E36-E566-4610-A5A9-58EAA3A0A286}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "visitorgenerator", "visitorgenerator\visitorgenerator.csproj", "{21040DD5-B347-4A5C-B40C-1C470BA9A67A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +22,13 @@ Global {240E1F81-DB04-46CE-AB7B-60616B6D868C}.Debug|Any CPU.Build.0 = Debug|Any CPU {240E1F81-DB04-46CE-AB7B-60616B6D868C}.Release|Any CPU.ActiveCfg = Release|Any CPU {240E1F81-DB04-46CE-AB7B-60616B6D868C}.Release|Any CPU.Build.0 = Release|Any CPU + {C8E93E36-E566-4610-A5A9-58EAA3A0A286}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8E93E36-E566-4610-A5A9-58EAA3A0A286}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8E93E36-E566-4610-A5A9-58EAA3A0A286}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8E93E36-E566-4610-A5A9-58EAA3A0A286}.Release|Any CPU.Build.0 = Release|Any CPU + {21040DD5-B347-4A5C-B40C-1C470BA9A67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21040DD5-B347-4A5C-B40C-1C470BA9A67A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21040DD5-B347-4A5C-B40C-1C470BA9A67A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21040DD5-B347-4A5C-B40C-1C470BA9A67A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/README.md b/README.md index 8dab8f4..0bdfb48 100644 --- a/README.md +++ b/README.md @@ -179,13 +179,18 @@ Their type is an `u8` array with length of the string in bytes. ``` ###### use ``` + + let a: [u8] = "foo"; let b: u8 = a[1]; let d: [s32; 4] = []{1,2,3,4}; let e = [u8]{1,2,3,4}; +let f = d[1:3]; // f has type [s32] (slice) now + + type Arr = [u8]; -let f = Arr[]{1,2,3}; +let g = Arr[]{1,2,3}; ``` ##### struct @@ -202,6 +207,7 @@ type Point = struct { z: s32; } + type Options = struct { api: struct { int foo; diff --git a/compiler/Compiler.cs b/compiler/Compiler.cs index 2905f6a..599a3a9 100644 --- a/compiler/Compiler.cs +++ b/compiler/Compiler.cs @@ -1,5 +1,6 @@ using System; using meowlang.parser; +using meowlang.typechecker; namespace meowlang.compiler; @@ -9,6 +10,8 @@ static class Compiler { var path = "example.mew"; var model = Parser.Parse(path); - Console.WriteLine(model.AutoToString()); + Console.Write(model.AutoToString()); + if (model == null) return; + TypeChecker.CheckAndInferTypes(model); } } \ No newline at end of file diff --git a/compiler/compiler.csproj b/compiler/compiler.csproj index 56d2268..8e2e7ea 100644 --- a/compiler/compiler.csproj +++ b/compiler/compiler.csproj @@ -14,6 +14,7 @@ + diff --git a/compiler/example.mew b/compiler/example.mew index 84c5c4e..877de5c 100644 --- a/compiler/example.mew +++ b/compiler/example.mew @@ -94,9 +94,23 @@ type F = Foo>; type X = [Y; 10]; */ +/* +tuple X (A,A,A); +type X = [T; 10]; +type X = (T1, T2); + fn foo() { + + let foo = X {a: 1, b: 2}; + let bar = X {a: "foo" , b: "bar"}; + + let test = Imported:X@bar []{1,2,3}; + + foo.a + 1; + bar.a + 1; + meoooow let x-nyaaaa = []{1-nya, meow 2}; outer: loop let x = 1; x < 10; x += 1 { @@ -109,4 +123,67 @@ fn foo() { default: bar(), } } -} \ No newline at end of file +} + + + +struct Bar { + y: Foo; +} + + +struct Foo { + x: enum {Foo, Bar}; +} + +struct A { + x: B; + y: s32; +} + +struct B { + x: T; +} + +struct C { + x: B; +} + +enum E { + A, + B, + C +} + +enum F { + A(u8), + B(B), + C(C) +} + +fn foo(x: u32) {} +fn foo(x: s32) {} +fn bar(x: f32) {} +fn bar(x: f64) {} + +fn test() { + let x = 1; // no idea what the type is + foo(x); // could be u32 or s32 + bar(x); // f32 and f64 conflict with u32 and s32 + +} + + + +type A = int*; + +struct B { + x: (int, int); +}*/ + +type A = [(T,int); 10]; + +struct A { + x: B; + y: s32; +} diff --git a/parser/ArrayTypeModel.cs b/parser/ArrayTypeModel.cs index 63c7465..768fc69 100644 --- a/parser/ArrayTypeModel.cs +++ b/parser/ArrayTypeModel.cs @@ -1,3 +1,3 @@ namespace meowlang.parser; -public record ArrayTypeModel(Span Span, TypeReferenceModel Type, string Length) : TypeReferenceModel(Span); \ No newline at end of file +public record ArrayTypeModel(Span Span, TypeReferenceModel Type, uint Size) : TypeReferenceModel(Span); \ No newline at end of file diff --git a/parser/ConstraintTopLevelConstructModel.cs b/parser/ConstraintDeclarationModel.cs similarity index 80% rename from parser/ConstraintTopLevelConstructModel.cs rename to parser/ConstraintDeclarationModel.cs index f43f65c..43db612 100644 --- a/parser/ConstraintTopLevelConstructModel.cs +++ b/parser/ConstraintDeclarationModel.cs @@ -1,4 +1,4 @@ namespace meowlang.parser; -public record ConstraintTopLevelConstructModel +public record ConstraintDeclarationModel (Span Span, List Attributes, bool Pub, string Name, List TypeNames, List Rules) : TopLevelConstructModel(Span); \ No newline at end of file diff --git a/parser/DeclarationVisitorNya.cs b/parser/DeclarationVisitorNya.cs index 1118255..5ed2f13 100644 --- a/parser/DeclarationVisitorNya.cs +++ b/parser/DeclarationVisitorNya.cs @@ -1,4 +1,3 @@ -using Antlr4.Runtime.Tree; using meowlang.parser.antlr; namespace meowlang.parser; @@ -33,7 +32,7 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya functionReturns, constraints, body); } - public override ConstraintTopLevelConstructModel VisitConstraintDeclaration( + public override ConstraintDeclarationModel VisitConstraintDeclaration( MeowParser.ConstraintDeclarationContext context) { var attributes = context.attribute().Select(x => new AttributeVisitorNya().Visit(x)).ToList(); @@ -41,7 +40,7 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya 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); + return new ConstraintDeclarationModel(context.GetSpan(), attributes, pub, name, typeNames, rules); } public override TopLevelConstructModel VisitStructDeclaration(MeowParser.StructDeclarationContext context) @@ -53,7 +52,7 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya 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!); + return new StructDeclarationModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, structModel!); } public override TopLevelConstructModel VisitEnumDeclaration(MeowParser.EnumDeclarationContext context) @@ -66,7 +65,7 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya new List(); var enumModel = new TypeReferenceVisitorNya().Visit(context.enumType()) as EnumTypeModel; - return new EnumTopLevelConstructModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, enumModel!); + return new EnumDeclarationModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, enumModel!); } public override TopLevelConstructModel VisitTupleDeclaration(MeowParser.TupleDeclarationContext context) @@ -78,7 +77,7 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya 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!); + return new TupleDeclarationModel(context.GetSpan(), attributes, pub, name, typeParameters, constraints, tupleModel!); } public override TopLevelConstructModel VisitTypeAlias(MeowParser.TypeAliasContext context) @@ -90,12 +89,4 @@ public class DeclarationVisitorNya : MeowBaseVisitorNya 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/EnumDeclarationModel.cs b/parser/EnumDeclarationModel.cs new file mode 100644 index 0000000..34905f4 --- /dev/null +++ b/parser/EnumDeclarationModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record EnumDeclarationModel(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/EnumTopLevelConstructModel.cs b/parser/EnumTopLevelConstructModel.cs deleted file mode 100644 index 18acbf3..0000000 --- a/parser/EnumTopLevelConstructModel.cs +++ /dev/null @@ -1,4 +0,0 @@ -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/ExpressionModel.cs b/parser/ExpressionModel.cs index fe13677..1ec380f 100644 --- a/parser/ExpressionModel.cs +++ b/parser/ExpressionModel.cs @@ -1,3 +1,5 @@ namespace meowlang.parser; -public abstract record ExpressionModel(Span Span) : ModelBase(Span); \ No newline at end of file +public abstract record ExpressionModel(Span Span) : ModelBase(Span) +{ +} \ No newline at end of file diff --git a/parser/ExpressionVisitorNya.cs b/parser/ExpressionVisitorNya.cs index 71d0660..3a1ea0e 100644 --- a/parser/ExpressionVisitorNya.cs +++ b/parser/ExpressionVisitorNya.cs @@ -160,7 +160,7 @@ public class ExpressionVisitorNya : MeowBaseVisitorNya { 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])) + if (name.Contains('.') || (char.IsDigit(name[0]) && !char.IsDigit(name.TrimStart('0')[0]))) { throw new InvalidStructAccessorException(current.name, ""); } diff --git a/parser/IfExpressionModel.cs b/parser/IfExpressionModel.cs index 0f7457e..07913f1 100644 --- a/parser/IfExpressionModel.cs +++ b/parser/IfExpressionModel.cs @@ -2,4 +2,19 @@ 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 + BlockExpressionModel? Else) : ExpressionModel(Span) +{ + public override IEnumerable GetChildren() + { + foreach (var modelBase in base.GetChildren()) + { + yield return modelBase; + } + + foreach (var (condition, block) in IfElses) + { + yield return condition; + yield return block; + } + } +} \ No newline at end of file diff --git a/parser/InvalidArrayLengthException.cs b/parser/InvalidArrayLengthException.cs new file mode 100644 index 0000000..eb775d6 --- /dev/null +++ b/parser/InvalidArrayLengthException.cs @@ -0,0 +1,10 @@ +using Antlr4.Runtime; + +namespace meowlang.parser; + +public class InvalidArrayLengthException : MeowVisitorException +{ + public InvalidArrayLengthException(IToken token) : base(token, $"invalid array size `{token.Text}`") + { + } +} \ No newline at end of file diff --git a/parser/Meow.g4 b/parser/Meow.g4 index 9a336cd..7accc19 100644 --- a/parser/Meow.g4 +++ b/parser/Meow.g4 @@ -399,7 +399,7 @@ Identifier: [a-zA-Z_][a-zA-Z_0-9]*; NumericLiteral: DecimalNumberLiteral /*| HexadecimalNumberLiteral | OctalNumberLiteral | BinaryNumberLiteral*/; -fragment DecimalNumberLiteral: DecimalNumberPart ('.' DecimalNumberPart)? | '.' DecimalNumberPart; +fragment DecimalNumberLiteral: '-'? DecimalNumberPart ('.' DecimalNumberPart)? | '.' DecimalNumberPart; fragment DecimalNumberPart: [0-9] [0-9_]*; BoolLiteral: 'true' | 'false' ; CharacterLiteral: '\'' (CharacterEscape | ~['\\]) '\''; diff --git a/parser/MeowBaseVisitorNya.cs b/parser/MeowBaseVisitorNya.cs new file mode 100644 index 0000000..ebd4f3c --- /dev/null +++ b/parser/MeowBaseVisitorNya.cs @@ -0,0 +1,12 @@ +using Antlr4.Runtime.Tree; +using meowlang.parser.antlr; + +namespace meowlang.parser; + +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/MeowModelVisitor.cs b/parser/MeowModelVisitor.cs new file mode 100644 index 0000000..5d775b7 --- /dev/null +++ b/parser/MeowModelVisitor.cs @@ -0,0 +1,1303 @@ +// automatically generated + +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable MemberCanBePrivate.Global +#pragma warning disable CS8603 +#pragma warning disable CS8600 +#pragma warning disable CS8509 + +using System.CodeDom.Compiler; +namespace meowlang.parser; + +[GeneratedCode("meow-visitorgenerator", "1")] +public class MeowModelVisitor +{ + + public T? TryVisit(ModelBase? m) + { + return m == null ? default : Visit(m); + } + + public T Visit(ModelBase m) + { + switch(m) + { + + case ArrayAccessExpressionModel x: return VisitArrayAccessExpression(x); + case ArrayConstructorExpressionModel x: return VisitArrayConstructorExpression(x); + case ArrayTypeModel x: return VisitArrayType(x); + case AssignmentExpressionModel x: return VisitAssignmentExpression(x); + case AttributeModel x: return VisitAttribute(x); + case BinaryOperationExpressionModel x: return VisitBinaryOperationExpression(x); + case BlockExpressionModel x: return VisitBlockExpression(x); + case BoolLiteralModel x: return VisitBoolLiteral(x); + case BreakStatementModel x: return VisitBreakStatement(x); + case CharacterLiteralModel x: return VisitCharacterLiteral(x); + case ConstantDeclarationStatementModel x: return VisitConstantDeclarationStatement(x); + case ConstraintDeclarationModel x: return VisitConstraintDeclaration(x); + case ConstraintModel x: return VisitConstraint(x); + case ContinueStatementModel x: return VisitContinueStatement(x); + case EmbedConstraintRuleModel x: return VisitEmbedConstraintRule(x); + case EnumConstructorExpressionModel x: return VisitEnumConstructorExpression(x); + case EnumDeclarationModel x: return VisitEnumDeclaration(x); + case EnumMemberModel x: return VisitEnumMember(x); + case EnumTypeModel x: return VisitEnumType(x); + case ExpressionStatementModel x: return VisitExpressionStatement(x); + case ForLoopStatementModel x: return VisitForLoopStatement(x); + case FunctionCallExpressionModel x: return VisitFunctionCallExpression(x); + case FunctionConstraintRuleModel x: return VisitFunctionConstraintRule(x); + case FunctionModel x: return VisitFunction(x); + case FunctionParameterModel x: return VisitFunctionParameter(x); + case IdentifierAttributeValueModel x: return VisitIdentifierAttributeValue(x); + case IdentifierNameModel x: return VisitIdentifierName(x); + case IfExpressionModel x: return VisitIfExpression(x); + case ImportModel x: return VisitImport(x); + case InfiniteLoopStatementModel x: return VisitInfiniteLoopStatement(x); + case LiteralAttributeValueModel x: return VisitLiteralAttributeValue(x); + case LiteralExpressionModel x: return VisitLiteralExpression(x); + case Model x: return Visit(x); + case NameExpressionModel x: return VisitNameExpression(x); + case NumericLiteralModel x: return VisitNumericLiteral(x); + case ParenthesisExpressionModel x: return VisitParenthesisExpression(x); + case PatternModel x: return VisitPattern(x); + case PointerDereferenceExpressionModel x: return VisitPointerDereferenceExpression(x); + case PointerReferenceExpressionModel x: return VisitPointerReferenceExpression(x); + case PointerTypeReferenceModel x: return VisitPointerTypeReference(x); + case ReturnStatementModel x: return VisitReturnStatement(x); + case SliceTypeModel x: return VisitSliceType(x); + case StringLiteralModel x: return VisitStringLiteral(x); + case StructAccessExpressionModel x: return VisitStructAccessExpression(x); + case StructConstructorExpressionModel x: return VisitStructConstructorExpression(x); + case StructConstructorMemberModel x: return VisitStructConstructorMember(x); + case StructDeclarationModel x: return VisitStructDeclaration(x); + case StructMemberModel x: return VisitStructMember(x); + case StructTypeModel x: return VisitStructType(x); + case SwitchExpressionModel x: return VisitSwitchExpression(x); + case TopLevelStatementModel x: return VisitTopLevelStatement(x); + case TupleConstructorExpressionModel x: return VisitTupleConstructorExpression(x); + case TupleDeclarationModel x: return VisitTupleDeclaration(x); + case TupleTypeModel x: return VisitTupleType(x); + case TypeAliasModel x: return VisitTypeAlias(x); + case TypeNameModel x: return VisitTypeName(x); + case TypeParameterModel x: return VisitTypeParameter(x); + case UnaryOperationExpressionModel x: return VisitUnaryOperationExpression(x); + case VariableDeclarationStatementModel x: return VisitVariableDeclarationStatement(x); + case WhileLoopStatementModel x: return VisitWhileLoopStatement(x); + } + return default; + } + + public virtual T VisitArrayAccessExpression(ArrayAccessExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitArrayConstructorExpression(ArrayConstructorExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitArrayType(ArrayTypeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitAssignmentExpression(AssignmentExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitAttribute(AttributeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitBinaryOperationExpression(BinaryOperationExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitBlockExpression(BlockExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitBoolLiteral(BoolLiteralModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitBreakStatement(BreakStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitCharacterLiteral(CharacterLiteralModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitConstantDeclarationStatement(ConstantDeclarationStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitConstraintDeclaration(ConstraintDeclarationModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitConstraint(ConstraintModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitContinueStatement(ContinueStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitEmbedConstraintRule(EmbedConstraintRuleModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitEnumConstructorExpression(EnumConstructorExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitEnumDeclaration(EnumDeclarationModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitEnumMember(EnumMemberModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitEnumType(EnumTypeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitExpressionStatement(ExpressionStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitForLoopStatement(ForLoopStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitFunctionCallExpression(FunctionCallExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitFunctionConstraintRule(FunctionConstraintRuleModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitFunction(FunctionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitFunctionParameter(FunctionParameterModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitIdentifierAttributeValue(IdentifierAttributeValueModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitIdentifierName(IdentifierNameModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitIfExpression(IfExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitImport(ImportModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitInfiniteLoopStatement(InfiniteLoopStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitLiteralAttributeValue(LiteralAttributeValueModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitLiteralExpression(LiteralExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T Visit(Model m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitNameExpression(NameExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitNumericLiteral(NumericLiteralModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitParenthesisExpression(ParenthesisExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitPattern(PatternModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitPointerDereferenceExpression(PointerDereferenceExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitPointerReferenceExpression(PointerReferenceExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitPointerTypeReference(PointerTypeReferenceModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitReturnStatement(ReturnStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitSliceType(SliceTypeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStringLiteral(StringLiteralModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructAccessExpression(StructAccessExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructConstructorExpression(StructConstructorExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructConstructorMember(StructConstructorMemberModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructDeclaration(StructDeclarationModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructMember(StructMemberModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitStructType(StructTypeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitSwitchExpression(SwitchExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTopLevelStatement(TopLevelStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTupleConstructorExpression(TupleConstructorExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTupleDeclaration(TupleDeclarationModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTupleType(TupleTypeModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTypeAlias(TypeAliasModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTypeName(TypeNameModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitTypeParameter(TypeParameterModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitUnaryOperationExpression(UnaryOperationExpressionModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitVariableDeclarationStatement(VariableDeclarationStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + + public virtual T VisitWhileLoopStatement(WhileLoopStatementModel m) + { + T result = default; + foreach (var modelBase in m.GetChildren()) + { + result = Visit(modelBase); + } + + return result; + } + +} + +[GeneratedCode("meow-visitorgenerator", "1")] +public class MeowModelVisitor +{ + public void Visit(ModelBase m) + { + switch(m) + { + + case ArrayAccessExpressionModel x: VisitArrayAccessExpression(x); break; + case ArrayConstructorExpressionModel x: VisitArrayConstructorExpression(x); break; + case ArrayTypeModel x: VisitArrayType(x); break; + case AssignmentExpressionModel x: VisitAssignmentExpression(x); break; + case AttributeModel x: VisitAttribute(x); break; + case BinaryOperationExpressionModel x: VisitBinaryOperationExpression(x); break; + case BlockExpressionModel x: VisitBlockExpression(x); break; + case BoolLiteralModel x: VisitBoolLiteral(x); break; + case BreakStatementModel x: VisitBreakStatement(x); break; + case CharacterLiteralModel x: VisitCharacterLiteral(x); break; + case ConstantDeclarationStatementModel x: VisitConstantDeclarationStatement(x); break; + case ConstraintDeclarationModel x: VisitConstraintDeclaration(x); break; + case ConstraintModel x: VisitConstraint(x); break; + case ContinueStatementModel x: VisitContinueStatement(x); break; + case EmbedConstraintRuleModel x: VisitEmbedConstraintRule(x); break; + case EnumConstructorExpressionModel x: VisitEnumConstructorExpression(x); break; + case EnumDeclarationModel x: VisitEnumDeclaration(x); break; + case EnumMemberModel x: VisitEnumMember(x); break; + case EnumTypeModel x: VisitEnumType(x); break; + case ExpressionStatementModel x: VisitExpressionStatement(x); break; + case ForLoopStatementModel x: VisitForLoopStatement(x); break; + case FunctionCallExpressionModel x: VisitFunctionCallExpression(x); break; + case FunctionConstraintRuleModel x: VisitFunctionConstraintRule(x); break; + case FunctionModel x: VisitFunction(x); break; + case FunctionParameterModel x: VisitFunctionParameter(x); break; + case IdentifierAttributeValueModel x: VisitIdentifierAttributeValue(x); break; + case IdentifierNameModel x: VisitIdentifierName(x); break; + case IfExpressionModel x: VisitIfExpression(x); break; + case ImportModel x: VisitImport(x); break; + case InfiniteLoopStatementModel x: VisitInfiniteLoopStatement(x); break; + case LiteralAttributeValueModel x: VisitLiteralAttributeValue(x); break; + case LiteralExpressionModel x: VisitLiteralExpression(x); break; + case Model x: Visit(x); break; + case NameExpressionModel x: VisitNameExpression(x); break; + case NumericLiteralModel x: VisitNumericLiteral(x); break; + case ParenthesisExpressionModel x: VisitParenthesisExpression(x); break; + case PatternModel x: VisitPattern(x); break; + case PointerDereferenceExpressionModel x: VisitPointerDereferenceExpression(x); break; + case PointerReferenceExpressionModel x: VisitPointerReferenceExpression(x); break; + case PointerTypeReferenceModel x: VisitPointerTypeReference(x); break; + case ReturnStatementModel x: VisitReturnStatement(x); break; + case SliceTypeModel x: VisitSliceType(x); break; + case StringLiteralModel x: VisitStringLiteral(x); break; + case StructAccessExpressionModel x: VisitStructAccessExpression(x); break; + case StructConstructorExpressionModel x: VisitStructConstructorExpression(x); break; + case StructConstructorMemberModel x: VisitStructConstructorMember(x); break; + case StructDeclarationModel x: VisitStructDeclaration(x); break; + case StructMemberModel x: VisitStructMember(x); break; + case StructTypeModel x: VisitStructType(x); break; + case SwitchExpressionModel x: VisitSwitchExpression(x); break; + case TopLevelStatementModel x: VisitTopLevelStatement(x); break; + case TupleConstructorExpressionModel x: VisitTupleConstructorExpression(x); break; + case TupleDeclarationModel x: VisitTupleDeclaration(x); break; + case TupleTypeModel x: VisitTupleType(x); break; + case TypeAliasModel x: VisitTypeAlias(x); break; + case TypeNameModel x: VisitTypeName(x); break; + case TypeParameterModel x: VisitTypeParameter(x); break; + case UnaryOperationExpressionModel x: VisitUnaryOperationExpression(x); break; + case VariableDeclarationStatementModel x: VisitVariableDeclarationStatement(x); break; + case WhileLoopStatementModel x: VisitWhileLoopStatement(x); break; + } + } + + public virtual void VisitArrayAccessExpression(ArrayAccessExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitArrayConstructorExpression(ArrayConstructorExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitArrayType(ArrayTypeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitAssignmentExpression(AssignmentExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitAttribute(AttributeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitBinaryOperationExpression(BinaryOperationExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitBlockExpression(BlockExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitBoolLiteral(BoolLiteralModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitBreakStatement(BreakStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitCharacterLiteral(CharacterLiteralModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitConstantDeclarationStatement(ConstantDeclarationStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitConstraintDeclaration(ConstraintDeclarationModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitConstraint(ConstraintModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitContinueStatement(ContinueStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitEmbedConstraintRule(EmbedConstraintRuleModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitEnumConstructorExpression(EnumConstructorExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitEnumDeclaration(EnumDeclarationModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitEnumMember(EnumMemberModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitEnumType(EnumTypeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitExpressionStatement(ExpressionStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitForLoopStatement(ForLoopStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitFunctionCallExpression(FunctionCallExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitFunctionConstraintRule(FunctionConstraintRuleModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitFunction(FunctionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitFunctionParameter(FunctionParameterModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitIdentifierAttributeValue(IdentifierAttributeValueModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitIdentifierName(IdentifierNameModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitIfExpression(IfExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitImport(ImportModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitInfiniteLoopStatement(InfiniteLoopStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitLiteralAttributeValue(LiteralAttributeValueModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitLiteralExpression(LiteralExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void Visit(Model m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitNameExpression(NameExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitNumericLiteral(NumericLiteralModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitParenthesisExpression(ParenthesisExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitPattern(PatternModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitPointerDereferenceExpression(PointerDereferenceExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitPointerReferenceExpression(PointerReferenceExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitPointerTypeReference(PointerTypeReferenceModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitReturnStatement(ReturnStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitSliceType(SliceTypeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStringLiteral(StringLiteralModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructAccessExpression(StructAccessExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructConstructorExpression(StructConstructorExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructConstructorMember(StructConstructorMemberModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructDeclaration(StructDeclarationModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructMember(StructMemberModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitStructType(StructTypeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitSwitchExpression(SwitchExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTopLevelStatement(TopLevelStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTupleConstructorExpression(TupleConstructorExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTupleDeclaration(TupleDeclarationModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTupleType(TupleTypeModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTypeAlias(TypeAliasModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTypeName(TypeNameModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitTypeParameter(TypeParameterModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitUnaryOperationExpression(UnaryOperationExpressionModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitVariableDeclarationStatement(VariableDeclarationStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + + public virtual void VisitWhileLoopStatement(WhileLoopStatementModel m) + { + foreach (var modelBase in m.GetChildren()) + { + Visit(modelBase); + } + } + +} diff --git a/parser/ModelBase.cs b/parser/ModelBase.cs index 2cb10a8..75f59f5 100644 --- a/parser/ModelBase.cs +++ b/parser/ModelBase.cs @@ -1,3 +1,30 @@ +using System.Collections; + namespace meowlang.parser; -public record ModelBase([property:Ignore] Span Span); \ No newline at end of file +public abstract record ModelBase([property: Ignore] Span Span) +{ + public Dictionary Metadata { get; } = new(); + + public virtual IEnumerable GetChildren() + { + var properties = GetType().GetProperties(); + foreach (var propertyInfo in properties) + { + if (propertyInfo.PropertyType.IsAssignableTo(typeof(ModelBase))) + { + if (propertyInfo.GetValue(this) is ModelBase value) yield return value; + } + else if (propertyInfo.PropertyType.IsAssignableTo(typeof(IEnumerable))) + { + if (propertyInfo.GetValue(this) is IEnumerable values) + { + foreach (var value in values) + { + yield return value; + } + } + } + } + } +} \ No newline at end of file diff --git a/parser/StructDeclarationModel.cs b/parser/StructDeclarationModel.cs new file mode 100644 index 0000000..f868a57 --- /dev/null +++ b/parser/StructDeclarationModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record StructDeclarationModel(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/StructTopLevelConstructModel.cs b/parser/StructTopLevelConstructModel.cs deleted file mode 100644 index 9aa92da..0000000 --- a/parser/StructTopLevelConstructModel.cs +++ /dev/null @@ -1,4 +0,0 @@ -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/SwitchExpressionModel.cs b/parser/SwitchExpressionModel.cs index 2c87a19..8751a35 100644 --- a/parser/SwitchExpressionModel.cs +++ b/parser/SwitchExpressionModel.cs @@ -1,4 +1,19 @@ 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 + List<(LiteralModel Value, ExpressionModel? Body)> Cases, ExpressionModel? Default) : ExpressionModel(Span) +{ + public override IEnumerable GetChildren() + { + foreach (var modelBase in base.GetChildren()) + { + yield return modelBase; + } + + foreach (var (condition, block) in Cases) + { + yield return condition; + if (block != null) yield return block; + } + } +} \ No newline at end of file diff --git a/parser/TupleDeclarationModel.cs b/parser/TupleDeclarationModel.cs new file mode 100644 index 0000000..0093a5d --- /dev/null +++ b/parser/TupleDeclarationModel.cs @@ -0,0 +1,4 @@ +namespace meowlang.parser; + +public record TupleDeclarationModel(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/TupleTopLevelConstructModel.cs b/parser/TupleTopLevelConstructModel.cs deleted file mode 100644 index b093318..0000000 --- a/parser/TupleTopLevelConstructModel.cs +++ /dev/null @@ -1,4 +0,0 @@ -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/TypeReferenceVisitorNya.cs b/parser/TypeReferenceVisitorNya.cs index 788d250..4253f43 100644 --- a/parser/TypeReferenceVisitorNya.cs +++ b/parser/TypeReferenceVisitorNya.cs @@ -31,7 +31,14 @@ public class TypeReferenceVisitorNya : MeowBaseVisitorNya return new SliceTypeModel(context.GetSpan(), type); } - return new ArrayTypeModel(context.GetSpan(), type, context.length.Text); + if (context.length.Text.Contains('.') || context.length.Text.Contains('-')) + { + throw new InvalidArrayLengthException(context.length); + } + + var size = uint.Parse(context.length.Text.Replace("_", "")); + + return new ArrayTypeModel(context.GetSpan(), type, size); } public override TypeReferenceModel VisitTupleType(MeowParser.TupleTypeContext context) diff --git a/parser/Utils.cs b/parser/Utils.cs index 8a9e933..4bfe3c2 100644 --- a/parser/Utils.cs +++ b/parser/Utils.cs @@ -40,6 +40,12 @@ public static class ObjectExtensions return $"\"{val}\""; } + if (type.IsAssignableTo(typeof(Guid))) + { + var val = o.ToString(); + return $"\"{val}\""; + } + string json; if (o is ITuple t) @@ -48,7 +54,25 @@ public static class ObjectExtensions return values.AutoToString(); } - if (type.IsAssignableTo(typeof(IEnumerable))) + if (type.IsAssignableTo(typeof(IDictionary))) + { + var dictionary = (o as IDictionary); + var sb = new StringBuilder(); + + sb.Append('{'); + + var first = true; + foreach (DictionaryEntry entry in dictionary!) + { + if (!first) sb.Append(','); + first = false; + sb.Append($"\"{entry.Key.ToString()}\": {entry.Value.AutoToString()}"); + } + + sb.Append('}'); + json = sb.ToString(); + } + else if (type.IsAssignableTo(typeof(IEnumerable))) { var enumerable = (o as IEnumerable)!.Cast(); var sb = new StringBuilder(); diff --git a/parser/VisitorNya.cs b/parser/VisitorNya.cs index 52f1dd0..e87b49b 100644 --- a/parser/VisitorNya.cs +++ b/parser/VisitorNya.cs @@ -10,7 +10,7 @@ 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(); + var declarations = context.topLevelDeclaration().Select(x => new DeclarationVisitorNya().Visit(x.unterminatedTopLevelDeclaration())).ToList(); return new Model(context.GetSpan(), imports, declarations); } diff --git a/typechecker/GenericTypeId.cs b/typechecker/GenericTypeId.cs new file mode 100644 index 0000000..83e050b --- /dev/null +++ b/typechecker/GenericTypeId.cs @@ -0,0 +1,3 @@ +namespace meowlang.typechecker; + +public record GenericTypeId(PossiblyGenericTypeRef Key, List GenericParams); \ No newline at end of file diff --git a/typechecker/ModelExtensions.cs b/typechecker/ModelExtensions.cs new file mode 100644 index 0000000..1848f26 --- /dev/null +++ b/typechecker/ModelExtensions.cs @@ -0,0 +1,20 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +public static class ModelExtensions +{ + private static readonly Guid ExpressionTypeKey = new Guid("6560485F-A4B0-4E24-A03D-D87776BBF9F4"); + + public static void SetType(this ExpressionModel m, TypeId t) + { + m.Metadata[ExpressionTypeKey] = t; + } + + public static TypeId? GetType(this ExpressionModel m) + { + m.Metadata.TryGetValue(ExpressionTypeKey, out var value); + return value as TypeId; + } + +} \ No newline at end of file diff --git a/typechecker/PossiblyGenericTypeRef.cs b/typechecker/PossiblyGenericTypeRef.cs new file mode 100644 index 0000000..31fdacb --- /dev/null +++ b/typechecker/PossiblyGenericTypeRef.cs @@ -0,0 +1,19 @@ +namespace meowlang.typechecker; + +public record PossiblyGenericTypeRef +{ + public Guid? TypeKey { get; } + public string? GenericParameterName { get; } + + public bool IsGeneric => GenericParameterName != null; + + public PossiblyGenericTypeRef(string genericParameterName) + { + GenericParameterName = genericParameterName; + } + + public PossiblyGenericTypeRef(Guid typeKey) + { + TypeKey = typeKey; + } +}; \ No newline at end of file diff --git a/typechecker/Scope.cs b/typechecker/Scope.cs new file mode 100644 index 0000000..bb06354 --- /dev/null +++ b/typechecker/Scope.cs @@ -0,0 +1,125 @@ +namespace meowlang.typechecker; + +public class Scope +{ + private readonly Dictionary _variableScope = new(); + private readonly Dictionary<(string, int), Guid> _typeScope = new(); + + private readonly TypeRegistry _typeRegistry; + + private readonly Scope? _parent; + + + public Scope? DebugGetParent => _parent; + public Dictionary DebugGetVariableScope => _variableScope; + public Dictionary<(string, int), Guid> DebugGetTypeScope => _typeScope; + + + public Scope(TypeRegistry typeRegistry, Scope? parent = null) + { + _typeRegistry = typeRegistry; + _parent = parent; + } + + public void AddVariable(string name, TypeId type) + { + if (_variableScope.ContainsKey(name)) + { + throw new DuplicateVariableNameException(name); + } + + _variableScope[name] = type; + } + + public bool HasVariable(string name) + { + if (_variableScope.ContainsKey(name)) return true; + return _parent?.HasVariable(name) ?? false; + } + + public TypeId GetVariableType(string name) + { + return _variableScope.TryGetValue(name, out var value) ? value : throw new UnknownVariableNameException(name); + } + + public Guid AddAnonymousType(TypeDescription type) + { + var guid = Guid.NewGuid(); + _typeRegistry.Add(guid, type); + return guid; + } + + public Guid AddNamedType(string name, int arity, TypeDescription type) + { + Guid guid; + if (_typeScope.TryGetValue((name, arity), out guid)) + { + if (_typeRegistry.Has(guid)) + { + throw new DuplicateTypeNameException(name, arity); + } + } + else + { + if (HasType(name, arity)) + { + throw new DuplicateTypeNameException(name, arity); + } + guid = Guid.NewGuid(); + _typeScope[(name, arity)] = guid; + } + _typeRegistry.Add(guid, type); + return guid; + } + + public bool HasType(string name, int arity) + { + if (_typeScope.ContainsKey((name, arity))) return true; + return _parent?.HasType(name, arity) ?? false; + } + + public TypeDescription GetType(Guid guid) + { + return _typeRegistry.Get(guid); + } + + private Guid? GetTypeGuidWithoutCreate(string name, int arity) + { + if (_typeScope.ContainsKey((name, arity))) return _typeScope[(name, arity)]; + return _parent?.GetTypeGuidWithoutCreate(name, arity); + } + + public Guid GetTypeGuid(string name, int arity) + { + var key = GetTypeGuidWithoutCreate(name, arity); + if (key == null) + { + key = Guid.NewGuid(); + _typeScope[(name, arity)] = key.Value; + } + + return key.Value; + } +} + +public class UnknownTypeException : Exception +{ + private readonly string _name; + private readonly int _arity; + + public UnknownTypeException(string name, int arity): base($"unknown type `{name}` with arity {arity}") + { + _name = name; + _arity = arity; + } +} + +public class UnknownVariableNameException : Exception +{ + public string Name { get; } + + public UnknownVariableNameException(string name) : base($"unknown variable `{name}`") + { + Name = name; + } +} \ No newline at end of file diff --git a/typechecker/TypeChecker.cs b/typechecker/TypeChecker.cs new file mode 100644 index 0000000..a074402 --- /dev/null +++ b/typechecker/TypeChecker.cs @@ -0,0 +1,41 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +public static class TypeChecker +{ + public static void CheckAndInferTypes(Model model) + { + var typeRegistry = new TypeRegistry(); + var topLevelScope = new Scope(typeRegistry); + InitialiseTopLevelScope(topLevelScope); + + new CollectTypesVisitor(topLevelScope).Visit(model); + + Console.Write(topLevelScope.AutoToString()); + Console.Write(typeRegistry.AutoToString()); + return; + + + } + + private static void InitialiseTopLevelScope(Scope scope) + { + scope.AddNamedType("s8", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("s16", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("s32", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("s64", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("s128", 0, new PrimitiveTypeDescription()); + + scope.AddNamedType("u8", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("u16", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("u32", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("u64", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("u128", 0, new PrimitiveTypeDescription()); + + scope.AddNamedType("f32", 0, new PrimitiveTypeDescription()); + scope.AddNamedType("f64", 0, new PrimitiveTypeDescription()); + + scope.AddNamedType("bool", 0, new PrimitiveTypeDescription()); + } +} \ No newline at end of file diff --git a/typechecker/TypeId.cs b/typechecker/TypeId.cs new file mode 100644 index 0000000..56046bf --- /dev/null +++ b/typechecker/TypeId.cs @@ -0,0 +1,3 @@ +namespace meowlang.typechecker; + +public record TypeId(Guid Key, List GenericParams); \ No newline at end of file diff --git a/typechecker/TypeRegistry.cs b/typechecker/TypeRegistry.cs new file mode 100644 index 0000000..0866cb4 --- /dev/null +++ b/typechecker/TypeRegistry.cs @@ -0,0 +1,25 @@ +namespace meowlang.typechecker; + +public class TypeRegistry +{ + private readonly Dictionary _types = new (); + + public Dictionary DebugGetTypes => _types; + + public void Add(Guid guid, TypeDescription description) + { + _types[guid] = description; + } + + public TypeDescription Get(Guid guid) + { + return _types[guid]; + } + + public bool Has(Guid guid) + { + return _types.ContainsKey(guid); + } + + +} \ No newline at end of file diff --git a/typechecker/exceptions/DuplicateTypeNameException.cs b/typechecker/exceptions/DuplicateTypeNameException.cs new file mode 100644 index 0000000..3883169 --- /dev/null +++ b/typechecker/exceptions/DuplicateTypeNameException.cs @@ -0,0 +1,13 @@ +namespace meowlang.typechecker; + +public class DuplicateTypeNameException : Exception +{ + public string Name { get; } + public int Arity { get; } + + public DuplicateTypeNameException(string name, int arity) : base($"duplicate type name `{name}` with arity {arity}") + { + Name = name; + Arity = arity; + } +} \ No newline at end of file diff --git a/typechecker/exceptions/DuplicateVariableNameException.cs b/typechecker/exceptions/DuplicateVariableNameException.cs new file mode 100644 index 0000000..d3043e5 --- /dev/null +++ b/typechecker/exceptions/DuplicateVariableNameException.cs @@ -0,0 +1,11 @@ +namespace meowlang.typechecker; + +public class DuplicateVariableNameException : Exception +{ + public string Name { get; } + + public DuplicateVariableNameException(string name) : base($"duplicate variable name `{name}` in scope") + { + Name = name; + } +} \ No newline at end of file diff --git a/typechecker/exceptions/UndeclaredGenericParameterException.cs b/typechecker/exceptions/UndeclaredGenericParameterException.cs new file mode 100644 index 0000000..352a840 --- /dev/null +++ b/typechecker/exceptions/UndeclaredGenericParameterException.cs @@ -0,0 +1,11 @@ +namespace meowlang.typechecker; + +public class UndeclaredGenericParameterException : Exception +{ + public string Name { get; } + + public UndeclaredGenericParameterException(string name) + { + Name = name; + } +} \ No newline at end of file diff --git a/typechecker/exceptions/UnknownEnumMemberException.cs b/typechecker/exceptions/UnknownEnumMemberException.cs new file mode 100644 index 0000000..7e9b8b5 --- /dev/null +++ b/typechecker/exceptions/UnknownEnumMemberException.cs @@ -0,0 +1,11 @@ +namespace meowlang.typechecker; + +public class UnknownEnumMemberException : Exception +{ + public string Name { get; } + + public UnknownEnumMemberException(string name) : base($"unknown enum member `{name}`") + { + Name = name; + } +} \ No newline at end of file diff --git a/typechecker/exceptions/UnknownStructMemberException.cs b/typechecker/exceptions/UnknownStructMemberException.cs new file mode 100644 index 0000000..2630f20 --- /dev/null +++ b/typechecker/exceptions/UnknownStructMemberException.cs @@ -0,0 +1,11 @@ +namespace meowlang.typechecker; + +public class UnknownStructMemberException : Exception +{ + public string Name { get; } + + public UnknownStructMemberException(string name) : base($"unknown struct member `{name}`") + { + Name = name; + } +} \ No newline at end of file diff --git a/typechecker/exceptions/UnknownTupleMemberException.cs b/typechecker/exceptions/UnknownTupleMemberException.cs new file mode 100644 index 0000000..b005472 --- /dev/null +++ b/typechecker/exceptions/UnknownTupleMemberException.cs @@ -0,0 +1,11 @@ +namespace meowlang.typechecker; + +public class UnknownTupleMemberException : Exception +{ + public ushort Index { get; } + + public UnknownTupleMemberException(ushort index) : base($"unknown tuple member `{index}`") + { + Index = index; + } +} \ No newline at end of file diff --git a/typechecker/typechecker.csproj b/typechecker/typechecker.csproj new file mode 100644 index 0000000..f5e6a10 --- /dev/null +++ b/typechecker/typechecker.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + meowlang.typechecker + + + + + + + diff --git a/typechecker/typechecker.csproj.DotSettings b/typechecker/typechecker.csproj.DotSettings new file mode 100644 index 0000000..e966f15 --- /dev/null +++ b/typechecker/typechecker.csproj.DotSettings @@ -0,0 +1,4 @@ + + True + True + True \ No newline at end of file diff --git a/typechecker/types/ArrayTypeDescription.cs b/typechecker/types/ArrayTypeDescription.cs new file mode 100644 index 0000000..7578063 --- /dev/null +++ b/typechecker/types/ArrayTypeDescription.cs @@ -0,0 +1,25 @@ +namespace meowlang.typechecker; + +public record ArrayTypeDescription : TypeDescription +{ + private readonly TypeId _elementType; + private readonly uint _size; + + public ArrayTypeDescription(TypeId elementType, uint size) + { + _elementType = elementType; + _size = size; + } + + public TypeId ElementType => _elementType; + + public uint Size => _size; +} +public record PrimitiveTypeDescription : TypeDescription +{ + + public PrimitiveTypeDescription() + { + + } +} \ No newline at end of file diff --git a/typechecker/types/EnumTypeDescription.cs b/typechecker/types/EnumTypeDescription.cs new file mode 100644 index 0000000..6cf42ce --- /dev/null +++ b/typechecker/types/EnumTypeDescription.cs @@ -0,0 +1,24 @@ +namespace meowlang.typechecker; + +public record EnumTypeDescription : TypeDescription +{ + private readonly List<(string Name, TypeId? Type)> _members; + private readonly Dictionary _memberMap; + + public Dictionary DebugGetMembers => _memberMap; + + public EnumTypeDescription(List<(string Name, TypeId? Type)> members) + { + _members = members; + _memberMap = members.ToDictionary(x => x.Name, x => x.Type); + } + + public IReadOnlyList MemberNames => _members.Select(x => x.Name).ToList(); + + public TypeId? GetTypeForMember(string name) + { + return _memberMap.TryGetValue(name, out var value) ? value : throw new UnknownEnumMemberException(name); + } + + public bool HasMember(string name) => _memberMap.ContainsKey(name); +}; \ No newline at end of file diff --git a/typechecker/types/FunctionTypeDescription.cs b/typechecker/types/FunctionTypeDescription.cs new file mode 100644 index 0000000..48ac4e1 --- /dev/null +++ b/typechecker/types/FunctionTypeDescription.cs @@ -0,0 +1,19 @@ +namespace meowlang.typechecker; + +public record FunctionTypeDescription : TypeDescription +{ + private readonly List _parameters; + private readonly List _returns; + + public FunctionTypeDescription(List parameters, List returns) + { + _parameters = parameters; + _returns = returns; + } + + public IReadOnlyList Parameters => _parameters; + public IReadOnlyList Returns => _returns; + + public int ParameterArity => _parameters.Count; + public int ReturnArity => _returns.Count; +} \ No newline at end of file diff --git a/typechecker/types/GenericArrayTypeDescription.cs b/typechecker/types/GenericArrayTypeDescription.cs new file mode 100644 index 0000000..303f136 --- /dev/null +++ b/typechecker/types/GenericArrayTypeDescription.cs @@ -0,0 +1,18 @@ +namespace meowlang.typechecker; + +public record GenericArrayTypeDescription : GenericTypeDescription +{ + private readonly GenericTypeId _elementType; + private readonly uint _size; + + public GenericArrayTypeDescription(List genericNames, GenericTypeId elementType, uint size) : base(genericNames) + { + _elementType = elementType; + _size = size; + } + + public override ArrayTypeDescription Concretize(List typeParams) + { + return new ArrayTypeDescription(ConcretizeGenericType(_elementType, typeParams), _size); + } +} \ No newline at end of file diff --git a/typechecker/types/GenericEnumTypeDescription.cs b/typechecker/types/GenericEnumTypeDescription.cs new file mode 100644 index 0000000..bb4f7b2 --- /dev/null +++ b/typechecker/types/GenericEnumTypeDescription.cs @@ -0,0 +1,21 @@ +namespace meowlang.typechecker; + +public record GenericEnumTypeDescription : GenericTypeDescription +{ + private readonly List<(string Name, GenericTypeId? Type)> _members; + + public GenericEnumTypeDescription(List genericNames, List<(string Name, GenericTypeId? Type)> members) : + base(genericNames) + { + _members = members; + CheckGenericNames(members.Where(x => x.Type != null).Select(x => x.Type!).ToList()); + } + + + public override EnumTypeDescription Concretize(List typeParams) + { + var members = _members.Select(x => + x.Type == null ? (x.Name, null) : (x.Name, ConcretizeGenericType(x.Type, typeParams))).ToList(); + return new EnumTypeDescription(members); + } +} \ No newline at end of file diff --git a/typechecker/types/GenericFunctionTypeDescription.cs b/typechecker/types/GenericFunctionTypeDescription.cs new file mode 100644 index 0000000..df43890 --- /dev/null +++ b/typechecker/types/GenericFunctionTypeDescription.cs @@ -0,0 +1,21 @@ +namespace meowlang.typechecker; + +public record GenericFunctionTypeDescription : GenericTypeDescription +{ + private readonly List _parameters; + private readonly List _returns; + + public GenericFunctionTypeDescription(List genericNames, List parameters, List returns) : base(genericNames) + { + _parameters = parameters; + _returns = returns; + } + + + public override FunctionTypeDescription Concretize(List typeParams) + { + var parameters = _parameters.Select(x => ConcretizeGenericType(x, typeParams)).ToList(); + var returns = _returns.Select(x => ConcretizeGenericType(x, typeParams)).ToList(); + return new FunctionTypeDescription(parameters, returns); + } +}; \ No newline at end of file diff --git a/typechecker/types/GenericSliceTypeDescription.cs b/typechecker/types/GenericSliceTypeDescription.cs new file mode 100644 index 0000000..80a3374 --- /dev/null +++ b/typechecker/types/GenericSliceTypeDescription.cs @@ -0,0 +1,16 @@ +namespace meowlang.typechecker; + +public record GenericSliceTypeDescription : GenericTypeDescription +{ + private readonly GenericTypeId _elementType; + + public GenericSliceTypeDescription(List genericNames, GenericTypeId elementType) : base(genericNames) + { + _elementType = elementType; + } + + public override SliceTypeDescription Concretize(List typeParams) + { + return new SliceTypeDescription(ConcretizeGenericType(_elementType, typeParams)); + } +} \ No newline at end of file diff --git a/typechecker/types/GenericStructTypeDescription.cs b/typechecker/types/GenericStructTypeDescription.cs new file mode 100644 index 0000000..3924621 --- /dev/null +++ b/typechecker/types/GenericStructTypeDescription.cs @@ -0,0 +1,21 @@ +namespace meowlang.typechecker; + +public record GenericStructTypeDescription : GenericTypeDescription +{ + private readonly List<(string Name, GenericTypeId Type)> _members; + + public List<(string Name, GenericTypeId Type)> DebugGetMembers => _members; + + public GenericStructTypeDescription(List genericNames, List<(string Name, GenericTypeId Type)> members) : base(genericNames) + { + _members = members; + CheckGenericNames(members.Select(x => x.Type).ToList()); + } + + public override StructTypeDescription Concretize(List typeParams) + { + var members = _members.Select(x => (x.Name, ConcretizeGenericType(x.Type, typeParams))).ToList(); + + return new StructTypeDescription(members); + } +} \ No newline at end of file diff --git a/typechecker/types/GenericTupleTypeDescription.cs b/typechecker/types/GenericTupleTypeDescription.cs new file mode 100644 index 0000000..02f0b28 --- /dev/null +++ b/typechecker/types/GenericTupleTypeDescription.cs @@ -0,0 +1,20 @@ +namespace meowlang.typechecker; + +public record GenericTupleTypeDescription : GenericTypeDescription +{ + private readonly List _members; + + public GenericTupleTypeDescription(List genericNames, List members) : base(genericNames) + { + _members = members; + CheckGenericNames(members); + } + + + public override TupleTypeDescription Concretize(List typeParams) + { + var members = _members.Select(x => ConcretizeGenericType(x, typeParams)).ToList(); + return new TupleTypeDescription(members); + } + +} \ No newline at end of file diff --git a/typechecker/types/GenericTypeDescription.cs b/typechecker/types/GenericTypeDescription.cs new file mode 100644 index 0000000..3a4580e --- /dev/null +++ b/typechecker/types/GenericTypeDescription.cs @@ -0,0 +1,45 @@ +namespace meowlang.typechecker; + +public abstract record GenericTypeDescription : TypeDescription +{ + protected readonly List GenericNames; + + public int Arity => GenericNames.Count; + + public GenericTypeDescription(List genericNames) + { + GenericNames = genericNames; + } + + protected void CheckGenericNames(List genericTypes) + { + foreach (var typeId in genericTypes) + { + if (typeId.Key.IsGeneric) + { + if (GenericNames.IndexOf(typeId.Key.GenericParameterName!) < 0) + { + throw new UndeclaredGenericParameterException(typeId.Key.GenericParameterName!); + } + } + + CheckGenericNames(typeId.GenericParams); + } + } + public abstract TypeDescription Concretize(List typeParams); + + + + protected TypeId ConcretizeGenericType(GenericTypeId genericType, List concreteTypes) + { + return new TypeId(ConcretizeGenericTypeRef(genericType.Key, concreteTypes), + genericType.GenericParams.Select(x => ConcretizeGenericType(x, concreteTypes)).ToList()); + } + + private Guid ConcretizeGenericTypeRef(PossiblyGenericTypeRef typeRef, List concreteTypes) + { + if (!typeRef.IsGeneric) return typeRef.TypeKey!.Value; + var typeIndex = GenericNames.IndexOf(typeRef.GenericParameterName!); + return concreteTypes[typeIndex]; + } +} \ No newline at end of file diff --git a/typechecker/types/SliceTypeDescription.cs b/typechecker/types/SliceTypeDescription.cs new file mode 100644 index 0000000..9a09267 --- /dev/null +++ b/typechecker/types/SliceTypeDescription.cs @@ -0,0 +1,13 @@ +namespace meowlang.typechecker; + +public record SliceTypeDescription : TypeDescription +{ + private readonly TypeId _elementType; + + public SliceTypeDescription(TypeId elementType) + { + _elementType = elementType; + } + + public TypeId ElementType => _elementType; +} \ No newline at end of file diff --git a/typechecker/types/StructTypeDescription.cs b/typechecker/types/StructTypeDescription.cs new file mode 100644 index 0000000..be42866 --- /dev/null +++ b/typechecker/types/StructTypeDescription.cs @@ -0,0 +1,25 @@ +namespace meowlang.typechecker; + +public record StructTypeDescription : TypeDescription +{ + private readonly List<(string Name, TypeId Type)> _members; + private readonly Dictionary _memberMap; + + public Dictionary DebugGetMembers => _memberMap; + + public StructTypeDescription(List<(string Name, TypeId Type)> members) + { + _members = members; + _memberMap = members.ToDictionary(x => x.Name, x => x.Type); + } + + public TypeId GetTypeForMember(string name) + { + return _memberMap.TryGetValue(name, out var value) ? value : throw new UnknownStructMemberException(name); + } + + public IReadOnlyList MemberNames => _members.Select(x => x.Name).ToList(); + + + public bool HasMember(string name) => _memberMap.ContainsKey(name); +}; \ No newline at end of file diff --git a/typechecker/types/TupleTypeDescription.cs b/typechecker/types/TupleTypeDescription.cs new file mode 100644 index 0000000..e62bfea --- /dev/null +++ b/typechecker/types/TupleTypeDescription.cs @@ -0,0 +1,24 @@ +namespace meowlang.typechecker; + +public record TupleTypeDescription : TypeDescription +{ + private readonly List _members; + + public List DebugGetMembers => _members; + + public TupleTypeDescription(List members) + { + _members = members; + } + + public int Length => _members.Count; + + public TypeId GetTypeForMember(ushort index) + { + if (index > Length) + { + throw new UnknownTupleMemberException(index); + } + return _members[index]; + } +} \ No newline at end of file diff --git a/typechecker/types/TypeDescription.cs b/typechecker/types/TypeDescription.cs new file mode 100644 index 0000000..50f4874 --- /dev/null +++ b/typechecker/types/TypeDescription.cs @@ -0,0 +1,3 @@ +namespace meowlang.typechecker; + +public abstract record TypeDescription(); \ No newline at end of file diff --git a/typechecker/visitor/CollectTypesVisitor.cs b/typechecker/visitor/CollectTypesVisitor.cs new file mode 100644 index 0000000..0abb3da --- /dev/null +++ b/typechecker/visitor/CollectTypesVisitor.cs @@ -0,0 +1,77 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +public class CollectTypesVisitor : MeowModelVisitor +{ + private readonly Scope _scope; + + public CollectTypesVisitor(Scope scope) + { + _scope = scope; + } + + public override void VisitStructDeclaration(StructDeclarationModel m) + { + TypeDescription structDescription; + var arity = m.TypeParameters.Count; + if (arity > 0) + { + structDescription = new GenericTypeDescriptionVisitor(_scope, m.TypeParameters, m.Name).Visit(m); + } + else + { + structDescription = new TypeDescriptionVisitor(_scope, m.Name).Visit(m); + } + + _scope.AddNamedType(m.Name, arity, structDescription); + } + + public override void VisitEnumDeclaration(EnumDeclarationModel m) + { + TypeDescription enumDescription; + var arity = m.TypeParameters.Count; + if (arity > 0) + { + enumDescription = new GenericTypeDescriptionVisitor(_scope, m.TypeParameters, m.Name).Visit(m); + } + else + { + enumDescription = new TypeDescriptionVisitor(_scope, m.Name).Visit(m); + } + + _scope.AddNamedType(m.Name, arity, enumDescription); + } + + public override void VisitTupleDeclaration(TupleDeclarationModel m) + { + TypeDescription tupleDescription; + var arity = m.TypeParameters.Count; + if (arity > 0) + { + tupleDescription = new GenericTypeDescriptionVisitor(_scope, m.TypeParameters, m.Name).Visit(m); + } + else + { + tupleDescription = new TypeDescriptionVisitor(_scope, m.Name).Visit(m); + } + + _scope.AddNamedType(m.Name, arity, tupleDescription); + } + + public override void VisitTypeAlias(TypeAliasModel m) + { + TypeDescription typeDescription; + var arity = m.TypeParameters.Count; + if (arity > 0) + { + typeDescription = new GenericTypeDescriptionVisitor(_scope, m.TypeParameters, m.Name).Visit(m); + } + else + { + typeDescription = new TypeDescriptionVisitor(_scope, m.Name).Visit(m); + } + + _scope.AddNamedType(m.Name, arity, typeDescription); + } +} \ No newline at end of file diff --git a/typechecker/visitor/GenericTypeDescriptionVisitor.cs b/typechecker/visitor/GenericTypeDescriptionVisitor.cs new file mode 100644 index 0000000..263fa9d --- /dev/null +++ b/typechecker/visitor/GenericTypeDescriptionVisitor.cs @@ -0,0 +1,59 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +class GenericTypeDescriptionVisitor : MeowModelVisitor +{ + private readonly Scope _scope; + private readonly List _typeParams; + private readonly string? _name; + + public GenericTypeDescriptionVisitor(Scope scope, List typeParams, string? name) + { + _scope = scope; + _typeParams = typeParams; + _name = name; + } + + public override GenericTypeDescription VisitStructType(StructTypeModel m) + { + var members = new List<(string, GenericTypeId)>(); + foreach (var (_, typeReferenceModel, name) in m.Members) + { + var fullName = _name == null ? null : $"{_name}@{name}"; + members.Add((name, new GenericTypeIdVisitor(_scope, _typeParams, fullName).Visit(typeReferenceModel))); + } + + return new GenericStructTypeDescription(_typeParams, members); + } + + public override GenericTypeDescription VisitEnumType(EnumTypeModel m) + { + var members = new List<(string, GenericTypeId?)>(); + foreach (var (_, name, typeReferenceModel) in m.Members) + { + var fullName = _name == null ? null : $"{_name}@{name}"; + members.Add((name, new GenericTypeIdVisitor(_scope, _typeParams, fullName).TryVisit(typeReferenceModel))); + } + + return new GenericEnumTypeDescription(_typeParams, members); + } + + public override GenericTypeDescription VisitTupleType(TupleTypeModel m) + { + var members = m.Types.Select((t, i) => new GenericTypeIdVisitor(_scope, _typeParams, $"{_name}@{i}").Visit(t)).ToList(); + return new GenericTupleTypeDescription(_typeParams, members); + } + + public override GenericTypeDescription VisitArrayType(ArrayTypeModel m) + { + var elementType = new GenericTypeIdVisitor(_scope, _typeParams, $"{_name}@inner").Visit(m.Type); + return new GenericArrayTypeDescription(_typeParams, elementType, m.Size); + } + + public override GenericTypeDescription VisitSliceType(SliceTypeModel m) + { + var elementType = new GenericTypeIdVisitor(_scope, _typeParams, $"{_name}@inner").Visit(m.Type); + return new GenericSliceTypeDescription(_typeParams, elementType); + } +} \ No newline at end of file diff --git a/typechecker/visitor/GenericTypeIdVisitor.cs b/typechecker/visitor/GenericTypeIdVisitor.cs new file mode 100644 index 0000000..22b8207 --- /dev/null +++ b/typechecker/visitor/GenericTypeIdVisitor.cs @@ -0,0 +1,54 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +public class GenericTypeIdVisitor : MeowModelVisitor +{ + private readonly Scope _scope; + private readonly List _genericParameters; + private readonly string? _name; + + public GenericTypeIdVisitor(Scope scope, List genericParameters, string? name) + { + _scope = scope; + _genericParameters = genericParameters; + _name = name; + } + + public override GenericTypeId VisitTypeName(TypeNameModel m) + { + var typeParams = m.TypeParameters + .Select(t => new GenericTypeIdVisitor(_scope, _genericParameters, null).Visit(t)).ToList(); + + var name = m.Name.Name; + if (m.Name.ImportName != null) + { + name = $"{m.Name.ImportName}:{name}"; + } + + foreach (var nested in m.Nested) + { + name = $"{name}@{nested}"; + } + + PossiblyGenericTypeRef genericKey; + + if (_genericParameters.Contains(name)) + { + genericKey = new PossiblyGenericTypeRef(name); + } + else + { + genericKey = new PossiblyGenericTypeRef(_scope.GetTypeGuid(name, typeParams.Count)); + } + + return new GenericTypeId(genericKey, typeParams); + } + + public override GenericTypeId VisitStructType(StructTypeModel m) + { + var type = new GenericTypeDescriptionVisitor(_scope, _genericParameters, _name).Visit(m); + var guid = _scope.AddAnonymousType(type); + return new GenericTypeId(new PossiblyGenericTypeRef(guid), new List()); + } +} \ No newline at end of file diff --git a/typechecker/visitor/TypeDescriptionVisitor.cs b/typechecker/visitor/TypeDescriptionVisitor.cs new file mode 100644 index 0000000..96d26bd --- /dev/null +++ b/typechecker/visitor/TypeDescriptionVisitor.cs @@ -0,0 +1,60 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +class TypeDescriptionVisitor : MeowModelVisitor +{ + private readonly Scope _scope; + private readonly string? _name; + + public TypeDescriptionVisitor(Scope scope) + { + _scope = scope; + } + public TypeDescriptionVisitor(Scope scope, string? name) + { + _scope = scope; + _name = name; + } + + public override TypeDescription VisitStructType(StructTypeModel m) + { + var members = new List<(string, TypeId)>(); + foreach (var (_, typeReferenceModel, name) in m.Members) + { + var fullName = _name == null ? null : $"{_name}@{name}"; + members.Add((name, new TypeIdVisitor(_scope, fullName).Visit(typeReferenceModel))); + } + + return new StructTypeDescription(members); + } + + public override TypeDescription VisitEnumType(EnumTypeModel m) + { + var members = new List<(string, TypeId?)>(); + foreach (var (_, name, typeReferenceModel) in m.Members) + { + var fullName = _name == null ? null : $"{_name}@{name}"; + members.Add((name, new TypeIdVisitor(_scope, fullName).TryVisit(typeReferenceModel))); + } + + return new EnumTypeDescription(members); + } + + public override TypeDescription VisitTupleType(TupleTypeModel m) + { + var members = m.Types.Select((t, i) => new TypeIdVisitor(_scope, $"{_name}@{i}").Visit(t)).ToList(); + return new TupleTypeDescription(members); + } + + public override TypeDescription VisitArrayType(ArrayTypeModel m) + { + var elementType = new TypeIdVisitor(_scope, $"{_name}@inner").Visit(m.Type); + return new ArrayTypeDescription(elementType, m.Size); + } + public override TypeDescription VisitSliceType(SliceTypeModel m) + { + var elementType = new TypeIdVisitor(_scope, $"{_name}@inner").Visit(m.Type); + return new SliceTypeDescription(elementType); + } +} \ No newline at end of file diff --git a/typechecker/visitor/TypeIdVisitor.cs b/typechecker/visitor/TypeIdVisitor.cs new file mode 100644 index 0000000..b95d193 --- /dev/null +++ b/typechecker/visitor/TypeIdVisitor.cs @@ -0,0 +1,69 @@ +using meowlang.parser; + +namespace meowlang.typechecker; + +public class TypeIdVisitor : MeowModelVisitor +{ + private readonly Scope _scope; + private readonly string? _name; + public TypeIdVisitor(Scope scope, string? name) + { + _scope = scope; + _name = name; + } + + public override TypeId VisitTypeName(TypeNameModel m) + { + var typeParams = m.TypeParameters.Select(t => new TypeIdVisitor(_scope, null).Visit(t)).ToList(); + + var name = m.Name.Name; + if (m.Name.ImportName != null) + { + name = $"{m.Name.ImportName}:{name}"; + } + + foreach (var nested in m.Nested) + { + name = $"{name}@{nested}"; + } + + var guid = _scope.GetTypeGuid(name, typeParams.Count); + + return new TypeId(guid, typeParams); + } + + private TypeId RegisterAnonymousType(ModelBase m) + { + var type = new TypeDescriptionVisitor(_scope, _name).Visit(m); + Guid guid; + if (_name == null) + { + guid = _scope.AddAnonymousType(type); + } + else + { + guid = _scope.AddNamedType(_name, 0, type); + } + return new TypeId(guid, new List()); + } + public override TypeId VisitStructType(StructTypeModel m) + { + return RegisterAnonymousType(m); + } + public override TypeId VisitEnumType(EnumTypeModel m) + { + return RegisterAnonymousType(m); + } + public override TypeId VisitTupleType(TupleTypeModel m) + { + return RegisterAnonymousType(m); + } + public override TypeId VisitArrayType(ArrayTypeModel m) + { + return RegisterAnonymousType(m); + } + public override TypeId VisitSliceType(SliceTypeModel m) + { + return RegisterAnonymousType(m); + } +} \ No newline at end of file diff --git a/visitorgenerator/Program.cs b/visitorgenerator/Program.cs new file mode 100644 index 0000000..b8882c1 --- /dev/null +++ b/visitorgenerator/Program.cs @@ -0,0 +1,124 @@ +using System.Reflection; +using meowlang.parser; + + +var className = args[0]; +var destinatinDir = args[1] ?? "."; +var destinationPath = Path.Join(destinatinDir, $"{className}.cs"); + + +var parserType = typeof(Parser); +var nameSpace = parserType.Namespace; +var modelTypes = parserType.Assembly.DefinedTypes.Where(t => t.IsAssignableTo(typeof(ModelBase))).Where(t => !t.IsAbstract); + +string UnModelifyName(string name) +{ + var nameWithoutModel = name; + var modelIndex = nameWithoutModel.LastIndexOf("Model", StringComparison.Ordinal); + if (modelIndex > -1) + { + nameWithoutModel = nameWithoutModel.Remove(modelIndex); + } + + return nameWithoutModel; +} + +string MakeVisitorMethod(TypeInfo model, bool isVoid) +{ + if (model == null) throw new ArgumentNullException(nameof(model)); + var typeName = model.Name; + var visitorName = $"Visit{UnModelifyName(typeName)}"; + return isVoid ? @$" + public virtual void {visitorName}({typeName} m) + {{ + foreach (var modelBase in m.GetChildren()) + {{ + Visit(modelBase); + }} + }} +" : @$" + public virtual T {visitorName}({typeName} m) + {{ + T result = default; + foreach (var modelBase in m.GetChildren()) + {{ + result = Visit(modelBase); + }} + + return result; + }} +"; +} + + +string MakeSwitchArm(TypeInfo model, bool isVoid) +{ + if (model == null) throw new ArgumentNullException(nameof(model)); + var typeName = model.Name; + var visitorName = $"Visit{UnModelifyName(typeName)}"; + return isVoid ? $@" + case {typeName} x: {visitorName}(x); break;" : $@" + case {typeName} x: return {visitorName}(x);"; +} + +var arms = new List(); +var voidArms = new List(); +var methods = new List(); +var voidMethods = new List(); + +foreach (var modelType in modelTypes) +{ + arms.Add(MakeSwitchArm(modelType, false)); + voidArms.Add(MakeSwitchArm(modelType, true)); + methods.Add(MakeVisitorMethod(modelType, false)); + voidMethods.Add(MakeVisitorMethod(modelType, true)); +} + + +var sourceCode = $@"// automatically generated + +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable MemberCanBePrivate.Global +#pragma warning disable CS8603 +#pragma warning disable CS8600 +#pragma warning disable CS8509 + +using System.CodeDom.Compiler; +namespace {nameSpace}; + +[GeneratedCode(""meow-visitorgenerator"", ""1"")] +public class {className} +{{ + + public T? TryVisit(ModelBase? m) + {{ + return m == null ? default : Visit(m); + }} + + public T Visit(ModelBase m) + {{ + switch(m) + {{ +{string.Join("", arms)} + }} + return default; + }} +{string.Join("", methods)} +}} + +[GeneratedCode(""meow-visitorgenerator"", ""1"")] +public class {className} +{{ + public void Visit(ModelBase m) + {{ + switch(m) + {{ +{string.Join("", voidArms)} + }} + }} +{string.Join("", voidMethods)} +}} +"; + +File.WriteAllText(destinationPath, sourceCode); +Console.WriteLine($"output written to {destinationPath}"); \ No newline at end of file diff --git a/visitorgenerator/visitorgenerator.csproj b/visitorgenerator/visitorgenerator.csproj new file mode 100644 index 0000000..e085704 --- /dev/null +++ b/visitorgenerator/visitorgenerator.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + +