From 8c44d94e7fa198b3674726bb9f96945815c250d1 Mon Sep 17 00:00:00 2001 From: Stepami Date: Tue, 10 Oct 2023 15:09:33 +0300 Subject: [PATCH] complete type loading system rework --- .../Instructions/WithAssignment/AsString.cs | 4 +- .../ComplexData/Write/DotAssignment.cs | 8 +- .../ComplexData/Write/IndexAssignment.cs | 8 +- .../Instructions/WithAssignment/Simple.cs | 20 +-- .../FrontEnd/TopDownParse/Impl/Parser.cs | 105 ++++++------ .../FrontEnd/TopDownParse/ParserException.cs | 2 +- .../IR/Ast/AbstractSyntaxTreeNode.cs | 27 +-- .../IR/Ast/Impl/AbstractSyntaxTree.cs | 23 +-- .../Nodes/Declarations/FunctionDeclaration.cs | 46 ++--- .../Nodes/Declarations/LexicalDeclaration.cs | 1 - .../Nodes/Declarations/TypeDeclaration.cs | 17 +- .../Ast/Impl/Nodes/Declarations/TypeValue.cs | 62 +++++++ .../AccessExpressions/AccessExpression.cs | 2 - .../AccessExpressions/DotAccess.cs | 18 -- .../AccessExpressions/IndexAccess.cs | 19 --- .../Nodes/Expressions/AssignmentExpression.cs | 76 +-------- .../Nodes/Expressions/BinaryExpression.cs | 86 ---------- .../Impl/Nodes/Expressions/CallExpression.cs | 81 --------- .../Nodes/Expressions/CastAsExpression.cs | 11 +- .../ComplexLiterals/ArrayLiteral.cs | 18 -- .../ComplexLiterals/ObjectLiteral.cs | 24 --- .../Expressions/ConditionalExpression.cs | 21 --- .../Ast/Impl/Nodes/Expressions/Expression.cs | 2 +- .../Nodes/Expressions/MemberExpression.cs | 18 -- .../PrimaryExpressions/IdentifierReference.cs | 24 +-- .../PrimaryExpressions/ImplicitLiteral.cs | 28 +++ .../Expressions/PrimaryExpressions/Literal.cs | 13 +- .../Impl/Nodes/Expressions/UnaryExpression.cs | 23 --- .../IR/Ast/Impl/Nodes/ScriptBody.cs | 4 + .../Ast/Impl/Nodes/Statements/IfStatement.cs | 1 + .../Nodes/Statements/InsideStatementJump.cs | 1 + .../Impl/Nodes/Statements/ReturnStatement.cs | 1 + .../Impl/Nodes/Statements/WhileStatement.cs | 1 + .../Exceptions/TypeDoNotExists.cs | 10 ++ .../IR/CheckSemantics/Types/ArrayType.cs | 7 - .../IR/CheckSemantics/Types/FunctionType.cs | 7 - .../IR/CheckSemantics/Types/NullableType.cs | 7 - .../IR/CheckSemantics/Types/ObjectType.cs | 161 ++++++++++++++++-- .../Types/{Visitors => }/ReferenceResolver.cs | 10 +- .../IR/CheckSemantics/Types/Type.cs | 13 +- .../IR/CheckSemantics/Types/TypeUtils.cs | 43 ----- .../Types/Visitors/ObjectTypeHasher.cs | 49 ------ .../Types/Visitors/ObjectTypePrinter.cs | 75 -------- .../CheckSemantics/Variables/SymbolTable.cs | 8 +- .../Variables/SymbolTableUtils.cs | 51 ------ .../Variables/Symbols/FunctionSymbol.cs | 2 - .../Visitors/DeclarationVisitor.cs | 32 ++-- .../Visitors/SemanticChecker.cs | 63 ------- .../SemanticChecker/SemanticChecker.cs | 103 +++++++++++ .../Service/IDefaultValueForTypeCalculator.cs | 6 + .../Impl/DefaultValueForTypeCalculator.cs | 30 ++++ .../Service/IStandardLibraryProvider.cs | 8 + .../Service/Impl/StandardLibraryProvider.cs | 36 ++++ .../Impl/SymbolTableInitializerService.cs | 2 +- .../SymbolTableInitializer.cs | 11 +- .../Service/ITypeDeclarationsResolver.cs | 10 ++ .../Service/Impl/TypeDeclarationsResolver.cs | 51 ++++++ .../TypeSystemLoader/TypeSystemLoader.cs | 45 +++++ Interpreter.Lib/Interpreter.Lib.csproj | 4 + Interpreter.Tests/Unit/IR/AstNodeTests.cs | 12 +- .../Unit/IR/Types/ObjectTypeTests.cs | 21 ++- Interpreter.Tests/Unit/IR/Types/TypeTests.cs | 8 +- Interpreter/Program.cs | 2 +- .../ParserProvider/Impl/ParserProvider.cs | 2 +- .../Impl/StructureProvider.cs | 2 +- 65 files changed, 760 insertions(+), 926 deletions(-) create mode 100644 Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs create mode 100644 Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/TypeDoNotExists.cs rename Interpreter.Lib/IR/CheckSemantics/Types/{Visitors => }/ReferenceResolver.cs (87%) delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/TypeUtils.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypeHasher.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTableUtils.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/SemanticChecker.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/IDefaultValueForTypeCalculator.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/Impl/DefaultValueForTypeCalculator.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/IStandardLibraryProvider.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/StandardLibraryProvider.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/ITypeDeclarationsResolver.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/Impl/TypeDeclarationsResolver.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/TypeSystemLoader.cs diff --git a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/AsString.cs b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/AsString.cs index d5996a3e..19140b84 100644 --- a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/AsString.cs +++ b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/AsString.cs @@ -14,7 +14,7 @@ public override IAddress Execute(VirtualMachine vm) { var frame = vm.Frames.Peek(); frame[Left] = JsonSerializer.Serialize( - right.right.Get(frame), + Right.right.Get(frame), new JsonSerializerOptions { WriteIndented = true, @@ -28,5 +28,5 @@ public override IAddress Execute(VirtualMachine vm) } protected override string ToStringInternal() => - $"{Left} = {right.right} as string"; + $"{Left} = {Right.right} as string"; } \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs index 5e58931b..e9c8fa45 100644 --- a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs +++ b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs @@ -13,14 +13,14 @@ public override IAddress Execute(VirtualMachine vm) { var frame = vm.Frames.Peek(); var obj = (Dictionary) frame[Left]; - var field = (string) right.left.Get(frame) ?? string.Empty; - obj[field] = right.right.Get(frame); + var field = (string) Right.left.Get(frame) ?? string.Empty; + obj[field] = Right.right.Get(frame); return Address.Next; } public Simple ToSimple() => - new DotRead(new Name(Left), right.left); + new DotRead(new Name(Left), Right.left); protected override string ToStringInternal() => - $"{Left}.{right.left} = {right.right}"; + $"{Left}.{Right.left} = {Right.right}"; } \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs index 286fba79..11ecf0a3 100644 --- a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs +++ b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs @@ -13,14 +13,14 @@ public override IAddress Execute(VirtualMachine vm) { var frame = vm.Frames.Peek(); var obj = (List) frame[Left]; - var index = Convert.ToInt32(right.left.Get(frame)); - obj[index] = right.right.Get(frame); + var index = Convert.ToInt32(Right.left.Get(frame)); + obj[index] = Right.right.Get(frame); return Address.Next; } public Simple ToSimple() => - new IndexRead(new Name(Left), right.left); + new IndexRead(new Name(Left), Right.left); protected override string ToStringInternal() => - $"{Left}[{right.left}] = {right.right}"; + $"{Left}[{Right.left}] = {Right.right}"; } \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/Simple.cs b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/Simple.cs index 8abf74f4..a2031d6c 100644 --- a/Interpreter.Lib/BackEnd/Instructions/WithAssignment/Simple.cs +++ b/Interpreter.Lib/BackEnd/Instructions/WithAssignment/Simple.cs @@ -7,7 +7,7 @@ public class Simple : Instruction { public string Left { get; set; } - protected (IValue left, IValue right) right; + protected (IValue left, IValue right) Right; private readonly string _operator; public Simple(string left, @@ -15,7 +15,7 @@ public Simple(string left, string @operator) { Left = left; - this.right = right; + Right = right; _operator = @operator; } @@ -43,21 +43,21 @@ protected override void OnSetOfAddress(IAddress address) => public override IAddress Execute(VirtualMachine vm) { var frame = vm.Frames.Peek(); - if (right.left == null) + if (Right.left == null) { - var value = right.right.Get(frame); + var value = Right.right.Get(frame); frame[Left] = _operator switch { "-" => -Convert.ToDouble(value), "!" => !Convert.ToBoolean(value), "~" => ((List) value).Count, "" => value, - _ => throw new NotImplementedException() + _ => throw new NotSupportedException($"_operator {_operator} is not supported") }; } else { - object lValue = right.left.Get(frame), rValue = right.right.Get(frame); + object lValue = Right.left.Get(frame), rValue = Right.right.Get(frame); frame[Left] = _operator switch { "+" when lValue is string => lValue.ToString() + rValue, @@ -77,7 +77,7 @@ public override IAddress Execute(VirtualMachine vm) "." => ((Dictionary) lValue)[rValue.ToString()!], "[]" => ((List) lValue)[Convert.ToInt32(rValue)], "++" => ((List) lValue).Concat((List) rValue).ToList(), - _ => throw new NotImplementedException() + _ => throw new NotSupportedException($"_operator {_operator} is not supported") }; } if (vm.CallStack.Any()) @@ -97,7 +97,7 @@ public override IAddress Execute(VirtualMachine vm) return Address.Next; } - protected override string ToStringInternal() => right.left == null - ? $"{Left} = {_operator}{right.right}" - : $"{Left} = {right.left} {_operator} {right.right}"; + protected override string ToStringInternal() => Right.left == null + ? $"{Left} = {_operator}{Right.right}" + : $"{Left} = {Right.left} {_operator} {Right.right}"; } \ No newline at end of file diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs b/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs index 91586b99..313164c5 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs +++ b/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs @@ -11,8 +11,6 @@ using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; namespace Interpreter.Lib.FrontEnd.TopDownParse.Impl; @@ -208,17 +206,15 @@ private TypeDeclaration TypeDeclaration() Expect("Assign"); var type = TypeValue(); - type.Recursive = type.ToString().Contains(ident.Value); - return new TypeDeclaration(ident.Value, type) { Segment = typeWord.Segment + ident.Segment }; } - private Type TypeValue() + private TypeValue TypeValue() { if (CurrentIs("Ident")) { var ident = Expect("Ident"); - var identType = new Type(ident.Value); + var identType = new TypeIdentValue(ident.Value); return WithSuffix(identType); } @@ -226,26 +222,31 @@ private Type TypeValue() if (CurrentIs("LeftCurl")) { Expect("LeftCurl"); - var propertyTypes = new List(); + var propertyTypes = new List(); while (CurrentIs("Ident")) { var ident = Expect("Ident"); Expect("Colon"); var propType = TypeValue(); - propertyTypes.Add(new PropertyType(ident.Value, propType)); + propertyTypes.Add( + new PropertyTypeValue( + ident.Value, + propType)); Expect("SemiColon"); } Expect("RightCurl"); - return WithSuffix(new ObjectType(propertyTypes)); + return WithSuffix(new ObjectTypeValue(propertyTypes)); } if (CurrentIs("LeftParen")) { Expect("LeftParen"); - var args = new List(); - while (CurrentIs("Ident") || CurrentIs("LeftCurl") || CurrentIs("LeftParen")) + var args = new List(); + while (CurrentIs("Ident") || + CurrentIs("LeftCurl") || + CurrentIs("LeftParen")) { args.Add(TypeValue()); if (!CurrentIs("RightParen")) @@ -256,13 +257,13 @@ private Type TypeValue() Expect("RightParen"); Expect("Arrow"); var returnType = TypeValue(); - return new FunctionType(returnType, args); + return new FunctionTypeValue(returnType, args); } return null; } - private Type WithSuffix(Type baseType) + private TypeValue WithSuffix(TypeValue baseType) { var type = baseType; while (CurrentIs("LeftBracket") || CurrentIs("QuestionMark")) @@ -271,12 +272,12 @@ private Type WithSuffix(Type baseType) { Expect("LeftBracket"); Expect("RightBracket"); - type = new ArrayType(type); + type = new ArrayTypeValue(type); } else if (CurrentIs("QuestionMark")) { Expect("QuestionMark"); - type = new NullableType(type); + type = new NullableTypeValue(type); } } @@ -309,13 +310,13 @@ private FunctionDeclaration FunctionDeclaration() var ident = Expect("Ident"); Expect("LeftParen"); - var args = new List(); + var args = new List(); if (CurrentIs("Ident")) { var arg = Expect("Ident").Value; Expect("Colon"); var type = TypeValue(); - args.Add(new VariableSymbol(arg, type)); + args.Add(new PropertyTypeValue(arg, type)); } while (CurrentIs("Comma")) @@ -324,24 +325,19 @@ private FunctionDeclaration FunctionDeclaration() var arg = Expect("Ident").Value; Expect("Colon"); var type = TypeValue(); - args.Add(new VariableSymbol(arg, type)); + args.Add(new PropertyTypeValue(arg, type)); } Expect("RightParen"); - var returnType = TypeUtils.JavaScriptTypes.Void; + TypeValue returnType = new TypeIdentValue(TypeId: "undefined"); if (CurrentIs("Colon")) { Expect("Colon"); returnType = TypeValue(); } - var functionSymbol = - new FunctionSymbol(ident.Value, args, - new FunctionType(returnType, args.Select(x => x.Type)) - ); - - return new FunctionDeclaration(functionSymbol, BlockStatement()) + return new FunctionDeclaration(ident.Value, returnType, args, BlockStatement()) { Segment = ident.Segment }; } @@ -390,13 +386,11 @@ private void AddToDeclaration(LexicalDeclaration declaration) } else { - var expression = new Literal( - type, TypeUtils.GetDefaultValue(type), - label: TypeUtils.GetDefaultValue(type) == null ? "null" : null - ); + var expression = new ImplicitLiteral(type); assignment = new AssignmentExpression( - new MemberExpression(identRef), - expression, type); + lhs: new MemberExpression(identRef), + expression, + type); } } declaration.AddAssignment(assignment); @@ -672,26 +666,36 @@ private Literal Literal() { var str = Expect("StringLiteral"); return new Literal( - TypeUtils.JavaScriptTypes.String, - Regex.Unescape(str.Value.Trim('"')), + new TypeIdentValue(TypeId: "string"), + value: Regex.Unescape(str.Value.Trim('"')), segment, - str.Value + label: str.Value .Replace(@"\", @"\\") - .Replace(@"""", @"\""") - ); + .Replace(@"""", @"\""")); } return _tokens.Current.Type.Tag switch { - "NullLiteral" => new Literal(TypeUtils.JavaScriptTypes.Null, - Expect("NullLiteral").Value == "null" ? null : "", segment, "null"), - "IntegerLiteral" => new Literal(TypeUtils.JavaScriptTypes.Number, - double.Parse(Expect("IntegerLiteral").Value), segment), - "FloatLiteral" => new Literal(TypeUtils.JavaScriptTypes.Number, - double.Parse(Expect("FloatLiteral").Value, CultureInfo.InvariantCulture), segment), - "BooleanLiteral" => new Literal(TypeUtils.JavaScriptTypes.Boolean, - bool.Parse(Expect("BooleanLiteral").Value), segment), - _ => new Literal(TypeUtils.JavaScriptTypes.Undefined, new TypeUtils.Undefined()) + "NullLiteral" => new Literal( + new TypeIdentValue(TypeId: "null"), + Expect("NullLiteral").Value == "null" ? null : string.Empty, + segment, + label: "null"), + "IntegerLiteral" => new Literal( + new TypeIdentValue(TypeId: "number"), + value: double.Parse(Expect("IntegerLiteral").Value), + segment), + "FloatLiteral" => new Literal( + new TypeIdentValue(TypeId: "number"), + value: double.Parse( + Expect("FloatLiteral").Value, + CultureInfo.InvariantCulture), + segment), + "BooleanLiteral" => new Literal( + new TypeIdentValue(TypeId: "boolean"), + value: bool.Parse(Expect("BooleanLiteral").Value), + segment), + _ => throw new ParserException("There are no more supported literals") }; } @@ -715,30 +719,27 @@ private ObjectLiteral ObjectLiteral() { Expect("Arrow"); Expect("LeftParen"); - var args = new List(); + var args = new List(); while (CurrentIs("Ident")) { var name = Expect("Ident").Value; Expect("Colon"); var type = TypeValue(); - args.Add(new VariableSymbol(name, type)); + args.Add(new PropertyTypeValue(name, type)); if (!CurrentIs("RightParen")) { Expect("Comma"); } } Expect("RightParen"); - var returnType = TypeUtils.JavaScriptTypes.Void; + TypeValue returnType = new TypeIdentValue(TypeId: "undefined"); if (CurrentIs("Colon")) { Expect("Colon"); returnType = TypeValue(); } - var functionSymbol = new FunctionSymbol(idToken.Value, args, - new FunctionType(returnType, args.Select(a => a.Type)) - ); - methods.Add(new FunctionDeclaration(functionSymbol, BlockStatement()) + methods.Add(new FunctionDeclaration(idToken.Value, returnType, args, BlockStatement()) { Segment = idToken.Segment } ); } diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs b/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs index f2e80a96..78d72412 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs +++ b/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs @@ -8,7 +8,7 @@ public class ParserException : Exception { public ParserException() { } - protected ParserException(string message) : base(message) { } + public ParserException(string message) : base(message) { } protected ParserException(string message, Exception inner) : base(message, inner) { } diff --git a/Interpreter.Lib/IR/Ast/AbstractSyntaxTreeNode.cs b/Interpreter.Lib/IR/Ast/AbstractSyntaxTreeNode.cs index f5e6c134..30130c53 100644 --- a/Interpreter.Lib/IR/Ast/AbstractSyntaxTreeNode.cs +++ b/Interpreter.Lib/IR/Ast/AbstractSyntaxTreeNode.cs @@ -1,11 +1,12 @@ using System.Collections; using Interpreter.Lib.BackEnd; using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Variables; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader; using Visitor.NET; namespace Interpreter.Lib.IR.Ast; @@ -14,21 +15,16 @@ public abstract class AbstractSyntaxTreeNode : IEnumerable, IVisitable, IVisitable, + IVisitable, IVisitable { public AbstractSyntaxTreeNode Parent { get; set; } - + public SymbolTable SymbolTable { get; set; } public bool CanEvaluate { get; protected init; } - - public Segment Segment { get; init; } - protected AbstractSyntaxTreeNode() - { - Parent = null; - CanEvaluate = false; - } + public Segment Segment { get; init; } internal List GetAllNodes() { @@ -59,15 +55,7 @@ public bool ChildOf() where T : AbstractSyntaxTreeNode return false; } - public void SemanticCheck() - { - if (CanEvaluate && !ChildOf()) - { - NodeCheck(); - } - } - - internal virtual Type NodeCheck() => null; + //internal virtual Type NodeCheck() => null; public abstract IEnumerator GetEnumerator(); @@ -83,6 +71,9 @@ IEnumerator IEnumerable.GetEnumerator() => public virtual Unit Accept(SymbolTableInitializer visitor) => visitor.Visit(this); + public virtual Unit Accept(TypeSystemLoader visitor) => + visitor.Visit(this); + public virtual Unit Accept(DeclarationVisitor visitor) => visitor.Visit(this); diff --git a/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs b/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs index 73527308..326c626e 100644 --- a/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs +++ b/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs @@ -2,8 +2,12 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker.Service.Impl; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer.Service.Impl; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader.Service.Impl; namespace Interpreter.Lib.IR.Ast.Impl; @@ -12,6 +16,7 @@ public class AbstractSyntaxTree : IAbstractSyntaxTree private readonly AbstractSyntaxTreeNode _root; private readonly SymbolTableInitializer _symbolTableInitializer; + private readonly TypeSystemLoader _typeSystemLoader; private readonly DeclarationVisitor _declarationVisitor; private readonly SemanticChecker _semanticChecker; @@ -21,22 +26,20 @@ public AbstractSyntaxTree(AbstractSyntaxTreeNode root) { _root = root; - _symbolTableInitializer = new SymbolTableInitializer(new SymbolTableInitializerService()); - _declarationVisitor = new(); + _symbolTableInitializer = new SymbolTableInitializer( + new SymbolTableInitializerService(), + new StandardLibraryProvider()); + _typeSystemLoader = new TypeSystemLoader(new TypeDeclarationsResolver()); + _declarationVisitor = new DeclarationVisitor(); - _semanticChecker = new(); - _instructionProvider = new(); + _semanticChecker = new SemanticChecker(new DefaultValueForTypeCalculator()); + _instructionProvider = new InstructionProvider(); } - private void Check() => - GetAllNodes().ToList().ForEach(node => node.SemanticCheck()); - - private IEnumerable GetAllNodes() => - _root.GetAllNodes(); - public AddressedInstructions GetInstructions() { _root.Accept(_symbolTableInitializer); + _root.Accept(_typeSystemLoader); _root.Accept(_declarationVisitor); _root.Accept(_semanticChecker); diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/FunctionDeclaration.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/FunctionDeclaration.cs index 89e464fe..bc972375 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/FunctionDeclaration.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/FunctionDeclaration.cs @@ -1,10 +1,7 @@ using Interpreter.Lib.BackEnd; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; using Interpreter.Lib.IR.CheckSemantics.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer; using Visitor.NET; @@ -14,20 +11,24 @@ namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; public class FunctionDeclaration : Declaration { public string Name { get; } - public FunctionSymbol Function { get; } + public TypeValue ReturnTypeValue { get; } + public List Arguments { get; } public BlockStatement Statements { get; } public ObjectLiteral Object => Parent as ObjectLiteral; - public FunctionDeclaration(FunctionSymbol function, BlockStatement statements) + public FunctionDeclaration( + string name, + TypeValue returnTypeValue, + List arguments, + BlockStatement blockStatement) { - Function = function; - function.Body = this; + Name = name; + ReturnTypeValue = returnTypeValue; + Arguments = arguments; - Name = function.Id; - - Statements = statements; + Statements = blockStatement; Statements.Parent = this; } @@ -36,31 +37,6 @@ public bool HasReturnStatement() => .OfType() .Any(); - public void SetArguments(CallExpression call, List expressions) - { - if (Function.Type.Arguments.Count == expressions.Count) - { - expressions.Select((e, i) => (e, i)).ToList() - .ForEach(pair => - { - var (e, i) = pair; - var eType = e.NodeCheck(); - if (Function.Type.Arguments[i].Equals(eType)) - { - SymbolTable.AddSymbol(Function.Parameters[i]); - } - else throw new WrongTypeOfArgument(e.Segment, Function.Type.Arguments[i], eType); - }); - } - else throw new WrongNumberOfArguments(call.Segment, Function.Parameters.Count, expressions.Count); - } - - public void Clear() - { - Statements.GetAllNodes().ForEach(x => x.SymbolTable?.Clear()); - SymbolTable.Clear(); - } - public override IEnumerator GetEnumerator() { yield return Statements; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/LexicalDeclaration.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/LexicalDeclaration.cs index 0685c7f8..9c2ee39e 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/LexicalDeclaration.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/LexicalDeclaration.cs @@ -19,7 +19,6 @@ public LexicalDeclaration(bool @readonly) public void AddAssignment(AssignmentExpression assignment) { - assignment.SymbolTable = SymbolTable; assignment.Parent = this; Assignments.Add(assignment); } diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs index 78350b7b..119df819 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs @@ -1,20 +1,24 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader; using Visitor.NET; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; public class TypeDeclaration : Declaration { + private readonly TypeValue _typeValue; public string TypeId { get; } - public Type TypeValue { get; } - public TypeDeclaration(string typeId, Type typeValue) + public TypeDeclaration(string typeId, TypeValue typeValue) { TypeId = typeId; - TypeValue = typeValue; + _typeValue = typeValue; } + + public Type BuildType() => + _typeValue.BuildType(SymbolTable); public override IEnumerator GetEnumerator() { @@ -22,10 +26,13 @@ public override IEnumerator GetEnumerator() } protected override string NodeRepresentation() => - $"type {TypeId} = {TypeValue}"; + $"type {TypeId} = {_typeValue}"; public override AddressedInstructions Accept(InstructionProvider visitor) => new(); - public override Unit Accept(DeclarationVisitor visitor) => + public override Unit Accept(TypeSystemLoader visitor) => visitor.Visit(this); + + public override Unit Accept(DeclarationVisitor visitor) => + default; } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs new file mode 100644 index 00000000..99c11154 --- /dev/null +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs @@ -0,0 +1,62 @@ +using Interpreter.Lib.IR.CheckSemantics.Exceptions; +using Interpreter.Lib.IR.CheckSemantics.Types; +using Interpreter.Lib.IR.CheckSemantics.Variables; +using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; + +public abstract record TypeValue +{ + public abstract Type BuildType(SymbolTable symbolTable); +} + +public record TypeIdentValue( + string TypeId +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + symbolTable.FindSymbol(TypeId)?.Type ?? + throw new TypeDoNotExists(TypeId); +} + +public record ArrayTypeValue( + TypeValue TypeValue +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new ArrayType(TypeValue.BuildType(symbolTable)); +} + +public record NullableTypeValue( + TypeValue TypeValue +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new NullableType(TypeValue.BuildType(symbolTable)); +} + +public record PropertyTypeValue( + string Key, + TypeValue TypeValue); + +public record ObjectTypeValue( + IEnumerable Properties +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new ObjectType( + Properties.Select(x => new PropertyType( + Id: x.Key, + x.TypeValue.BuildType(symbolTable)))); +} + +public record FunctionTypeValue( + TypeValue ReturnTypeValue, + IEnumerable Arguments +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new FunctionType( + ReturnTypeValue.BuildType(symbolTable), + Arguments.Select(x => x.BuildType(symbolTable))); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs index 568db7ac..564aadb7 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs @@ -16,8 +16,6 @@ protected AccessExpression(AccessExpression prev) } } - public abstract Type Check(Type prev); - public bool HasNext() => Next is not null; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs index 6ab3f6f9..4592e755 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs @@ -1,8 +1,6 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; @@ -16,22 +14,6 @@ public DotAccess(IdentifierReference property, AccessExpression prev = null) : b Property.Parent = this; } - public override Type Check(Type prev) - { - if (prev is ObjectType objectType) - { - var fieldType = objectType[Property.Name]; - if (fieldType != null) - { - return HasNext() ? Next.Check(fieldType) : fieldType; - } - - throw new ObjectAccessException(Segment, objectType, Property.Name); - } - - return null; - } - public override IEnumerator GetEnumerator() { yield return Property; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs index df1b16da..285aeb10 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs @@ -1,7 +1,5 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; @@ -24,23 +22,6 @@ public override IEnumerator GetEnumerator() } } - public override Type Check(Type prev) - { - if (prev is ArrayType arrayType) - { - var indexType = Index.NodeCheck(); - if (indexType.Equals(TypeUtils.JavaScriptTypes.Number)) - { - var elemType = arrayType.Type; - return HasNext() ? Next.Check(elemType) : elemType; - } - - throw new ArrayAccessException(Segment, indexType); - } - - return null; - } - protected override string NodeRepresentation() => "[]"; public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs index a885d6fc..b6cbb8cc 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs @@ -1,9 +1,6 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -11,9 +8,12 @@ public class AssignmentExpression : Expression { public LeftHandSideExpression Destination { get; } public Expression Source { get; } - public Type DestinationType { get; } + public TypeValue DestinationType { get; } - public AssignmentExpression(LeftHandSideExpression lhs, Expression source, Type destinationType = null) + public AssignmentExpression( + LeftHandSideExpression lhs, + Expression source, + TypeValue destinationType = null) { Destination = lhs; lhs.Parent = this; @@ -24,72 +24,6 @@ public AssignmentExpression(LeftHandSideExpression lhs, Expression source, Type DestinationType = destinationType; } - internal override Type NodeCheck() - { - var id = Destination.Id; - var type = Source.NodeCheck(); - if (Parent is LexicalDeclaration declaration) - { - if (declaration.Readonly && type.Equals(TypeUtils.JavaScriptTypes.Undefined)) - { - throw new ConstWithoutInitializer(Destination.Id); - } - - if (SymbolTable.ContainsSymbol(Destination.Id)) - { - throw new DeclarationAlreadyExists(Destination.Id); - } - - if (DestinationType != null && type.Equals(TypeUtils.JavaScriptTypes.Undefined)) - { - type = DestinationType; - } - - if (DestinationType != null && !DestinationType.Equals(type)) - { - throw new IncompatibleTypesOfOperands(Segment, DestinationType, type); - } - - if (DestinationType == null && type.Equals(TypeUtils.JavaScriptTypes.Undefined)) - { - throw new CannotDefineType(Segment); - } - - var typeOfSymbol = DestinationType != null && type.Equals(TypeUtils.JavaScriptTypes.Undefined) - ? DestinationType - : type; - if (typeOfSymbol is ObjectType objectTypeOfSymbol) - { - SymbolTable.AddSymbol(new ObjectSymbol(id, objectTypeOfSymbol, declaration.Readonly, Source.SymbolTable) - { - Table = Source.SymbolTable - }); - } - else - { - SymbolTable.AddSymbol(new VariableSymbol(id, typeOfSymbol, declaration.Readonly)); - } - } - else - { - var symbol = SymbolTable.FindSymbol(id); - if (symbol != null) - { - if (symbol.ReadOnly) - { - throw new AssignmentToConst(Destination.Id); - } - - if (!Destination.NodeCheck().Equals(type)) - { - throw new IncompatibleTypesOfOperands(Segment, symbol.Type, type); - } - } - } - - return type; - } - public override IEnumerator GetEnumerator() { yield return Destination; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs index bef262be..e2f005f2 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs @@ -1,7 +1,5 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -22,90 +20,6 @@ public BinaryExpression(Expression left, string @operator, Expression right) Right.Parent = this; } - internal override Type NodeCheck() - { - var lType = Left.NodeCheck(); - var rType = Right.NodeCheck(); - Type retType = null; - if (Operator != "::" && !lType.Equals(rType)) - { - throw new IncompatibleTypesOfOperands(Segment, lType, rType); - } - - switch (Operator) - { - case "+": - if (lType.Equals(TypeUtils.JavaScriptTypes.Number)) - { - retType = TypeUtils.JavaScriptTypes.Number; - } - else if (lType.Equals(TypeUtils.JavaScriptTypes.String)) - { - retType = TypeUtils.JavaScriptTypes.String; - } - else throw new UnsupportedOperation(Segment, lType, Operator); - - break; - case "-": - case "*": - case "/": - case "%": - if (lType.Equals(TypeUtils.JavaScriptTypes.Number)) - { - retType = TypeUtils.JavaScriptTypes.Number; - } - else throw new UnsupportedOperation(Segment, lType, Operator); - - break; - case "||": - case "&&": - if (lType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - retType = TypeUtils.JavaScriptTypes.Boolean; - } - else throw new UnsupportedOperation(Segment, lType, Operator); - - break; - case "==": - case "!=": - retType = TypeUtils.JavaScriptTypes.Boolean; - break; - case ">": - case ">=": - case "<": - case "<=": - if (lType.Equals(TypeUtils.JavaScriptTypes.Number)) - { - retType = TypeUtils.JavaScriptTypes.Boolean; - } - else throw new UnsupportedOperation(Segment, lType, Operator); - - break; - case "++": - if (lType is ArrayType && rType is ArrayType) - { - retType = lType; - } - else throw new UnsupportedOperation(Segment, lType, Operator); - - break; - case "::": - if (!(lType is ArrayType)) - { - throw new UnsupportedOperation(Segment, lType, Operator); - } - if (rType.Equals(TypeUtils.JavaScriptTypes.Number)) - { - retType = TypeUtils.JavaScriptTypes.Void; - } - else throw new ArrayAccessException(Segment, rType); - - break; - } - - return retType; - } - public override IEnumerator GetEnumerator() { yield return Left; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs index 3731ebfe..3384c971 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs @@ -1,11 +1,6 @@ using Interpreter.Lib.BackEnd; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -29,82 +24,6 @@ public CallExpression(MemberExpression member, IEnumerable expressio public override bool Empty() => Member.Empty(); - private FunctionSymbol GetFunction() - { - if (Member.Any()) - { - var table = SymbolTable.FindSymbol(Member.Id).Table; - var chain = Member.AccessChain; - while (chain.HasNext()) - { - table = chain switch - { - DotAccess dot => table.FindSymbol(dot.Property).Table, - IndexAccess => throw new NotImplementedException(), - _ => throw new NotImplementedException() - }; - chain = chain.Next; - } - - return table.FindSymbol(((DotAccess) chain).Property); - } - - return SymbolTable.FindSymbol(Member.Id); - } - - internal override Type NodeCheck() - { - if (Member.Any()) - { - Member.NodeCheck(); - } - else - { - IdentifierReference idRef = Member.Id; - idRef.NodeCheck(); - } - - var function = GetFunction(); - if (function == null) - { - throw new SymbolIsNotCallable(Member.Id, Segment); - } - - if (!function.Type.ReturnType.Equals(TypeUtils.JavaScriptTypes.Void)) - { - if (!function.Body.HasReturnStatement()) - { - throw new FunctionWithoutReturnStatement(function.Body.Segment); - } - } - - function.Body.SetArguments(this, Parameters); - - var block = function.Body.First().GetAllNodes(); - foreach (var node in block) - { - if (node is ReturnStatement retStmt) - { - var retType = retStmt.NodeCheck(); - if (retType.Equals(function.Type.ReturnType)) - { - function.Body.Clear(); - return retType; - } - - throw new WrongReturnType(retStmt.Segment, function.Type.ReturnType, retType); - } - - if (node.CanEvaluate && !(node is CallExpression call && call.Member.Id == Member.Id)) - { - node.NodeCheck(); - } - } - - function.Body.Clear(); - return TypeUtils.JavaScriptTypes.Void; - } - public override IEnumerator GetEnumerator() { var nodes = new List diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs index c047adfc..d4d98f2e 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs @@ -1,16 +1,17 @@ using Interpreter.Lib.BackEnd; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Types; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; public class CastAsExpression : Expression { public Expression Expression { get; } - private readonly Type _cast; + private readonly TypeValue _cast; - public CastAsExpression(Expression expression, Type cast) + public CastAsExpression(Expression expression, TypeValue cast) { Expression = expression; Expression.Parent = this; @@ -29,5 +30,7 @@ public override AddressedInstructions Accept(ExpressionInstructionProvider visit visitor.Visit(this); public override Type Accept(SemanticChecker visitor) => - TypeUtils.JavaScriptTypes.String; + _cast.BuildType(SymbolTable) == "string" + ? "string" + : throw new NotSupportedException("Other types but 'string' have not been supported for casting yet"); } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs index c10c4b10..41f746d4 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs @@ -1,7 +1,5 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; @@ -15,22 +13,6 @@ public ArrayLiteral(IEnumerable expressions) Expressions.ForEach(expr => expr.Parent = this); } - internal override Type NodeCheck() - { - if (Expressions.Any()) - { - var type = Expressions.First().NodeCheck(); - if (Expressions.All(e => e.NodeCheck().Equals(type))) - { - return new ArrayType(type); - } - - throw new WrongArrayLiteralDeclaration(Segment, type); - } - - return TypeUtils.JavaScriptTypes.Undefined; - } - public override IEnumerator GetEnumerator() => Expressions.GetEnumerator(); diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs index a7db06fa..6e7299cb 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs @@ -1,8 +1,6 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer; using Visitor.NET; @@ -22,28 +20,6 @@ public ObjectLiteral(IEnumerable properties, IEnumerable m.Parent = this); } - internal override Type NodeCheck() - { - var propertyTypes = new List(); - Properties.ForEach(prop => - { - var propType = prop.Expression.NodeCheck(); - propertyTypes.Add(new PropertyType(prop.Id.Name, propType)); - prop.Id.SymbolTable.AddSymbol(propType is ObjectType objectType - ? new ObjectSymbol(prop.Id.Name, objectType) {Table = prop.Expression.SymbolTable} - : new VariableSymbol(prop.Id.Name, propType) - ); - }); - Methods.ForEach(m => - { - var symbol = m.Function; - propertyTypes.Add(new PropertyType(symbol.Id, symbol.Type)); - }); - var type = new ObjectType(propertyTypes); - SymbolTable.AddSymbol(new VariableSymbol("this", type, true)); - return type; - } - public override IEnumerator GetEnumerator() => Properties.Concat(Methods).GetEnumerator(); diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs index cb7781d0..5bce861a 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs @@ -1,7 +1,5 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -22,25 +20,6 @@ public ConditionalExpression(Expression test, Expression consequent, Expression Alternate.Parent = this; } - internal override Type NodeCheck() - { - var tType = Test.NodeCheck(); - - if (tType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - var cType = Consequent.NodeCheck(); - var aType = Alternate.NodeCheck(); - if (cType.Equals(aType)) - { - return cType; - } - - throw new WrongConditionalTypes(Consequent.Segment, cType, Alternate.Segment, aType); - } - - throw new NotBooleanTestExpression(Test.Segment, tType); - } - public override IEnumerator GetEnumerator() { yield return Test; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs index 9f4efa1c..ddfe0d83 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs @@ -15,5 +15,5 @@ protected Expression() public abstract AddressedInstructions Accept(ExpressionInstructionProvider visitor); public override AddressedInstructions Accept(InstructionProvider visitor) => - throw new NotImplementedException(); + throw new NotSupportedException(); } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs index f57a21d4..7d5e6371 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs @@ -2,8 +2,6 @@ using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -35,22 +33,6 @@ public MemberExpression(IdentifierReference identifierReference, public override bool Empty() => AccessChain is null; - internal override Type NodeCheck() - { - if (AccessChain == null) - { - return _identifierReference.NodeCheck(); - } - - var symbol = SymbolTable.FindSymbol(_identifierReference); - if (symbol == null) - { - throw new UnknownIdentifierReference(_identifierReference); - } - - return AccessChain.Check(symbol.Type); - } - public override IEnumerator GetEnumerator() { if (AccessChain is not null) diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs index b15c1c1b..7f705fe7 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs @@ -1,7 +1,6 @@ using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; +using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; @@ -14,26 +13,13 @@ public IdentifierReference(string name) Name = name; } - internal override Type NodeCheck() - { - if (!ChildOf()) - { - var symbol = SymbolTable.FindSymbol(Name); - return symbol switch - { - VariableSymbol v => v.Type, - FunctionSymbol f => f.Type, - _ => throw new UnknownIdentifierReference(this) - }; - } - - return null; - } - protected override string NodeRepresentation() => Name; public override IValue ToValue() => new Name(Name); + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + public static implicit operator string(IdentifierReference identifierReference) => identifierReference.Name; } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs new file mode 100644 index 00000000..ed3a5ae3 --- /dev/null +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs @@ -0,0 +1,28 @@ +using Interpreter.Lib.BackEnd.Values; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; +using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; + +namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +public class ImplicitLiteral : PrimaryExpression +{ + public TypeValue TypeValue { get; } + public object ComputedDefaultValue { private get; set; } + + public ImplicitLiteral(TypeValue typeValue) => + TypeValue = typeValue; + + protected override string NodeRepresentation() => + TypeValue.ToString(); + + public override IValue ToValue() => + new Constant( + ComputedDefaultValue, + ComputedDefaultValue is null + ? "null" + : ComputedDefaultValue.ToString()); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs index adda0265..8961e375 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs @@ -1,16 +1,22 @@ using Interpreter.Lib.BackEnd.Values; using Interpreter.Lib.FrontEnd.GetTokens.Data; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; public class Literal : PrimaryExpression { - private readonly Type _type; + private readonly TypeValue _type; private readonly object _value; private readonly string _label; - public Literal(Type type, object value, Segment segment = null, string label = null) + public Literal( + TypeValue type, + object value, + Segment segment, + string label = null) { _type = type; _label = label ?? value.ToString(); @@ -23,5 +29,6 @@ public Literal(Type type, object value, Segment segment = null, string label = n public override IValue ToValue() => new Constant(_value, _label); - public override Type Accept(SemanticChecker visitor) => _type; + public override Type Accept(SemanticChecker visitor) => + _type.BuildType(Parent.SymbolTable); } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs index 81eb3eb4..218b8da6 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs @@ -1,7 +1,5 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions; @@ -18,27 +16,6 @@ public UnaryExpression(string @operator, Expression expression) Expression.Parent = this; } - internal override Type NodeCheck() - { - var eType = Expression.NodeCheck(); - Type retType; - if (eType.Equals(TypeUtils.JavaScriptTypes.Number) && Operator == "-") - { - retType = TypeUtils.JavaScriptTypes.Number; - } - else if (eType.Equals(TypeUtils.JavaScriptTypes.Boolean) && Operator == "!") - { - retType = TypeUtils.JavaScriptTypes.Boolean; - } - else if (eType is ArrayType && Operator == "~") - { - retType = TypeUtils.JavaScriptTypes.Number; - } - else throw new UnsupportedOperation(Segment, eType, Operator); - - return retType; - } - public override IEnumerator GetEnumerator() { yield return Expression; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs index 7acebf4e..82859061 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs @@ -1,6 +1,7 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader; using Visitor.NET; namespace Interpreter.Lib.IR.Ast.Impl.Nodes; @@ -25,4 +26,7 @@ public override AddressedInstructions Accept(InstructionProvider visitor) => public override Unit Accept(SymbolTableInitializer visitor) => visitor.Visit(this); + + public override Unit Accept(TypeSystemLoader visitor) => + visitor.Visit(this); } \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs index 69abea69..46cf6713 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs @@ -1,6 +1,7 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs index e3196de9..1f90c2fe 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs @@ -1,6 +1,7 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs index 355fcecf..32dceefe 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs @@ -1,6 +1,7 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs index 02f911ee..8815cd93 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs @@ -1,6 +1,7 @@ using Interpreter.Lib.BackEnd; using Interpreter.Lib.IR.Ast.Visitors; using Interpreter.Lib.IR.CheckSemantics.Visitors; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/TypeDoNotExists.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/TypeDoNotExists.cs new file mode 100644 index 00000000..227172a3 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Exceptions/TypeDoNotExists.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class TypeDoNotExists : SemanticException +{ + public TypeDoNotExists(string typeId) : + base($"Type '{typeId}' do not exists") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs index 43cccd65..eadd619e 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs @@ -1,4 +1,3 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; using Visitor.NET; namespace Interpreter.Lib.IR.CheckSemantics.Types; @@ -14,12 +13,6 @@ public ArrayType(Type type) : base($"{type}[]") public override Unit Accept(ReferenceResolver visitor) => visitor.Visit(this); - - public override string Accept(ObjectTypePrinter visitor) => - visitor.Visit(this); - - public override int Accept(ObjectTypeHasher visitor) => - visitor.Visit(this); public override bool Equals(object obj) { diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs index e97882cc..d758a7bc 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs @@ -1,5 +1,4 @@ using System.Text; -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; using Visitor.NET; namespace Interpreter.Lib.IR.CheckSemantics.Types; @@ -19,12 +18,6 @@ public FunctionType(Type returnType, IEnumerable arguments) public override Unit Accept(ReferenceResolver visitor) => visitor.Visit(this); - public override string Accept(ObjectTypePrinter visitor) => - visitor.Visit(this); - - public override int Accept(ObjectTypeHasher visitor) => - visitor.Visit(this); - public override bool Equals(object obj) { if (ReferenceEquals(this, obj)) return true; diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs index 169a40f8..a829f85d 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs @@ -1,4 +1,3 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; using Visitor.NET; namespace Interpreter.Lib.IR.CheckSemantics.Types; @@ -18,12 +17,6 @@ protected NullableType() public override Unit Accept(ReferenceResolver visitor) => visitor.Visit(this); - - public override string Accept(ObjectTypePrinter visitor) => - visitor.Visit(this); - - public override int Accept(ObjectTypeHasher visitor) => - visitor.Visit(this); public override bool Equals(object obj) { diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs index 5aea3e2a..156b1f05 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs @@ -1,4 +1,4 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; +using System.Text; using Visitor.NET; namespace Interpreter.Lib.IR.CheckSemantics.Types; @@ -23,26 +23,17 @@ public ObjectType(IEnumerable properties) public Type this[string id] { - get => _properties.ContainsKey(id) - ? _properties[id] + get => _properties.TryGetValue(id, out var type) + ? type : null; set => _properties[id] = value; } - public IEnumerable Keys => _properties.Keys; - - public void ResolveSelfReferences(string self) => - new ReferenceResolver(this, self) - .Visit(this); + public IEnumerable Keys => + _properties.Keys; public override Unit Accept(ReferenceResolver visitor) => visitor.Visit(this); - - public override string Accept(ObjectTypePrinter visitor) => - visitor.Visit(this); - - public override int Accept(ObjectTypeHasher visitor) => - visitor.Visit(this); public override bool Equals(object obj) { @@ -61,10 +52,148 @@ public override bool Equals(object obj) } public override int GetHashCode() => - _hasher.Visit(this); + _hasher.HashObjectType(this); public override string ToString() => - _serializer.Visit(this); + _serializer.PrintObjectType(this); + + private class ObjectTypeHasher + { + private readonly ObjectType _reference; + + public ObjectTypeHasher(ObjectType reference) => + _reference = reference; + + // ReSharper disable once SuggestBaseTypeForParameter + private int Hash(Type type) => type switch + { + ArrayType arrayType => HashArrayType(arrayType), + FunctionType functionType => HashFunctionType(functionType), + ObjectType objectType => HashObjectType(objectType), + NullableType nullableType => HashNullableType(nullableType), + _ => type.GetHashCode() + }; + + public int HashObjectType(ObjectType objectType) => + objectType.Keys.Select(key => HashCode.Combine( + key, + objectType[key].Equals(_reference) + ? "@this".GetHashCode() + : objectType[key].GetType().GetHashCode())) + .Aggregate(36, HashCode.Combine); + + private int HashArrayType(ArrayType arrayType) => + arrayType.Type.Equals(_reference) + ? "@this".GetHashCode() + : Hash(arrayType.Type); + + private int HashNullableType(NullableType nullableType) => + nullableType.Type.Equals(_reference) + ? "@this".GetHashCode() + : Hash(nullableType.Type); + + private int HashFunctionType(FunctionType functionType) => + HashCode.Combine( + functionType.ReturnType.Equals(_reference) + ? "@this".GetHashCode() + : Hash(functionType.ReturnType), + functionType.Arguments.Select(arg => + arg.Equals(_reference) + ? "@this".GetHashCode() + : Hash(arg) + ).Aggregate(36, HashCode.Combine)); + } + + private class ObjectTypePrinter + { + private readonly ObjectType _reference; + private readonly ISet _visited; + + public ObjectTypePrinter(ObjectType reference) + { + _reference = reference; + _visited = new HashSet(); + } + + // ReSharper disable once SuggestBaseTypeForParameter + private string Print(Type type) => type switch + { + ArrayType arrayType => PrintArrayType(arrayType), + FunctionType functionType => PrintFunctionType(functionType), + ObjectType objectType => PrintObjectType(objectType), + NullableType nullableType => PrintNullableType(nullableType), + _ => type.ToString() + }; + + public string PrintObjectType(ObjectType objectType) + { + if (_visited.Contains(objectType)) + return string.Empty; + if (!objectType.Equals(_reference)) + { + _visited.Add(objectType); + } + + var sb = new StringBuilder("{"); + foreach (var key in objectType.Keys) + { + var type = objectType[key]; + var prop = $"{key}: "; + + if (type.Equals(_reference)) + prop += "@this"; + else + { + var printedType = Print(type); + prop += string.IsNullOrEmpty(printedType) + ? key + : printedType; + } + + sb.Append(prop).Append(';'); + } + + return sb.Append('}').ToString(); + } + + private string PrintArrayType(ArrayType arrayType) + { + var sb = new StringBuilder(); + sb.Append(arrayType.Type.Equals(_reference) + ? "@this" + : Print(arrayType.Type) + ); + + return sb.Append("[]").ToString(); + } + + private string PrintNullableType(NullableType nullableType) + { + var sb = new StringBuilder(); + sb.Append(nullableType.Type.Equals(_reference) + ? "@this" + : Print(nullableType.Type) + ); + + return sb.Append('?').ToString(); + } + + private string PrintFunctionType(FunctionType functionType) + { + var sb = new StringBuilder("("); + sb.AppendJoin(", ", functionType.Arguments.Select( + x => x.Equals(_reference) + ? "@this" + : Print(x) + )).Append(") => "); + sb.Append(functionType.ReturnType.Equals(_reference) + ? "@this" + : Print(functionType.ReturnType) + ); + + return sb.ToString(); + } + } } public record PropertyType(string Id, Type Type); \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs b/Interpreter.Lib/IR/CheckSemantics/Types/ReferenceResolver.cs similarity index 87% rename from Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs rename to Interpreter.Lib/IR/CheckSemantics/Types/ReferenceResolver.cs index c5a881c9..850a44a4 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/ReferenceResolver.cs @@ -1,6 +1,6 @@ using Visitor.NET; -namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors; +namespace Interpreter.Lib.IR.CheckSemantics.Types; public class ReferenceResolver : IVisitor, @@ -9,15 +9,15 @@ public class ReferenceResolver : IVisitor, IVisitor { - private readonly ObjectType _reference; + private readonly Type _reference; private readonly string _refId; - private readonly HashSet _visited; + private readonly ISet _visited; - public ReferenceResolver(ObjectType reference, string refId) + public ReferenceResolver(Type reference, string refId) { _reference = reference; _refId = refId; - _visited = new(); + _visited = new HashSet(); } public Unit Visit(ObjectType visitable) diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs b/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs index 885d6988..5f691269 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs @@ -1,12 +1,9 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; using Visitor.NET; namespace Interpreter.Lib.IR.CheckSemantics.Types; public class Type : - IVisitable, - IVisitable, - IVisitable + IVisitable { private readonly string _name; @@ -16,17 +13,9 @@ protected Type() public Type(string name) => _name = name; - public bool Recursive { get; set; } - public virtual Unit Accept(ReferenceResolver visitor) => visitor.Visit(this); - public virtual string Accept(ObjectTypePrinter visitor) => - visitor.Visit(this); - - public virtual int Accept(ObjectTypeHasher visitor) => - visitor.Visit(this); - public override bool Equals(object obj) { if (ReferenceEquals(this, obj)) return true; diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/TypeUtils.cs b/Interpreter.Lib/IR/CheckSemantics/Types/TypeUtils.cs deleted file mode 100644 index 7f78bc92..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/TypeUtils.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public static class TypeUtils -{ - public static ( - Type Number, Type Boolean, Type String, Type Null, Type Undefined, Type Void - ) JavaScriptTypes { get; } = ( - new Type("number"), - new Type("boolean"), - new Type("string"), - new NullType(), - new Type("undefined"), - new Type("void") - ); - - public static object GetDefaultValue(Type type) - { - if (type.Equals(JavaScriptTypes.Boolean)) - return false; - if (type.Equals(JavaScriptTypes.Number)) - return 0; - if (type.Equals(JavaScriptTypes.String)) - return ""; - if (type.Equals(JavaScriptTypes.Void)) - return new Void(); - if (type.Equals(JavaScriptTypes.Null)) - return null; - if (type is ArrayType) - return new List(); - - return new Undefined(); - } - - public struct Undefined - { - public override string ToString() => JavaScriptTypes.Undefined.ToString(); - } - - private struct Void - { - public override string ToString() => JavaScriptTypes.Void.ToString(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypeHasher.cs b/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypeHasher.cs deleted file mode 100644 index cb5e160b..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypeHasher.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Visitor.NET; - -namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors; - -public class ObjectTypeHasher : - IVisitor, - IVisitor, - IVisitor, - IVisitor, - IVisitor -{ - private readonly ObjectType _reference; - - public ObjectTypeHasher(ObjectType reference) => - _reference = reference; - - public int Visit(Type visitable) => - visitable.GetHashCode(); - - public int Visit(ObjectType visitable) => - visitable.Keys.Select(key => HashCode.Combine(key, - visitable[key].Equals(_reference) - ? "@this".GetHashCode() - : visitable[key].Recursive - ? key.GetHashCode() - : visitable[key].Accept(this)) - ).Aggregate(36, HashCode.Combine); - - public int Visit(ArrayType visitable) => - visitable.Type.Equals(_reference) - ? "@this".GetHashCode() - : visitable.Type.Accept(this); - - public int Visit(NullableType visitable) => - visitable.Type.Equals(_reference) - ? "@this".GetHashCode() - : visitable.Type.Accept(this); - - public int Visit(FunctionType visitable) => - HashCode.Combine( - visitable.ReturnType.Equals(_reference) - ? "@this".GetHashCode() - : visitable.ReturnType.Accept(this), - visitable.Arguments.Select(arg => - arg.Equals(_reference) - ? "@this".GetHashCode() - : arg.Accept(this) - ).Aggregate(36, HashCode.Combine)); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs b/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs deleted file mode 100644 index 597ab4f4..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Text; -using Visitor.NET; - -namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors; - -public class ObjectTypePrinter : - IVisitor, - IVisitor, - IVisitor, - IVisitor, - IVisitor -{ - private readonly ObjectType _reference; - - public ObjectTypePrinter(ObjectType reference) => - _reference = reference; - - public string Visit(Type visitable) => - visitable.ToString(); - - public string Visit(ObjectType visitable) - { - var sb = new StringBuilder("{"); - foreach (var key in visitable.Keys) - { - var type = visitable[key]; - var prop = $"{key}: "; - prop += type.Equals(_reference) - ? "@this" - : type.Recursive - ? key - : type.Accept(this); - sb.Append(prop).Append(';'); - } - - return sb.Append('}').ToString(); - } - - public string Visit(ArrayType visitable) - { - var sb = new StringBuilder(); - sb.Append(visitable.Type.Equals(_reference) - ? "@this" - : visitable.Type.Accept(this) - ); - - return sb.Append("[]").ToString(); - } - - public string Visit(NullableType visitable) - { - var sb = new StringBuilder(); - sb.Append(visitable.Type.Equals(_reference) - ? "@this" - : visitable.Type.Accept(this) - ); - - return sb.Append('?').ToString(); - } - - public string Visit(FunctionType visitable) - { - var sb = new StringBuilder("("); - sb.AppendJoin(", ", visitable.Arguments.Select(x => x.Equals(_reference) - ? "@this" - : x.Accept(this) - )).Append(") => "); - sb.Append(visitable.ReturnType.Equals(_reference) - ? "@this" - : visitable.ReturnType.Accept(this) - ); - - return sb.ToString(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs index b01b6b08..edc8ebe8 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs @@ -13,6 +13,12 @@ public void AddOpenScope(SymbolTable table) _openScope = table; } + /// + /// Список доступных идентификаторов в области видимости таблицы символов + /// + public IEnumerable AvailableSymbolIds => + _symbols.Keys.Concat(_openScope?.AvailableSymbolIds ?? Array.Empty()); + public void AddSymbol(Symbol symbol) => _symbols[symbol.Id] = symbol; @@ -32,6 +38,4 @@ public T FindSymbol(string id) where T : Symbol /// public bool ContainsSymbol(string id) => _symbols.ContainsKey(id); - - public void Clear() => _symbols.Clear(); } \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTableUtils.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTableUtils.cs deleted file mode 100644 index b0da7415..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTableUtils.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.Ast.Impl.Nodes; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.CheckSemantics.Variables; - -public static class SymbolTableUtils -{ - public static SymbolTable GetStandardLibrary() - { - var library = new SymbolTable(); - - library.AddSymbol(new TypeSymbol(TypeUtils.JavaScriptTypes.Number)); - library.AddSymbol(new TypeSymbol(TypeUtils.JavaScriptTypes.Boolean)); - library.AddSymbol(new TypeSymbol(TypeUtils.JavaScriptTypes.String)); - library.AddSymbol(new TypeSymbol(TypeUtils.JavaScriptTypes.Null)); - library.AddSymbol(new TypeSymbol(TypeUtils.JavaScriptTypes.Void)); - - var print = new FunctionSymbol( - "print", - new List - { - new VariableSymbol("str", TypeUtils.JavaScriptTypes.String) - }, - new FunctionType(TypeUtils.JavaScriptTypes.Void, new[] {TypeUtils.JavaScriptTypes.String}) - ); - print.Body = new FunctionDeclaration( - print, - new BlockStatement(new List()) - { - SymbolTable = new SymbolTable() - } - ) - { - SymbolTable = new SymbolTable(), - Segment = new Segment( - new Coordinates(0, 0), - new Coordinates(0, 0) - ) - }; - - library.AddSymbol(print); - - var symbolTable = new SymbolTable(); - symbolTable.AddOpenScope(library); - return symbolTable; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs index b37b5947..12991c67 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs @@ -1,6 +1,5 @@ using System.Text; using Interpreter.Lib.BackEnd; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.CheckSemantics.Types; namespace Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; @@ -10,7 +9,6 @@ public class FunctionSymbol : Symbol public override string Id { get; } public override FunctionType Type { get; } public List Parameters { get; } - public FunctionDeclaration Body { get; set; } public FunctionInfo CallInfo { get; } public FunctionSymbol(string id, IEnumerable parameters, FunctionType type) diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs index 0a6cfd56..d81d3da6 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs @@ -8,7 +8,6 @@ namespace Interpreter.Lib.IR.CheckSemantics.Visitors; public class DeclarationVisitor : IVisitor, - IVisitor, IVisitor, IVisitor { @@ -20,23 +19,16 @@ public Unit Visit(AbstractSyntaxTreeNode visitable) return default; } - public Unit Visit(TypeDeclaration visitable) - { - visitable.SymbolTable.AddSymbol( - new TypeSymbol( - visitable.TypeValue, - visitable.TypeId)); - return default; - } - public Unit Visit(LexicalDeclaration visitable) { foreach (var assignment in visitable.Assignments) { + var destinationType = assignment.DestinationType?.BuildType( + assignment.SymbolTable) ?? "undefined"; visitable.SymbolTable.AddSymbol( new VariableSymbol( assignment.Destination.Id, - assignment.DestinationType ?? TypeUtils.JavaScriptTypes.Undefined, + destinationType, visitable.Readonly)); } @@ -45,7 +37,23 @@ public Unit Visit(LexicalDeclaration visitable) public Unit Visit(FunctionDeclaration visitable) { - visitable.Parent.SymbolTable.AddSymbol(visitable.Function); + var parameters = visitable.Arguments.Select(x => + { + var arg = new VariableSymbol( + id: x.Key, + x.TypeValue.BuildType(visitable.Parent.SymbolTable)); + visitable.SymbolTable.AddSymbol(arg); + return arg; + }).ToList(); + + var functionSymbol = new FunctionSymbol( + visitable.Name, + parameters, + new FunctionType( + visitable.ReturnTypeValue.BuildType(visitable.Parent.SymbolTable), + arguments: parameters.Select(x => x.Type))); + + visitable.Parent.SymbolTable.AddSymbol(functionSymbol); return default; } } \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs deleted file mode 100644 index e1b41878..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Visitor.NET; - -namespace Interpreter.Lib.IR.CheckSemantics.Visitors; - -public class SemanticChecker : - IVisitor, - IVisitor, - IVisitor, - IVisitor -{ - public Type Visit(WhileStatement visitable) - { - var condType = visitable.Condition.Accept(this); - if (!condType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - throw new NotBooleanTestExpression(visitable.Segment, condType); - } - - return default; - } - - public Type Visit(IfStatement visitable) - { - var testType = visitable.Test.Accept(this); - if (!testType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - throw new NotBooleanTestExpression(visitable.Segment, testType); - } - - return default; - } - - public Type Visit(InsideStatementJump visitable) - { - switch (visitable.Keyword) - { - case InsideStatementJump.Break: - if (!(visitable.ChildOf() || visitable.ChildOf())) - throw new OutsideOfStatement(visitable.Segment, InsideStatementJump.Break, "if|while"); - break; - case InsideStatementJump.Continue: - if (!visitable.ChildOf()) - throw new OutsideOfStatement(visitable.Segment, InsideStatementJump.Continue, "while"); - break; - } - - return default; - } - - public Type Visit(ReturnStatement visitable) - { - if (!visitable.ChildOf()) - { - throw new ReturnOutsideFunction(visitable.Segment); - } - - return visitable.Expression?.NodeCheck() ?? TypeUtils.JavaScriptTypes.Void; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/SemanticChecker.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/SemanticChecker.cs new file mode 100644 index 00000000..a2732e8d --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/SemanticChecker.cs @@ -0,0 +1,103 @@ +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; +using Interpreter.Lib.IR.CheckSemantics.Exceptions; +using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker.Service; +using Visitor.NET; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker; + +public class SemanticChecker : + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor +{ + private readonly IDefaultValueForTypeCalculator _calculator; + + public SemanticChecker(IDefaultValueForTypeCalculator calculator) => + _calculator = calculator; + + public Type Visit(WhileStatement visitable) + { + var condType = visitable.Condition.Accept(this); + Type boolean = "boolean"; + if (!condType.Equals(boolean)) + { + throw new NotBooleanTestExpression(visitable.Segment, condType); + } + + return default; + } + + public Type Visit(IfStatement visitable) + { + var testType = visitable.Test.Accept(this); + Type boolean = "boolean"; + if (!testType.Equals(boolean)) + { + throw new NotBooleanTestExpression(visitable.Segment, testType); + } + + return default; + } + + public Type Visit(InsideStatementJump visitable) + { + switch (visitable.Keyword) + { + case InsideStatementJump.Break: + if (!(visitable.ChildOf() || visitable.ChildOf())) + throw new OutsideOfStatement( + visitable.Segment, + keyword: InsideStatementJump.Break, + statement: "if|while"); + break; + case InsideStatementJump.Continue: + if (!visitable.ChildOf()) + throw new OutsideOfStatement( + visitable.Segment, + keyword: InsideStatementJump.Continue, + statement: "while"); + break; + } + + return default; + } + + public Type Visit(ReturnStatement visitable) + { + if (!visitable.ChildOf()) + { + throw new ReturnOutsideFunction(visitable.Segment); + } + + return visitable.Expression?.Accept(this) ?? "void"; + } + + public Type Visit(IdentifierReference visitable) + { + if (visitable.ChildOf()) + return null; + + var symbol = visitable.SymbolTable.FindSymbol(visitable.Name); + return symbol switch + { + { State: SymbolState.Declared } => throw new NotSupportedException(), // todo symbol not init error + { State: SymbolState.Initialized } => symbol.Type, + null => throw new UnknownIdentifierReference(visitable), + _ => throw new ArgumentOutOfRangeException(nameof(symbol)) + }; + } + + public Type Visit(ImplicitLiteral visitable) + { + var type = visitable.TypeValue.BuildType(visitable.Parent.SymbolTable); + visitable.ComputedDefaultValue = _calculator.GetDefaultValueForType(type); + return type; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/IDefaultValueForTypeCalculator.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/IDefaultValueForTypeCalculator.cs new file mode 100644 index 00000000..92bf3d40 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/IDefaultValueForTypeCalculator.cs @@ -0,0 +1,6 @@ +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker.Service; + +public interface IDefaultValueForTypeCalculator +{ + public object GetDefaultValueForType(Type type); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/Impl/DefaultValueForTypeCalculator.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/Impl/DefaultValueForTypeCalculator.cs new file mode 100644 index 00000000..86e38f45 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SemanticChecker/Service/Impl/DefaultValueForTypeCalculator.cs @@ -0,0 +1,30 @@ +using Interpreter.Lib.IR.CheckSemantics.Types; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker.Service.Impl; + +internal class DefaultValueForTypeCalculator : IDefaultValueForTypeCalculator +{ + private readonly Type _boolean = "boolean"; + private readonly Type _number = "number"; + private readonly Type _string = "string"; + private readonly Type _void = "void"; + private readonly Type _null = new NullType(); + + public object GetDefaultValueForType(Type type) + { + if (type.Equals(_boolean)) + return false; + if (type.Equals(_number)) + return 0; + if (type.Equals(_string)) + return string.Empty; + if (type.Equals(_void)) + return new object(); + if (type.Equals(_null)) + return null; + if (type is ArrayType) + return new List(); + + return new object(); + } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/IStandardLibraryProvider.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/IStandardLibraryProvider.cs new file mode 100644 index 00000000..6d3f1999 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/IStandardLibraryProvider.cs @@ -0,0 +1,8 @@ +using Interpreter.Lib.IR.CheckSemantics.Variables; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer.Service; + +public interface IStandardLibraryProvider +{ + SymbolTable GetStandardLibrary(); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/StandardLibraryProvider.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/StandardLibraryProvider.cs new file mode 100644 index 00000000..b718cd80 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/StandardLibraryProvider.cs @@ -0,0 +1,36 @@ +using Interpreter.Lib.IR.CheckSemantics.Types; +using Interpreter.Lib.IR.CheckSemantics.Variables; +using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer.Service.Impl; + +internal class StandardLibraryProvider : IStandardLibraryProvider +{ + public SymbolTable GetStandardLibrary() + { + var library = new SymbolTable(); + + library.AddSymbol(new TypeSymbol("number")); + library.AddSymbol(new TypeSymbol("boolean")); + library.AddSymbol(new TypeSymbol("string")); + library.AddSymbol(new TypeSymbol(new NullType())); + library.AddSymbol(new TypeSymbol("void")); + + var print = new FunctionSymbol( + "print", + new List + { + new VariableSymbol("str", "string") + }, + new FunctionType( + "void", + new Type[] {"string"}) + ); + + library.AddSymbol(print); + + var symbolTable = new SymbolTable(); + symbolTable.AddOpenScope(library); + return symbolTable; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/SymbolTableInitializerService.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/SymbolTableInitializerService.cs index 5719e36e..5acb0c16 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/SymbolTableInitializerService.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/Service/Impl/SymbolTableInitializerService.cs @@ -2,7 +2,7 @@ namespace Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer.Service.Impl; -public class SymbolTableInitializerService : ISymbolTableInitializerService +internal class SymbolTableInitializerService : ISymbolTableInitializerService { public void InitThroughParent(AbstractSyntaxTreeNode node) => node.SymbolTable = node.Parent.SymbolTable; diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/SymbolTableInitializer.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/SymbolTableInitializer.cs index 66818c6c..abe5d49d 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/SymbolTableInitializer.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer/SymbolTableInitializer.cs @@ -3,7 +3,6 @@ using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Variables; using Interpreter.Lib.IR.CheckSemantics.Visitors.SymbolTableInitializer.Service; using Visitor.NET; @@ -17,9 +16,15 @@ public class SymbolTableInitializer : IVisitor { private readonly ISymbolTableInitializerService _initializerService; + private readonly IStandardLibraryProvider _provider; - public SymbolTableInitializer(ISymbolTableInitializerService initializerService) => + public SymbolTableInitializer( + ISymbolTableInitializerService initializerService, + IStandardLibraryProvider provider) + { _initializerService = initializerService; + _provider = provider; + } public Unit Visit(AbstractSyntaxTreeNode visitable) { @@ -31,7 +36,7 @@ public Unit Visit(AbstractSyntaxTreeNode visitable) public Unit Visit(ScriptBody visitable) { - visitable.SymbolTable = SymbolTableUtils.GetStandardLibrary(); + visitable.SymbolTable = _provider.GetStandardLibrary(); visitable.StatementList.ForEach(item => item.Accept(this)); return default; } diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/ITypeDeclarationsResolver.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/ITypeDeclarationsResolver.cs new file mode 100644 index 00000000..5c1ba40f --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/ITypeDeclarationsResolver.cs @@ -0,0 +1,10 @@ +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader.Service; + +public interface ITypeDeclarationsResolver +{ + void Store(TypeDeclaration declaration); + + void Resolve(); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/Impl/TypeDeclarationsResolver.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/Impl/TypeDeclarationsResolver.cs new file mode 100644 index 00000000..2a395acd --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/Service/Impl/TypeDeclarationsResolver.cs @@ -0,0 +1,51 @@ +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; +using Interpreter.Lib.IR.CheckSemantics.Types; +using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader.Service.Impl; + +internal class TypeDeclarationsResolver : ITypeDeclarationsResolver +{ + private readonly Queue _declarationsToResolve = new(); + + public void Store(TypeDeclaration declaration) => + _declarationsToResolve.Enqueue(declaration); + + public void Resolve() + { + // todo replace with provider + Type[] defaults = + { + new("number"), + new("boolean"), + new("string"), + new NullType(), + new("undefined"), + new("void") + }; + + while (_declarationsToResolve.Any()) + { + var declarationToResolve = _declarationsToResolve.Dequeue(); + + var type = declarationToResolve.BuildType(); + declarationToResolve.SymbolTable.AddSymbol( + new TypeSymbol( + type, + declarationToResolve.TypeId)); + + var resolvingCandidates = declarationToResolve.SymbolTable + .AvailableSymbolIds + .Except(defaults.Select(x => x.ToString())); + + foreach (var refId in resolvingCandidates) + { + var referenceSymbol = declarationToResolve.SymbolTable + .FindSymbol(refId); + if (referenceSymbol is null) + continue; + type.Accept(new ReferenceResolver(referenceSymbol.Type, refId)); + } + } + } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/TypeSystemLoader.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/TypeSystemLoader.cs new file mode 100644 index 00000000..74be4114 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader/TypeSystemLoader.cs @@ -0,0 +1,45 @@ +using Interpreter.Lib.IR.Ast; +using Interpreter.Lib.IR.Ast.Impl.Nodes; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; +using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; +using Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader.Service; +using Visitor.NET; + +namespace Interpreter.Lib.IR.CheckSemantics.Visitors.TypeSystemLoader; + +public class TypeSystemLoader : + IVisitor, + IVisitor, + IVisitor +{ + private readonly ITypeDeclarationsResolver _resolver; + + public TypeSystemLoader(ITypeDeclarationsResolver resolver) => + _resolver = resolver; + + public Unit Visit(ScriptBody visitable) + { + visitable.StatementList.ForEach(item => item.Accept(this)); + _resolver.Resolve(); + return default; + } + + public Unit Visit(AbstractSyntaxTreeNode visitable) + { + foreach (var child in visitable) + child.Accept(this); + + return default; + } + + public Unit Visit(TypeDeclaration visitable) + { + visitable.SymbolTable.AddSymbol( + new TypeSymbol( + visitable.TypeId, + visitable.TypeId)); + + _resolver.Store(visitable); + return default; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/Interpreter.Lib.csproj b/Interpreter.Lib/Interpreter.Lib.csproj index 410c681f..5e8b02ba 100644 --- a/Interpreter.Lib/Interpreter.Lib.csproj +++ b/Interpreter.Lib/Interpreter.Lib.csproj @@ -9,4 +9,8 @@ + + + + diff --git a/Interpreter.Tests/Unit/IR/AstNodeTests.cs b/Interpreter.Tests/Unit/IR/AstNodeTests.cs index 7d46ad44..00eb5c02 100644 --- a/Interpreter.Tests/Unit/IR/AstNodeTests.cs +++ b/Interpreter.Tests/Unit/IR/AstNodeTests.cs @@ -1,9 +1,6 @@ using Interpreter.Lib.IR.Ast.Impl.Nodes; using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations; using Interpreter.Lib.IR.Ast.Impl.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; -using Moq; using Xunit; namespace Interpreter.Tests.Unit.IR; @@ -13,16 +10,17 @@ public class AstNodeTests [Fact] public void PrecedenceTest() { - var fType = new Mock(new Mock("").Object, new List()); - var funcSymbol = new FunctionSymbol("f", new List(), fType.Object); - var lexicalDecl = new LexicalDeclaration(false); var stmtItemList = new List { lexicalDecl }; // ReSharper disable once UnusedVariable - var func = new FunctionDeclaration(funcSymbol, new BlockStatement(stmtItemList)); + var func = new FunctionDeclaration( + name: Guid.NewGuid().ToString(), + new TypeIdentValue(TypeId: Guid.NewGuid().ToString()), + arguments: new List(), + new BlockStatement(stmtItemList)); Assert.True(lexicalDecl.ChildOf()); } diff --git a/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs b/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs index 73422c99..fa6526f6 100644 --- a/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs +++ b/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs @@ -66,7 +66,8 @@ public void RecursiveTypeReferenceResolvingTest() } ); - linkedListType.ResolveSelfReferences("self"); + new ReferenceResolver(linkedListType, "self") + .Visit(linkedListType); Assert.Equal(linkedListType, ((ObjectType)linkedListType["wrapped"])["next"]); Assert.Equal(linkedListType, array.Type); @@ -86,7 +87,7 @@ public void NonSpecifiedTypesVisitingTest() new("prop", new Type("number")) } ); - var ex = Record.Exception(() => objectType.ResolveSelfReferences("self")); + var ex = Record.Exception(() => new ReferenceResolver(objectType, "self").Visit(objectType)); Assert.Null(ex); Assert.Equal(objectType["next"], objectType); } @@ -111,8 +112,10 @@ public void ObjectTypeToStringTest() new("compare", method) } ); - - linkedListType.ResolveSelfReferences("self"); + + new ReferenceResolver(linkedListType, "self") + .Visit(linkedListType); + Assert.Contains("@this", linkedListType.ToString()); } @@ -125,8 +128,9 @@ public void SerializationOfTypeWithRecursivePropertyTest() new("data", new Type("number")), new("next", new Type("self")) } - ) { Recursive = true }; - nodeType.ResolveSelfReferences("self"); + ); + new ReferenceResolver(nodeType, "self") + .Visit(nodeType); var linkedListType = new ObjectType( new List @@ -139,8 +143,9 @@ public void SerializationOfTypeWithRecursivePropertyTest() ), new("copy", new FunctionType(new Type("self"), Array.Empty())) } - ) { Recursive = true }; - linkedListType.ResolveSelfReferences("self"); + ); + new ReferenceResolver(linkedListType, "self") + .Visit(linkedListType); Assert.Contains("head: head;", linkedListType.ToString()); } diff --git a/Interpreter.Tests/Unit/IR/Types/TypeTests.cs b/Interpreter.Tests/Unit/IR/Types/TypeTests.cs index 1593de75..b5895a1b 100644 --- a/Interpreter.Tests/Unit/IR/Types/TypeTests.cs +++ b/Interpreter.Tests/Unit/IR/Types/TypeTests.cs @@ -1,4 +1,5 @@ using Interpreter.Lib.IR.CheckSemantics.Types; +using Interpreter.Lib.IR.CheckSemantics.Visitors.SemanticChecker.Service.Impl; using Xunit; namespace Interpreter.Tests.Unit.IR.Types; @@ -42,8 +43,9 @@ public void TypeWrappingTest() [Fact] public void DefaultValueTest() { - Assert.Null(TypeUtils.GetDefaultValue(new NullableType(new Any()))); - Assert.Null(TypeUtils.GetDefaultValue(new NullType())); - Assert.Null(TypeUtils.GetDefaultValue(new ObjectType(new List()))); + var calculator = new DefaultValueForTypeCalculator(); + Assert.Null(calculator.GetDefaultValueForType(new NullableType(new Any()))); + Assert.Null(calculator.GetDefaultValueForType(new NullType())); + Assert.Null(calculator.GetDefaultValueForType(new ObjectType(new List()))); } } \ No newline at end of file diff --git a/Interpreter/Program.cs b/Interpreter/Program.cs index 9a9f0a43..10d9c26e 100644 --- a/Interpreter/Program.cs +++ b/Interpreter/Program.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using CommandLine; -using Microsoft.Extensions.DependencyInjection; using Interpreter.Services.Executor; using Interpreter.Services.Executor.Impl; using Interpreter.Services.Parsing; @@ -11,6 +10,7 @@ using Interpreter.Services.Providers.ParserProvider.Impl; using Interpreter.Services.Providers.StructureProvider; using Interpreter.Services.Providers.StructureProvider.Impl; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Interpreter; diff --git a/Interpreter/Services/Providers/ParserProvider/Impl/ParserProvider.cs b/Interpreter/Services/Providers/ParserProvider/Impl/ParserProvider.cs index e3d43bd4..9d0d90ca 100644 --- a/Interpreter/Services/Providers/ParserProvider/Impl/ParserProvider.cs +++ b/Interpreter/Services/Providers/ParserProvider/Impl/ParserProvider.cs @@ -1,8 +1,8 @@ using System.IO.Abstractions; using Interpreter.Lib.FrontEnd.TopDownParse; +using Interpreter.Lib.FrontEnd.TopDownParse.Impl; using Interpreter.Services.Providers.LexerProvider; using Microsoft.Extensions.Options; -using Parser = Interpreter.Lib.FrontEnd.TopDownParse.Impl.Parser; namespace Interpreter.Services.Providers.ParserProvider.Impl; diff --git a/Interpreter/Services/Providers/StructureProvider/Impl/StructureProvider.cs b/Interpreter/Services/Providers/StructureProvider/Impl/StructureProvider.cs index dd79bbf7..cb68bac2 100644 --- a/Interpreter/Services/Providers/StructureProvider/Impl/StructureProvider.cs +++ b/Interpreter/Services/Providers/StructureProvider/Impl/StructureProvider.cs @@ -41,6 +41,6 @@ public override Structure Read(ref Utf8JsonReader reader, public override void Write(Utf8JsonWriter writer, Structure value, JsonSerializerOptions options) => - throw new NotImplementedException(); + throw new NotSupportedException(); } } \ No newline at end of file