From 03d64543d4ae650c2165ee84d36e8870127184e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D1=82=D0=B5=D0=BF=D0=B0=D0=BD?= Date: Sat, 20 Jul 2024 03:26:11 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B5=D0=B7=D0=B4=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=B0=D1=82=D1=82=D0=B5=D1=80=D0=BD=20"?= =?UTF-8?q?=D0=9F=D0=BE=D1=81=D0=B5=D1=82=D0=B8=D1=82=D0=B5=D0=BB=D1=8C"?= =?UTF-8?q?=20(#4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Добавил пакет с контрактом паттерна "Посетитель", на который переведу AST * migration to Visitor.NET 2.0.0 * базис внедрения шаблона Посетитель * move folder * merge * small refactoring + two nodes * fix build * Новая система адресации инструкций (#21) * initial of the branch * контракт адреса * Переезд на .NET 7 (#24) * обновление sdk в проекте * обновление sdk в ci * переход на json raw string literal * обновление nuget пакетов * Генерация отчёта о покрытии на уровне конфигурации проекта https://github.com/coverlet-coverage/coverlet/issues/1391 * Генерация отчёта о покрытии на уровне конфигурации проекта https://github.com/coverlet-coverage/coverlet/issues/1391 * versioning * Update Readme.md * draft алгоритма работы коллекции * Использование последних наворотов шарпа (#26) * versioning * enabling implicit usings (#25) * local scoped namespaces (#27) * after merge * разработка алгоритма вставки в коллекцию * пакетная вставка * доработка алгоритма вставки * индексатор * прямая итерация над коллекцией * важная доработка вставки - сгенерированный адрес проставляется инструкции, больше не требуется создавать адрес для создания инструкции * переименовал сущность адреса * доработка массовой вставки * алгоритм удаления инструкции * unit tests * more tests * переписал новые визиторы на AddressedInstructions * удаление конструкта "номер инструкции" * допиливание работы с Label.cs * удаление конструкта номера из алгоритмов инструкций * прогон инструкций в виртуальной машине по адресу * переписывание алгоритмов инструкций на работу с адресами * текущая реализация не требует такой сложной конструкции инструкции возврата * remove unused * подправил контракт AST * block statement * Proper HasReturnStatementImplementation * removed unused code * перегруппировка * address system refactoring * HashedAddress.cs fix * AddressedInstructions.cs fix * introducing brand new visitor architecture * unary expression visitor * refactoring + error removal * Simple.cs fix * BinaryExpression refactoring * move AddressedInstructions.cs back * remove unused * as string code gen * Constant.cs refactoring * доработка генерации существующих функций ExpressionInstructionProvider.cs * ArrayLiteral.cs visit * TypeStatement.cs fix * InsideLoopStatement.cs visit * ExpressionStatement.cs visit * ReturnStatement.cs visit * Label.cs fix * remove redunant override * Property.cs refactoring * ObjectLiteral.cs + FunctionDeclaration.cs visitor refactoring & decoupling * WhileStatement.cs visit refactoring * IfStatement.cs refactoring with visitor * IfStatement.cs fix * ConditionalExpression.cs visit fix * AssignmentExpression.cs visitor * fix * fix tests * ComplexLiteral.cs * AssignmentExpression visit fix * Исправление некорректной грамматики (#28) * new grammar.txt content * format grammar.txt * grammar fix * MemberExpression.cs visiting * refactoring * fix * replacement function in AddressedInstructions.cs * AssignmentExpression visiting fix * fix * call expr print * fix parser * parser fix 2 * restructuring * script body visit fix * formatting * parser fix * refactoring * semantic assertion draft * break support in if statatement * enum rename * rename * exceptions excluded from codecov * some semantic analysis rework * removed some tests * supress code cov * suppress * ReturnStatement.cs semantic * renane * parser fix * rename * move * mv SemanticChecker.cs * new visitor * region * SymbolTableBuilder.cs completed * module refactoring * removed symbol table construction from parsing * SymbolTableInitializer fix * integration with symbol table initializer * refactoring * DeclarationVisitor.cs * usage of decl visitor * fix recursion * - Visiting type decl - New type symbol - Removed types dict from symbol table * fix * small fix * update nuget * symbol refactoring * some work stuck long time ago * symbol state * предварительная версия инициализатора имён * fix ci * complete type loading system rework * type resolving example * refactoring of default js types consuming and custom types resolving * fix function codegen bug - end label was not emitted * type domain refactored * pre-load built types before reference resolving * fix bug in object type ref resolving * hierarchy enhancement * guard of type duplicates and built-in types declaration * initialized/declared type symbols * some new checks * more refac * proper render of type values * guard declarations from duplicates * do not return null * binary and unary expressions check * fix bug sequence has no elements * guard against no initializer * formatting * there is not symbol without initializer thus symbol cannot be not initialized * working with assignments * checking access expressions * check object literal without methods * реструктуризация сервисов посетителей * рефакторинг после реструктуризации * удалил ненавистный Utils * рефакторинг объектного типа * сохранение функций в хранилище, для которых не был сразу выведен возвращаемый тип, чтобы впоследствии его вычислить * call expr check v1 * fix * перенос проверок функции статическим анализом * Починил бекенд при работе с анонимными массивами и объектами * доработка вывода типов * поправил вывод типов в части необработанных функций * обновление версий экшенов * вторая волна обновлений * upd workflows * global using visitor.net * fix func decl gen * Revert "fix func decl gen" This reverts commit ef976231995909a2394a24170e5944ec4fc8dd4f. * visit fix * Имеет ли функция пустое тело * исправил ошибку кодогенерации if statement при отсутствии else блока * базовая кодогенерация для вызова функции без учета метода объекта * доработка вывода типов * починил статический анализ доступа к элементу массива по индексу * fix * rename to hydrascript * #15 - удалил методы из объекта * #15 - удалил концепцию метода из бекенда * #15 - удалил FunctionType.cs * #15 - статический анализ вызова метода * #15 - кодогенерация вызова метода * #15 - актуализация лексической структуры * #15 - доработка "забытого" статического анализа * #15 - поправил кодген if-else * rm * #15 - если у функции не прописан тип и нет return'ов, то она void * #15 - корректировка примеров * #23 - рабочий пример --- .github/workflows/cla.yml | 2 +- .github/workflows/develop.yml | 18 +- .github/workflows/release.yml | 12 +- CONTRIBUTING.md | 2 +- ExtendedJavaScriptSubset.sln | 6 +- .../BackEnd/AddressedInstructions.cs | 83 ++ .../BackEnd/Addresses/HashAddress.cs | 29 + HydraScript.Lib/BackEnd/Addresses/IAddress.cs | 6 + HydraScript.Lib/BackEnd/Addresses/Label.cs | 25 + .../BackEnd/Instructions/BlockLabel.cs | 48 + HydraScript.Lib/BackEnd/Instructions/Halt.cs | 16 + .../BackEnd/Instructions/Instruction.cs | 29 + HydraScript.Lib/BackEnd/Instructions/Print.cs | 21 + .../BackEnd/Instructions/PushParameter.cs | 22 + .../BackEnd/Instructions/RemoveFromArray.cs | 24 + .../BackEnd/Instructions/Return.cs | 27 + .../Instructions/WithAssignment/AsString.cs | 32 + .../WithAssignment/CallFunction.cs | 49 + .../ComplexData/Create/CreateArray.cs | 22 + .../ComplexData/Create/CreateObject.cs | 21 + .../ComplexData/Read/DotRead.cs | 29 + .../ComplexData/Read/IReadFromComplexData.cs | 10 + .../ComplexData/Read/IndexRead.cs | 27 + .../ComplexData/Write/DotAssignment.cs | 26 + .../ComplexData/Write/IWriteToComplexData.cs | 6 + .../ComplexData/Write/IndexAssignment.cs | 26 + .../Instructions/WithAssignment/Simple.cs | 101 +++ .../BackEnd/Instructions/WithJump/Goto.cs | 31 + .../Instructions/WithJump/IfNotGoto.cs | 24 + .../BackEnd/Values/Constant.cs | 5 +- .../BackEnd/Values/IValue.cs | 2 +- .../BackEnd/Values/Name.cs | 2 +- HydraScript.Lib/BackEnd/VirtualMachine.cs | 67 ++ .../FrontEnd/GetTokens/Data/Structure.cs | 8 +- .../FrontEnd/GetTokens/Data/Token.cs | 4 +- .../Data/TokenTypes/EndOfProgramType.cs | 2 +- .../GetTokens/Data/TokenTypes/ErrorType.cs | 2 +- .../Data/TokenTypes/IgnorableType.cs | 2 +- .../GetTokens/Data/TokenTypes/TokenType.cs | 2 +- .../FrontEnd/GetTokens/ILexer.cs | 4 +- .../FrontEnd/GetTokens/Impl/Lexer.cs | 8 +- .../FrontEnd/GetTokens/LexerException.cs | 7 +- .../FrontEnd/TopDownParse/IParser.cs | 4 +- .../FrontEnd/TopDownParse/Impl/Parser.cs | 745 ++++++++++++++++ .../TopDownParse/Impl/TokensStream.cs | 4 +- .../FrontEnd/TopDownParse/ParserException.cs | 9 +- HydraScript.Lib/GlobalUsings.cs | 5 + .../HydraScript.Lib.csproj | 6 +- .../IR/Ast/AbstractSyntaxTreeNode.cs | 79 ++ HydraScript.Lib/IR/Ast/IAbstractSyntaxTree.cs | 8 + .../IR/Ast/Impl/AbstractSyntaxTree.cs | 63 ++ .../AfterTypesAreLoadedDeclaration.cs | 8 + .../FunctionDeclaration.cs | 63 ++ .../AfterTypesAreLoaded/LexicalDeclaration.cs | 39 + .../Nodes/Declarations/TypeDeclaration.cs | 34 + .../Ast/Impl/Nodes/Declarations/TypeValue.cs | 65 ++ .../AccessExpressions/AccessExpression.cs | 30 + .../AccessExpressions/DotAccess.cs | 34 + .../AccessExpressions/IndexAccess.cs | 33 + .../Nodes/Expressions/AssignmentExpression.cs | 41 + .../Nodes/Expressions/BinaryExpression.cs | 37 + .../Impl/Nodes/Expressions/CallExpression.cs | 45 + .../Nodes/Expressions/CastAsExpression.cs | 33 + .../ComplexLiterals/ArrayLiteral.cs | 27 + .../ComplexLiterals/ComplexLiteral.cs | 8 + .../ComplexLiterals/ObjectLiteral.cs | 27 + .../Expressions/ComplexLiterals/Property.cs | 20 +- .../Expressions/ConditionalExpression.cs | 38 + .../Ast/Impl/Nodes/Expressions/Expression.cs | 13 + .../Expressions/LeftHandSideExpression.cs | 10 + .../Nodes/Expressions/MemberExpression.cs | 62 ++ .../PrimaryExpressions/IdentifierReference.cs | 24 + .../PrimaryExpressions/ImplicitLiteral.cs | 27 + .../Expressions/PrimaryExpressions/Literal.cs | 33 + .../PrimaryExpressions/PrimaryExpression.cs | 18 + .../Impl/Nodes/Expressions/UnaryExpression.cs | 32 + .../IR/Ast/Impl/Nodes/ScriptBody.cs | 33 + .../IR/Ast/Impl/Nodes/StatementListItem.cs | 10 + .../Impl/Nodes/Statements/BlockStatement.cs | 30 + .../Nodes/Statements/ExpressionStatement.cs | 29 + .../Ast/Impl/Nodes/Statements/IfStatement.cs | 51 ++ .../Nodes/Statements/InsideStatementJump.cs | 31 + .../Impl/Nodes/Statements/ReturnStatement.cs | 37 + .../Impl/Nodes/Statements/WhileStatement.cs | 34 + .../Visitors/ExpressionInstructionProvider.cs | 324 +++++++ .../IR/Ast/Visitors/InstructionProvider.cs | 202 +++++ .../Exceptions/ArrayAccessException.cs | 6 +- .../Exceptions/AssignmentToConst.cs | 11 + .../Exceptions/CannotDefineType.cs | 11 + .../Exceptions/ConstWithoutInitializer.cs | 11 + .../Exceptions/DeclarationAlreadyExists.cs | 11 + .../FunctionWithoutReturnStatement.cs | 6 +- .../Exceptions/IncompatibleTypesOfOperands.cs | 6 +- .../Exceptions/NonAccessibleType.cs | 10 + .../Exceptions/NotBooleanTestExpression.cs | 6 +- .../Exceptions/ObjectAccessException.cs | 8 +- .../Exceptions/OutsideOfStatement.cs | 11 + .../Exceptions/ReturnOutsideFunction.cs | 6 +- .../Exceptions/SemanticException.cs | 7 +- .../Exceptions/SymbolIsNotCallable.cs | 11 + .../Exceptions/UnknownIdentifierReference.cs | 11 + .../Exceptions/UnsupportedOperation.cs | 6 +- .../WrongArrayLiteralDeclaration.cs | 6 +- .../Exceptions/WrongAssignmentTarget.cs | 11 + .../Exceptions/WrongConditionalTypes.cs | 6 +- .../Exceptions/WrongNumberOfArguments.cs | 6 +- .../Exceptions/WrongReturnType.cs | 6 +- .../Exceptions/WrongTypeOfArgument.cs | 6 +- .../IR/CheckSemantics/Types/Any.cs | 2 +- .../IR/CheckSemantics/Types/ArrayType.cs | 32 + .../IR/CheckSemantics/Types/NullType.cs | 8 +- .../IR/CheckSemantics/Types/NullableType.cs | 37 + .../IR/CheckSemantics/Types/ObjectType.cs | 188 ++++ .../IR/CheckSemantics/Types/Type.cs | 42 + .../CheckSemantics/Variables/SymbolTable.cs | 41 + .../Variables/Symbols/FunctionSymbol.cs | 35 + .../Variables/Symbols/ObjectSymbol.cs | 14 + .../Variables/Symbols/Symbol.cs | 7 + .../Variables/Symbols/TypeSymbol.cs | 30 + .../Variables/Symbols/VariableSymbol.cs | 11 +- .../Visitors/DeclarationVisitor.cs | 99 +++ .../Visitors/SemanticChecker.cs | 459 ++++++++++ .../IDefaultValueForTypeCalculator.cs | 6 + .../IFunctionWithUndefinedReturnStorage.cs | 15 + .../Services/IJavaScriptTypesProvider.cs | 6 + .../Visitors/Services/IMethodStorage.cs | 11 + .../Services/IStandardLibraryProvider.cs | 8 + .../ISymbolTableInitializerService.cs | 10 + .../Services/ITypeDeclarationsResolver.cs | 10 + .../Impl/DefaultValueForTypeCalculator.cs | 30 + .../FunctionWithUndefinedReturnStorage.cs | 40 + .../Services/Impl/JavaScriptTypesProvider.cs | 16 + .../Visitors/Services/Impl/MethodStorage.cs | 20 + .../Services/Impl/StandardLibraryProvider.cs | 38 + .../Impl/SymbolTableInitializerService.cs | 15 + .../Services/Impl/TypeDeclarationsResolver.cs | 51 ++ .../Visitors/SymbolTableInitializer.cs | 54 ++ .../Visitors/TypeSystemLoader.cs | 55 ++ HydraScript.Tests/GlobalUsings.cs | 3 + HydraScript.Tests/Helpers/ListExtensions.cs | 14 + HydraScript.Tests/Helpers/MockExtensions.cs | 38 + .../HydraScript.Tests.csproj | 8 +- .../Properties/AssemblyInfo.cs | 0 .../Stubs/SemanticExceptionStub.cs | 5 + .../TestData/InstructionsData.cs | 127 +++ .../TestData/LexerData.cs | 2 +- .../TestData/ParserData.cs | 9 +- .../BackEnd/AddressedInstructionsTests.cs | 95 ++ .../Unit/BackEnd/CallTests.cs | 9 +- .../Unit/BackEnd/InstructionsTests.cs | 23 + .../Unit/BackEnd/ValuesTests.cs | 8 +- .../Unit/BackEnd/VirtualMachineTests.cs | 158 ++++ .../Unit/FrontEnd/LexerTests.cs | 10 +- .../Unit/FrontEnd/ParserTests.cs | 12 +- .../Unit/FrontEnd/StructureTests.cs | 6 +- HydraScript.Tests/Unit/IR/AstNodeTests.cs | 31 + ...FunctionWithUndefinedReturnStorageTests.cs | 41 + .../Unit/IR/SymbolTableTests.cs | 12 +- .../Unit/IR/Types/ObjectTypeTests.cs | 43 +- .../Unit/IR/Types/TypeTests.cs | 12 +- .../Unit/Infrastructure/ExecutorTests.cs | 25 +- .../Infrastructure/LoggingEntitiesTests.cs | 21 +- .../Infrastructure/ParsingServiceTests.cs | 10 +- .../Unit/Infrastructure/ProvidersTests.cs | 19 +- .../CommandLineSettings.cs | 4 +- .../HydraScript.csproj | 6 +- {Interpreter => HydraScript}/Program.cs | 20 +- .../Services/Executor/IExecutor.cs | 2 +- .../Services/Executor/Impl/Executor.cs | 14 +- .../Services/Parsing/IParsingService.cs | 4 +- .../Services/Parsing/Impl/ParsingService.cs | 6 +- .../Providers/LexerProvider/ILexerProvider.cs | 8 + .../LexerProvider/Impl}/LexerProvider.cs | 7 +- .../LexerProvider/Impl}/LoggingLexer.cs | 6 +- .../ParserProvider/IParserProvider.cs | 8 + .../Impl}/LoggingAbstractSyntaxTree.cs | 10 +- .../ParserProvider/Impl}/LoggingParser.cs | 6 +- .../ParserProvider/Impl}/ParserProvider.cs | 7 +- .../StructureProvider/IStructureProvider.cs | 8 + .../Impl}/StructureProvider.cs | 8 +- {Interpreter => HydraScript}/TokenTypes.cs | 7 +- {Interpreter => HydraScript}/grammar.txt | 41 +- .../BackEnd/Instructions/AsString.cs | 53 -- .../BackEnd/Instructions/BeginFunction.cs | 15 - .../BackEnd/Instructions/CallFunction.cs | 47 - .../BackEnd/Instructions/CreateArray.cs | 22 - .../BackEnd/Instructions/CreateObject.cs | 20 - .../BackEnd/Instructions/DotAssignment.cs | 23 - Interpreter.Lib/BackEnd/Instructions/Goto.cs | 19 - Interpreter.Lib/BackEnd/Instructions/Halt.cs | 18 - .../BackEnd/Instructions/IfNotGoto.cs | 26 - .../BackEnd/Instructions/IndexAssignment.cs | 23 - .../BackEnd/Instructions/Instruction.cs | 21 - Interpreter.Lib/BackEnd/Instructions/Print.cs | 21 - .../BackEnd/Instructions/PushParameter.cs | 27 - .../BackEnd/Instructions/RemoveFromArray.cs | 26 - .../BackEnd/Instructions/Return.cs | 38 - .../BackEnd/Instructions/Simple.cs | 90 -- Interpreter.Lib/BackEnd/VirtualMachine.cs | 74 -- .../Data/TokenTypes/TokenTypeUtils.cs | 7 - .../FrontEnd/TopDownParse/Impl/Parser.cs | 839 ------------------ Interpreter.Lib/GlobalUsings.cs | 3 - Interpreter.Lib/IR/Ast/IAbstractSyntaxTree.cs | 8 - .../IR/Ast/Impl/AbstractSyntaxTree.cs | 64 -- .../IR/Ast/Nodes/AbstractSyntaxTreeNode.cs | 73 -- .../IR/Ast/Nodes/Declarations/Declaration.cs | 6 - .../Nodes/Declarations/FunctionDeclaration.cs | 84 -- .../Nodes/Declarations/LexicalDeclaration.cs | 63 -- .../AccessExpressions/AccessExpression.cs | 33 - .../AccessExpressions/DotAccess.cs | 62 -- .../AccessExpressions/IndexAccess.cs | 68 -- .../Nodes/Expressions/AssignmentExpression.cs | 183 ---- .../Ast/Nodes/Expressions/BinaryExpression.cs | 209 ----- .../Ast/Nodes/Expressions/CallExpression.cs | 195 ---- .../Ast/Nodes/Expressions/CastAsExpression.cs | 52 -- .../ComplexLiterals/ArrayLiteral.cs | 73 -- .../ComplexLiterals/ObjectLiteral.cs | 83 -- .../Expressions/ConditionalExpression.cs | 88 -- .../IR/Ast/Nodes/Expressions/Expression.cs | 15 - .../Ast/Nodes/Expressions/MemberExpression.cs | 70 -- .../PrimaryExpressions/IdentifierReference.cs | 36 - .../Expressions/PrimaryExpressions/Literal.cs | 25 - .../PrimaryExpressions/PrimaryExpression.cs | 20 - .../Ast/Nodes/Expressions/UnaryExpression.cs | 89 -- Interpreter.Lib/IR/Ast/Nodes/ScriptBody.cs | 16 - .../IR/Ast/Nodes/StatementListItem.cs | 8 - .../IR/Ast/Nodes/Statements/BlockStatement.cs | 51 -- .../IR/Ast/Nodes/Statements/BreakStatement.cs | 14 - .../Ast/Nodes/Statements/ContinueStatement.cs | 14 - .../Nodes/Statements/ExpressionStatement.cs | 24 - .../IR/Ast/Nodes/Statements/IfStatement.cs | 126 --- .../Nodes/Statements/InsideLoopStatement.cs | 25 - .../Ast/Nodes/Statements/ReturnStatement.cs | 92 -- .../IR/Ast/Nodes/Statements/Statement.cs | 6 - .../IR/Ast/Nodes/Statements/TypeStatement.cs | 21 - .../IR/Ast/Nodes/Statements/WhileStatement.cs | 91 -- .../Exceptions/AssignmentToConst.cs | 9 - .../Exceptions/CannotDefineType.cs | 9 - .../Exceptions/ConstWithoutInitializer.cs | 9 - .../Exceptions/DeclarationAlreadyExists.cs | 9 - .../Exceptions/OutsideOfLoop.cs | 9 - .../Exceptions/SymbolIsNotCallable.cs | 9 - .../Exceptions/UnknownIdentifierReference.cs | 9 - .../IR/CheckSemantics/Types/ArrayType.cs | 35 - .../IR/CheckSemantics/Types/FunctionType.cs | 56 -- .../IR/CheckSemantics/Types/NullableType.cs | 40 - .../IR/CheckSemantics/Types/ObjectType.cs | 70 -- .../IR/CheckSemantics/Types/Type.cs | 48 - .../IR/CheckSemantics/Types/TypeUtils.cs | 43 - .../Types/Visitors/ObjectTypeHasher.cs | 49 - .../Types/Visitors/ObjectTypePrinter.cs | 75 -- .../Types/Visitors/ReferenceResolver.cs | 75 -- .../CheckSemantics/Variables/SymbolTable.cs | 43 - .../Variables/SymbolTableUtils.cs | 51 -- .../Variables/Symbols/FunctionSymbol.cs | 33 - .../Variables/Symbols/ObjectSymbol.cs | 27 - .../Variables/Symbols/Symbol.cs | 12 - Interpreter.Tests/GlobalUsings.cs | 3 - Interpreter.Tests/MockExtensions.cs | 21 - .../Stubs/SemanticExceptionStub.cs | 5 - .../TestData/InstructionsData.cs | 105 --- .../Unit/BackEnd/FunctionInfoTests.cs | 13 - .../Unit/BackEnd/InstructionsTests.cs | 39 - .../Unit/BackEnd/VirtualMachineTests.cs | 131 --- Interpreter.Tests/Unit/IR/AstNodeTests.cs | 29 - Interpreter.Tests/Unit/IR/ExpressionTests.cs | 22 - .../Services/Providers/ILexerProvider.cs | 8 - .../Services/Providers/IParserProvider.cs | 8 - .../Services/Providers/IStructureProvider.cs | 8 - Readme.md | 18 +- samples/equals.js | 15 +- samples/forwardref.js | 15 + samples/linkedlist.js | 42 +- samples/settable.js | 14 +- samples/summator.js | 14 +- samples/this.js | 17 +- samples/typeresolving.js | 14 + samples/vec2d.js | 3 +- 278 files changed, 5701 insertions(+), 4938 deletions(-) create mode 100644 HydraScript.Lib/BackEnd/AddressedInstructions.cs create mode 100644 HydraScript.Lib/BackEnd/Addresses/HashAddress.cs create mode 100644 HydraScript.Lib/BackEnd/Addresses/IAddress.cs create mode 100644 HydraScript.Lib/BackEnd/Addresses/Label.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/BlockLabel.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/Halt.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/Instruction.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/Print.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/PushParameter.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/RemoveFromArray.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/Return.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/AsString.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/CallFunction.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateArray.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateObject.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/DotRead.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IReadFromComplexData.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IndexRead.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IWriteToComplexData.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithAssignment/Simple.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithJump/Goto.cs create mode 100644 HydraScript.Lib/BackEnd/Instructions/WithJump/IfNotGoto.cs rename {Interpreter.Lib => HydraScript.Lib}/BackEnd/Values/Constant.cs (81%) rename {Interpreter.Lib => HydraScript.Lib}/BackEnd/Values/IValue.cs (65%) rename {Interpreter.Lib => HydraScript.Lib}/BackEnd/Values/Name.cs (90%) create mode 100644 HydraScript.Lib/BackEnd/VirtualMachine.cs rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/Structure.cs (87%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/Token.cs (93%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs (67%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs (65%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs (74%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs (83%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/ILexer.cs (52%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/Impl/Lexer.cs (89%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/GetTokens/LexerException.cs (66%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/TopDownParse/IParser.cs (50%) create mode 100644 HydraScript.Lib/FrontEnd/TopDownParse/Impl/Parser.cs rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/TopDownParse/Impl/TokensStream.cs (85%) rename {Interpreter.Lib => HydraScript.Lib}/FrontEnd/TopDownParse/ParserException.cs (62%) create mode 100644 HydraScript.Lib/GlobalUsings.cs rename Interpreter.Lib/Interpreter.Lib.csproj => HydraScript.Lib/HydraScript.Lib.csproj (58%) create mode 100644 HydraScript.Lib/IR/Ast/AbstractSyntaxTreeNode.cs create mode 100644 HydraScript.Lib/IR/Ast/IAbstractSyntaxTree.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/AfterTypesAreLoadedDeclaration.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/FunctionDeclaration.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ComplexLiteral.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs rename {Interpreter.Lib/IR/Ast => HydraScript.Lib/IR/Ast/Impl}/Nodes/Expressions/ComplexLiterals/Property.cs (59%) create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/LeftHandSideExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/StatementListItem.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/BlockStatement.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ExpressionStatement.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs create mode 100644 HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs create mode 100644 HydraScript.Lib/IR/Ast/Visitors/ExpressionInstructionProvider.cs create mode 100644 HydraScript.Lib/IR/Ast/Visitors/InstructionProvider.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/ArrayAccessException.cs (57%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs (57%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs (57%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/NonAccessibleType.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs (55%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/ObjectAccessException.cs (51%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/OutsideOfStatement.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs (50%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/SemanticException.cs (68%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs (56%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs (60%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongAssignmentTarget.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs (63%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs (58%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/WrongReturnType.cs (56%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs (57%) rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Types/Any.cs (78%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Types/ArrayType.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Types/NullType.cs (50%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Types/NullableType.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Types/ObjectType.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Types/Type.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Variables/SymbolTable.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/TypeSymbol.cs rename {Interpreter.Lib => HydraScript.Lib}/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs (56%) create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IDefaultValueForTypeCalculator.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IFunctionWithUndefinedReturnStorage.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IJavaScriptTypesProvider.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IMethodStorage.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IStandardLibraryProvider.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ISymbolTableInitializerService.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ITypeDeclarationsResolver.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/DefaultValueForTypeCalculator.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/FunctionWithUndefinedReturnStorage.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/JavaScriptTypesProvider.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/MethodStorage.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/StandardLibraryProvider.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/SymbolTableInitializerService.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/TypeDeclarationsResolver.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer.cs create mode 100644 HydraScript.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader.cs create mode 100644 HydraScript.Tests/GlobalUsings.cs create mode 100644 HydraScript.Tests/Helpers/ListExtensions.cs create mode 100644 HydraScript.Tests/Helpers/MockExtensions.cs rename Interpreter.Tests/Interpreter.Tests.csproj => HydraScript.Tests/HydraScript.Tests.csproj (87%) rename {Interpreter.Tests => HydraScript.Tests}/Properties/AssemblyInfo.cs (100%) create mode 100644 HydraScript.Tests/Stubs/SemanticExceptionStub.cs create mode 100644 HydraScript.Tests/TestData/InstructionsData.cs rename {Interpreter.Tests => HydraScript.Tests}/TestData/LexerData.cs (95%) rename {Interpreter.Tests => HydraScript.Tests}/TestData/ParserData.cs (52%) create mode 100644 HydraScript.Tests/Unit/BackEnd/AddressedInstructionsTests.cs rename {Interpreter.Tests => HydraScript.Tests}/Unit/BackEnd/CallTests.cs (50%) create mode 100644 HydraScript.Tests/Unit/BackEnd/InstructionsTests.cs rename {Interpreter.Tests => HydraScript.Tests}/Unit/BackEnd/ValuesTests.cs (83%) create mode 100644 HydraScript.Tests/Unit/BackEnd/VirtualMachineTests.cs rename {Interpreter.Tests => HydraScript.Tests}/Unit/FrontEnd/LexerTests.cs (84%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/FrontEnd/ParserTests.cs (66%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/FrontEnd/StructureTests.cs (80%) create mode 100644 HydraScript.Tests/Unit/IR/AstNodeTests.cs create mode 100644 HydraScript.Tests/Unit/IR/FunctionWithUndefinedReturnStorageTests.cs rename {Interpreter.Tests => HydraScript.Tests}/Unit/IR/SymbolTableTests.cs (83%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/IR/Types/ObjectTypeTests.cs (73%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/IR/Types/TypeTests.cs (68%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/Infrastructure/ExecutorTests.cs (81%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/Infrastructure/LoggingEntitiesTests.cs (84%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/Infrastructure/ParsingServiceTests.cs (77%) rename {Interpreter.Tests => HydraScript.Tests}/Unit/Infrastructure/ProvidersTests.cs (77%) rename {Interpreter => HydraScript}/CommandLineSettings.cs (94%) rename Interpreter/Interpreter.csproj => HydraScript/HydraScript.csproj (86%) rename {Interpreter => HydraScript}/Program.cs (72%) rename {Interpreter => HydraScript}/Services/Executor/IExecutor.cs (55%) rename {Interpreter => HydraScript}/Services/Executor/Impl/Executor.cs (74%) rename {Interpreter => HydraScript}/Services/Parsing/IParsingService.cs (53%) rename {Interpreter => HydraScript}/Services/Parsing/Impl/ParsingService.cs (74%) create mode 100644 HydraScript/Services/Providers/LexerProvider/ILexerProvider.cs rename {Interpreter/Services/Providers/Impl/LexerProvider => HydraScript/Services/Providers/LexerProvider/Impl}/LexerProvider.cs (77%) rename {Interpreter/Services/Providers/Impl/LexerProvider => HydraScript/Services/Providers/LexerProvider/Impl}/LoggingLexer.cs (83%) create mode 100644 HydraScript/Services/Providers/ParserProvider/IParserProvider.cs rename {Interpreter/Services/Providers/Impl/ParserProvider => HydraScript/Services/Providers/ParserProvider/Impl}/LoggingAbstractSyntaxTree.cs (70%) rename {Interpreter/Services/Providers/Impl/ParserProvider => HydraScript/Services/Providers/ParserProvider/Impl}/LoggingParser.cs (83%) rename {Interpreter/Services/Providers/Impl/ParserProvider => HydraScript/Services/Providers/ParserProvider/Impl}/ParserProvider.cs (76%) create mode 100644 HydraScript/Services/Providers/StructureProvider/IStructureProvider.cs rename {Interpreter/Services/Providers/Impl/StructureProvider => HydraScript/Services/Providers/StructureProvider/Impl}/StructureProvider.cs (87%) rename {Interpreter => HydraScript}/TokenTypes.cs (95%) rename {Interpreter => HydraScript}/grammar.txt (69%) delete mode 100644 Interpreter.Lib/BackEnd/Instructions/AsString.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/BeginFunction.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/CallFunction.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/CreateArray.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/CreateObject.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/DotAssignment.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Goto.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Halt.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/IfNotGoto.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/IndexAssignment.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Instruction.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Print.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/PushParameter.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/RemoveFromArray.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Return.cs delete mode 100644 Interpreter.Lib/BackEnd/Instructions/Simple.cs delete mode 100644 Interpreter.Lib/BackEnd/VirtualMachine.cs delete mode 100644 Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenTypeUtils.cs delete mode 100644 Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs delete mode 100644 Interpreter.Lib/GlobalUsings.cs delete mode 100644 Interpreter.Lib/IR/Ast/IAbstractSyntaxTree.cs delete mode 100644 Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/AbstractSyntaxTreeNode.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Declarations/Declaration.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Declarations/FunctionDeclaration.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Declarations/LexicalDeclaration.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/AccessExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/DotAccess.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/IndexAccess.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/AssignmentExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/BinaryExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/CallExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/CastAsExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/ConditionalExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/Expression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/MemberExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/Literal.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Expressions/UnaryExpression.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/ScriptBody.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/StatementListItem.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/BlockStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/BreakStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/ContinueStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/ExpressionStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/IfStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/InsideLoopStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/ReturnStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/Statement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/TypeStatement.cs delete mode 100644 Interpreter.Lib/IR/Ast/Nodes/Statements/WhileStatement.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/OutsideOfLoop.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Types/Type.cs 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/Types/Visitors/ReferenceResolver.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTableUtils.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs delete mode 100644 Interpreter.Tests/GlobalUsings.cs delete mode 100644 Interpreter.Tests/MockExtensions.cs delete mode 100644 Interpreter.Tests/Stubs/SemanticExceptionStub.cs delete mode 100644 Interpreter.Tests/TestData/InstructionsData.cs delete mode 100644 Interpreter.Tests/Unit/BackEnd/FunctionInfoTests.cs delete mode 100644 Interpreter.Tests/Unit/BackEnd/InstructionsTests.cs delete mode 100644 Interpreter.Tests/Unit/BackEnd/VirtualMachineTests.cs delete mode 100644 Interpreter.Tests/Unit/IR/AstNodeTests.cs delete mode 100644 Interpreter.Tests/Unit/IR/ExpressionTests.cs delete mode 100644 Interpreter/Services/Providers/ILexerProvider.cs delete mode 100644 Interpreter/Services/Providers/IParserProvider.cs delete mode 100644 Interpreter/Services/Providers/IStructureProvider.cs create mode 100644 samples/forwardref.js create mode 100644 samples/typeresolving.js diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 471d51ee..90c08059 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -23,7 +23,7 @@ jobs: PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} with: path-to-signatures: 'signatures.json' - path-to-document: 'https://github.com/Stepami/extended-js-subset/blob/master/contributor-licence-agreement.md' + path-to-document: 'https://github.com/Stepami/hydrascript/blob/master/contributor-licence-agreement.md' allowlist: Stepami,bot* branch: 'main' remote-repository-name: hydrascript-cla-signatures \ No newline at end of file diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 3d9d44dd..03815244 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -14,13 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: 7.0.x - name: Cache NuGet packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj*') }} @@ -36,9 +36,9 @@ jobs: if: github.event_name == 'pull_request' uses: 5monkeys/cobertura-action@master with: - path: ./Interpreter.Tests/coverage.cobertura.xml + path: ./HydraScript.Tests/coverage.cobertura.xml repo_token: ${{ secrets.GITHUB_TOKEN }} - minimum_coverage: 80 + minimum_coverage: 20 fail_below_threshold: true show_class_names: true show_missing: true @@ -49,7 +49,7 @@ jobs: if: github.ref == 'refs/heads/master' && github.event_name == 'push' uses: irongut/CodeCoverageSummary@v1.3.0 with: - filename: ./Interpreter.Tests/coverage.cobertura.xml + filename: ./HydraScript.Tests/coverage.cobertura.xml badge: true fail_below_min: false format: markdown @@ -57,13 +57,13 @@ jobs: hide_complexity: true thresholds: '80 100' - name: ReportGenerator - uses: danielpalme/ReportGenerator-GitHub-Action@5.1.10 + uses: danielpalme/ReportGenerator-GitHub-Action@5.2.1 with: - reports: './Interpreter.Tests/coverage.cobertura.xml' + reports: './HydraScript.Tests/coverage.cobertura.xml' targetdir: './coverage-report' - name: Upload coverage report artifact if: github.event_name == 'push' - uses: actions/upload-artifact@v2.2.3 + uses: actions/upload-artifact@v4 with: name: CoverageReport path: coverage-report diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f16a1013..8a2b937e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Create release id: create_release uses: ncipollo/release-action@v1 @@ -38,21 +38,21 @@ jobs: runs-on: ${{ matrix.config.os }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: 7.0.x - name: Publish run: | mkdir output - dotnet publish ./Interpreter/Interpreter.csproj -c Release -r ${{ matrix.config.rid }} -p:PublishSingleFile=true -p:DebugType=embedded --self-contained false -o ./output + dotnet publish ./HydraScript/HydraScript.csproj -c Release -r ${{ matrix.config.rid }} -p:PublishSingleFile=true -p:DebugType=embedded --self-contained false -o ./output - name: Upload release assets uses: shogo82148/actions-upload-release-asset@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_name: interpreter-${{ matrix.config.rid }}${{ matrix.config.rid == 'win-x64' && '.exe' || '' }} - asset_path: ./output/Interpreter${{ matrix.config.rid == 'win-x64' && '.exe' || '' }} + asset_name: hydrascript-${{ matrix.config.rid }}${{ matrix.config.rid == 'win-x64' && '.exe' || '' }} + asset_path: ./output/HydraScript${{ matrix.config.rid == 'win-x64' && '.exe' || '' }} asset_content_type: ${{ matrix.config.type }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e67a471..0908662d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ Contributions are welcomed! Here's a few things to know: ## Steps to Contributing Here are the basic steps to get started with your first contribution. Please reach out with any questions. -1. Use [open issues](https://github.com/stepami/extended-js-subset/issues) to discuss the proposed changes. Create an issue describing changes if necessary to collect feedback. Also, please use provided labels to tag issues so everyone can easily sort issues of interest. +1. Use [open issues](https://github.com/stepami/hydrascript/issues) to discuss the proposed changes. Create an issue describing changes if necessary to collect feedback. Also, please use provided labels to tag issues so everyone can easily sort issues of interest. 1. [Fork the repo](https://help.github.com/articles/fork-a-repo/) in order if you want to make and test local changes. 1. Create a new branch **from master** for the issue. We suggest prefixing the branch with type of contribution (`bugfix`/`feature`), your username and then a descriptive title: (e.g. `bugfix/user1/object-comparision` or `feature/user2/variable-initialization-check`) 1. Make code changes. diff --git a/ExtendedJavaScriptSubset.sln b/ExtendedJavaScriptSubset.sln index b37528cd..6257864f 100644 --- a/ExtendedJavaScriptSubset.sln +++ b/ExtendedJavaScriptSubset.sln @@ -1,10 +1,10 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interpreter.Lib", "Interpreter.Lib\Interpreter.Lib.csproj", "{83524079-4A56-4AF0-9011-F7CA871536E9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydraScript.Lib", "HydraScript.Lib\HydraScript.Lib.csproj", "{83524079-4A56-4AF0-9011-F7CA871536E9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interpreter", "Interpreter\Interpreter.csproj", "{5DA79C0C-2B98-4E64-81EA-92AFFC5204D3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydraScript", "HydraScript\HydraScript.csproj", "{5DA79C0C-2B98-4E64-81EA-92AFFC5204D3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interpreter.Tests", "Interpreter.Tests\Interpreter.Tests.csproj", "{F0DD56CB-C68A-4CDC-AA54-0A07342FE08B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydraScript.Tests", "HydraScript.Tests\HydraScript.Tests.csproj", "{F0DD56CB-C68A-4CDC-AA54-0A07342FE08B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/HydraScript.Lib/BackEnd/AddressedInstructions.cs b/HydraScript.Lib/BackEnd/AddressedInstructions.cs new file mode 100644 index 00000000..62c4d6fe --- /dev/null +++ b/HydraScript.Lib/BackEnd/AddressedInstructions.cs @@ -0,0 +1,83 @@ +using System.Collections; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; + +namespace HydraScript.Lib.BackEnd; + +public class AddressedInstructions : IEnumerable +{ + private readonly LinkedList _addresses = new(); + private readonly Dictionary> _addressToNode = new(); + private readonly Dictionary, Instruction> _instructions = new(); + + public Instruction this[IAddress address] + { + get => _instructions[_addressToNode[address]]; + private set => _instructions[_addressToNode[address]] = value; + } + + public IAddress Start => + _addresses.First?.Value; + + public IAddress End => + _addresses.Last?.Value; + + public void Add(Instruction instruction, string label = null) + { + IAddress newAddress = label is null + ? new HashAddress(seed: instruction.GetHashCode()) + : new Label(label); + instruction.Address = newAddress; + + AddWithAddress(instruction, newAddress); + } + + public void Replace(Instruction old, Instruction @new) + { + var address = old.Address; + @new.Address = address; + + this[address] = @new; + } + + private void AddWithAddress(Instruction instruction, IAddress newAddress) + { + var last = _addresses.Last; + if (last is not null) + last.Value.Next = newAddress; + + var newNode = _addresses.AddLast(newAddress); + + _addressToNode.Add(newAddress, newNode); + _instructions.Add(newNode, instruction); + } + + public void AddRange(IEnumerable instructions) + { + foreach (var instruction in instructions) + AddWithAddress(instruction, instruction.Address); + } + + public void Remove(Instruction instruction) + { + var address = instruction.Address; + var nodeToRemove = _addressToNode[address]; + + var prev = nodeToRemove.Previous; + if (prev is not null) + { + prev.Value.Next = nodeToRemove.Next?.Value; + } + + _addressToNode.Remove(address); + _instructions.Remove(nodeToRemove); + _addresses.Remove(nodeToRemove); + } + + public IEnumerator GetEnumerator() => + _addresses.Select(address => this[address]) + .GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + GetEnumerator(); +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Addresses/HashAddress.cs b/HydraScript.Lib/BackEnd/Addresses/HashAddress.cs new file mode 100644 index 00000000..a83ef24e --- /dev/null +++ b/HydraScript.Lib/BackEnd/Addresses/HashAddress.cs @@ -0,0 +1,29 @@ +namespace HydraScript.Lib.BackEnd.Addresses; + +public class HashAddress : IAddress +{ + private readonly int _seed; + + public IAddress Next { get; set; } + + public HashAddress(int seed) => + _seed = seed; + + public bool Equals(IAddress other) + { + if (other is HashAddress hashed) + return _seed == hashed._seed; + + return false; + } + + public override int GetHashCode() + { + var i1 = _seed ^ 17; + var i2 = 31 * _seed + i1; + + return HashCode.Combine(i1, i2); + } + + public override string ToString() => "\t"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Addresses/IAddress.cs b/HydraScript.Lib/BackEnd/Addresses/IAddress.cs new file mode 100644 index 00000000..df222575 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Addresses/IAddress.cs @@ -0,0 +1,6 @@ +namespace HydraScript.Lib.BackEnd.Addresses; + +public interface IAddress : IEquatable +{ + IAddress Next { get; set; } +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Addresses/Label.cs b/HydraScript.Lib/BackEnd/Addresses/Label.cs new file mode 100644 index 00000000..ae41adde --- /dev/null +++ b/HydraScript.Lib/BackEnd/Addresses/Label.cs @@ -0,0 +1,25 @@ +namespace HydraScript.Lib.BackEnd.Addresses; + +public class Label : IAddress +{ + public string Name { get; } + + public Label(string name) => + Name = name; + + public IAddress Next { get; set; } + + public bool Equals(IAddress other) + { + if (other is Label label) + return Name == label.Name; + + return false; + } + + public override int GetHashCode() => + Name.GetHashCode(); + + public override string ToString() => + $"{Name}:\n\t"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/BlockLabel.cs b/HydraScript.Lib/BackEnd/Instructions/BlockLabel.cs new file mode 100644 index 00000000..46c528fb --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/BlockLabel.cs @@ -0,0 +1,48 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public abstract class BlockLabel : Instruction +{ + private readonly BlockPosition _blockPosition; + private readonly BlockType _blockType; + private readonly string _blockId; + + protected BlockLabel(BlockPosition blockPosition, BlockType blockType, string blockId) + { + _blockPosition = blockPosition; + _blockType = blockType; + _blockId = blockId; + } + + public override IAddress Execute(VirtualMachine vm) => + Address.Next; + + protected override string ToStringInternal() => + $"{_blockPosition}{_blockType} {_blockId}"; + + protected enum BlockPosition + { + Begin, + End + } +} + +public enum BlockType +{ + Function, + Loop, + Condition +} + +public class BeginBlock : BlockLabel +{ + public BeginBlock(BlockType blockType, string blockId) : + base(BlockPosition.Begin, blockType, blockId) { } +} + +public class EndBlock : BlockLabel +{ + public EndBlock(BlockType blockType, string blockId) : + base(BlockPosition.End, blockType, blockId) { } +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/Halt.cs b/HydraScript.Lib/BackEnd/Instructions/Halt.cs new file mode 100644 index 00000000..b2757935 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/Halt.cs @@ -0,0 +1,16 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public class Halt : Instruction +{ + public override bool End() => true; + + public override IAddress Execute(VirtualMachine vm) + { + vm.Frames.Pop(); + return new HashAddress(seed: 0); + } + + protected override string ToStringInternal() => "End"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/Instruction.cs b/HydraScript.Lib/BackEnd/Instructions/Instruction.cs new file mode 100644 index 00000000..e57bdd7b --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/Instruction.cs @@ -0,0 +1,29 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public abstract class Instruction +{ + private IAddress _address; + + public IAddress Address + { + get => _address; + set + { + OnSetOfAddress(value); + _address = value; + } + } + + protected virtual void OnSetOfAddress(IAddress address) { } + + public abstract IAddress Execute(VirtualMachine vm); + + public virtual bool End() => false; + + protected abstract string ToStringInternal(); + + public override string ToString() => + $"{Address}{ToStringInternal()}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/Print.cs b/HydraScript.Lib/BackEnd/Instructions/Print.cs new file mode 100644 index 00000000..7ecafbd8 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/Print.cs @@ -0,0 +1,21 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public class Print : Instruction +{ + private readonly IValue _value; + + public Print(IValue value) => + _value = value; + + public override IAddress Execute(VirtualMachine vm) + { + vm.Writer.WriteLine(_value.Get(vm.Frames.Peek())); + return Address.Next; + } + + protected override string ToStringInternal() => + $"Print {_value}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/PushParameter.cs b/HydraScript.Lib/BackEnd/Instructions/PushParameter.cs new file mode 100644 index 00000000..0d81cce0 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/PushParameter.cs @@ -0,0 +1,22 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public class PushParameter : Instruction +{ + private readonly string _parameter; + private readonly IValue _value; + + public PushParameter(string parameter, IValue value) => + (_parameter, _value) = (parameter, value); + + public override IAddress Execute(VirtualMachine vm) + { + vm.Arguments.Push((_parameter, _value.Get(vm.Frames.Peek()))); + return Address.Next; + } + + protected override string ToStringInternal() => + $"PushParameter {_parameter} = {_value}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/RemoveFromArray.cs b/HydraScript.Lib/BackEnd/Instructions/RemoveFromArray.cs new file mode 100644 index 00000000..0883f60a --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/RemoveFromArray.cs @@ -0,0 +1,24 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public class RemoveFromArray : Instruction +{ + private readonly string _id; + private readonly IValue _index; + + public RemoveFromArray(string id, IValue index) => + (_id, _index) = (id, index); + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + var list = (List) frame[_id]; + list.RemoveAt(Convert.ToInt32(_index.Get(frame))); + return Address.Next; + } + + protected override string ToStringInternal() => + $"RemoveFrom {_id} at {_index}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/Return.cs b/HydraScript.Lib/BackEnd/Instructions/Return.cs new file mode 100644 index 00000000..352ea780 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/Return.cs @@ -0,0 +1,27 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions; + +public class Return : Instruction +{ + private readonly IValue _value; + + public Return(IValue value = null) => + _value = value; + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Pop(); + var call = vm.CallStack.Pop(); + if (call.Where != null && _value != null) + { + vm.Frames.Peek()[call.Where] = _value.Get(frame); + } + + return frame.ReturnAddress; + } + + protected override string ToStringInternal() => + $"Return{(_value != null ? $" {_value}" : "")}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/AsString.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/AsString.cs new file mode 100644 index 00000000..1a894e37 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/AsString.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment; + +public class AsString : Simple +{ + public AsString(IValue value) : + base(value) { } + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + frame[Left] = JsonSerializer.Serialize( + Right.right.Get(frame), + new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals + } + ); + + return Address.Next; + } + + protected override string ToStringInternal() => + $"{Left} = {Right.right} as string"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/CallFunction.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/CallFunction.cs new file mode 100644 index 00000000..93bfe383 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/CallFunction.cs @@ -0,0 +1,49 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment; + +public class CallFunction : Simple +{ + private readonly FunctionInfo _function; + private readonly int _numberOfArguments; + private readonly bool _hasReturnValue; + + public CallFunction( + FunctionInfo function, + int numberOfArguments, + bool hasReturnValue) : + base(null, (null, null), "Call ") + { + _function = function; + _numberOfArguments = numberOfArguments; + _hasReturnValue = hasReturnValue; + } + + protected override void OnSetOfAddress(IAddress address) + { + if (_hasReturnValue) + base.OnSetOfAddress(address); + } + + public override IAddress Execute(VirtualMachine vm) + { + var frame = new Frame(Address.Next, vm.Frames.Peek()); + + var i = 0; + var args = new List<(string Id, object Value)>(); + while (i < _numberOfArguments) + { + args.Add(vm.Arguments.Pop()); + frame[args[i].Id] = args[i].Value; + i++; + } + + vm.CallStack.Push(new Call(Address, _function, args, Left)); + vm.Frames.Push(frame); + return _function.Start; + } + + protected override string ToStringInternal() => Left == null + ? $"Call {_function}, {_numberOfArguments}" + : $"{Left} = Call {_function}, {_numberOfArguments}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateArray.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateArray.cs new file mode 100644 index 00000000..66df229b --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateArray.cs @@ -0,0 +1,22 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Create; + +public class CreateArray : Simple +{ + private readonly string _id; + private readonly int _size; + + public CreateArray(string id, int size) : base(id) => + (_id, _size) = (id, size); + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + frame[_id] = new object[_size].ToList(); + return Address.Next; + } + + protected override string ToStringInternal() => + $"array {_id} = [{_size}]"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateObject.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateObject.cs new file mode 100644 index 00000000..71d5228b --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Create/CreateObject.cs @@ -0,0 +1,21 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Create; + +public class CreateObject : Simple +{ + private readonly string _id; + + public CreateObject(string id) : base(id) => + _id = id; + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + frame[_id] = new Dictionary(); + return Address.Next; + } + + protected override string ToStringInternal() => + $"object {_id} = {{}}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/DotRead.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/DotRead.cs new file mode 100644 index 00000000..ffac8bac --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/DotRead.cs @@ -0,0 +1,29 @@ +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; + +public class DotRead : Simple, IReadFromComplexData +{ + private readonly Name _objectName; + private readonly IValue _property; + + public string Property => (string)_property.Get(frame: null); + + public DotRead(Name @object, IValue property) : base( + leftValue: @object, + binaryOperator: ".", + rightValue: property) + { + _objectName = @object; + _property = property; + } + + public Simple ToAssignment(IValue value) => + new DotAssignment(_objectName.ToString(), _property, value); + + public Instruction ToInstruction() => this; + + protected override string ToStringInternal() => + $"{Left} = {_objectName}.{_property}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IReadFromComplexData.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IReadFromComplexData.cs new file mode 100644 index 00000000..e9e0c816 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IReadFromComplexData.cs @@ -0,0 +1,10 @@ +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; + +public interface IReadFromComplexData +{ + Simple ToAssignment(IValue value); + + Instruction ToInstruction(); +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IndexRead.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IndexRead.cs new file mode 100644 index 00000000..6f249726 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Read/IndexRead.cs @@ -0,0 +1,27 @@ +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; + +public class IndexRead : Simple, IReadFromComplexData +{ + private readonly Name _arrayName; + private readonly IValue _index; + + public IndexRead(Name array, IValue index) : base( + leftValue: array, + binaryOperator: "[]", + rightValue: index) + { + _arrayName = array; + _index = index; + } + + public Simple ToAssignment(IValue value) => + new IndexAssignment(_arrayName.ToString(), _index, value); + + public Instruction ToInstruction() => this; + + protected override string ToStringInternal() => + $"{Left} = {_arrayName}[{_index}]"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs new file mode 100644 index 00000000..de404640 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/DotAssignment.cs @@ -0,0 +1,26 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; + +public class DotAssignment : Simple, IWriteToComplexData +{ + public DotAssignment(string @object, IValue property, IValue value) : + base(left: @object, (property, value), ".") { } + + 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); + return Address.Next; + } + + public Simple ToSimple() => + new DotRead(new Name(Left), Right.left); + + protected override string ToStringInternal() => + $"{Left}.{Right.left} = {Right.right}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IWriteToComplexData.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IWriteToComplexData.cs new file mode 100644 index 00000000..ac1531f1 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IWriteToComplexData.cs @@ -0,0 +1,6 @@ +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; + +public interface IWriteToComplexData +{ + Simple ToSimple(); +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs new file mode 100644 index 00000000..f8acb620 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/ComplexData/Write/IndexAssignment.cs @@ -0,0 +1,26 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; + +public class IndexAssignment : Simple, IWriteToComplexData +{ + public IndexAssignment(string array, IValue index, IValue value) : + base(left: array, right: (index, value), "[]") { } + + 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); + return Address.Next; + } + + public Simple ToSimple() => + new IndexRead(new Name(Left), Right.left); + + protected override string ToStringInternal() => + $"{Left}[{Right.left}] = {Right.right}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithAssignment/Simple.cs b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/Simple.cs new file mode 100644 index 00000000..fd1ae75b --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithAssignment/Simple.cs @@ -0,0 +1,101 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithAssignment; + +public class Simple : Instruction +{ + public string Left { get; set; } + + protected readonly (IValue left, IValue right) Right; + private readonly string _operator; + + protected Simple(string left) => Left = left; + + public Simple( + string left, + (IValue left, IValue right) right, + string @operator) + { + Left = left; + Right = right; + _operator = @operator; + } + + public Simple(IValue value) : this( + left: null, + right: (null, value), + @operator: string.Empty) + { + } + + public Simple(string unaryOperator, IValue value) : this( + left: null, + right: (null, value), + @operator: unaryOperator) + { + } + + public Simple( + IValue leftValue, + string binaryOperator, + IValue rightValue) : + this( + left: null, + right: (leftValue, rightValue), + @operator: binaryOperator) + { + } + + protected override void OnSetOfAddress(IAddress address) => + Left ??= $"_t{unchecked((uint)address.GetHashCode())}"; + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + if (Right.left == null) + { + var value = Right.right.Get(frame); + frame[Left] = _operator switch + { + "-" => -Convert.ToDouble(value), + "!" => !Convert.ToBoolean(value), + "~" => ((List)value).Count, + "" => value, + _ => throw new NotSupportedException($"_operator {_operator} is not supported") + }; + } + else + { + object lValue = Right.left.Get(frame), rValue = Right.right.Get(frame); + frame[Left] = _operator switch + { + "+" when lValue is string => lValue.ToString() + rValue, + "+" => Convert.ToDouble(lValue) + Convert.ToDouble(rValue), + "-" => Convert.ToDouble(lValue) - Convert.ToDouble(rValue), + "*" => Convert.ToDouble(lValue) * Convert.ToDouble(rValue), + "/" => Convert.ToDouble(lValue) / Convert.ToDouble(rValue), + "%" => Convert.ToDouble(lValue) % Convert.ToDouble(rValue), + "||" => Convert.ToBoolean(lValue) || Convert.ToBoolean(rValue), + "&&" => Convert.ToBoolean(lValue) && Convert.ToBoolean(rValue), + "==" => Equals(lValue, rValue), + "!=" => !Equals(lValue, rValue), + ">" => Convert.ToDouble(lValue) > Convert.ToDouble(rValue), + ">=" => Convert.ToDouble(lValue) >= Convert.ToDouble(rValue), + "<" => Convert.ToDouble(lValue) < Convert.ToDouble(rValue), + "<=" => Convert.ToDouble(lValue) <= Convert.ToDouble(rValue), + "." => ((Dictionary)lValue)[rValue.ToString()!], + "[]" => ((List)lValue)[Convert.ToInt32(rValue)], + "++" => ((List)lValue).Concat((List)rValue).ToList(), + _ => throw new NotSupportedException($"_operator {_operator} is not supported") + }; + } + + return Address.Next; + } + + 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/HydraScript.Lib/BackEnd/Instructions/WithJump/Goto.cs b/HydraScript.Lib/BackEnd/Instructions/WithJump/Goto.cs new file mode 100644 index 00000000..78537886 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithJump/Goto.cs @@ -0,0 +1,31 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd.Instructions.WithJump; + +public class Goto : Instruction +{ + protected Label jump; + + public InsideStatementJumpType? JumpType { get; } + + public Goto(Label jump) => + this.jump = jump; + + public Goto(InsideStatementJumpType jumpType) => + JumpType = jumpType; + + public override IAddress Execute(VirtualMachine vm) => + jump; + + public void SetJump(Label newJump) => + jump = newJump; + + protected override string ToStringInternal() => + $"Goto {jump.Name}"; +} + +public enum InsideStatementJumpType +{ + Break, + Continue +} \ No newline at end of file diff --git a/HydraScript.Lib/BackEnd/Instructions/WithJump/IfNotGoto.cs b/HydraScript.Lib/BackEnd/Instructions/WithJump/IfNotGoto.cs new file mode 100644 index 00000000..d3580220 --- /dev/null +++ b/HydraScript.Lib/BackEnd/Instructions/WithJump/IfNotGoto.cs @@ -0,0 +1,24 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Lib.BackEnd.Instructions.WithJump; + +public class IfNotGoto : Goto +{ + private readonly IValue _test; + + public IfNotGoto(IValue test, Label jump) : + base(jump) => + _test = test; + + public override IAddress Execute(VirtualMachine vm) + { + var frame = vm.Frames.Peek(); + return !Convert.ToBoolean(_test.Get(frame)) + ? jump + : Address.Next; + } + + protected override string ToStringInternal() => + $"IfNot {_test} Goto {jump.Name}"; +} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Values/Constant.cs b/HydraScript.Lib/BackEnd/Values/Constant.cs similarity index 81% rename from Interpreter.Lib/BackEnd/Values/Constant.cs rename to HydraScript.Lib/BackEnd/Values/Constant.cs index bba39f9b..f89fb9a1 100644 --- a/Interpreter.Lib/BackEnd/Values/Constant.cs +++ b/HydraScript.Lib/BackEnd/Values/Constant.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.BackEnd.Values; +namespace HydraScript.Lib.BackEnd.Values; public class Constant : IValue { @@ -11,6 +11,9 @@ public Constant(object value, string representation) _representation = representation; } + public Constant(object value) : + this(value, value.ToString()) { } + public object Get(Frame frame) => _value; public override string ToString() => _representation; diff --git a/Interpreter.Lib/BackEnd/Values/IValue.cs b/HydraScript.Lib/BackEnd/Values/IValue.cs similarity index 65% rename from Interpreter.Lib/BackEnd/Values/IValue.cs rename to HydraScript.Lib/BackEnd/Values/IValue.cs index 11bd4a39..15fd3c21 100644 --- a/Interpreter.Lib/BackEnd/Values/IValue.cs +++ b/HydraScript.Lib/BackEnd/Values/IValue.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.BackEnd.Values; +namespace HydraScript.Lib.BackEnd.Values; public interface IValue : IEquatable { diff --git a/Interpreter.Lib/BackEnd/Values/Name.cs b/HydraScript.Lib/BackEnd/Values/Name.cs similarity index 90% rename from Interpreter.Lib/BackEnd/Values/Name.cs rename to HydraScript.Lib/BackEnd/Values/Name.cs index 9558c340..ba6ad82d 100644 --- a/Interpreter.Lib/BackEnd/Values/Name.cs +++ b/HydraScript.Lib/BackEnd/Values/Name.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.BackEnd.Values; +namespace HydraScript.Lib.BackEnd.Values; public class Name : IValue { diff --git a/HydraScript.Lib/BackEnd/VirtualMachine.cs b/HydraScript.Lib/BackEnd/VirtualMachine.cs new file mode 100644 index 00000000..95796bcf --- /dev/null +++ b/HydraScript.Lib/BackEnd/VirtualMachine.cs @@ -0,0 +1,67 @@ +using HydraScript.Lib.BackEnd.Addresses; + +namespace HydraScript.Lib.BackEnd; + +public record VirtualMachine( + Stack CallStack, Stack Frames, + Stack<(string Id, object Value)> Arguments, + TextWriter Writer +) +{ + public VirtualMachine() : + this(new(), new(), new(), Console.Out) { } + + public void Run(AddressedInstructions instructions) + { + Frames.Push(new Frame(instructions.Start)); + + var address = instructions.Start; + while (!instructions[address].End()) + { + var instruction = instructions[address]; + var jump = instruction.Execute(this); + address = jump; + } + + instructions[address].Execute(this); + } +} + +public record Call( + IAddress From, FunctionInfo To, + List<(string Id, object Value)> Parameters, + string Where = null) +{ + public override string ToString() => + $"{From} => {To.Start}: {To.Id}({string.Join(", ", Parameters.Select(x => $"{x.Id}: {x.Value}"))})"; +} + +public record FunctionInfo(string Id) +{ + public Label Start => + new($"Start_{this}"); + + public Label End => + new($"End_{this}"); + + public override string ToString() => Id; +} + +public class Frame +{ + private readonly Dictionary _variables = new(); + private readonly Frame _parentFrame; + + public IAddress ReturnAddress { get; } + + public Frame(IAddress returnAddress, Frame parentFrame = null) => + (ReturnAddress, _parentFrame) = (returnAddress, parentFrame); + + public object this[string id] + { + get => _variables.TryGetValue(id, out var value) + ? value + : _parentFrame?[id]; + set => _variables[id] = value; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/Structure.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/Structure.cs similarity index 87% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/Structure.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/Structure.cs index 04a5f964..7e0a1b03 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/Structure.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/Structure.cs @@ -2,9 +2,9 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.RegularExpressions; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; -namespace Interpreter.Lib.FrontEnd.GetTokens.Data; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data; public class Structure : IEnumerable { @@ -12,8 +12,8 @@ public Structure(List types) { types.AddRange(new List { - TokenTypeUtils.End, - TokenTypeUtils.Error + new EndOfProgramType(), + new ErrorType() }); types = types .OrderBy(t => t.Priority) diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/Token.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/Token.cs similarity index 93% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/Token.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/Token.cs index 0da227fd..6906132f 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/Token.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/Token.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; -namespace Interpreter.Lib.FrontEnd.GetTokens.Data; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data; [ExcludeFromCodeCoverage] public record Token(TokenType Type) diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs similarity index 67% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs index bccc907b..a23c7a9d 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/EndOfProgramType.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; internal record EndOfProgramType() : TokenType("EOP", "", int.MaxValue - 1) { diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs similarity index 65% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs index da510a76..d76f0128 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/ErrorType.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; internal record ErrorType() : TokenType("ERROR", @"\S+", int.MaxValue) { diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs similarity index 74% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs index 60a3ca59..20532502 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/IgnorableType.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; public record IgnorableType(string Tag = null, string Pattern = null, int Priority = 0) : TokenType(Tag, Pattern, Priority) diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs similarity index 83% rename from Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs index aacd802f..d14c21cd 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenType.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +namespace HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; public record TokenType(string Tag, string Pattern, int Priority) { diff --git a/Interpreter.Lib/FrontEnd/GetTokens/ILexer.cs b/HydraScript.Lib/FrontEnd/GetTokens/ILexer.cs similarity index 52% rename from Interpreter.Lib/FrontEnd/GetTokens/ILexer.cs rename to HydraScript.Lib/FrontEnd/GetTokens/ILexer.cs index 902d7318..eef28abe 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/ILexer.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/ILexer.cs @@ -1,6 +1,6 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.FrontEnd.GetTokens; +namespace HydraScript.Lib.FrontEnd.GetTokens; public interface ILexer { diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Impl/Lexer.cs b/HydraScript.Lib/FrontEnd/GetTokens/Impl/Lexer.cs similarity index 89% rename from Interpreter.Lib/FrontEnd/GetTokens/Impl/Lexer.cs rename to HydraScript.Lib/FrontEnd/GetTokens/Impl/Lexer.cs index 224749a7..6e0dbc1c 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/Impl/Lexer.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/Impl/Lexer.cs @@ -1,10 +1,10 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; -namespace Interpreter.Lib.FrontEnd.GetTokens.Impl; +namespace HydraScript.Lib.FrontEnd.GetTokens.Impl; public class Lexer : ILexer, IEnumerable { @@ -58,7 +58,7 @@ public IEnumerator GetEnumerator() } } - yield return new Token(TokenTypeUtils.End); + yield return new Token(new EndOfProgramType()); } [ExcludeFromCodeCoverage] diff --git a/Interpreter.Lib/FrontEnd/GetTokens/LexerException.cs b/HydraScript.Lib/FrontEnd/GetTokens/LexerException.cs similarity index 66% rename from Interpreter.Lib/FrontEnd/GetTokens/LexerException.cs rename to HydraScript.Lib/FrontEnd/GetTokens/LexerException.cs index c6ff2439..28b42e20 100644 --- a/Interpreter.Lib/FrontEnd/GetTokens/LexerException.cs +++ b/HydraScript.Lib/FrontEnd/GetTokens/LexerException.cs @@ -1,8 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.FrontEnd.GetTokens; +namespace HydraScript.Lib.FrontEnd.GetTokens; -[Serializable] +[Serializable, ExcludeFromCodeCoverage] public class LexerException : Exception { public LexerException() { } diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/IParser.cs b/HydraScript.Lib/FrontEnd/TopDownParse/IParser.cs similarity index 50% rename from Interpreter.Lib/FrontEnd/TopDownParse/IParser.cs rename to HydraScript.Lib/FrontEnd/TopDownParse/IParser.cs index 4ab21651..261ba4d0 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/IParser.cs +++ b/HydraScript.Lib/FrontEnd/TopDownParse/IParser.cs @@ -1,6 +1,6 @@ -using Interpreter.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast; -namespace Interpreter.Lib.FrontEnd.TopDownParse; +namespace HydraScript.Lib.FrontEnd.TopDownParse; public interface IParser { diff --git a/HydraScript.Lib/FrontEnd/TopDownParse/Impl/Parser.cs b/HydraScript.Lib/FrontEnd/TopDownParse/Impl/Parser.cs new file mode 100644 index 00000000..7ed8db15 --- /dev/null +++ b/HydraScript.Lib/FrontEnd/TopDownParse/Impl/Parser.cs @@ -0,0 +1,745 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast.Impl; +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +namespace HydraScript.Lib.FrontEnd.TopDownParse.Impl; + +public class Parser : IParser +{ + private TokensStream _tokens; + private readonly ILexer _lexer; + + public Parser(ILexer lexer) => + _lexer = lexer; + + public IAbstractSyntaxTree TopDownParse(string text) + { + _tokens = _lexer.GetTokens(text); + + var root = Script(); + Expect("EOP"); + return new AbstractSyntaxTree(root); + } + + private Token Expect(string expectedTag, string expectedValue = null) + { + var current = _tokens.Current; + + if (!CurrentIs(expectedTag)) + throw new ParserException(_tokens.Current!.Segment, expectedTag, _tokens.Current); + if (_tokens.Current!.Value != (expectedValue ?? _tokens.Current.Value)) + throw new ParserException(_tokens.Current.Segment, expectedValue, _tokens.Current); + + _tokens.MoveNext(); + return current; + } + + private bool CurrentIs(string tag) => + _tokens.Current!.Type == _lexer.Structure.FindByTag(tag); + + private bool CurrentIsLiteral() => + CurrentIs("NullLiteral") || + CurrentIs("IntegerLiteral") || + CurrentIs("FloatLiteral") || + CurrentIs("StringLiteral") || + CurrentIs("BooleanLiteral"); + + private bool CurrentIsKeyword(string keyword) => + CurrentIs("Keyword") && + _tokens.Current!.Value == keyword; + + private bool CurrentIsOperator(string @operator) => + CurrentIs("Operator") && + _tokens.Current!.Value == @operator; + + private ScriptBody Script() => + new(StatementList()); + + private IEnumerable StatementList() + { + var statementList = new List(); + while ( + CurrentIsKeyword("function") || CurrentIsKeyword("let") || CurrentIsKeyword("const") || + CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || + CurrentIsOperator("-") || CurrentIsOperator("!") || CurrentIsOperator("~") || + CurrentIs("LeftCurl") || CurrentIsKeyword("return") || CurrentIsKeyword("break") || + CurrentIsKeyword("continue") || CurrentIsKeyword("if") || CurrentIsKeyword("while") || + CurrentIsKeyword("type") + ) + { + statementList.Add(StatementListItem()); + } + + return statementList; + } + + private StatementListItem StatementListItem() + { + if (CurrentIsKeyword("function") || CurrentIsKeyword("let") || + CurrentIsKeyword("const") || CurrentIsKeyword("type")) + { + return Declaration(); + } + + return Statement(); + } + + private Statement Statement() + { + if (CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || CurrentIsOperator("-") || + CurrentIsOperator("!") || CurrentIsOperator("~")) + { + return ExpressionStatement(); + } + + if (CurrentIs("LeftCurl")) + { + return BlockStatement(); + } + + if (CurrentIsKeyword("return")) + { + return ReturnStatement(); + } + + if (CurrentIsKeyword("break")) + { + return new InsideStatementJump(InsideStatementJump.Break) + { + Segment = Expect("Keyword", "break").Segment + }; + } + + if (CurrentIsKeyword("continue")) + { + return new InsideStatementJump(InsideStatementJump.Continue) + { + Segment = Expect("Keyword", "continue").Segment + }; + } + + if (CurrentIsKeyword("if")) + { + return IfStatement(); + } + + if (CurrentIsKeyword("while")) + { + return WhileStatement(); + } + + return null; + } + + private BlockStatement BlockStatement() + { + Expect("LeftCurl"); + var block = new BlockStatement(StatementList()); + Expect("RightCurl"); + + return block; + } + + private ExpressionStatement ExpressionStatement() + { + return new(Expression()); + } + + private ReturnStatement ReturnStatement() + { + var ret = Expect("Keyword", "return"); + if (CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen")|| + CurrentIsOperator("-") || CurrentIsOperator("!") || CurrentIsOperator("~") || + CurrentIs("LeftCurl") || CurrentIs("LeftBracket")) + { + return new ReturnStatement(Expression()) { Segment = ret.Segment }; + } + + return new ReturnStatement { Segment = ret.Segment }; + } + + private IfStatement IfStatement() + { + var token = Expect("Keyword", "if"); + Expect("LeftParen"); + var expr = Expression(); + Expect("RightParen"); + var then = Statement(); + if (CurrentIsKeyword("else")) + { + Expect("Keyword", "else"); + var @else = Statement(); + return new IfStatement(expr, then, @else) {Segment = token.Segment}; + } + + return new IfStatement(expr, then) {Segment = token.Segment}; + } + + private WhileStatement WhileStatement() + { + var token = Expect("Keyword", "while"); + Expect("LeftParen"); + var expr = Expression(); + Expect("RightParen"); + var stmt = Statement(); + return new WhileStatement(expr, stmt) {Segment = token.Segment}; + } + + private TypeDeclaration TypeDeclaration() + { + var typeWord = Expect("Keyword", "type"); + var ident = Expect("Ident"); + Expect("Assign"); + var type = TypeValue(); + + var typeId = new IdentifierReference(name: ident.Value) + { Segment = ident.Segment }; + + return new TypeDeclaration(typeId, type) { Segment = typeWord.Segment + ident.Segment }; + } + + private TypeValue TypeValue() + { + if (CurrentIs("Ident")) + { + var ident = Expect("Ident"); + var identType = new TypeIdentValue( + TypeId: new IdentifierReference(name: ident.Value) + { Segment = ident.Segment }); + + return WithSuffix(identType); + } + + if (CurrentIs("LeftCurl")) + { + Expect("LeftCurl"); + var propertyTypes = new List(); + while (CurrentIs("Ident")) + { + var ident = Expect("Ident"); + Expect("Colon"); + var propType = TypeValue(); + propertyTypes.Add( + new PropertyTypeValue( + ident.Value, + propType)); + Expect("SemiColon"); + } + + Expect("RightCurl"); + + return WithSuffix(new ObjectTypeValue(propertyTypes)); + } + + return null; + } + + private TypeValue WithSuffix(TypeValue baseType) + { + var type = baseType; + while (CurrentIs("LeftBracket") || CurrentIs("QuestionMark")) + { + if (CurrentIs("LeftBracket")) + { + Expect("LeftBracket"); + Expect("RightBracket"); + type = new ArrayTypeValue(type); + } + else if (CurrentIs("QuestionMark")) + { + Expect("QuestionMark"); + type = new NullableTypeValue(type); + } + } + + return type; + } + + private Declaration Declaration() + { + if (CurrentIsKeyword("function")) + { + return FunctionDeclaration(); + } + + if (CurrentIsKeyword("let") || CurrentIsKeyword("const")) + { + return LexicalDeclaration(); + } + + if (CurrentIsKeyword("type")) + { + return TypeDeclaration(); + } + + return null; + } + + private FunctionDeclaration FunctionDeclaration() + { + Expect("Keyword", "function"); + var ident = Expect("Ident"); + + Expect("LeftParen"); + var args = new List(); + if (CurrentIs("Ident")) + { + var arg = Expect("Ident").Value; + Expect("Colon"); + var type = TypeValue(); + args.Add(new PropertyTypeValue(arg, type)); + } + + while (CurrentIs("Comma")) + { + Expect("Comma"); + var arg = Expect("Ident").Value; + Expect("Colon"); + var type = TypeValue(); + args.Add(new PropertyTypeValue(arg, type)); + } + + var rp = Expect("RightParen"); + + TypeValue returnType = new TypeIdentValue( + TypeId: new IdentifierReference(name: "undefined") + { Segment = rp.Segment }); + + if (CurrentIs("Colon")) + { + Expect("Colon"); + returnType = TypeValue(); + } + + var name = new IdentifierReference(ident.Value) { Segment = ident.Segment }; + return new FunctionDeclaration(name, returnType, args, BlockStatement()) + { Segment = ident.Segment }; + } + + private LexicalDeclaration LexicalDeclaration() + { + var readOnly = CurrentIsKeyword("const"); + Expect("Keyword", readOnly ? "const" : "let"); + var declaration = new LexicalDeclaration(readOnly); + + AddToDeclaration(declaration); + + while (CurrentIs("Comma")) + { + Expect("Comma"); + AddToDeclaration(declaration); + } + + return declaration; + } + + private void AddToDeclaration(LexicalDeclaration declaration) + { + var ident = Expect("Ident"); + var identRef = new IdentifierReference(ident.Value) { Segment = ident.Segment }; + var assignment = new AssignmentExpression( + new MemberExpression(identRef), + new ImplicitLiteral( + new TypeIdentValue( + new IdentifierReference("undefined")))) + { Segment = ident.Segment }; + + if (CurrentIs("Assign")) + { + var assignSegment = Expect("Assign").Segment; + var expression = Expression(); + assignment = new AssignmentExpression( + new MemberExpression(identRef), expression + ) { Segment = assignSegment }; + } + else if (CurrentIs("Colon")) + { + Expect("Colon"); + var type = TypeValue(); + if (CurrentIs("Assign")) + { + var assignSegment = Expect("Assign").Segment; + var expression = Expression(); + assignment = new AssignmentExpression( + new MemberExpression(identRef), + expression, type + ) { Segment = assignSegment }; + } + else + { + var expression = new ImplicitLiteral(type); + assignment = new AssignmentExpression( + lhs: new MemberExpression(identRef), + expression, + type); + } + } + declaration.AddAssignment(assignment); + } + + private Expression Expression() + { + var expr = CastExpression(); + if (expr is LeftHandSideExpression lhs && CurrentIs("Assign")) + { + var assign = Expect("Assign"); + return new AssignmentExpression(lhs, Expression()) + {Segment = assign.Segment}; + } + return expr; + } + + private Expression CallExpression() + { + var member = MemberExpression(); + if (CurrentIs("LeftParen")) + { + var lp = Expect("LeftParen"); + var expressions = new List(); + if (CurrentIs("Ident") || CurrentIsLiteral() || + CurrentIs("LeftParen") || CurrentIsOperator("-") || + CurrentIsOperator("!") || CurrentIsOperator("~") || + CurrentIs("LeftCurl") || CurrentIs("LeftBracket")) + { + expressions.Add(Expression()); + } + + while (CurrentIs("Comma")) + { + Expect("Comma"); + expressions.Add(Expression()); + } + + Expect("RightParen"); + return new CallExpression(member as MemberExpression, expressions) + { Segment = lp.Segment }; + } + + return member; + } + + private Expression MemberExpression() + { + var primary = PrimaryExpression(); + + if (!CurrentIs("LeftBracket") && !CurrentIs("Dot") && + !CurrentIs("Assign") && !CurrentIs("LeftParen")) + return primary; + + var identRef = primary as IdentifierReference; + var accessChain = new List(); + while (CurrentIs("LeftBracket") || CurrentIs("Dot")) + { + Token access; + if (CurrentIs("LeftBracket")) + { + access = Expect("LeftBracket"); + var lb = access.Segment; + var expr = Expression(); + var rb = Expect("RightBracket").Segment; + accessChain.Add( + new IndexAccess(expr, accessChain.LastOrDefault()) {Segment = lb + rb} + ); + } + else if (CurrentIs("Dot")) + { + access = Expect("Dot"); + var identToken = Expect("Ident"); + var idRef = new IdentifierReference(identToken.Value) + { Segment = identToken.Segment }; + accessChain.Add( + new DotAccess(idRef, accessChain.LastOrDefault()) {Segment = access.Segment} + ); + } + } + + return new MemberExpression( + identRef, + accessChain.FirstOrDefault(), + tail: accessChain.LastOrDefault());; + } + + private Expression CastExpression() + { + var cond = ConditionalExpression(); + if (CurrentIsKeyword("as")) + { + var asKeyword = Expect("Keyword", "as"); + var type = TypeValue(); + return new CastAsExpression(cond, type) {Segment = asKeyword.Segment}; + } + + return cond; + } + + private Expression ConditionalExpression() + { + var test = OrExpression(); + if (CurrentIs("QuestionMark")) + { + Expect("QuestionMark"); + var consequent = Expression(); + Expect("Colon"); + var alternate = Expression(); + return new ConditionalExpression(test, consequent, alternate); + } + + return test; + } + + private Expression OrExpression() + { + var left = AndExpression(); + while (CurrentIsOperator("||")) + { + var op = Expect("Operator"); + var right = AndExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression AndExpression() + { + var left = EqualityExpression(); + while (CurrentIsOperator("&&")) + { + var op = Expect("Operator"); + var right = EqualityExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression EqualityExpression() + { + var left = RelationExpression(); + while (CurrentIsOperator("==") || CurrentIsOperator("!=")) + { + var op = Expect("Operator"); + var right = RelationExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression RelationExpression() + { + var left = AdditiveExpression(); + while (CurrentIsOperator(">") || CurrentIsOperator("<") || CurrentIsOperator(">=") || + CurrentIsOperator("<=")) + { + var op = Expect("Operator"); + var right = AdditiveExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression AdditiveExpression() + { + var left = MultiplicativeExpression(); + while (CurrentIsOperator("+") || CurrentIsOperator("-")) + { + var op = Expect("Operator"); + var right = MultiplicativeExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression MultiplicativeExpression() + { + var left = UnaryExpression(); + while (CurrentIsOperator("*") || CurrentIsOperator("/") || CurrentIsOperator("%") + || CurrentIsOperator("++") || CurrentIsOperator("::")) + { + var op = Expect("Operator"); + var right = UnaryExpression(); + left = new BinaryExpression(left, op.Value, right) + { + Segment = op.Segment + }; + } + + return left; + } + + private Expression UnaryExpression() + { + if (CurrentIsOperator("-") || CurrentIsOperator("!") || CurrentIsOperator("~")) + { + var op = Expect("Operator"); + return new UnaryExpression(op.Value, UnaryExpression()) + { + Segment = op.Segment + }; + } + + return LeftHandSideExpression(); + } + + private Expression LeftHandSideExpression() + { + return CallExpression(); + } + + private Expression PrimaryExpression() + { + if (CurrentIs("LeftParen")) + { + Expect("LeftParen"); + var expr = Expression(); + Expect("RightParen"); + return expr; + } + + if (CurrentIs("Ident")) + { + var ident = Expect("Ident"); + var id = new IdentifierReference(ident.Value) + { + Segment = ident.Segment + }; + + return id; + } + + if (CurrentIsLiteral()) + { + return Literal(); + } + + if (CurrentIs("LeftCurl")) + { + return ObjectLiteral(); + } + + if (CurrentIs("LeftBracket")) + { + return ArrayLiteral(); + } + + return null; + } + + private Literal Literal() + { + var segment = _tokens.Current!.Segment; + if (CurrentIs("StringLiteral")) + { + var str = Expect("StringLiteral"); + return new Literal( + new TypeIdentValue( + TypeId: new IdentifierReference(name: "string") + {Segment = str.Segment}), + value: Regex.Unescape(str.Value.Trim('"')), + segment, + label: str.Value + .Replace(@"\", @"\\") + .Replace(@"""", @"\""")); + } + + return _tokens.Current.Type.Tag switch + { + "NullLiteral" => new Literal( + new TypeIdentValue( + TypeId: new IdentifierReference(name: "null") + { Segment = _tokens.Current.Segment }), + Expect("NullLiteral").Value == "null" ? null : string.Empty, + segment, + label: "null"), + "IntegerLiteral" => new Literal( + new TypeIdentValue( + TypeId: new IdentifierReference(name: "number") + { Segment = _tokens.Current.Segment }), + value: double.Parse(Expect("IntegerLiteral").Value), + segment), + "FloatLiteral" => new Literal( + new TypeIdentValue( + TypeId: new IdentifierReference(name: "number") + { Segment = _tokens.Current.Segment }), + value: double.Parse( + Expect("FloatLiteral").Value, + CultureInfo.InvariantCulture), + segment), + "BooleanLiteral" => new Literal( + new TypeIdentValue( + TypeId: new IdentifierReference(name: "boolean") + { Segment = _tokens.Current.Segment }), + value: bool.Parse(Expect("BooleanLiteral").Value), + segment), + _ => throw new ParserException("There are no more supported literals") + }; + } + + private ObjectLiteral ObjectLiteral() + { + Expect("LeftCurl"); + var properties = new List(); + while (CurrentIs("Ident")) + { + var idToken = Expect("Ident"); + var id = new IdentifierReference(idToken.Value) + { Segment = idToken.Segment }; + + Expect("Colon"); + var expr = Expression(); + properties.Add(new Property(id, expr)); + + Expect("SemiColon"); + } + Expect("RightCurl"); + return new ObjectLiteral(properties); + } + + private ArrayLiteral ArrayLiteral() + { + var lb = Expect("LeftBracket").Segment; + var expressions = new List(); + while (CurrentIs("Ident") || CurrentIsLiteral() || + CurrentIs("LeftParen") || CurrentIsOperator("-") || + CurrentIsOperator("!") || CurrentIsOperator("~") || + CurrentIs("LeftCurl") || CurrentIs("LeftBracket")) + { + expressions.Add(Expression()); + if (!CurrentIs("RightBracket")) + { + Expect("Comma"); + } + } + var rb = Expect("RightBracket").Segment; + return new ArrayLiteral(expressions) {Segment = lb + rb}; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs b/HydraScript.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs similarity index 85% rename from Interpreter.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs rename to HydraScript.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs index 1c232a29..40ce2af1 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs +++ b/HydraScript.Lib/FrontEnd/TopDownParse/Impl/TokensStream.cs @@ -1,7 +1,7 @@ using System.Collections; -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.FrontEnd.TopDownParse.Impl; +namespace HydraScript.Lib.FrontEnd.TopDownParse.Impl; public class TokensStream : IEnumerator { diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs b/HydraScript.Lib/FrontEnd/TopDownParse/ParserException.cs similarity index 62% rename from Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs rename to HydraScript.Lib/FrontEnd/TopDownParse/ParserException.cs index 4d9ba3b6..3e0f70a7 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/ParserException.cs +++ b/HydraScript.Lib/FrontEnd/TopDownParse/ParserException.cs @@ -1,13 +1,14 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.FrontEnd.TopDownParse; +namespace HydraScript.Lib.FrontEnd.TopDownParse; -[Serializable] +[Serializable, ExcludeFromCodeCoverage] 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/HydraScript.Lib/GlobalUsings.cs b/HydraScript.Lib/GlobalUsings.cs new file mode 100644 index 00000000..bb877fed --- /dev/null +++ b/HydraScript.Lib/GlobalUsings.cs @@ -0,0 +1,5 @@ +// Global using directives + +global using Expression = HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.Expression; +global using Type = HydraScript.Lib.IR.CheckSemantics.Types.Type; +global using Visitor.NET; \ No newline at end of file diff --git a/Interpreter.Lib/Interpreter.Lib.csproj b/HydraScript.Lib/HydraScript.Lib.csproj similarity index 58% rename from Interpreter.Lib/Interpreter.Lib.csproj rename to HydraScript.Lib/HydraScript.Lib.csproj index e15b082f..c168c6de 100644 --- a/Interpreter.Lib/Interpreter.Lib.csproj +++ b/HydraScript.Lib/HydraScript.Lib.csproj @@ -6,7 +6,11 @@ - + + + + + diff --git a/HydraScript.Lib/IR/Ast/AbstractSyntaxTreeNode.cs b/HydraScript.Lib/IR/Ast/AbstractSyntaxTreeNode.cs new file mode 100644 index 00000000..35d651fe --- /dev/null +++ b/HydraScript.Lib/IR/Ast/AbstractSyntaxTreeNode.cs @@ -0,0 +1,79 @@ +using System.Collections; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Variables; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast; + +public abstract class AbstractSyntaxTreeNode : IEnumerable, + IVisitable, + IVisitable, + IVisitable, + IVisitable, + IVisitable +{ + public AbstractSyntaxTreeNode Parent { get; set; } + + public SymbolTable SymbolTable { get; set; } + + public Segment Segment { get; init; } + + internal List GetAllNodes() + { + var result = new List + { + this + }; + foreach (var child in this) + { + result.AddRange(child.GetAllNodes()); + } + + return result; + } + + public bool ChildOf() where T : AbstractSyntaxTreeNode + { + var parent = Parent; + while (parent != null) + { + if (parent is T) + { + return true; + } + parent = parent.Parent; + } + + return false; + } + + public abstract IEnumerator GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => + GetEnumerator(); + + #region Visitors + + 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); + + public virtual Type Accept(SemanticChecker visitor) => + "undefined"; + + public abstract AddressedInstructions Accept(InstructionProvider visitor); + + #endregion + + protected abstract string NodeRepresentation(); + + public override string ToString() => + $"{GetHashCode()} [label=\"{NodeRepresentation()}\"]"; +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/IAbstractSyntaxTree.cs b/HydraScript.Lib/IR/Ast/IAbstractSyntaxTree.cs new file mode 100644 index 00000000..9657cf9d --- /dev/null +++ b/HydraScript.Lib/IR/Ast/IAbstractSyntaxTree.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.BackEnd; + +namespace HydraScript.Lib.IR.Ast; + +public interface IAbstractSyntaxTree +{ + AddressedInstructions GetInstructions(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs b/HydraScript.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs new file mode 100644 index 00000000..3d36f9d0 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs @@ -0,0 +1,63 @@ +using System.Text; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +namespace HydraScript.Lib.IR.Ast.Impl; + +public class AbstractSyntaxTree : IAbstractSyntaxTree +{ + private readonly AbstractSyntaxTreeNode _root; + + private readonly SymbolTableInitializer _symbolTableInitializer; + private readonly TypeSystemLoader _typeSystemLoader; + private readonly DeclarationVisitor _declarationVisitor; + + private readonly SemanticChecker _semanticChecker; + private readonly InstructionProvider _instructionProvider; + + public AbstractSyntaxTree(AbstractSyntaxTreeNode root) + { + _root = root; + var functionStorage = new FunctionWithUndefinedReturnStorage(); + var methodStorage = new MethodStorage(); + + _symbolTableInitializer = new SymbolTableInitializer( + new SymbolTableInitializerService(), + new StandardLibraryProvider( + new JavaScriptTypesProvider())); + _typeSystemLoader = new TypeSystemLoader( + new TypeDeclarationsResolver( + new JavaScriptTypesProvider()), + new JavaScriptTypesProvider()); + _declarationVisitor = new DeclarationVisitor(functionStorage, methodStorage); + + _semanticChecker = new SemanticChecker( + new DefaultValueForTypeCalculator(), + functionStorage, + methodStorage); + _instructionProvider = new InstructionProvider(); + } + + public AddressedInstructions GetInstructions() + { + _root.Accept(_symbolTableInitializer); + _root.Accept(_typeSystemLoader); + _root.Accept(_declarationVisitor); + + _root.Accept(_semanticChecker); + return _root.Accept(_instructionProvider); + } + + public override string ToString() + { + var tree = new StringBuilder("digraph ast {\n"); + _root.GetAllNodes().ForEach(node => + { + tree.Append('\t').Append(node).Append('\n'); + node.ToList().ForEach(child => tree.Append($"\t{node.GetHashCode()}->{child.GetHashCode()}\n")); + }); + return tree.Append("}\n").ToString(); + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/AfterTypesAreLoadedDeclaration.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/AfterTypesAreLoadedDeclaration.cs new file mode 100644 index 00000000..4feb4636 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/AfterTypesAreLoadedDeclaration.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; + +public abstract class AfterTypesAreLoadedDeclaration : Declaration +{ + public abstract override Unit Accept(DeclarationVisitor visitor); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/FunctionDeclaration.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/FunctionDeclaration.cs new file mode 100644 index 00000000..0701a740 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/FunctionDeclaration.cs @@ -0,0 +1,63 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; + +public class FunctionDeclaration : AfterTypesAreLoadedDeclaration +{ + private IReadOnlyCollection _returnStatements; + + public IdentifierReference Name { get; } + public TypeValue ReturnTypeValue { get; } + public List Arguments { get; } + public BlockStatement Statements { get; } + + public FunctionDeclaration( + IdentifierReference name, + TypeValue returnTypeValue, + List arguments, + BlockStatement blockStatement) + { + Name = name; + ReturnTypeValue = returnTypeValue; + Arguments = arguments; + + Statements = blockStatement; + Statements.Parent = this; + } + + public bool HasReturnStatement() + { + _returnStatements ??= GetReturnStatements(); + return _returnStatements.Count > 0; + } + + public IReadOnlyCollection GetReturnStatements() => + _returnStatements ??= Statements + .GetAllNodes() + .OfType() + .ToArray(); + + public override IEnumerator GetEnumerator() + { + yield return Statements; + } + + protected override string NodeRepresentation() => + "function " + Name; + + public override Unit Accept(SymbolTableInitializer visitor) => + visitor.Visit(this); + + public override Unit Accept(DeclarationVisitor visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs new file mode 100644 index 00000000..35fe9bea --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs @@ -0,0 +1,39 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; + +public class LexicalDeclaration : AfterTypesAreLoadedDeclaration +{ + public bool ReadOnly { get; } + public List Assignments { get; } + + public LexicalDeclaration(bool readOnly) + { + ReadOnly = readOnly; + Assignments = new(); + } + + public void AddAssignment(AssignmentExpression assignment) + { + assignment.Parent = this; + Assignments.Add(assignment); + } + + public override IEnumerator GetEnumerator() => + Assignments.GetEnumerator(); + + protected override string NodeRepresentation() => + ReadOnly ? "const" : "let"; + + public override Unit Accept(DeclarationVisitor visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs new file mode 100644 index 00000000..bdb8a300 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeDeclaration.cs @@ -0,0 +1,34 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; + +public class TypeDeclaration : Declaration +{ + private readonly TypeValue _typeValue; + public IdentifierReference TypeId { get; } + + public TypeDeclaration(IdentifierReference typeId, TypeValue typeValue) + { + TypeId = typeId; + _typeValue = typeValue; + } + + public Type BuildType() => + _typeValue.BuildType(SymbolTable); + + public override IEnumerator GetEnumerator() + { + yield break; + } + + protected override string NodeRepresentation() => + $"type {TypeId.Name} = {_typeValue}"; + + public override AddressedInstructions Accept(InstructionProvider visitor) => new(); + + public override Unit Accept(TypeSystemLoader visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs new file mode 100644 index 00000000..bea24412 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Declarations/TypeValue.cs @@ -0,0 +1,65 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.CheckSemantics.Exceptions; +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Variables; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; + +public abstract record TypeValue +{ + public abstract Type BuildType(SymbolTable symbolTable); +} + +public record TypeIdentValue( + IdentifierReference TypeId +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + symbolTable.FindSymbol(TypeId)?.Type ?? + throw new UnknownIdentifierReference(TypeId); + + public override string ToString() => TypeId; +} + +public record ArrayTypeValue( + TypeValue TypeValue +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new ArrayType(TypeValue.BuildType(symbolTable)); + + public override string ToString() => $"{TypeValue}[]"; +} + +public record NullableTypeValue( + TypeValue TypeValue +) : TypeValue +{ + public override Type BuildType(SymbolTable symbolTable) => + new NullableType(TypeValue.BuildType(symbolTable)); + + public override string ToString() => $"{TypeValue}?"; +} + +public record PropertyTypeValue( + string Key, + TypeValue TypeValue) +{ + public override string ToString() => + $"{Key}: {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 override string ToString() => + $"{{{string.Join(';', Properties)}}}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs new file mode 100644 index 00000000..5be598e5 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/AccessExpression.cs @@ -0,0 +1,30 @@ +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; + +public abstract class AccessExpression : Expression +{ + public AccessExpression Next { get; private set; } + + public AccessExpression Prev => + Parent as AccessExpression; + + public Type ComputedType { get; set; } + + protected AccessExpression(AccessExpression prev) + { + if (prev is not null) + { + Parent = prev; + prev.Next = this; + } + } + + public bool HasNext() => + Next is not null; + + public bool HasPrev() => + Prev is not null; + + public abstract override Type Accept(SemanticChecker visitor); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs new file mode 100644 index 00000000..0263739b --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/DotAccess.cs @@ -0,0 +1,34 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; + +public class DotAccess : AccessExpression +{ + public IdentifierReference Property { get; } + + public DotAccess(IdentifierReference property, AccessExpression prev = null) : base(prev) + { + Property = property; + Property.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Property; + if (HasNext()) + { + yield return Next; + } + } + + protected override string NodeRepresentation() => "."; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs new file mode 100644 index 00000000..3c83762f --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AccessExpressions/IndexAccess.cs @@ -0,0 +1,33 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; + +public class IndexAccess : AccessExpression +{ + public Expression Index { get; } + + public IndexAccess(Expression index, AccessExpression prev = null) : base(prev) + { + Index = index; + Index.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Index; + if (HasNext()) + { + yield return Next; + } + } + + protected override string NodeRepresentation() => "[]"; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs new file mode 100644 index 00000000..6c959f6e --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/AssignmentExpression.cs @@ -0,0 +1,41 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class AssignmentExpression : Expression +{ + public LeftHandSideExpression Destination { get; } + public Expression Source { get; } + public TypeValue DestinationType { get; } + + public AssignmentExpression( + LeftHandSideExpression lhs, + Expression source, + TypeValue destinationType = null) + { + Destination = lhs; + lhs.Parent = this; + + Source = source; + source.Parent = this; + + DestinationType = destinationType; + } + + public override IEnumerator GetEnumerator() + { + yield return Destination; + yield return Source; + } + + protected override string NodeRepresentation() => "="; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs new file mode 100644 index 00000000..07be9f14 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/BinaryExpression.cs @@ -0,0 +1,37 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class BinaryExpression : Expression +{ + public Expression Left { get; } + public string Operator { get; } + public Expression Right { get; } + + public BinaryExpression(Expression left, string @operator, Expression right) + { + Left = left; + Left.Parent = this; + + Operator = @operator; + + Right = right; + Right.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Left; + yield return Right; + } + + protected override string NodeRepresentation() => Operator; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs new file mode 100644 index 00000000..8dacc95c --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CallExpression.cs @@ -0,0 +1,45 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class CallExpression : LeftHandSideExpression +{ + public MemberExpression Member { get; } + public List Parameters { get; } + + public CallExpression(MemberExpression member, IEnumerable expressions) + { + Member = member; + Member.Parent = this; + + Parameters = new List(expressions); + Parameters.ForEach(expr => expr.Parent = this); + } + + public override IdentifierReference Id => + Member.Id; + + public override bool Empty() => + Member.Empty(); + + public override IEnumerator GetEnumerator() + { + var nodes = new List + { + Member + }; + nodes.AddRange(Parameters); + return nodes.GetEnumerator(); + } + + protected override string NodeRepresentation() => "()"; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs new file mode 100644 index 00000000..4ea335d6 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/CastAsExpression.cs @@ -0,0 +1,33 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class CastAsExpression : Expression +{ + public Expression Expression { get; } + public TypeValue Cast { get; } + + public CastAsExpression(Expression expression, TypeValue cast) + { + Expression = expression; + Expression.Parent = this; + + Cast = cast; + } + + public override IEnumerator GetEnumerator() + { + yield return Expression; + } + + protected override string NodeRepresentation() => $"as {Cast}"; + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs new file mode 100644 index 00000000..29d7c60d --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs @@ -0,0 +1,27 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; + +public class ArrayLiteral : ComplexLiteral +{ + public List Expressions { get; } + + public ArrayLiteral(IEnumerable expressions) + { + Expressions = new List(expressions); + Expressions.ForEach(expr => expr.Parent = this); + } + + public override IEnumerator GetEnumerator() => + Expressions.GetEnumerator(); + + protected override string NodeRepresentation() => "[]"; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ComplexLiteral.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ComplexLiteral.cs new file mode 100644 index 00000000..df889c41 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ComplexLiteral.cs @@ -0,0 +1,8 @@ +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; + +public abstract class ComplexLiteral : Expression +{ + public string Id => Parent is AssignmentExpression assignment + ? assignment.Destination.Id + : $"_t{GetHashCode()}"; +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs new file mode 100644 index 00000000..be97943d --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs @@ -0,0 +1,27 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; + +public class ObjectLiteral : ComplexLiteral +{ + public List Properties { get; } + + public ObjectLiteral(IEnumerable properties) + { + Properties = new List(properties); + Properties.ForEach(prop => prop.Parent = this); + } + + public override IEnumerator GetEnumerator() => + Properties.GetEnumerator(); + + protected override string NodeRepresentation() => "{}"; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/Property.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/Property.cs similarity index 59% rename from Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/Property.cs rename to HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/Property.cs index ccd379fe..7b13c7ea 100644 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/Property.cs +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ComplexLiterals/Property.cs @@ -1,13 +1,17 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Visitors; -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.ComplexLiterals; +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; public class Property : Expression { public IdentifierReference Id { get; } public Expression Expression { get; } + public ObjectLiteral Object => + Parent as ObjectLiteral; + public Property(IdentifierReference id, Expression expression) { Id = id; @@ -19,10 +23,10 @@ public Property(IdentifierReference id, Expression expression) public void Deconstruct(out string id, out Expression expr) { - id = Id.Id; + id = Id.Name; expr = Expression; } - + public override IEnumerator GetEnumerator() { yield return Id; @@ -31,8 +35,6 @@ public override IEnumerator GetEnumerator() protected override string NodeRepresentation() => ":"; - public override List ToInstructions(int start, string temp) - { - throw new System.NotImplementedException(); - } + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); } \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs new file mode 100644 index 00000000..620de68b --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/ConditionalExpression.cs @@ -0,0 +1,38 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class ConditionalExpression : Expression +{ + public Expression Test { get; } + public Expression Consequent { get; } + public Expression Alternate { get; } + + public ConditionalExpression(Expression test, Expression consequent, Expression alternate) + { + Test = test; + Consequent = consequent; + Alternate = alternate; + + Test.Parent = this; + Consequent.Parent = this; + Alternate.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Test; + yield return Consequent; + yield return Alternate; + } + + protected override string NodeRepresentation() => "?:"; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs new file mode 100644 index 00000000..9da02668 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/Expression.cs @@ -0,0 +1,13 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public abstract class Expression : AbstractSyntaxTreeNode, + IVisitable +{ + public abstract AddressedInstructions Accept(ExpressionInstructionProvider visitor); + + public sealed override AddressedInstructions Accept(InstructionProvider visitor) => + throw new NotSupportedException(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/LeftHandSideExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/LeftHandSideExpression.cs new file mode 100644 index 00000000..b5d289b2 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/LeftHandSideExpression.cs @@ -0,0 +1,10 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public abstract class LeftHandSideExpression : Expression +{ + public abstract IdentifierReference Id { get; } + + public abstract bool Empty(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs new file mode 100644 index 00000000..963c2355 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/MemberExpression.cs @@ -0,0 +1,62 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class MemberExpression : LeftHandSideExpression +{ + private readonly IdentifierReference _identifierReference; + + public AccessExpression AccessChain { get; } + public AccessExpression Tail { get; } + + public Type ComputedIdType { get; set; } + + public MemberExpression(IdentifierReference identifierReference) : + this(identifierReference, accessChain: null, tail: null) + { + } + + public MemberExpression( + IdentifierReference identifierReference, + AccessExpression accessChain, + AccessExpression tail) + { + _identifierReference = identifierReference; + _identifierReference.Parent = this; + + AccessChain = accessChain; + if (accessChain is not null) + { + AccessChain.Parent = this; + } + + Tail = tail; + } + + public override IdentifierReference Id => + _identifierReference; + + public override bool Empty() => + AccessChain is null; + + public override IEnumerator GetEnumerator() + { + yield return Id; + if (AccessChain is not null) + { + yield return AccessChain; + } + } + + protected override string NodeRepresentation() => nameof(MemberExpression); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs new file mode 100644 index 00000000..04d99114 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs @@ -0,0 +1,24 @@ +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +public class IdentifierReference : PrimaryExpression +{ + public string Name { get; } + + public IdentifierReference(string name) + { + Name = name; + } + + 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/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs new file mode 100644 index 00000000..ec56306e --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/ImplicitLiteral.cs @@ -0,0 +1,27 @@ +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.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/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs new file mode 100644 index 00000000..2694cdad --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/Literal.cs @@ -0,0 +1,33 @@ +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +public class Literal : PrimaryExpression +{ + private readonly TypeValue _type; + private readonly object _value; + private readonly string _label; + + public Literal( + TypeValue type, + object value, + Segment segment, + string label = null) + { + _type = type; + _label = label ?? value.ToString(); + _value = value; + Segment = segment; + } + + protected override string NodeRepresentation() => _label; + + public override IValue ToValue() => + new Constant(_value, _label); + + public override Type Accept(SemanticChecker visitor) => + _type.BuildType(Parent.SymbolTable); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs new file mode 100644 index 00000000..1ba91197 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs @@ -0,0 +1,18 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.IR.Ast.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +public abstract class PrimaryExpression : Expression +{ + public override IEnumerator GetEnumerator() + { + yield break; + } + + public abstract IValue ToValue(); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs new file mode 100644 index 00000000..8b486c90 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Expressions/UnaryExpression.cs @@ -0,0 +1,32 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +public class UnaryExpression : Expression +{ + public string Operator { get; } + public Expression Expression { get; } + + public UnaryExpression(string @operator, Expression expression) + { + Operator = @operator; + + Expression = expression; + Expression.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Expression; + } + + protected override string NodeRepresentation() => Operator; + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(ExpressionInstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs new file mode 100644 index 00000000..cfd21691 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/ScriptBody.cs @@ -0,0 +1,33 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes; + +public class ScriptBody : AbstractSyntaxTreeNode +{ + public List StatementList { get; } + + public ScriptBody(IEnumerable statementList) + { + StatementList = new List(statementList); + StatementList.ForEach(item => item.Parent = this); + } + + public override IEnumerator GetEnumerator() => + StatementList.GetEnumerator(); + + protected override string NodeRepresentation() => "Script"; + + public override Unit Accept(SymbolTableInitializer visitor) => + visitor.Visit(this); + + public override Unit Accept(TypeSystemLoader visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/StatementListItem.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/StatementListItem.cs new file mode 100644 index 00000000..7c277f50 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/StatementListItem.cs @@ -0,0 +1,10 @@ +namespace HydraScript.Lib.IR.Ast.Impl.Nodes; + +public abstract class StatementListItem : + AbstractSyntaxTreeNode { } + +public abstract class Statement : + StatementListItem { } + +public abstract class Declaration : + StatementListItem { } \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/BlockStatement.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/BlockStatement.cs new file mode 100644 index 00000000..3feaca31 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/BlockStatement.cs @@ -0,0 +1,30 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class BlockStatement : Statement +{ + public List StatementList { get; } + + public BlockStatement(IEnumerable statementList) + { + StatementList = new List(statementList); + StatementList.ForEach(item => item.Parent = this); + } + + public override IEnumerator GetEnumerator() => + StatementList.GetEnumerator(); + + protected override string NodeRepresentation() => "{}"; + + public override Unit Accept(SymbolTableInitializer visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ExpressionStatement.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ExpressionStatement.cs new file mode 100644 index 00000000..c861c016 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ExpressionStatement.cs @@ -0,0 +1,29 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class ExpressionStatement : Statement +{ + public Expression Expression { get; } + + public ExpressionStatement(Expression expression) + { + Expression = expression; + expression.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Expression; + } + + protected override string NodeRepresentation() => nameof(ExpressionStatement); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs new file mode 100644 index 00000000..f9676cd1 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/IfStatement.cs @@ -0,0 +1,51 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class IfStatement : Statement +{ + public Expression Test { get; } + public Statement Then { get; } + public Statement Else { get; } + + public IfStatement(Expression test, Statement then, Statement @else = null) + { + Test = test; + Test.Parent = this; + + Then = then; + Then.Parent = this; + + if (@else is not null) + { + Else = @else; + Else.Parent = this; + } + } + + public bool Empty() => + !Then.Any() && !HasElseBlock(); + + public bool HasElseBlock() => + Else is not null && Else.Any(); + + public override IEnumerator GetEnumerator() + { + yield return Test; + yield return Then; + if (Else is not null) + { + yield return Else; + } + } + + protected override string NodeRepresentation() => "if"; + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs new file mode 100644 index 00000000..b1517eef --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/InsideStatementJump.cs @@ -0,0 +1,31 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class InsideStatementJump : Statement +{ + public const string Break = "break"; + public const string Continue = "continue"; + + public string Keyword { get; } + + public InsideStatementJump(string keyword) + { + Keyword = keyword; + } + + public override IEnumerator GetEnumerator() + { + yield break; + } + + protected override string NodeRepresentation() => Keyword; + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs new file mode 100644 index 00000000..3901f690 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/ReturnStatement.cs @@ -0,0 +1,37 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class ReturnStatement : Statement +{ + public Expression Expression { get; } + + public ReturnStatement(Expression expression = null) + { + Expression = expression; + if (expression is not null) + { + Expression.Parent = this; + } + } + + public override IEnumerator GetEnumerator() + { + if (Expression is null) + { + yield break; + } + + yield return Expression; + } + + protected override string NodeRepresentation() => "return"; + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs new file mode 100644 index 00000000..4224a763 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Impl/Nodes/Statements/WhileStatement.cs @@ -0,0 +1,34 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast.Visitors; +using HydraScript.Lib.IR.CheckSemantics.Visitors; + +namespace HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +public class WhileStatement : Statement +{ + public Expression Condition { get; } + public Statement Statement { get; } + + public WhileStatement(Expression condition, Statement statement) + { + Condition = condition; + Condition.Parent = this; + + Statement = statement; + Statement.Parent = this; + } + + public override IEnumerator GetEnumerator() + { + yield return Condition; + yield return Statement; + } + + protected override string NodeRepresentation() => "while"; + + public override AddressedInstructions Accept(InstructionProvider visitor) => + visitor.Visit(this); + + public override Type Accept(SemanticChecker visitor) => + visitor.Visit(this); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Visitors/ExpressionInstructionProvider.cs b/HydraScript.Lib/IR/Ast/Visitors/ExpressionInstructionProvider.cs new file mode 100644 index 00000000..02faff77 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Visitors/ExpressionInstructionProvider.cs @@ -0,0 +1,324 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Create; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Read; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; +using HydraScript.Lib.BackEnd.Instructions.WithJump; +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.Ast.Visitors; + +public class ExpressionInstructionProvider : + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor +{ + public AddressedInstructions Visit(PrimaryExpression visitable) => + new() { new Simple(visitable.ToValue()) }; + + public AddressedInstructions Visit(ArrayLiteral visitable) + { + var arraySize = visitable.Expressions.Count; + + var arrayName = visitable.Id; + var createArray = new CreateArray(arrayName, arraySize); + + var result = new AddressedInstructions { createArray }; + + for (var i = 0; i < arraySize; i++) + { + var expression = visitable.Expressions[i]; + var index = new Constant(i); + + if (expression is PrimaryExpression primary) + result.Add(new IndexAssignment(arrayName, index, primary.ToValue())); + else + { + result.AddRange(expression.Accept(this)); + var last = new Name(result.OfType().Last().Left); + result.Add(new IndexAssignment(arrayName, index, last)); + } + } + + return result; + } + + public AddressedInstructions Visit(ObjectLiteral visitable) + { + var objectId = visitable.Id; + var createObject = new CreateObject(objectId); + + var result = new AddressedInstructions { createObject }; + + result.AddRange(visitable.Properties + .SelectMany(property => + property.Accept(this))); + + return result; + } + + public AddressedInstructions Visit(Property visitable) + { + var objectId = visitable.Object.Id; + + var (id, expression) = visitable; + var propertyId = new Constant(id); + + if (expression is PrimaryExpression primary) + return new AddressedInstructions + { new DotAssignment(objectId, propertyId, primary.ToValue()) }; + + var instructions = expression.Accept(this); + var last = new Name(instructions.OfType().Last().Left); + instructions.Add(new DotAssignment(objectId, propertyId, last)); + + return instructions; + } + + public AddressedInstructions Visit(UnaryExpression visitable) + { + if (visitable.Expression is PrimaryExpression primary) + return new() { new Simple(visitable.Operator, primary.ToValue()) }; + + var result = visitable.Expression.Accept(this); + var last = new Name(result.OfType().Last().Left); + result.Add(new Simple(visitable.Operator, last)); + + return result; + } + + public AddressedInstructions Visit(BinaryExpression visitable) + { + if (visitable.Left is IdentifierReference arr && + visitable.Right is PrimaryExpression primary && + visitable.Operator == "::") + return new AddressedInstructions + { + new RemoveFromArray(arr.Name, primary.ToValue()) + }; + + var result = new AddressedInstructions(); + IValue left, right; + + if (visitable.Left is PrimaryExpression primaryLeft) + left = primaryLeft.ToValue(); + else + { + result.AddRange(visitable.Left.Accept(this)); + left = new Name(result.OfType().Last().Left); + } + + if (visitable.Right is PrimaryExpression primaryRight) + right = primaryRight.ToValue(); + else + { + result.AddRange(visitable.Right.Accept(this)); + right = new Name(result.OfType().Last().Left); + } + + result.Add(new Simple(left, visitable.Operator, right)); + + return result; + } + + public AddressedInstructions Visit(CastAsExpression visitable) + { + if (visitable.Expression is PrimaryExpression primary) + return new() { new AsString(primary.ToValue()) }; + + var result = visitable.Expression.Accept(this); + var last = new Name(result.OfType().Last().Left); + result.Add(new AsString(last)); + + return result; + } + + public AddressedInstructions Visit(ConditionalExpression visitable) + { + var blockId = $"cond_{visitable.GetHashCode()}"; + var startBlockLabel = new Label($"Start_{blockId}"); + var endBlockLabel = new Label($"End_{blockId}"); + + var result = new AddressedInstructions(); + + if (visitable.Test is PrimaryExpression primary) + result.Add(new IfNotGoto(primary.ToValue(), startBlockLabel)); + else + { + result.AddRange(visitable.Test.Accept(this)); + var last = new Name(result.OfType().Last().Left); + result.Add(new IfNotGoto(last, startBlockLabel)); + } + + result.AddRange(visitable.Consequent.Accept(this)); + var temp = result.OfType().Last().Left; + result.Add(new Goto(endBlockLabel)); + + result.Add(new BeginBlock(BlockType.Condition, blockId), startBlockLabel.Name); + result.AddRange(visitable.Alternate.Accept(this)); + result.OfType().Last().Left = temp; + result.Add(new EndBlock(BlockType.Condition, blockId), endBlockLabel.Name); + + result.Add(new Simple(new Name(temp))); + + return result; + } + + public AddressedInstructions Visit(AssignmentExpression visitable) + { + var result = visitable.Source.Accept(this); + if (visitable.Source is AssignmentExpression) + { + var last = result.OfType().Last(); + if (last is IWriteToComplexData assignment) + result.Add(assignment.ToSimple()); + else + result.Add(new Simple(new Name(last.Left))); + } + + if (visitable.Destination.Empty()) + result.OfType().Last().Left = visitable.Destination.Id; + else + { + var last = new Name(result.OfType().Last().Left); + result.AddRange(visitable.Destination.Accept(this)); + var lastRead = result.OfType().Last(); + result.Replace(lastRead.ToInstruction(), lastRead.ToAssignment(last)); + } + + return result; + } + + public AddressedInstructions Visit(MemberExpression visitable) => + visitable.Empty() + ? new AddressedInstructions() + : visitable.Tail.Accept(this); + + public AddressedInstructions Visit(DotAccess visitable) + { + var right = new Constant(visitable.Property.Name); + + if (!visitable.HasPrev() && visitable.Parent is LeftHandSideExpression lhs) + return new AddressedInstructions + { + new DotRead(new Name(lhs.Id), right) + }; + + var result = visitable.Prev.Accept(this); + var left = new Name(result.OfType().Last().Left); + result.Add(new DotRead(left, right)); + + return result; + } + + public AddressedInstructions Visit(IndexAccess visitable) + { + var result = new AddressedInstructions(); + + IValue right; + + if (visitable.Index is PrimaryExpression primary) + right = primary.ToValue(); + else + { + result.AddRange(visitable.Index.Accept(this)); + right = new Name(result.OfType().Last().Left); + } + + if (!visitable.HasPrev() && visitable.Parent is LeftHandSideExpression lhs) + result.Add(new IndexRead(new Name(lhs.Id), right)); + else + { + result.AddRange(visitable.Prev.Accept(this)); + var left = new Name(result.OfType().Last().Left); + result.Add(new IndexRead(left, right)); + } + + return result; + } + + public AddressedInstructions Visit(CallExpression visitable) + { + var methodCall = !visitable.Empty(); + if (visitable.Id.Name is "print" && !methodCall) + { + var param = visitable.Parameters[0]; + + if (param is PrimaryExpression prim) + return new AddressedInstructions { new Print(prim.ToValue()) }; + + var result = param.Accept(this); + var last = new Name(result.OfType().Last().Left); + result.Add(new Print(last)); + + return result; + } + else + { + FunctionSymbol functionSymbol; + AddressedInstructions result = new(); + if (methodCall) + { + var memberInstructions = visitable.Member.Accept(this); + var lastMemberInstruction = (DotRead)memberInstructions[memberInstructions.End]; + memberInstructions.Remove(lastMemberInstruction); + result.AddRange(memberInstructions); + + var methodName = lastMemberInstruction.Property; + functionSymbol = visitable.SymbolTable + .FindSymbol(methodName); + } + else + { + functionSymbol = visitable.SymbolTable + .FindSymbol(visitable.Id); + } + if (functionSymbol.IsEmpty) + return new AddressedInstructions(); + var functionInfo = new FunctionInfo(functionSymbol.Id); + + if (methodCall) + { + var caller = result.Any() ? result.OfType().Last().Left : visitable.Id; + result.Add(new PushParameter(functionSymbol.Parameters[0].Id, new Name(caller))); + } + foreach (var (expr, symbol) in visitable.Parameters + .Zip(functionSymbol.Parameters.ToArray()[(methodCall ? 1 : 0)..])) + { + if (expr is PrimaryExpression primary) + result.Add(new PushParameter(symbol.Id, primary.ToValue())); + else + { + result.AddRange(expr.Accept(this)); + var id = result.OfType().Last().Left; + result.Add(new PushParameter(symbol.Id, new Name(id))); + } + } + + Type @void = "void"; + var hasReturnValue = !functionSymbol.Type.Equals(@void); + result.Add(new CallFunction( + functionInfo, + numberOfArguments: visitable.Parameters.Count + (methodCall ? 1 : 0), + hasReturnValue)); + return result; + } + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/Ast/Visitors/InstructionProvider.cs b/HydraScript.Lib/IR/Ast/Visitors/InstructionProvider.cs new file mode 100644 index 00000000..8aa90562 --- /dev/null +++ b/HydraScript.Lib/IR/Ast/Visitors/InstructionProvider.cs @@ -0,0 +1,202 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment; +using HydraScript.Lib.BackEnd.Instructions.WithJump; +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; + +namespace HydraScript.Lib.IR.Ast.Visitors; + +public class InstructionProvider : + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor +{ + private readonly ExpressionInstructionProvider _expressionVisitor = new(); + + public AddressedInstructions Visit(ScriptBody visitable) + { + var result = new AddressedInstructions(); + foreach (var item in visitable.StatementList) + { + result.AddRange(item.Accept(this)); + } + + result.Add(new Halt()); + + return result; + } + + public AddressedInstructions Visit(LexicalDeclaration visitable) + { + var result = new AddressedInstructions(); + foreach (var assignment in visitable.Assignments) + { + result.AddRange(assignment.Accept(_expressionVisitor)); + } + + return result; + } + + public AddressedInstructions Visit(BlockStatement visitable) + { + var result = new AddressedInstructions(); + foreach (var item in visitable.StatementList) + { + result.AddRange(item.Accept(this)); + if (item is ReturnStatement) break; + } + + return result; + } + + public AddressedInstructions Visit(InsideStatementJump visitable) + { + var jumpType = visitable.Keyword switch + { + InsideStatementJump.Break => InsideStatementJumpType.Break, + InsideStatementJump.Continue => InsideStatementJumpType.Continue, + _ => throw new ArgumentOutOfRangeException( + nameof(visitable.Keyword), visitable.Keyword, + "Unsupported keyword inside loop") + }; + + return new() { new Goto(jumpType) }; + } + + public AddressedInstructions Visit(ExpressionStatement visitable) => + visitable.Expression.Accept(_expressionVisitor); + + public AddressedInstructions Visit(ReturnStatement visitable) + { + switch (visitable.Expression) + { + case null: + return new() { new Return() }; + case PrimaryExpression primary: + return new() { new Return(primary.ToValue()) }; + } + + var result = visitable.Expression.Accept(_expressionVisitor); + var last = new Name(result.OfType().Last().Left); + result.Add(new Return(last)); + + return result; + } + + public AddressedInstructions Visit(FunctionDeclaration visitable) + { + if (!visitable.Statements.Any()) + return new(); + + var functionInfo = new FunctionInfo(visitable.Name); + + var result = new AddressedInstructions + { + new Goto(functionInfo.End), + { + new BeginBlock(BlockType.Function, blockId: functionInfo.ToString()), + functionInfo.Start.Name + } + }; + + result.AddRange(visitable.Statements.Accept(this)); + if (!visitable.HasReturnStatement()) + result.Add(new Return()); + + result.Add(new EndBlock(BlockType.Function, blockId: functionInfo.ToString()), functionInfo.End.Name); + + return result; + } + + public AddressedInstructions Visit(WhileStatement visitable) + { + var blockId = $"while_{visitable.GetHashCode()}"; + var startBlockLabel = new Label($"Start_{blockId}"); + var endBlockLabel = new Label($"End_{blockId}"); + + var result = new AddressedInstructions + { + { new BeginBlock(BlockType.Loop, blockId), startBlockLabel.Name } + }; + + if (visitable.Condition is PrimaryExpression primary) + result.Add(new IfNotGoto(primary.ToValue(), endBlockLabel)); + else + { + result.AddRange(visitable.Condition.Accept(_expressionVisitor)); + var last = new Name(result.OfType().Last().Left); + result.Add(new IfNotGoto(last, endBlockLabel)); + } + + result.AddRange(visitable.Statement.Accept(this)); + result.OfType().Where(g => g.JumpType is not null) + .ToList().ForEach(g => + { + // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault + switch (g.JumpType) + { + case InsideStatementJumpType.Break: + g.SetJump(endBlockLabel); + break; + case InsideStatementJumpType.Continue: + g.SetJump(startBlockLabel); + break; + } + }); + result.Add(new Goto(startBlockLabel)); + + result.Add(new EndBlock(BlockType.Loop, blockId), endBlockLabel.Name); + + return result; + } + + public AddressedInstructions Visit(IfStatement visitable) + { + if (visitable.Empty()) + return new(); + + var blockId = $"if_else_{visitable.GetHashCode()}"; + var startBlockLabel = new Label($"Start_{blockId}"); + var endBlockLabel = new Label($"End_{blockId}"); + + var result = new AddressedInstructions(); + + if (visitable.Test is PrimaryExpression primary) + result.Add(new IfNotGoto(primary.ToValue(), startBlockLabel)); + else + { + result.AddRange(visitable.Test.Accept(_expressionVisitor)); + var last = new Name(result.OfType().Last().Left); + result.Add(new IfNotGoto(last, + visitable.HasElseBlock() + ? startBlockLabel + : endBlockLabel) + ); + } + + result.AddRange(visitable.Then.Accept(this)); + result.Add(new Goto(endBlockLabel)); + result.Add(new BeginBlock(BlockType.Condition, blockId), startBlockLabel.Name); + + if (visitable.HasElseBlock()) + result.AddRange(visitable.Else.Accept(this)); + + result.OfType().Where(g => g.JumpType is InsideStatementJumpType.Break) + .ToList().ForEach(g=> g.SetJump(endBlockLabel)); + + result.Add(new EndBlock(BlockType.Condition, blockId), endBlockLabel.Name); + + return result; + } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs similarity index 57% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs index bd176e61..59c91062 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ArrayAccessException.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class ArrayAccessException : SemanticException { public ArrayAccessException(Segment segment, Type type) : diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs new file mode 100644 index 00000000..48d187e9 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class AssignmentToConst : SemanticException +{ + public AssignmentToConst(IdentifierReference ident) : + base(ident.Segment,$"Cannot assign to const: {ident.Name}") { } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs new file mode 100644 index 00000000..df99c271 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class CannotDefineType : SemanticException +{ + public CannotDefineType(Segment segment) : + base(segment, "Cannot define type") { } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs new file mode 100644 index 00000000..2b0aa885 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class ConstWithoutInitializer : SemanticException +{ + public ConstWithoutInitializer(IdentifierReference ident) : + base(ident.Segment, $"'const' without initializer: {ident.Name}") { } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs new file mode 100644 index 00000000..ceafadc9 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class DeclarationAlreadyExists : SemanticException +{ + public DeclarationAlreadyExists(IdentifierReference ident) : + base(ident.Segment, $"Declaration already exists: {ident.Name}") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs similarity index 57% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs index 09098d33..26bdddf1 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/FunctionWithoutReturnStatement.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class FunctionWithoutReturnStatement : SemanticException { public FunctionWithoutReturnStatement(Segment segment) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs similarity index 57% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs index d896c792..8781ac8b 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/IncompatibleTypesOfOperands.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class IncompatibleTypesOfOperands : SemanticException { public IncompatibleTypesOfOperands(Segment segment, Type left, Type right) : diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/NonAccessibleType.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/NonAccessibleType.cs new file mode 100644 index 00000000..9b76fa14 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/NonAccessibleType.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class NonAccessibleType : SemanticException +{ + public NonAccessibleType(Type type) : + base($"Type '{type}' is not array-like or object-like") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs similarity index 55% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs index a1940bb2..66bb9b3c 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/NotBooleanTestExpression.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class NotBooleanTestExpression : SemanticException { public NotBooleanTestExpression(Segment segment, Type type) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs similarity index 51% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs index ae459389..2fbc9028 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ObjectAccessException.cs @@ -1,8 +1,10 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.CheckSemantics.Types; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.IR.CheckSemantics.Types; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class ObjectAccessException : SemanticException { public ObjectAccessException(Segment segment, ObjectType objectType, string field) : diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/OutsideOfStatement.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/OutsideOfStatement.cs new file mode 100644 index 00000000..799f8807 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/OutsideOfStatement.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class OutsideOfStatement : SemanticException +{ + public OutsideOfStatement(Segment segment, string keyword, string statement) : + base(segment, $"Jump \"{keyword}\" outside of statement \"{statement}\"") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs similarity index 50% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs index bd27215e..4fcb25b5 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/ReturnOutsideFunction.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class ReturnOutsideFunction : SemanticException { public ReturnOutsideFunction(Segment segment) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs similarity index 68% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs index 1571a424..e5c2d5e9 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/SemanticException.cs @@ -1,8 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; -[Serializable] +[Serializable, ExcludeFromCodeCoverage] public abstract class SemanticException : Exception { protected SemanticException() { } diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs new file mode 100644 index 00000000..9dd2e9cc --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class SymbolIsNotCallable : SemanticException +{ + public SymbolIsNotCallable(string symbol, Segment segment) : + base(segment, $"Symbol is not callable: {symbol}") { } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs new file mode 100644 index 00000000..523a01ce --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class UnknownIdentifierReference : SemanticException +{ + public UnknownIdentifierReference(IdentifierReference ident) : + base(ident.Segment, $"Unknown identifier reference: {ident.Name}") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs similarity index 56% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs index e6194f7f..e2fe77bc 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/UnsupportedOperation.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class UnsupportedOperation : SemanticException { public UnsupportedOperation(Segment segment, Type type, string @operator) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs similarity index 60% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs index 63b09d55..f14a072b 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongArrayLiteralDeclaration.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class WrongArrayLiteralDeclaration : SemanticException { public WrongArrayLiteralDeclaration(Segment segment, Type type) : diff --git a/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongAssignmentTarget.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongAssignmentTarget.cs new file mode 100644 index 00000000..5f04a672 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongAssignmentTarget.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; + +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class WrongAssignmentTarget : SemanticException +{ + public WrongAssignmentTarget(LeftHandSideExpression lhs) : + base(lhs.Segment, $"Assignment target must be variable, property or indexer. '{lhs.Id.Name}' is {lhs.GetType().Name}") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs similarity index 63% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs index eb2aaa3e..78e87b63 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongConditionalTypes.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class WrongConditionalTypes : SemanticException { public WrongConditionalTypes(Segment cSegment, Type cType, Segment aSegment, Type aType) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs similarity index 58% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs index 630cc175..0260cdc3 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongNumberOfArguments.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class WrongNumberOfArguments : SemanticException { public WrongNumberOfArguments(Segment segment, int expected, int actual) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs similarity index 56% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs index 203ad081..6a9feefc 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongReturnType.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class WrongReturnType : SemanticException { public WrongReturnType(Segment segment, Type expected, Type actual) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs similarity index 57% rename from Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs rename to HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs index 6b34e8c2..77ae4927 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Exceptions/WrongTypeOfArgument.cs @@ -1,7 +1,9 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using System.Diagnostics.CodeAnalysis; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; +namespace HydraScript.Lib.IR.CheckSemantics.Exceptions; +[ExcludeFromCodeCoverage] public class WrongTypeOfArgument : SemanticException { public WrongTypeOfArgument(Segment segment, Type expected, Type actual) : diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Any.cs b/HydraScript.Lib/IR/CheckSemantics/Types/Any.cs similarity index 78% rename from Interpreter.Lib/IR/CheckSemantics/Types/Any.cs rename to HydraScript.Lib/IR/CheckSemantics/Types/Any.cs index ff982fbc..652758fe 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Any.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Types/Any.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.IR.CheckSemantics.Types; +namespace HydraScript.Lib.IR.CheckSemantics.Types; public class Any : Type { diff --git a/HydraScript.Lib/IR/CheckSemantics/Types/ArrayType.cs b/HydraScript.Lib/IR/CheckSemantics/Types/ArrayType.cs new file mode 100644 index 00000000..60168d34 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Types/ArrayType.cs @@ -0,0 +1,32 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Types; + +public class ArrayType : Type +{ + public Type Type { get; private set; } + + public ArrayType(Type type) : + base($"{type}[]") => + Type = type; + + public override void ResolveReference( + Type reference, + string refId, + ISet visited = null) + { + if (Type == refId) + Type = reference; + else + Type.ResolveReference(reference, refId, visited); + } + + public override bool Equals(object obj) + { + if (obj is ArrayType that) + return Equals(Type, that.Type); + return obj is Any; + } + + public override int GetHashCode() => + // ReSharper disable once NonReadonlyMemberInGetHashCode + Type.GetHashCode(); +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/NullType.cs b/HydraScript.Lib/IR/CheckSemantics/Types/NullType.cs similarity index 50% rename from Interpreter.Lib/IR/CheckSemantics/Types/NullType.cs rename to HydraScript.Lib/IR/CheckSemantics/Types/NullType.cs index 8d78a520..b3886910 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Types/NullType.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Types/NullType.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Lib.IR.CheckSemantics.Types; +namespace HydraScript.Lib.IR.CheckSemantics.Types; public class NullType : Type { @@ -6,10 +6,8 @@ public NullType() : base("null") { } - public override bool Equals(object obj) - { - return obj is NullableType or NullType; - } + public override bool Equals(object obj) => + obj is NullableType or NullType or Any; public override int GetHashCode() => "null".GetHashCode(); diff --git a/HydraScript.Lib/IR/CheckSemantics/Types/NullableType.cs b/HydraScript.Lib/IR/CheckSemantics/Types/NullableType.cs new file mode 100644 index 00000000..f88327c3 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Types/NullableType.cs @@ -0,0 +1,37 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Types; + +public class NullableType : Type +{ + public Type Type { get; private set; } + + public NullableType(Type type) : + base($"{type}?") => + Type = type; + + protected NullableType() + { + } + + public override void ResolveReference( + Type reference, + string refId, + ISet visited = null) + { + if (Type == refId) + Type = reference; + else + Type.ResolveReference(reference, refId, visited); + } + + public override bool Equals(object obj) + { + if (obj is NullableType that) + return Equals(Type, that.Type); + + return obj is NullType or Any; + } + + public override int GetHashCode() => + // ReSharper disable once NonReadonlyMemberInGetHashCode + Type.GetHashCode(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Types/ObjectType.cs b/HydraScript.Lib/IR/CheckSemantics/Types/ObjectType.cs new file mode 100644 index 00000000..0726d241 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Types/ObjectType.cs @@ -0,0 +1,188 @@ +using System.Text; + +namespace HydraScript.Lib.IR.CheckSemantics.Types; + +public class ObjectType : NullableType +{ + private readonly Dictionary _properties; + private readonly HashSet _methods; + private readonly ObjectTypeHasher _hasher; + private readonly ObjectTypePrinter _serializer; + + public string LastAccessedMethod { get; private set; } + + public ObjectType(IEnumerable properties) + { + _properties = properties + .OrderBy(x => x.Id) + .ToDictionary( + x => x.Id, + x => x.Type); + _methods = new HashSet(); + + _hasher = new ObjectTypeHasher(this); + _serializer = new ObjectTypePrinter(this); + } + + public Type this[string id] + { + get => _properties.GetValueOrDefault(id); + private set => _properties[id] = value; + } + + public void AddMethod(string methodName) => + _methods.Add(methodName); + + public bool HasMethod(string methodName) + { + LastAccessedMethod = methodName; + return _methods.Contains(methodName); + } + + public override void ResolveReference( + Type reference, + string refId, + ISet visited = null) + { + visited ??= new HashSet(); + if (!visited.Add(this)) + return; + + foreach (var key in _properties.Keys) + if (refId == this[key]) + this[key] = reference; + else + this[key].ResolveReference(reference, refId, visited); + } + + public override bool Equals(object obj) + { + if (obj is ObjectType that) + return ReferenceEquals(this, that) || + _properties.Count == that._properties.Count && + _properties.Zip(that._properties) + .All(pair => + pair.First.Key == pair.Second.Key && + pair.First.Value.Equals(pair.Second.Value)); + + return obj is NullType or Any; + } + + public override int GetHashCode() => + _hasher.HashObjectType(this); + + public override string ToString() + { + var result = _serializer.PrintObjectType(this); + _serializer.Clear(); + return result; + } + + private class ObjectTypeHasher + { + private readonly ObjectType _reference; + + public ObjectTypeHasher(ObjectType reference) => + _reference = reference; + + private int Hash(Type type) => type switch + { + ArrayType arrayType => HashArrayType(arrayType), + ObjectType objectType => HashObjectType(objectType), + NullableType nullableType => HashNullableType(nullableType), + _ => type.GetHashCode() + }; + + public int HashObjectType(ObjectType objectType) => + objectType._properties.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 class ObjectTypePrinter + { + private readonly ObjectType _reference; + private readonly ISet _visited; + + public ObjectTypePrinter(ObjectType reference) + { + _reference = reference; + _visited = new HashSet(); + } + + public void Clear() => _visited.Clear(); + + private string Print(Type type) => type switch + { + ArrayType arrayType => PrintArrayType(arrayType), + 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._properties.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(); + } + } +} + +public record PropertyType(string Id, Type Type); \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Types/Type.cs b/HydraScript.Lib/IR/CheckSemantics/Types/Type.cs new file mode 100644 index 00000000..66a30874 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Types/Type.cs @@ -0,0 +1,42 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Types; + +public class Type +{ + private readonly string _name; + + protected Type() + { + } + + public Type(string name) => + _name = name; + + public virtual void ResolveReference( + Type reference, + string refId, + ISet visited = null) + { + } + + public override bool Equals(object obj) => + obj switch + { + Any => true, + Type that => _name == that._name, + _ => false + }; + + public override int GetHashCode() => + _name.GetHashCode(); + + public override string ToString() => _name; + + public static implicit operator Type(string alias) => + new(alias); + + public static bool operator ==(Type left, Type right) => + Equals(left, right); + + public static bool operator !=(Type left, Type right) => + !(left == right); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Variables/SymbolTable.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/SymbolTable.cs new file mode 100644 index 00000000..b36c2e63 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/SymbolTable.cs @@ -0,0 +1,41 @@ +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Variables; + +public class SymbolTable +{ + private readonly Dictionary _symbols = new(); + + private SymbolTable _openScope; + + public void AddOpenScope(SymbolTable table) + { + _openScope = table; + } + + /// + /// Символы доступные в области видимости таблицы + /// + public IEnumerable GetAvailableSymbols() => + _symbols.Values.Concat(_openScope?.GetAvailableSymbols() ?? Array.Empty()); + + public void AddSymbol(Symbol symbol) => + _symbols[symbol.Id] = symbol; + + /// + /// Поиск эффективного символа + /// + public TSymbol FindSymbol(string id) where TSymbol : Symbol + { + var hasInsideTheScope = _symbols.TryGetValue(id, out var symbol); + return !hasInsideTheScope + ? _openScope?.FindSymbol(id) + : symbol as TSymbol; + } + + /// + /// Проверяет наличие собственного символа + /// + public bool ContainsSymbol(string id) => + _symbols.ContainsKey(id); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs new file mode 100644 index 00000000..fc5bfb82 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs @@ -0,0 +1,35 @@ +using System.Text; + +namespace HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +public class FunctionSymbol : Symbol +{ + private Type _returnType; + + public override string Id { get; } + /// Тип возврата функции + public override Type Type => _returnType; + public IReadOnlyList Parameters { get; } + public bool IsEmpty { get; } + + public FunctionSymbol( + string id, + IEnumerable parameters, + Type returnType, + bool isEmpty) + { + Id = id; + Parameters = new List(parameters); + _returnType = returnType; + IsEmpty = isEmpty; + } + + public void DefineReturnType(Type returnType) => + _returnType = returnType; + + public override string ToString() => + new StringBuilder($"function {Id}(") + .AppendJoin(',', Parameters) + .Append($") => {Type}") + .ToString(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs new file mode 100644 index 00000000..db59ea0d --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs @@ -0,0 +1,14 @@ +using HydraScript.Lib.IR.CheckSemantics.Types; + +namespace HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +public class ObjectSymbol : VariableSymbol +{ + public override ObjectType Type { get; } + + public ObjectSymbol(string id, ObjectType objectType, bool readOnly = false) : + base(id, objectType, readOnly) + { + Type = objectType; + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs new file mode 100644 index 00000000..bf392ca4 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs @@ -0,0 +1,7 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +public abstract class Symbol +{ + public abstract string Id { get; } + public abstract Type Type { get; } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/TypeSymbol.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/TypeSymbol.cs new file mode 100644 index 00000000..f36267d0 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/TypeSymbol.cs @@ -0,0 +1,30 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +public class TypeSymbol : Symbol +{ + public override string Id { get; } + public override Type Type { get; } + + public TypeSymbol(Type type, string id = null) + { + Id = id ?? type.ToString(); + Type = type; + } + + public override bool Equals(object obj) + { + if (obj is TypeSymbol typeSymbol) + { + return Id == typeSymbol.Id && + Type.Equals(typeSymbol.Type); + } + + return false; + } + + public override int GetHashCode() => + HashCode.Combine(Id, Type); + + public override string ToString() => + $"type {Id} = {Type}"; +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs similarity index 56% rename from Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs rename to HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs index 9ef2db85..1bff17a3 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs +++ b/HydraScript.Lib/IR/CheckSemantics/Variables/Symbols/VariableSymbol.cs @@ -1,12 +1,17 @@ -namespace Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; +namespace HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; public class VariableSymbol : Symbol { + public override string Id { get; } + public override Type Type { get; } public bool ReadOnly { get; } - public VariableSymbol(string id, Type type, bool readOnly = false) : - base(id, type) => + public VariableSymbol(string id, Type type, bool readOnly = false) + { + Id = id; + Type = type; ReadOnly = readOnly; + } public override string ToString() => $"{(ReadOnly ? "const " : "")}{Id}: {Type}"; } \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs new file mode 100644 index 00000000..9a1c4f4f --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs @@ -0,0 +1,99 @@ +using HydraScript.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.CheckSemantics.Exceptions; +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors; + +public class DeclarationVisitor : + IVisitor, + IVisitor, + IVisitor +{ + private readonly IFunctionWithUndefinedReturnStorage _functionStorage; + private readonly IMethodStorage _methodStorage; + + public DeclarationVisitor( + IFunctionWithUndefinedReturnStorage functionStorage, + IMethodStorage methodStorage) + { + _functionStorage = functionStorage; + _methodStorage = methodStorage; + } + + public Unit Visit(AbstractSyntaxTreeNode visitable) + { + foreach (var child in visitable) + child.Accept(this); + + return default; + } + + public Unit Visit(LexicalDeclaration visitable) + { + foreach (var assignment in visitable.Assignments) + { + if (visitable.SymbolTable.ContainsSymbol(assignment.Destination.Id)) + throw new DeclarationAlreadyExists(assignment.Destination.Id); + + var destinationType = assignment.DestinationType?.BuildType( + assignment.SymbolTable) ?? "undefined"; + + if (destinationType == "undefined" && + assignment.Source is ImplicitLiteral or ArrayLiteral { Expressions.Count: 0 }) + throw visitable.ReadOnly + ? new ConstWithoutInitializer(assignment.Destination.Id) + : new CannotDefineType(assignment.Destination.Id.Segment); + + visitable.SymbolTable.AddSymbol( + new VariableSymbol( + assignment.Destination.Id, + destinationType)); + } + + return default; + } + + public Unit Visit(FunctionDeclaration visitable) + { + if (visitable.Parent.SymbolTable.ContainsSymbol(visitable.Name)) + throw new DeclarationAlreadyExists(visitable.Name); + + 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, + visitable.ReturnTypeValue.BuildType(visitable.Parent.SymbolTable), + isEmpty: !visitable.Statements.Any()); + if (parameters is [{ Type: ObjectType objectType }, ..] && + visitable.Arguments is [{ TypeValue: TypeIdentValue }, ..]) + { + _methodStorage.BindMethod(objectType, functionSymbol); + } + + Type undefined = "undefined"; + if (functionSymbol.Type.Equals(undefined)) + { + if (visitable.HasReturnStatement()) + _functionStorage.Save(functionSymbol, visitable); + else + functionSymbol.DefineReturnType("void"); + } + + visitable.Parent.SymbolTable.AddSymbol(functionSymbol); + return visitable.Statements.Accept(this); + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs new file mode 100644 index 00000000..36346fdb --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/SemanticChecker.cs @@ -0,0 +1,459 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.AccessExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; +using HydraScript.Lib.IR.CheckSemantics.Exceptions; +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors; + +public class SemanticChecker : + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor, + IVisitor +{ + private readonly IDefaultValueForTypeCalculator _calculator; + private readonly IFunctionWithUndefinedReturnStorage _functionStorage; + private readonly IMethodStorage _methodStorage; + + public SemanticChecker( + IDefaultValueForTypeCalculator calculator, + IFunctionWithUndefinedReturnStorage functionStorage, + IMethodStorage methodStorage) + { + _calculator = calculator; + _functionStorage = functionStorage; + _methodStorage = methodStorage; + } + + public Type Visit(ScriptBody visitable) + { + foreach (var statementListItem in visitable.StatementList) + statementListItem.Accept(this); + + foreach (var funcDecl in _functionStorage.Flush()) + funcDecl.Accept(this); + + return "undefined"; + } + + public Type Visit(WhileStatement visitable) + { + var condType = visitable.Condition.Accept(this); + Type boolean = "boolean"; + if (!condType.Equals(boolean)) + throw new NotBooleanTestExpression(visitable.Segment, condType); + + visitable.Statement.Accept(this); + + return "undefined"; + } + + public Type Visit(IfStatement visitable) + { + var testType = visitable.Test.Accept(this); + Type boolean = "boolean"; + if (!testType.Equals(boolean)) + throw new NotBooleanTestExpression(visitable.Segment, testType); + + visitable.Then.Accept(this); + visitable.Else?.Accept(this); + + return "undefined"; + } + + 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 "undefined"; + } + + public Type Visit(ReturnStatement visitable) + { + if (!visitable.ChildOf()) + throw new ReturnOutsideFunction(visitable.Segment); + + return visitable.Expression?.Accept(this) ?? "void"; + } + + public Type Visit(ExpressionStatement visitable) => + visitable.Expression.Accept(this); + + public Type Visit(IdentifierReference visitable) + { + var symbol = visitable.SymbolTable.FindSymbol(visitable.Name); + return symbol?.Type ?? throw new UnknownIdentifierReference(visitable); + } + + public Type Visit(ImplicitLiteral visitable) + { + var type = visitable.TypeValue.BuildType(visitable.Parent.SymbolTable); + visitable.ComputedDefaultValue = _calculator.GetDefaultValueForType(type); + return type; + } + + public Type Visit(ArrayLiteral visitable) + { + if (visitable.Expressions.Count == 0) + return new ArrayType(new Any()); + + var type = visitable.First().Accept(this); + if (visitable.Expressions.All(e => e.Accept(this).Equals(type))) + return new ArrayType(type); + + throw new WrongArrayLiteralDeclaration(visitable.Segment, type); + } + + public Type Visit(ObjectLiteral visitable) + { + var properties = visitable.Properties.Select(prop => + { + var propType = prop.Expression.Accept(this); + visitable.SymbolTable.AddSymbol(propType switch + { + ObjectType objectType => new ObjectSymbol(prop.Id, objectType), + _ => new VariableSymbol(prop.Id, propType) + }); + return new PropertyType(prop.Id, propType); + }); + var objectLiteralType = new ObjectType(properties); + return objectLiteralType; + } + + public Type Visit(ConditionalExpression visitable) + { + var tType = visitable.Test.Accept(this); + Type boolean = "boolean"; + if (!tType.Equals(boolean)) + throw new NotBooleanTestExpression(visitable.Test.Segment, tType); + + var cType = visitable.Consequent.Accept(this); + var aType = visitable.Alternate.Accept(this); + if (cType.Equals(aType)) + return cType; + + throw new WrongConditionalTypes( + cSegment: visitable.Consequent.Segment, + cType, + aSegment: visitable.Alternate.Segment, + aType); + } + + public Type Visit(BinaryExpression visitable) + { + var lType = visitable.Left.Accept(this); + var rType = visitable.Right.Accept(this); + + if (visitable.Operator != "::" && !lType.Equals(rType)) + throw new IncompatibleTypesOfOperands( + visitable.Segment, + left: lType, + right: rType); + + Type number = "number"; + Type @string = "string"; + Type boolean = "boolean"; + + return visitable.Operator switch + { + "+" when lType.Equals(number) => number, + "+" when lType.Equals(@string) => @string, + "+" => throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "-" or "*" or "/" or "%" => lType.Equals(number) + ? number + : throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "||" or "&&" => lType.Equals(boolean) + ? boolean + : throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "==" or "!=" => boolean, + ">" or ">=" or "<" or "<=" => lType.Equals(number) + ? boolean + : throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "++" when lType is ArrayType { Type: Any } && rType is ArrayType { Type: Any } => + throw new CannotDefineType(visitable.Segment), + "++" => lType is ArrayType lArrType && rType is ArrayType rArrType + ? new List { lArrType, rArrType }.First(x => x.Type is not Any) + : throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "::" when lType is not ArrayType => + throw new UnsupportedOperation(visitable.Segment, lType, visitable.Operator), + "::" => rType.Equals(number) ? "void" : throw new ArrayAccessException(visitable.Segment, rType), + _ => "undefined" + }; + } + + public Type Visit(UnaryExpression visitable) + { + var eType = visitable.Expression.Accept(this); + + Type number = "number"; + Type boolean = "boolean"; + + return visitable.Operator switch + { + "-" when eType.Equals(number) => number, + "!" when eType.Equals(boolean) => boolean, + "~" when eType is ArrayType => number, + _ => throw new UnsupportedOperation(visitable.Segment, eType, visitable.Operator) + }; + } + + public Type Visit(LexicalDeclaration visitable) + { + Type undefined = "undefined"; + + foreach (var assignment in visitable.Assignments) + { + var registeredSymbol = visitable.SymbolTable.FindSymbol( + assignment.Destination.Id); + var sourceType = assignment.Source.Accept(this); + if (sourceType.Equals(undefined)) + throw new CannotDefineType(assignment.Source.Segment); + if (!registeredSymbol.Type.Equals(undefined) && !registeredSymbol.Type.Equals(sourceType)) + throw new IncompatibleTypesOfOperands( + assignment.Segment, + left: registeredSymbol.Type, + right: sourceType); + + var actualType = registeredSymbol.Type.Equals(undefined) + ? sourceType + : registeredSymbol.Type; + var actualSymbol = actualType switch + { + ObjectType objectType => new ObjectSymbol(registeredSymbol.Id, objectType, visitable.ReadOnly), + _ => new VariableSymbol(registeredSymbol.Id, actualType, visitable.ReadOnly) + }; + visitable.SymbolTable.AddSymbol(actualSymbol); + } + + return undefined; + } + + public Type Visit(AssignmentExpression visitable) + { + if (visitable.Destination is CallExpression) + throw new WrongAssignmentTarget(visitable.Destination); + + var sourceType = visitable.Source.Accept(this); + if (!visitable.Destination.Empty()) + { + var destinationType = visitable.Destination.Accept(this); + if (!destinationType.Equals(sourceType)) + throw new IncompatibleTypesOfOperands( + visitable.Segment, + left: destinationType, + right: sourceType); + return destinationType; + } + + var symbol = + visitable.SymbolTable.FindSymbol( + visitable.Destination.Id) ?? + throw new UnknownIdentifierReference(visitable.Destination.Id); + + if (symbol.ReadOnly) + throw new AssignmentToConst(visitable.Destination.Id); + + if (!sourceType.Equals(symbol.Type)) + throw new IncompatibleTypesOfOperands( + visitable.Segment, + left: symbol.Type, + right: sourceType); + + return symbol.Type; + } + + public Type Visit(MemberExpression visitable) + { + var idType = visitable.Id.Accept(this); + visitable.ComputedIdType = idType; + return visitable.Empty() ? idType : visitable.AccessChain?.Accept(this); + } + + public Type Visit(IndexAccess visitable) + { + var prevType = + visitable.Prev?.ComputedType + ?? (visitable.Parent as MemberExpression)!.ComputedIdType; + + if (prevType is not ArrayType arrayType) + throw new NonAccessibleType(prevType); + + Type number = "number"; + var indexType = visitable.Index.Accept(this); + if (!indexType.Equals(number)) + throw new ArrayAccessException(visitable.Segment, indexType); + + var elemType = arrayType.Type; + visitable.ComputedType = elemType; + return visitable.HasNext() ? visitable.Next.Accept(this) : elemType; + } + + public Type Visit(DotAccess visitable) + { + var prevType = + visitable.Prev?.ComputedType + ?? (visitable.Parent as MemberExpression)!.ComputedIdType; + + if (prevType is not ObjectType objectType) + throw new NonAccessibleType(prevType); + + var fieldType = objectType[visitable.Property]; + var hasMethod = objectType.HasMethod(visitable.Property); + if (fieldType is null) + return hasMethod + ? objectType + : throw new ObjectAccessException(visitable.Segment, objectType, visitable.Property); + visitable.ComputedType = fieldType; + return visitable.HasNext() ? visitable.Next.Accept(this) : fieldType; + } + + public Type Visit(CastAsExpression visitable) + { + Type undefined = "undefined"; + var exprType = visitable.Expression.Accept(this); + + if (exprType.Equals(undefined)) + throw new CannotDefineType(visitable.Expression.Segment); + + return visitable.Cast.BuildType(visitable.SymbolTable) == "string" + ? "string" + : throw new NotSupportedException("Other types but 'string' have not been supported for casting yet"); + } + + public Type Visit(CallExpression visitable) + { + FunctionSymbol functionSymbol; + var methodCall = !visitable.Member.Empty(); + + if (methodCall) + { + var objectType = (ObjectType)visitable.Member.Accept(this); + var availableMethods = _methodStorage.GetAvailableMethods(objectType); + functionSymbol = availableMethods[objectType.LastAccessedMethod]; + } + else + { + var symbol = + visitable.SymbolTable.FindSymbol(visitable.Id) + ?? throw new UnknownIdentifierReference(visitable.Id); + functionSymbol = + symbol as FunctionSymbol + ?? throw new SymbolIsNotCallable(symbol.Id, visitable.Id.Segment); + } + + var functionReturnType = functionSymbol.Type; + + if (functionSymbol.Parameters.Count != visitable.Parameters.Count + (methodCall ? 1 : 0)) + throw new WrongNumberOfArguments( + visitable.Segment, + expected: functionSymbol.Parameters.Count, + actual: visitable.Parameters.Count); + + visitable.Parameters.Zip(functionSymbol.Parameters.ToArray()[(methodCall ? 1 : 0)..]) + .ToList().ForEach(pair => + { + var (expr, expected) = pair; + var actualType = expr.Accept(this); + if (!actualType.Equals(expected.Type)) + throw new WrongTypeOfArgument(expr.Segment, expected.Type, actualType); + }); + + Type undefined = "undefined"; + if (functionSymbol.Type.Equals(undefined)) + { + var declaration = _functionStorage.Get(functionSymbol); + functionReturnType = declaration.Accept(this); + } + + return functionReturnType; + } + + public Type Visit(FunctionDeclaration visitable) + { + var symbol = visitable.SymbolTable.FindSymbol(visitable.Name); + _functionStorage.RemoveIfPresent(symbol); + visitable.Statements.Accept(this); + + var returnStatements = visitable.GetReturnStatements() + .Select(x => new + { + Statement = x, + Type = x.Accept(this) + }); + Type undefined = "undefined"; + if (symbol.Type.Equals(undefined)) + { + var returnStatementTypes = returnStatements + .GroupBy(x => x.Type) + .Select(x => x.Key) + .ToList(); + if (returnStatementTypes.Count > 1) + throw new CannotDefineType(visitable.Segment); + symbol.DefineReturnType(returnStatementTypes.ElementAtOrDefault(0) ?? "void"); + } + else + { + var wrongReturn = returnStatements + .FirstOrDefault(x => !x.Type.Equals(symbol.Type)); + if (wrongReturn is not null) + throw new WrongReturnType( + wrongReturn.Statement.Segment, + expected: symbol.Type, + actual: wrongReturn.Type); + } + + Type @void = "void"; + var hasReturnStatement = visitable.HasReturnStatement(); + if (!symbol.Type.Equals(@void) && !hasReturnStatement) + throw new FunctionWithoutReturnStatement(visitable.Segment); + + return symbol.Type; + } + + public Type Visit(BlockStatement visitable) + { + visitable.StatementList.ForEach(x => x.Accept(this)); + return "undefined"; + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IDefaultValueForTypeCalculator.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IDefaultValueForTypeCalculator.cs new file mode 100644 index 00000000..a833943c --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IDefaultValueForTypeCalculator.cs @@ -0,0 +1,6 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface IDefaultValueForTypeCalculator +{ + public object GetDefaultValueForType(Type type); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IFunctionWithUndefinedReturnStorage.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IFunctionWithUndefinedReturnStorage.cs new file mode 100644 index 00000000..9f75a9c5 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IFunctionWithUndefinedReturnStorage.cs @@ -0,0 +1,15 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface IFunctionWithUndefinedReturnStorage +{ + void Save(FunctionSymbol symbol, FunctionDeclaration declaration); + + FunctionDeclaration Get(FunctionSymbol symbol); + + void RemoveIfPresent(FunctionSymbol symbol); + + IEnumerable Flush(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IJavaScriptTypesProvider.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IJavaScriptTypesProvider.cs new file mode 100644 index 00000000..5312c5f2 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IJavaScriptTypesProvider.cs @@ -0,0 +1,6 @@ +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface IJavaScriptTypesProvider +{ + IEnumerable GetDefaultTypes(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IMethodStorage.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IMethodStorage.cs new file mode 100644 index 00000000..d9dfff56 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IMethodStorage.cs @@ -0,0 +1,11 @@ +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface IMethodStorage +{ + void BindMethod(ObjectType objectType, FunctionSymbol method); + + IReadOnlyDictionary GetAvailableMethods(ObjectType objectType); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IStandardLibraryProvider.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IStandardLibraryProvider.cs new file mode 100644 index 00000000..4da013d6 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/IStandardLibraryProvider.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.IR.CheckSemantics.Variables; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface IStandardLibraryProvider +{ + SymbolTable GetStandardLibrary(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ISymbolTableInitializerService.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ISymbolTableInitializerService.cs new file mode 100644 index 00000000..cc06be62 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ISymbolTableInitializerService.cs @@ -0,0 +1,10 @@ +using HydraScript.Lib.IR.Ast; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface ISymbolTableInitializerService +{ + void InitThroughParent(AbstractSyntaxTreeNode node); + + void InitWithNewScope(AbstractSyntaxTreeNode node); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ITypeDeclarationsResolver.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ITypeDeclarationsResolver.cs new file mode 100644 index 00000000..8576b169 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/ITypeDeclarationsResolver.cs @@ -0,0 +1,10 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +public interface ITypeDeclarationsResolver +{ + void Store(TypeDeclaration declaration); + + void Resolve(); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/DefaultValueForTypeCalculator.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/DefaultValueForTypeCalculator.cs new file mode 100644 index 00000000..90c8baee --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/DefaultValueForTypeCalculator.cs @@ -0,0 +1,30 @@ +using HydraScript.Lib.IR.CheckSemantics.Types; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.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/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/FunctionWithUndefinedReturnStorage.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/FunctionWithUndefinedReturnStorage.cs new file mode 100644 index 00000000..3f4bab11 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/FunctionWithUndefinedReturnStorage.cs @@ -0,0 +1,40 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class FunctionWithUndefinedReturnStorage : IFunctionWithUndefinedReturnStorage +{ + private readonly Dictionary _declarations = new(); + private readonly Dictionary _keysWithOrder = new(); + + public void Save(FunctionSymbol symbol, FunctionDeclaration declaration) + { + _declarations[symbol.Id] = declaration; + _keysWithOrder[symbol.Id] = _declarations.Count; + } + + public FunctionDeclaration Get(FunctionSymbol symbol) + { + if (!_declarations.Remove(symbol.Id, out var declaration)) + throw new InvalidOperationException(message: "Cannot get function that has not been saved"); + + _keysWithOrder.Remove(symbol.Id); + return declaration; + } + + public void RemoveIfPresent(FunctionSymbol symbol) + { + _declarations.Remove(symbol.Id); + _keysWithOrder.Remove(symbol.Id); + } + + public IEnumerable Flush() => _declarations + .OrderBy(kvp => _keysWithOrder[kvp.Key]) + .Select(x => + { + _declarations.Remove(x.Key); + _keysWithOrder.Remove(x.Key); + return x.Value; + }); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/JavaScriptTypesProvider.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/JavaScriptTypesProvider.cs new file mode 100644 index 00000000..2af4f36f --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/JavaScriptTypesProvider.cs @@ -0,0 +1,16 @@ +using HydraScript.Lib.IR.CheckSemantics.Types; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class JavaScriptTypesProvider : IJavaScriptTypesProvider +{ + public IEnumerable GetDefaultTypes() + { + yield return "number"; + yield return "boolean"; + yield return "string"; + yield return new NullType(); + yield return "undefined"; + yield return "void"; + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/MethodStorage.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/MethodStorage.cs new file mode 100644 index 00000000..bb98d574 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/MethodStorage.cs @@ -0,0 +1,20 @@ +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class MethodStorage : IMethodStorage +{ + private readonly Dictionary> _bindings = new(); + + public void BindMethod(ObjectType objectType, FunctionSymbol method) + { + objectType.AddMethod(method.Id); + if (!_bindings.ContainsKey(objectType)) + _bindings[objectType] = new Dictionary(); + _bindings[objectType][method.Id] = method; + } + + public IReadOnlyDictionary GetAvailableMethods(ObjectType objectType) => + _bindings.GetValueOrDefault(objectType, new Dictionary()); +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/StandardLibraryProvider.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/StandardLibraryProvider.cs new file mode 100644 index 00000000..35d9494f --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/StandardLibraryProvider.cs @@ -0,0 +1,38 @@ +using HydraScript.Lib.IR.CheckSemantics.Variables; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class StandardLibraryProvider : IStandardLibraryProvider +{ + private readonly IJavaScriptTypesProvider _provider; + + public StandardLibraryProvider(IJavaScriptTypesProvider provider) => + _provider = provider; + + public SymbolTable GetStandardLibrary() + { + var library = new SymbolTable(); + + foreach (var type in _provider.GetDefaultTypes()) + { + library.AddSymbol(new TypeSymbol(type)); + } + + var print = new FunctionSymbol( + "print", + new List + { + new VariableSymbol("str", "string") + }, + "void", + isEmpty: false + ); + + library.AddSymbol(print); + + var symbolTable = new SymbolTable(); + symbolTable.AddOpenScope(library); + return symbolTable; + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/SymbolTableInitializerService.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/SymbolTableInitializerService.cs new file mode 100644 index 00000000..8564f59a --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/SymbolTableInitializerService.cs @@ -0,0 +1,15 @@ +using HydraScript.Lib.IR.Ast; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class SymbolTableInitializerService : ISymbolTableInitializerService +{ + public void InitThroughParent(AbstractSyntaxTreeNode node) => + node.SymbolTable = node.Parent.SymbolTable; + + public void InitWithNewScope(AbstractSyntaxTreeNode node) + { + node.SymbolTable = new(); + node.SymbolTable.AddOpenScope(node.Parent.SymbolTable); + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/TypeDeclarationsResolver.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/TypeDeclarationsResolver.cs new file mode 100644 index 00000000..0d8134b8 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/Services/Impl/TypeDeclarationsResolver.cs @@ -0,0 +1,51 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; + +internal class TypeDeclarationsResolver : ITypeDeclarationsResolver +{ + private readonly Queue _declarationsToResolve = new(); + private readonly IJavaScriptTypesProvider _provider; + + public TypeDeclarationsResolver(IJavaScriptTypesProvider provider) => + _provider = provider; + + public void Store(TypeDeclaration declaration) => + _declarationsToResolve.Enqueue(declaration); + + public void Resolve() + { + var defaults = _provider.GetDefaultTypes() + .Select(x => new TypeSymbol(x)) + .ToList(); + + foreach (var declarationToResolve in _declarationsToResolve) + { + declarationToResolve.SymbolTable.AddSymbol( + new TypeSymbol( + declarationToResolve.BuildType(), + declarationToResolve.TypeId)); + } + + while (_declarationsToResolve.Any()) + { + var declarationToResolve = _declarationsToResolve.Dequeue(); + + var typeSymbol = declarationToResolve.SymbolTable + .FindSymbol(declarationToResolve.TypeId); + + var resolvingCandidates = declarationToResolve.SymbolTable + .GetAvailableSymbols() + .OfType() + .Except(defaults); + + foreach (var referenceSymbol in resolvingCandidates) + { + typeSymbol.Type.ResolveReference( + referenceSymbol.Type, + referenceSymbol.Id); + } + } + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer.cs new file mode 100644 index 00000000..94bf278a --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/SymbolTableInitializer.cs @@ -0,0 +1,54 @@ +using HydraScript.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors; + +public class SymbolTableInitializer : + IVisitor, + IVisitor, + IVisitor, + IVisitor +{ + private readonly ISymbolTableInitializerService _initializerService; + private readonly IStandardLibraryProvider _provider; + + public SymbolTableInitializer( + ISymbolTableInitializerService initializerService, + IStandardLibraryProvider provider) + { + _initializerService = initializerService; + _provider = provider; + } + + public Unit Visit(AbstractSyntaxTreeNode visitable) + { + _initializerService.InitThroughParent(visitable); + foreach (var child in visitable) + child.Accept(this); + return default; + } + + public Unit Visit(ScriptBody visitable) + { + visitable.SymbolTable = _provider.GetStandardLibrary(); + visitable.StatementList.ForEach(item => item.Accept(this)); + return default; + } + + public Unit Visit(FunctionDeclaration visitable) + { + _initializerService.InitWithNewScope(visitable); + visitable.Statements.Accept(this); + return default; + } + + public Unit Visit(BlockStatement visitable) + { + _initializerService.InitWithNewScope(visitable); + visitable.StatementList.ForEach(item => item.Accept(this)); + return default; + } +} \ No newline at end of file diff --git a/HydraScript.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader.cs b/HydraScript.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader.cs new file mode 100644 index 00000000..871eb898 --- /dev/null +++ b/HydraScript.Lib/IR/CheckSemantics/Visitors/TypeSystemLoader.cs @@ -0,0 +1,55 @@ +using HydraScript.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.CheckSemantics.Exceptions; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services; + +namespace HydraScript.Lib.IR.CheckSemantics.Visitors; + +public class TypeSystemLoader : + IVisitor, + IVisitor, + IVisitor +{ + private readonly ITypeDeclarationsResolver _resolver; + private readonly ISet _defaultTypes; + + public TypeSystemLoader( + ITypeDeclarationsResolver resolver, + IJavaScriptTypesProvider provider) + { + _resolver = resolver; + _defaultTypes = provider.GetDefaultTypes().ToHashSet(); + } + + 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) + { + if (visitable.SymbolTable.ContainsSymbol(visitable.TypeId) || + _defaultTypes.Contains(visitable.TypeId.Name)) + throw new DeclarationAlreadyExists(visitable.TypeId); + + visitable.SymbolTable.AddSymbol( + new TypeSymbol( + visitable.TypeId.Name, + visitable.TypeId)); + + _resolver.Store(visitable); + return default; + } +} \ No newline at end of file diff --git a/HydraScript.Tests/GlobalUsings.cs b/HydraScript.Tests/GlobalUsings.cs new file mode 100644 index 00000000..62a254b9 --- /dev/null +++ b/HydraScript.Tests/GlobalUsings.cs @@ -0,0 +1,3 @@ +// Global using directives + +global using Type = HydraScript.Lib.IR.CheckSemantics.Types.Type; \ No newline at end of file diff --git a/HydraScript.Tests/Helpers/ListExtensions.cs b/HydraScript.Tests/Helpers/ListExtensions.cs new file mode 100644 index 00000000..76d0f164 --- /dev/null +++ b/HydraScript.Tests/Helpers/ListExtensions.cs @@ -0,0 +1,14 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Instructions; + +namespace HydraScript.Tests.Helpers; + +public static class ListExtensions +{ + public static AddressedInstructions ToAddressedInstructions(this List instructions) + { + var result = new AddressedInstructions(); + instructions.ForEach(x => result.Add(x)); + return result; + } +} \ No newline at end of file diff --git a/HydraScript.Tests/Helpers/MockExtensions.cs b/HydraScript.Tests/Helpers/MockExtensions.cs new file mode 100644 index 00000000..31c53040 --- /dev/null +++ b/HydraScript.Tests/Helpers/MockExtensions.cs @@ -0,0 +1,38 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using Microsoft.Extensions.Options; +using Moq; + +namespace HydraScript.Tests.Helpers; + +public static class MockExtensions +{ + public static Mock Trackable(this Mock halt) + { + halt.Setup(x => x.Execute(It.IsAny())) + .Returns(new HashAddress(seed: 0)).Verifiable(); + halt.Setup(x => x.End()).Returns(true); + return halt; + } + + public static IOptions ToOptions + (this Mock commandLineSettings) => + Options.Create(commandLineSettings.Object); + + public static Mock ToInstructionMock(this int number) + { + var result = new Mock(MockBehavior.Default) + { + CallBase = true + }; + + result.Setup(x => x.GetHashCode()) + .Returns(number); + + result.Setup(x => x.ToString()) + .Returns(number.ToString()); + + return result; + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Interpreter.Tests.csproj b/HydraScript.Tests/HydraScript.Tests.csproj similarity index 87% rename from Interpreter.Tests/Interpreter.Tests.csproj rename to HydraScript.Tests/HydraScript.Tests.csproj index 4a4d264c..31970460 100644 --- a/Interpreter.Tests/Interpreter.Tests.csproj +++ b/HydraScript.Tests/HydraScript.Tests.csproj @@ -12,8 +12,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -30,8 +30,8 @@ - - + + diff --git a/Interpreter.Tests/Properties/AssemblyInfo.cs b/HydraScript.Tests/Properties/AssemblyInfo.cs similarity index 100% rename from Interpreter.Tests/Properties/AssemblyInfo.cs rename to HydraScript.Tests/Properties/AssemblyInfo.cs diff --git a/HydraScript.Tests/Stubs/SemanticExceptionStub.cs b/HydraScript.Tests/Stubs/SemanticExceptionStub.cs new file mode 100644 index 00000000..aa55647a --- /dev/null +++ b/HydraScript.Tests/Stubs/SemanticExceptionStub.cs @@ -0,0 +1,5 @@ +using HydraScript.Lib.IR.CheckSemantics.Exceptions; + +namespace HydraScript.Tests.Stubs; + +public class SemanticExceptionStub : SemanticException { } \ No newline at end of file diff --git a/HydraScript.Tests/TestData/InstructionsData.cs b/HydraScript.Tests/TestData/InstructionsData.cs new file mode 100644 index 00000000..506c1276 --- /dev/null +++ b/HydraScript.Tests/TestData/InstructionsData.cs @@ -0,0 +1,127 @@ +using System.Collections; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Create; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; +using HydraScript.Lib.BackEnd.Instructions.WithJump; +using HydraScript.Lib.BackEnd.Values; + +namespace HydraScript.Tests.TestData; + +public class InstructionsData : IEnumerable +{ + public IEnumerator GetEnumerator() + { + yield return new object[] + { + new AsString(new Name("num")) + { + Left = "str" + }, + "str = num as string" + }; + yield return new object[] + { + new BeginBlock(BlockType.Function, blockId: "func") + { + Address = new Label("Start_func") + }, + "Start_func:\n\tBeginFunction func" + }; + yield return new object[] + { + new CallFunction(new FunctionInfo("func"), 2, false), + "Call func, 2" + }; + yield return new object[] + { + new CallFunction(new FunctionInfo("func"), 2, true) + { + Left = "ret" + }, + "ret = Call func, 2" + }; + yield return new object[] + { + new CreateArray("arr", 5), + "array arr = [5]" + }; + yield return new object[] + { + new CreateObject("obj"), + "object obj = {}" + }; + yield return new object[] + { + new DotAssignment("obj", new Constant("prop"), new Constant(3)), + "obj.prop = 3" + }; + yield return new object[] + { + new EndBlock(BlockType.Function, blockId: "func") + { + Address = new Label("End_func") + }, + "End_func:\n\tEndFunction func" + }; + yield return new object[] + { + new Goto(new Label("10")), + "Goto 10" + }; + yield return new object[] + { + new Halt(), + "End" + }; + yield return new object[] + { + new IfNotGoto(new Name("test"), new Label("17")), + "IfNot test Goto 17" + }; + yield return new object[] + { + new IndexAssignment("arr", new Constant(1), new Constant(1)), + "arr[1] = 1" + }; + yield return new object[] + { + new Print(new Name("str")), + "Print str" + }; + yield return new object[] + { + new PushParameter("param", new Name("value")), + "PushParameter param = value" + }; + yield return new object[] + { + new RemoveFromArray("arr", new Constant(0)), + "RemoveFrom arr at 0" + }; + yield return new object[] + { + new Return(), + "Return" + }; + yield return new object[] + { + new Return(new Name("result")), + "Return result" + }; + yield return new object[] + { + new Simple("a", (new Name("b"), new Name("c")), "+"), + "a = b + c" + }; + yield return new object[] + { + new Simple("b", (null, new Name("c")), "-"), + "b = -c" + }; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} \ No newline at end of file diff --git a/Interpreter.Tests/TestData/LexerData.cs b/HydraScript.Tests/TestData/LexerData.cs similarity index 95% rename from Interpreter.Tests/TestData/LexerData.cs rename to HydraScript.Tests/TestData/LexerData.cs index a6addcfb..7d60d269 100644 --- a/Interpreter.Tests/TestData/LexerData.cs +++ b/HydraScript.Tests/TestData/LexerData.cs @@ -1,6 +1,6 @@ using System.Collections; -namespace Interpreter.Tests.TestData; +namespace HydraScript.Tests.TestData; public class LexerSuccessData : IEnumerable { diff --git a/Interpreter.Tests/TestData/ParserData.cs b/HydraScript.Tests/TestData/ParserData.cs similarity index 52% rename from Interpreter.Tests/TestData/ParserData.cs rename to HydraScript.Tests/TestData/ParserData.cs index 8a9cda65..317c7e12 100644 --- a/Interpreter.Tests/TestData/ParserData.cs +++ b/HydraScript.Tests/TestData/ParserData.cs @@ -1,17 +1,24 @@ using System.Collections; -namespace Interpreter.Tests.TestData; +namespace HydraScript.Tests.TestData; public class ParserSuccessTestData : IEnumerable { public IEnumerator GetEnumerator() { + yield return new object[] { "-21" }; + yield return new object[] { "!false" }; + yield return new object[] { "~[]" }; + yield return new object[] { "x = ([1,2] ++ [3,4])::0" }; yield return new object[] {"i[0].j"}; yield return new object[] {"i[0].j()"}; yield return new object[] {"i = 1"}; yield return new object[] {"i[0] = 1"}; yield return new object[] {"i[a.b][1].x(1)"}; yield return new object[] {"(1 + 2) * (3 - (2 / 2)) as string"}; + yield return new object[] { "return {x:1;y:2;}" }; + yield return new object[] { "while (~arr != 0) { arr::0 continue }" }; + yield return new object[] { "if (!(true || (false && false))) { break } else { break }" }; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/HydraScript.Tests/Unit/BackEnd/AddressedInstructionsTests.cs b/HydraScript.Tests/Unit/BackEnd/AddressedInstructionsTests.cs new file mode 100644 index 00000000..dd1e719f --- /dev/null +++ b/HydraScript.Tests/Unit/BackEnd/AddressedInstructionsTests.cs @@ -0,0 +1,95 @@ +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment; +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Tests.Helpers; +using Xunit; + +namespace HydraScript.Tests.Unit.BackEnd; + +public class AddressedInstructionsTests +{ + [Fact] + public void EnumerationPreservedAfterRemovalTest() + { + var instructions = new List + { + new AsString(new Constant(2)) + { + Left = "s" + }, + new Print(new Name("s")), + new Halt() + }.ToAddressedInstructions(); + + instructions.Remove(instructions[instructions.Start.Next]); + + Assert.Same(instructions.Last(), instructions[instructions.Start.Next]); + } + + [Fact] + public void RemovalOfLastDoesNotThrowTest() + { + var instructions = new List + { + new AsString(new Constant(2)), + new Halt() + }.ToAddressedInstructions(); + + Assert.Null(Record.Exception(() => instructions.Remove(instructions.Last()))); + Assert.Null(instructions.Start.Next); + } + + [Fact] + public void ReplacementPreservesOrderTest() + { + var instructions = new AddressedInstructions + { + new Simple("a", (new Constant(1), new Constant(2)), "-"), + { + new AsString(new Constant(true)) + { Left = "s" }, + "as_str" + }, + new Print(new Name("s")) + }; + + var old = instructions[new Label("as_str")]; + var @new = new AsString(new Name("a")) { Left = "s" }; + instructions.Replace(old, @new); + + var prev = instructions.First(); + var next = instructions.Last(); + + Assert.Same(@new, instructions[prev.Address.Next]); + Assert.Same(next, instructions[@new.Address.Next]); + } + + [Fact] + public void GetEnumeratorTests() + { + AddressedInstructions collection = new(); + collection.Add(1.ToInstructionMock().Object); + + var collectionToAdd = new AddressedInstructions + { + 2.ToInstructionMock().Object, + 3.ToInstructionMock().Object, + 4.ToInstructionMock().Object + }; + + collection.AddRange(collectionToAdd); + + collection.Add(5.ToInstructionMock().Object); + + Assert.Collection( + collection.Select(x => x.ToString()), + x => Assert.Equal("1", x), + x => Assert.Equal("2", x), + x => Assert.Equal("3", x), + x => Assert.Equal("4", x), + x => Assert.Equal("5", x) + ); + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/BackEnd/CallTests.cs b/HydraScript.Tests/Unit/BackEnd/CallTests.cs similarity index 50% rename from Interpreter.Tests/Unit/BackEnd/CallTests.cs rename to HydraScript.Tests/Unit/BackEnd/CallTests.cs index 48571a99..e774efcd 100644 --- a/Interpreter.Tests/Unit/BackEnd/CallTests.cs +++ b/HydraScript.Tests/Unit/BackEnd/CallTests.cs @@ -1,20 +1,21 @@ -using Interpreter.Lib.BackEnd; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; using Xunit; -namespace Interpreter.Tests.Unit.BackEnd; +namespace HydraScript.Tests.Unit.BackEnd; public class CallTests { [Fact] public void ToStringCorrect() { - var call = new Call(9, new FunctionInfo("func"), + var call = new Call(new Label("9"), new FunctionInfo("func"), new List<(string Id, object Value)> { ("arg", 1) } ); - const string expected = "9 => 0: func(arg: 1)"; + const string expected = "9:\n\t => Start_func:\n\t: func(arg: 1)"; Assert.Equal(expected, call.ToString()); } } \ No newline at end of file diff --git a/HydraScript.Tests/Unit/BackEnd/InstructionsTests.cs b/HydraScript.Tests/Unit/BackEnd/InstructionsTests.cs new file mode 100644 index 00000000..9caed316 --- /dev/null +++ b/HydraScript.Tests/Unit/BackEnd/InstructionsTests.cs @@ -0,0 +1,23 @@ +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithJump; +using HydraScript.Tests.TestData; +using Xunit; + +namespace HydraScript.Tests.Unit.BackEnd; + +public class InstructionsTests +{ + [Theory] + [ClassData(typeof(InstructionsData))] + public void ToStringCorrectTest(Instruction instruction, string expected) => + Assert.Equal(expected, instruction.ToString()); + + [Fact] + public void GotoJumpChangedTest() + { + var @goto = new Goto(new Label("1")); + @goto.SetJump(new Label("5")); + Assert.Equal(new Label("5"), @goto.Execute(vm: null)); + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/BackEnd/ValuesTests.cs b/HydraScript.Tests/Unit/BackEnd/ValuesTests.cs similarity index 83% rename from Interpreter.Tests/Unit/BackEnd/ValuesTests.cs rename to HydraScript.Tests/Unit/BackEnd/ValuesTests.cs index 20dc7dc6..866fc92b 100644 --- a/Interpreter.Tests/Unit/BackEnd/ValuesTests.cs +++ b/HydraScript.Tests/Unit/BackEnd/ValuesTests.cs @@ -1,7 +1,7 @@ -using Interpreter.Lib.BackEnd.Values; +using HydraScript.Lib.BackEnd.Values; using Xunit; -namespace Interpreter.Tests.Unit.BackEnd; +namespace HydraScript.Tests.Unit.BackEnd; public class ValuesTests { @@ -9,7 +9,7 @@ public class ValuesTests public void ConstantNotEqualToNameTest() { var name = new Name("a"); - var constant = new Constant("a", "a"); + var constant = new Constant("a"); Assert.False(name.Equals(constant)); Assert.False(constant.Equals(name)); @@ -37,7 +37,7 @@ public void NameEqualsCorrectTest() [Fact] public void ConstantEqualsCorrectTest() { - var constant1 = new Constant(1, "1"); + var constant1 = new Constant(1); var constant2 = new Constant(1, "1.0"); Assert.True(constant1.Equals(constant2)); diff --git a/HydraScript.Tests/Unit/BackEnd/VirtualMachineTests.cs b/HydraScript.Tests/Unit/BackEnd/VirtualMachineTests.cs new file mode 100644 index 00000000..387d9d99 --- /dev/null +++ b/HydraScript.Tests/Unit/BackEnd/VirtualMachineTests.cs @@ -0,0 +1,158 @@ +#nullable enable +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Addresses; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Create; +using HydraScript.Lib.BackEnd.Instructions.WithAssignment.ComplexData.Write; +using HydraScript.Lib.BackEnd.Instructions.WithJump; +using HydraScript.Lib.BackEnd.Values; +using HydraScript.Tests.Helpers; +using Moq; +using Xunit; + +namespace HydraScript.Tests.Unit.BackEnd; + +public class VirtualMachineTests +{ + private readonly VirtualMachine _vm; + + public VirtualMachineTests() + { + _vm = new(new(), new(), new(), TextWriter.Null); + } + + [Fact] + public void CorrectPrintToOutTest() + { + var writer = new Mock(); + writer.Setup(x => x.WriteLine(It.IsAny())) + .Verifiable(); + + var vm = new VirtualMachine(new(), new Stack(new[] { new Frame(new HashAddress(0)) }), new(), writer.Object); + var print = new Print(new Constant(223)) + { + Address = new HashAddress(1) + }; + + print.Execute(vm); + writer.Verify(x => x.WriteLine( + It.Is(v => v!.Equals(223)) + ), Times.Once()); + } + + [Fact] + public void ProgramWithoutHaltWillNotRunTest() + { + var program = new AddressedInstructions(); + Assert.Throws(() => _vm.Run(program)); + + program.Add(new Halt()); + Assert.Null(Record.Exception(() => _vm.Run(program))); + } + + [Fact] + public void VirtualMachineFramesClearedAfterExecutionTest() + { + var program = new List + { + new Simple("a", (new Constant(1), new Constant(2)), "+"), + new AsString(new Name("a")) + { + Left = "s" + }, + new Halt() + }.ToAddressedInstructions(); + + _vm.Run(program); + Assert.Empty(_vm.Frames); + } + + [Fact] + public void VirtualMachineHandlesRecursionTest() + { + var halt = new Mock().Trackable(); + var factorial = new FunctionInfo("fact"); + var program = new AddressedInstructions + { + new Goto(factorial.End), + { new BeginBlock(BlockType.Function, blockId: factorial.ToString()), factorial.Start.Name }, + new Simple("_t2", (new Name("n"), new Constant(2)), "<"), + new IfNotGoto(new Name("_t2"), new Label("5")), + new Return(new Name("n")), + { new Simple("_t5", (new Name("n"), new Constant(1)), "-"), "5" }, + new PushParameter("n", new Name("_t5")), + new CallFunction(factorial, 1, true) + { + Left = "f" + }, + new Simple("_t8", (new Name("n"), new Name("f")), "*"), + new Return(new Name("_t8")), + { new EndBlock(BlockType.Function, blockId: factorial.ToString()), factorial.End.Name }, + new PushParameter("n", new Constant(6)), + new CallFunction(factorial, 1, true) + { + Left = "fa6" + }, + halt.Object + }; + + _vm.Run(program); + Assert.Empty(_vm.CallStack); + Assert.Empty(_vm.Arguments); + halt.Verify(x => x.Execute( + It.Is( + vm => Convert.ToInt32(vm.Frames.Peek()["fa6"]) == 720 + ) + ), Times.Once()); + _vm.Frames.Pop(); + } + + [Fact] + public void CreateArrayReservesCertainSpaceTest() + { + var vm = new VirtualMachine(); + vm.Frames.Push(new Frame(new HashAddress(0))); + + var createArray = new CreateArray("arr", 6) + { + Address = new HashAddress(1) + }; + createArray.Execute(vm); + Assert.Equal(6, ((List) vm.Frames.Peek()["arr"]).Count); + + var indexAssignment = new IndexAssignment("arr", new Constant(0), new Constant(0)) + { + Address = new HashAddress(2) + }; + indexAssignment.Execute(vm); + Assert.Equal(0, ((List) vm.Frames.Peek()["arr"])[0]); + + var removeFromArray = new RemoveFromArray("arr", new Constant(5)) + { + Address = new HashAddress(3) + }; + removeFromArray.Execute(vm); + Assert.Equal(5, ((List) vm.Frames.Peek()["arr"]).Count); + } + + [Fact] + public void ObjectCreationTest() + { + var halt = new Mock().Trackable(); + var program = new List + { + new CreateObject("obj"), + new DotAssignment("obj", new Constant("prop"), new Constant(null, "null")), + halt.Object + }.ToAddressedInstructions(); + + _vm.Run(program); + halt.Verify(x => x.Execute( + It.Is( + vm => ((Dictionary)vm.Frames.Peek()["obj"])["prop"] == null + ) + ), Times.Once()); + _vm.Frames.Pop(); + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/FrontEnd/LexerTests.cs b/HydraScript.Tests/Unit/FrontEnd/LexerTests.cs similarity index 84% rename from Interpreter.Tests/Unit/FrontEnd/LexerTests.cs rename to HydraScript.Tests/Unit/FrontEnd/LexerTests.cs index fe187cb8..41da0480 100644 --- a/Interpreter.Tests/Unit/FrontEnd/LexerTests.cs +++ b/HydraScript.Tests/Unit/FrontEnd/LexerTests.cs @@ -1,10 +1,10 @@ -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Impl; -using Interpreter.Services.Providers.Impl.StructureProvider; -using Interpreter.Tests.TestData; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Impl; +using HydraScript.Services.Providers.StructureProvider.Impl; +using HydraScript.Tests.TestData; using Xunit; -namespace Interpreter.Tests.Unit.FrontEnd; +namespace HydraScript.Tests.Unit.FrontEnd; public class LexerTests { diff --git a/Interpreter.Tests/Unit/FrontEnd/ParserTests.cs b/HydraScript.Tests/Unit/FrontEnd/ParserTests.cs similarity index 66% rename from Interpreter.Tests/Unit/FrontEnd/ParserTests.cs rename to HydraScript.Tests/Unit/FrontEnd/ParserTests.cs index 2628b567..ebb513c8 100644 --- a/Interpreter.Tests/Unit/FrontEnd/ParserTests.cs +++ b/HydraScript.Tests/Unit/FrontEnd/ParserTests.cs @@ -1,11 +1,11 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Impl; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.FrontEnd.TopDownParse.Impl; -using Interpreter.Services.Providers.Impl.StructureProvider; -using Interpreter.Tests.TestData; +using HydraScript.Lib.FrontEnd.GetTokens.Impl; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.FrontEnd.TopDownParse.Impl; +using HydraScript.Services.Providers.StructureProvider.Impl; +using HydraScript.Tests.TestData; using Xunit; -namespace Interpreter.Tests.Unit.FrontEnd; +namespace HydraScript.Tests.Unit.FrontEnd; public class ParserTests { diff --git a/Interpreter.Tests/Unit/FrontEnd/StructureTests.cs b/HydraScript.Tests/Unit/FrontEnd/StructureTests.cs similarity index 80% rename from Interpreter.Tests/Unit/FrontEnd/StructureTests.cs rename to HydraScript.Tests/Unit/FrontEnd/StructureTests.cs index 9035b6a5..4e822857 100644 --- a/Interpreter.Tests/Unit/FrontEnd/StructureTests.cs +++ b/HydraScript.Tests/Unit/FrontEnd/StructureTests.cs @@ -1,8 +1,8 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; using Xunit; -namespace Interpreter.Tests.Unit.FrontEnd; +namespace HydraScript.Tests.Unit.FrontEnd; public class StructureTests { diff --git a/HydraScript.Tests/Unit/IR/AstNodeTests.cs b/HydraScript.Tests/Unit/IR/AstNodeTests.cs new file mode 100644 index 00000000..55367f6d --- /dev/null +++ b/HydraScript.Tests/Unit/IR/AstNodeTests.cs @@ -0,0 +1,31 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; +using Xunit; + +namespace HydraScript.Tests.Unit.IR; + +public class AstNodeTests +{ + [Fact] + public void PrecedenceTest() + { + var lexicalDecl = new LexicalDeclaration(false); + var stmtItemList = new List + { + lexicalDecl + }; + // ReSharper disable once UnusedVariable + var func = new FunctionDeclaration( + name: new IdentifierReference(name: Guid.NewGuid().ToString()), + new TypeIdentValue( + TypeId: new IdentifierReference( + name: Guid.NewGuid().ToString())), + arguments: new List(), + new BlockStatement(stmtItemList)); + + Assert.True(lexicalDecl.ChildOf()); + } +} \ No newline at end of file diff --git a/HydraScript.Tests/Unit/IR/FunctionWithUndefinedReturnStorageTests.cs b/HydraScript.Tests/Unit/IR/FunctionWithUndefinedReturnStorageTests.cs new file mode 100644 index 00000000..8433b945 --- /dev/null +++ b/HydraScript.Tests/Unit/IR/FunctionWithUndefinedReturnStorageTests.cs @@ -0,0 +1,41 @@ +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; +using HydraScript.Lib.IR.Ast.Impl.Nodes.Statements; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; +using Moq; +using Xunit; + +namespace HydraScript.Tests.Unit.IR; + +public class FunctionWithUndefinedReturnStorageTests +{ + [Fact] + public void StorageIsEmptyAfterFlushTest() + { + const string functionName = nameof(functionName); + IFunctionWithUndefinedReturnStorage storage = new FunctionWithUndefinedReturnStorage(); + + var symbol = new FunctionSymbol( + id: functionName, + parameters: new List(), + "undefined", + isEmpty: false); + + var decl = new FunctionDeclaration( + name: new IdentifierReference(functionName), + returnTypeValue: Mock.Of(), + arguments: new List(), + new BlockStatement(new List())); + + storage.Save(symbol, decl); + + var declarations = storage.Flush(); + Assert.Contains(decl, declarations); + + Assert.Empty(storage.Flush()); + } +} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/IR/SymbolTableTests.cs b/HydraScript.Tests/Unit/IR/SymbolTableTests.cs similarity index 83% rename from Interpreter.Tests/Unit/IR/SymbolTableTests.cs rename to HydraScript.Tests/Unit/IR/SymbolTableTests.cs index d526c30d..4f52e041 100644 --- a/Interpreter.Tests/Unit/IR/SymbolTableTests.cs +++ b/HydraScript.Tests/Unit/IR/SymbolTableTests.cs @@ -1,10 +1,10 @@ -using Interpreter.Lib.IR.Ast.Nodes; -using Interpreter.Lib.IR.CheckSemantics.Variables; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; +using HydraScript.Lib.IR.Ast.Impl.Nodes; +using HydraScript.Lib.IR.CheckSemantics.Variables; +using HydraScript.Lib.IR.CheckSemantics.Variables.Symbols; using Moq; using Xunit; -namespace Interpreter.Tests.Unit.IR; +namespace HydraScript.Tests.Unit.IR; public class SymbolTableTests { @@ -14,7 +14,7 @@ public void FindSymbolTest() const string id = "ident"; var type = new Mock(id); - var symbol = new Mock(id, type.Object); + var symbol = new Mock(); symbol.Setup(s => s.Id).Returns(id); symbol.Setup(s => s.Type).Returns(type.Object); @@ -46,7 +46,7 @@ public void FlatteningScopeTest() const string id = "ident"; var type = new Mock(id); - var symbol = new Mock(id, type.Object); + var symbol = new Mock(); symbol.Setup(s => s.Id).Returns(id); symbol.Setup(s => s.Type).Returns(type.Object); diff --git a/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs b/HydraScript.Tests/Unit/IR/Types/ObjectTypeTests.cs similarity index 73% rename from Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs rename to HydraScript.Tests/Unit/IR/Types/ObjectTypeTests.cs index 73422c99..79db637e 100644 --- a/Interpreter.Tests/Unit/IR/Types/ObjectTypeTests.cs +++ b/HydraScript.Tests/Unit/IR/Types/ObjectTypeTests.cs @@ -1,7 +1,7 @@ -using Interpreter.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Types; using Xunit; -namespace Interpreter.Tests.Unit.IR.Types; +namespace HydraScript.Tests.Unit.IR.Types; public class ObjectTypeTests { @@ -50,7 +50,6 @@ public void RecursiveTypeReferenceResolvingTest() { var number = new Type("number"); var array = new ArrayType(new Type("self")); - var method = new FunctionType(number, new List { new("self") }); var nullable = new NullableType(new Type("self")); var linkedListType = new ObjectType( new List @@ -61,17 +60,15 @@ public void RecursiveTypeReferenceResolvingTest() new("next", new Type("self")) })), new("children", array), - new("parent", nullable), - new("compare", method) + new("parent", nullable) } ); - linkedListType.ResolveSelfReferences("self"); + linkedListType.ResolveReference(linkedListType, refId: "self"); Assert.Equal(linkedListType, ((ObjectType)linkedListType["wrapped"])["next"]); Assert.Equal(linkedListType, array.Type); Assert.Equal(linkedListType, nullable.Type); - Assert.Equal(linkedListType, method.Arguments[0]); } [Fact] @@ -86,7 +83,10 @@ public void NonSpecifiedTypesVisitingTest() new("prop", new Type("number")) } ); - var ex = Record.Exception(() => objectType.ResolveSelfReferences("self")); + var ex = Record.Exception( + () => objectType.ResolveReference( + objectType, + refId: "self")); Assert.Null(ex); Assert.Equal(objectType["next"], objectType); } @@ -96,7 +96,6 @@ public void ObjectTypeToStringTest() { var number = new Type("number"); var array = new ArrayType(new Type("self")); - var method = new FunctionType(number, new List { new("self") }); var nullable = new NullableType(new Type("self")); var linkedListType = new ObjectType( new List @@ -107,12 +106,12 @@ public void ObjectTypeToStringTest() new("next", new Type("self")) })), new("children", array), - new("parent", nullable), - new("compare", method) + new("parent", nullable) } ); - - linkedListType.ResolveSelfReferences("self"); + + linkedListType.ResolveReference(linkedListType, refId: "self"); + Assert.Contains("@this", linkedListType.ToString()); } @@ -125,23 +124,17 @@ public void SerializationOfTypeWithRecursivePropertyTest() new("data", new Type("number")), new("next", new Type("self")) } - ) { Recursive = true }; - nodeType.ResolveSelfReferences("self"); + ); + nodeType.ResolveReference(nodeType, refId: "self"); var linkedListType = new ObjectType( new List { - new("head", nodeType), - new("append", new FunctionType( - new Type("void"), - new List { nodeType } - ) - ), - new("copy", new FunctionType(new Type("self"), Array.Empty())) + new("head", nodeType) } - ) { Recursive = true }; - linkedListType.ResolveSelfReferences("self"); + ); + linkedListType.ResolveReference(linkedListType, refId: "self"); - Assert.Contains("head: head;", linkedListType.ToString()); + Assert.Contains("next: next;", linkedListType.ToString()); } } \ No newline at end of file diff --git a/Interpreter.Tests/Unit/IR/Types/TypeTests.cs b/HydraScript.Tests/Unit/IR/Types/TypeTests.cs similarity index 68% rename from Interpreter.Tests/Unit/IR/Types/TypeTests.cs rename to HydraScript.Tests/Unit/IR/Types/TypeTests.cs index 1593de75..3462dc33 100644 --- a/Interpreter.Tests/Unit/IR/Types/TypeTests.cs +++ b/HydraScript.Tests/Unit/IR/Types/TypeTests.cs @@ -1,7 +1,8 @@ -using Interpreter.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Types; +using HydraScript.Lib.IR.CheckSemantics.Visitors.Services.Impl; using Xunit; -namespace Interpreter.Tests.Unit.IR.Types; +namespace HydraScript.Tests.Unit.IR.Types; public class TypeTests { @@ -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.Tests/Unit/Infrastructure/ExecutorTests.cs b/HydraScript.Tests/Unit/Infrastructure/ExecutorTests.cs similarity index 81% rename from Interpreter.Tests/Unit/Infrastructure/ExecutorTests.cs rename to HydraScript.Tests/Unit/Infrastructure/ExecutorTests.cs index 3c0d04f3..713ca87e 100644 --- a/Interpreter.Tests/Unit/Infrastructure/ExecutorTests.cs +++ b/HydraScript.Tests/Unit/Infrastructure/ExecutorTests.cs @@ -1,15 +1,16 @@ -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.IR.Ast; -using Interpreter.Services.Executor.Impl; -using Interpreter.Services.Parsing; -using Interpreter.Tests.Stubs; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.IR.Ast; +using HydraScript.Services.Executor.Impl; +using HydraScript.Services.Parsing; +using HydraScript.Tests.Helpers; +using HydraScript.Tests.Stubs; using Moq; using Xunit; -namespace Interpreter.Tests.Unit.Infrastructure; +namespace HydraScript.Tests.Unit.Infrastructure; public class ExecutorTests { @@ -30,7 +31,7 @@ public void ExecuteGoesOkTest() { var ast = new Mock(); ast.Setup(x => x.GetInstructions()) - .Returns(new List { new Halt(0) }); + .Returns(new AddressedInstructions { new Halt() }); _parsingService.Setup(x => x.Parse(It.IsAny())) .Returns(ast.Object); @@ -76,13 +77,13 @@ public void ParserExceptionCaughtTest() [Fact] public void InternalInterpreterErrorCaughtTest() { - var instruction = new Mock(MockBehavior.Default, 0); + var instruction = new Mock(); instruction.Setup(x => x.Execute(It.IsAny())) .Throws(); var ast = new Mock(); ast.Setup(x => x.GetInstructions()) - .Returns(new List { instruction.Object, new Halt(1) }); + .Returns(new AddressedInstructions { instruction.Object, new Halt() }); _parsingService.Setup(x => x.Parse(It.IsAny())) .Returns(ast.Object); diff --git a/Interpreter.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs b/HydraScript.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs similarity index 84% rename from Interpreter.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs rename to HydraScript.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs index 53e63e33..1d97f9d5 100644 --- a/Interpreter.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs +++ b/HydraScript.Tests/Unit/Infrastructure/LoggingEntitiesTests.cs @@ -1,15 +1,16 @@ using System.IO.Abstractions; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.IR.Ast; -using Interpreter.Services.Providers.Impl.LexerProvider; -using Interpreter.Services.Providers.Impl.ParserProvider; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.BackEnd.Instructions; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.IR.Ast; +using HydraScript.Services.Providers.LexerProvider.Impl; +using HydraScript.Services.Providers.ParserProvider.Impl; using Moq; using Xunit; -namespace Interpreter.Tests.Unit.Infrastructure; +namespace HydraScript.Tests.Unit.Infrastructure; public class LoggingEntitiesTests { @@ -76,7 +77,7 @@ public void CorrectFileNameProducedByTreeTest() { var ast = new Mock(); ast.Setup(x => x.GetInstructions()) - .Returns(new List { new Halt(0) }); + .Returns(new AddressedInstructions { new Halt() }); _file.Setup(x => x.WriteAllLines( It.IsAny(), It.IsAny>() @@ -87,7 +88,7 @@ public void CorrectFileNameProducedByTreeTest() _file.Verify(x => x.WriteAllLines( It.Is(p => p == "file.tac"), - It.Is>(c => c.SequenceEqual(new[] { "0: End" })) + It.Is>(c => c.SequenceEqual(new[] { "\tEnd" })) ), Times.Once()); } } \ No newline at end of file diff --git a/Interpreter.Tests/Unit/Infrastructure/ParsingServiceTests.cs b/HydraScript.Tests/Unit/Infrastructure/ParsingServiceTests.cs similarity index 77% rename from Interpreter.Tests/Unit/Infrastructure/ParsingServiceTests.cs rename to HydraScript.Tests/Unit/Infrastructure/ParsingServiceTests.cs index d9ee4fd6..37f4393b 100644 --- a/Interpreter.Tests/Unit/Infrastructure/ParsingServiceTests.cs +++ b/HydraScript.Tests/Unit/Infrastructure/ParsingServiceTests.cs @@ -1,11 +1,11 @@ -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.IR.Ast; -using Interpreter.Services.Parsing.Impl; -using Interpreter.Services.Providers; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.IR.Ast; +using HydraScript.Services.Parsing.Impl; +using HydraScript.Services.Providers.ParserProvider; using Moq; using Xunit; -namespace Interpreter.Tests.Unit.Infrastructure; +namespace HydraScript.Tests.Unit.Infrastructure; public class ParsingServiceTests { diff --git a/Interpreter.Tests/Unit/Infrastructure/ProvidersTests.cs b/HydraScript.Tests/Unit/Infrastructure/ProvidersTests.cs similarity index 77% rename from Interpreter.Tests/Unit/Infrastructure/ProvidersTests.cs rename to HydraScript.Tests/Unit/Infrastructure/ProvidersTests.cs index 1d7a103a..8a3e14a2 100644 --- a/Interpreter.Tests/Unit/Infrastructure/ProvidersTests.cs +++ b/HydraScript.Tests/Unit/Infrastructure/ProvidersTests.cs @@ -1,17 +1,18 @@ -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; -using Interpreter.Lib.FrontEnd.GetTokens.Impl; -using Interpreter.Lib.FrontEnd.TopDownParse.Impl; -using Interpreter.Services.Providers; -using Interpreter.Services.Providers.Impl.LexerProvider; -using Interpreter.Services.Providers.Impl.ParserProvider; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Impl; +using HydraScript.Lib.FrontEnd.TopDownParse.Impl; +using HydraScript.Services.Providers.LexerProvider; +using HydraScript.Services.Providers.LexerProvider.Impl; +using HydraScript.Services.Providers.ParserProvider.Impl; +using HydraScript.Services.Providers.StructureProvider; using Microsoft.Extensions.Options; using Moq; using Xunit; using SystemType = System.Type; -namespace Interpreter.Tests.Unit.Infrastructure; +namespace HydraScript.Tests.Unit.Infrastructure; public class ProvidersTests { diff --git a/Interpreter/CommandLineSettings.cs b/HydraScript/CommandLineSettings.cs similarity index 94% rename from Interpreter/CommandLineSettings.cs rename to HydraScript/CommandLineSettings.cs index a56c9ea6..3d9e4c2e 100644 --- a/Interpreter/CommandLineSettings.cs +++ b/HydraScript/CommandLineSettings.cs @@ -2,7 +2,7 @@ using CommandLine; using CommandLine.Text; -namespace Interpreter; +namespace HydraScript; [SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global")] @@ -16,7 +16,7 @@ public class CommandLineSettings [Option('d', "dump", Default = false, HelpText = "Show dump data of interpreter")] public virtual bool Dump { get; set; } - [Usage(ApplicationAlias = "Interpreter")] + [Usage(ApplicationAlias = "HydraScript")] public static IEnumerable Examples { get diff --git a/Interpreter/Interpreter.csproj b/HydraScript/HydraScript.csproj similarity index 86% rename from Interpreter/Interpreter.csproj rename to HydraScript/HydraScript.csproj index c6708e46..4a9d0b3b 100644 --- a/Interpreter/Interpreter.csproj +++ b/HydraScript/HydraScript.csproj @@ -8,14 +8,14 @@ - + - - + + diff --git a/Interpreter/Program.cs b/HydraScript/Program.cs similarity index 72% rename from Interpreter/Program.cs rename to HydraScript/Program.cs index 4c450e67..bf58d911 100644 --- a/Interpreter/Program.cs +++ b/HydraScript/Program.cs @@ -1,17 +1,19 @@ using System.Diagnostics.CodeAnalysis; using CommandLine; +using HydraScript.Services.Executor; +using HydraScript.Services.Executor.Impl; +using HydraScript.Services.Parsing; +using HydraScript.Services.Parsing.Impl; +using HydraScript.Services.Providers.LexerProvider; +using HydraScript.Services.Providers.LexerProvider.Impl; +using HydraScript.Services.Providers.ParserProvider; +using HydraScript.Services.Providers.ParserProvider.Impl; +using HydraScript.Services.Providers.StructureProvider; +using HydraScript.Services.Providers.StructureProvider.Impl; using Microsoft.Extensions.DependencyInjection; -using Interpreter.Services.Executor; -using Interpreter.Services.Executor.Impl; -using Interpreter.Services.Parsing; -using Interpreter.Services.Parsing.Impl; -using Interpreter.Services.Providers; -using Interpreter.Services.Providers.Impl.LexerProvider; -using Interpreter.Services.Providers.Impl.ParserProvider; -using Interpreter.Services.Providers.Impl.StructureProvider; using Microsoft.Extensions.Options; -namespace Interpreter; +namespace HydraScript; [ExcludeFromCodeCoverage] public static class Program diff --git a/Interpreter/Services/Executor/IExecutor.cs b/HydraScript/Services/Executor/IExecutor.cs similarity index 55% rename from Interpreter/Services/Executor/IExecutor.cs rename to HydraScript/Services/Executor/IExecutor.cs index f2f22248..bc9711ed 100644 --- a/Interpreter/Services/Executor/IExecutor.cs +++ b/HydraScript/Services/Executor/IExecutor.cs @@ -1,4 +1,4 @@ -namespace Interpreter.Services.Executor; +namespace HydraScript.Services.Executor; public interface IExecutor { diff --git a/Interpreter/Services/Executor/Impl/Executor.cs b/HydraScript/Services/Executor/Impl/Executor.cs similarity index 74% rename from Interpreter/Services/Executor/Impl/Executor.cs rename to HydraScript/Services/Executor/Impl/Executor.cs index 9b12c337..738ee018 100644 --- a/Interpreter/Services/Executor/Impl/Executor.cs +++ b/HydraScript/Services/Executor/Impl/Executor.cs @@ -1,11 +1,11 @@ -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Services.Parsing; +using HydraScript.Services.Parsing; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.IR.CheckSemantics.Exceptions; using Microsoft.Extensions.Options; -namespace Interpreter.Services.Executor.Impl; +namespace HydraScript.Services.Executor.Impl; public class Executor : IExecutor { @@ -35,7 +35,7 @@ public void Execute() } catch (Exception ex) { - Console.WriteLine("Internal Interpreter Error"); + Console.WriteLine("Internal HydraScript Error"); Console.WriteLine(ex); } } diff --git a/Interpreter/Services/Parsing/IParsingService.cs b/HydraScript/Services/Parsing/IParsingService.cs similarity index 53% rename from Interpreter/Services/Parsing/IParsingService.cs rename to HydraScript/Services/Parsing/IParsingService.cs index 7b9249e2..fbe4a389 100644 --- a/Interpreter/Services/Parsing/IParsingService.cs +++ b/HydraScript/Services/Parsing/IParsingService.cs @@ -1,6 +1,6 @@ -using Interpreter.Lib.IR.Ast; +using HydraScript.Lib.IR.Ast; -namespace Interpreter.Services.Parsing; +namespace HydraScript.Services.Parsing; public interface IParsingService { diff --git a/Interpreter/Services/Parsing/Impl/ParsingService.cs b/HydraScript/Services/Parsing/Impl/ParsingService.cs similarity index 74% rename from Interpreter/Services/Parsing/Impl/ParsingService.cs rename to HydraScript/Services/Parsing/Impl/ParsingService.cs index 2c24a572..57a775a8 100644 --- a/Interpreter/Services/Parsing/Impl/ParsingService.cs +++ b/HydraScript/Services/Parsing/Impl/ParsingService.cs @@ -1,7 +1,7 @@ -using Interpreter.Lib.IR.Ast; -using Interpreter.Services.Providers; +using HydraScript.Services.Providers.ParserProvider; +using HydraScript.Lib.IR.Ast; -namespace Interpreter.Services.Parsing.Impl; +namespace HydraScript.Services.Parsing.Impl; public class ParsingService : IParsingService { diff --git a/HydraScript/Services/Providers/LexerProvider/ILexerProvider.cs b/HydraScript/Services/Providers/LexerProvider/ILexerProvider.cs new file mode 100644 index 00000000..58f3f5c5 --- /dev/null +++ b/HydraScript/Services/Providers/LexerProvider/ILexerProvider.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.FrontEnd.GetTokens; + +namespace HydraScript.Services.Providers.LexerProvider; + +public interface ILexerProvider +{ + ILexer CreateLexer(); +} \ No newline at end of file diff --git a/Interpreter/Services/Providers/Impl/LexerProvider/LexerProvider.cs b/HydraScript/Services/Providers/LexerProvider/Impl/LexerProvider.cs similarity index 77% rename from Interpreter/Services/Providers/Impl/LexerProvider/LexerProvider.cs rename to HydraScript/Services/Providers/LexerProvider/Impl/LexerProvider.cs index 4ff77b32..7ac47e3e 100644 --- a/Interpreter/Services/Providers/Impl/LexerProvider/LexerProvider.cs +++ b/HydraScript/Services/Providers/LexerProvider/Impl/LexerProvider.cs @@ -1,9 +1,10 @@ using System.IO.Abstractions; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Impl; +using HydraScript.Services.Providers.StructureProvider; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Impl; using Microsoft.Extensions.Options; -namespace Interpreter.Services.Providers.Impl.LexerProvider; +namespace HydraScript.Services.Providers.LexerProvider.Impl; public class LexerProvider : ILexerProvider { diff --git a/Interpreter/Services/Providers/Impl/LexerProvider/LoggingLexer.cs b/HydraScript/Services/Providers/LexerProvider/Impl/LoggingLexer.cs similarity index 83% rename from Interpreter/Services/Providers/Impl/LexerProvider/LoggingLexer.cs rename to HydraScript/Services/Providers/LexerProvider/Impl/LoggingLexer.cs index ed297b16..33a0bc74 100644 --- a/Interpreter/Services/Providers/Impl/LexerProvider/LoggingLexer.cs +++ b/HydraScript/Services/Providers/LexerProvider/Impl/LoggingLexer.cs @@ -1,9 +1,9 @@ using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens; +using HydraScript.Lib.FrontEnd.GetTokens.Data; -namespace Interpreter.Services.Providers.Impl.LexerProvider; +namespace HydraScript.Services.Providers.LexerProvider.Impl; public class LoggingLexer : ILexer { diff --git a/HydraScript/Services/Providers/ParserProvider/IParserProvider.cs b/HydraScript/Services/Providers/ParserProvider/IParserProvider.cs new file mode 100644 index 00000000..a846c091 --- /dev/null +++ b/HydraScript/Services/Providers/ParserProvider/IParserProvider.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.FrontEnd.TopDownParse; + +namespace HydraScript.Services.Providers.ParserProvider; + +public interface IParserProvider +{ + IParser CreateParser(); +} \ No newline at end of file diff --git a/Interpreter/Services/Providers/Impl/ParserProvider/LoggingAbstractSyntaxTree.cs b/HydraScript/Services/Providers/ParserProvider/Impl/LoggingAbstractSyntaxTree.cs similarity index 70% rename from Interpreter/Services/Providers/Impl/ParserProvider/LoggingAbstractSyntaxTree.cs rename to HydraScript/Services/Providers/ParserProvider/Impl/LoggingAbstractSyntaxTree.cs index b8160dbc..6db8a936 100644 --- a/Interpreter/Services/Providers/Impl/ParserProvider/LoggingAbstractSyntaxTree.cs +++ b/HydraScript/Services/Providers/ParserProvider/Impl/LoggingAbstractSyntaxTree.cs @@ -1,8 +1,8 @@ using System.IO.Abstractions; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast; +using HydraScript.Lib.BackEnd; +using HydraScript.Lib.IR.Ast; -namespace Interpreter.Services.Providers.Impl.ParserProvider; +namespace HydraScript.Services.Providers.ParserProvider.Impl; public class LoggingAbstractSyntaxTree : IAbstractSyntaxTree { @@ -17,12 +17,12 @@ public LoggingAbstractSyntaxTree(IAbstractSyntaxTree ast, string fileName, IFile _fileSystem = fileSystem; } - public List GetInstructions() + public AddressedInstructions GetInstructions() { var instructions = _ast.GetInstructions(); _fileSystem.File.WriteAllLines( $"{_fileName}.tac", - instructions.OrderBy(i => i).Select(i => i.ToString()) + instructions.Select(i => i.ToString()) ); return instructions; } diff --git a/Interpreter/Services/Providers/Impl/ParserProvider/LoggingParser.cs b/HydraScript/Services/Providers/ParserProvider/Impl/LoggingParser.cs similarity index 83% rename from Interpreter/Services/Providers/Impl/ParserProvider/LoggingParser.cs rename to HydraScript/Services/Providers/ParserProvider/Impl/LoggingParser.cs index 3fd04d97..93a92d85 100644 --- a/Interpreter/Services/Providers/Impl/ParserProvider/LoggingParser.cs +++ b/HydraScript/Services/Providers/ParserProvider/Impl/LoggingParser.cs @@ -1,8 +1,8 @@ using System.IO.Abstractions; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Interpreter.Lib.IR.Ast; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.IR.Ast; -namespace Interpreter.Services.Providers.Impl.ParserProvider; +namespace HydraScript.Services.Providers.ParserProvider.Impl; public class LoggingParser : IParser { diff --git a/Interpreter/Services/Providers/Impl/ParserProvider/ParserProvider.cs b/HydraScript/Services/Providers/ParserProvider/Impl/ParserProvider.cs similarity index 76% rename from Interpreter/Services/Providers/Impl/ParserProvider/ParserProvider.cs rename to HydraScript/Services/Providers/ParserProvider/Impl/ParserProvider.cs index 25b5b3a2..924c9d79 100644 --- a/Interpreter/Services/Providers/Impl/ParserProvider/ParserProvider.cs +++ b/HydraScript/Services/Providers/ParserProvider/Impl/ParserProvider.cs @@ -1,9 +1,10 @@ using System.IO.Abstractions; -using Interpreter.Lib.FrontEnd.TopDownParse; -using Parser = Interpreter.Lib.FrontEnd.TopDownParse.Impl.Parser; +using HydraScript.Services.Providers.LexerProvider; +using HydraScript.Lib.FrontEnd.TopDownParse; +using HydraScript.Lib.FrontEnd.TopDownParse.Impl; using Microsoft.Extensions.Options; -namespace Interpreter.Services.Providers.Impl.ParserProvider; +namespace HydraScript.Services.Providers.ParserProvider.Impl; public class ParserProvider : IParserProvider { diff --git a/HydraScript/Services/Providers/StructureProvider/IStructureProvider.cs b/HydraScript/Services/Providers/StructureProvider/IStructureProvider.cs new file mode 100644 index 00000000..8f4521ea --- /dev/null +++ b/HydraScript/Services/Providers/StructureProvider/IStructureProvider.cs @@ -0,0 +1,8 @@ +using HydraScript.Lib.FrontEnd.GetTokens.Data; + +namespace HydraScript.Services.Providers.StructureProvider; + +public interface IStructureProvider +{ + Structure CreateStructure(); +} \ No newline at end of file diff --git a/Interpreter/Services/Providers/Impl/StructureProvider/StructureProvider.cs b/HydraScript/Services/Providers/StructureProvider/Impl/StructureProvider.cs similarity index 87% rename from Interpreter/Services/Providers/Impl/StructureProvider/StructureProvider.cs rename to HydraScript/Services/Providers/StructureProvider/Impl/StructureProvider.cs index 90f5e186..d03b5cd3 100644 --- a/Interpreter/Services/Providers/Impl/StructureProvider/StructureProvider.cs +++ b/HydraScript/Services/Providers/StructureProvider/Impl/StructureProvider.cs @@ -1,10 +1,10 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; +using HydraScript.Lib.FrontEnd.GetTokens.Data; +using HydraScript.Lib.FrontEnd.GetTokens.Data.TokenTypes; -namespace Interpreter.Services.Providers.Impl.StructureProvider; +namespace HydraScript.Services.Providers.StructureProvider.Impl; public class StructureProvider : IStructureProvider { @@ -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 diff --git a/Interpreter/TokenTypes.cs b/HydraScript/TokenTypes.cs similarity index 95% rename from Interpreter/TokenTypes.cs rename to HydraScript/TokenTypes.cs index f604bdba..dc86c0a4 100644 --- a/Interpreter/TokenTypes.cs +++ b/HydraScript/TokenTypes.cs @@ -1,4 +1,4 @@ -namespace Interpreter; +namespace HydraScript; public static class TokenTypes { @@ -51,11 +51,6 @@ public static class TokenTypes "pattern": "[+]{1,2}|[-]|[*]|[\/]|[%]|([!]|[=])[=]|([<]|[>])[=]?|[!]|[|]{2}|[&]{2}|[~]|[:]{2}", "priority": 12 }, - { - "tag": "Arrow", - "pattern": "[=][>]", - "priority": 13 - }, { "tag": "Comma", "pattern": "[,]", diff --git a/Interpreter/grammar.txt b/HydraScript/grammar.txt similarity index 69% rename from Interpreter/grammar.txt rename to HydraScript/grammar.txt index a6eec2fc..0546398d 100644 --- a/Interpreter/grammar.txt +++ b/HydraScript/grammar.txt @@ -10,31 +10,37 @@ Statement -> BlockStatement ContinueStatement BreakStatement ReturnStatement - TypeStatement Declaration -> LexicalDeclaration FunctionDeclaration + TypeDeclaration BlockStatement -> '{' StatementList '}' ExpressionStatement -> Expression -Expression -> AssignExpression -AssignExpression -> LeftHandSideExpression ('=' AssignExpression)? -LeftHandSideExpression -> CastExpression +Expression -> CastExpression + AssignmentExpression + +CastExpression -> ConditionalExpression 'as' 'string' + +AssignmentExpression -> LeftHandSideExpression '=' Expression + +LeftHandSideExpression -> MemberExpression CallExpression -CallExpression -> MemberExpression Arguments* -Arguments -> '(' ArgumentsList? ')' -ArgumentsList -> AssignExpression (',' AssignExpression)* -MemberExpression -> "Ident" ('[' Expression ']' | '.' "Ident" )* -CastExpression -> ConditionalExpression 'as' TypeIdentifier -ConditionalExpression -> OrExpression ('?' AssignExpression ':' AssignExpression)? +CallExpression -> MemberExpression Arguments (Arguments | '[' Expression ']' | '.' 'Ident')* +MemberExpression -> "Ident" ('[' Expression ']' | '.' 'Ident')* + +Arguments -> '(' (Expression ',')* ')' + +ConditionalExpression -> OrExpression ('?' Expression ':' Expression)? OrExpression -> AndExpression ('||' AndExpression)* AndExpression -> EqExpression ('&&' EqExpression)* EqExpression -> RelExpression (('=='|'!=') RelExpression)* RelExpression -> AddExpression (('<'|'>'|'<='|'>=') AddExpression)* AddExpression -> MulExpression (('+'|'-') MulExpression)* -MulExpression -> UnaryExpression (('*'|'/'|'%') UnaryExpression)* -UnaryExpression -> PrimaryExpression | ('-'|'!') UnaryExpression +MulExpression -> UnaryExpression (('*'|'/'|'%'|'++'|'::') UnaryExpression)* +UnaryExpression -> LeftHandSideExpression | ('-'|'!'|'~') UnaryExpression + PrimaryExpression -> "Ident" | Literal | '(' Expression ')' | ObjectLiteral | ArrayLiteral Literal -> "NullLiteral" "IntegerLiteral" @@ -42,12 +48,9 @@ Literal -> "NullLiteral" "StringLiteral" "BooleanLiteral" ObjectLiteral -> '{' PropertyDefinitionList '}' -PropertyDefinitionList -> (Property ';')* -Property -> FieldProperty - MethodProperty +PropertyDefinitionList -> (FieldProperty ';')* FieldProperty -> "Ident" ':' Expression -MethodProperty -> "Ident" '=>' MethodDeclaration -MethodDeclaration -> '(' FunctionParameters? ')' Type? BlockStatement + ArrayLiteral -> '[' ElementList ']' ElementList -> (Expression ',')* @@ -61,15 +64,13 @@ BreakStatement -> 'break' ReturnStatement -> 'return' Expression? -TypeStatement -> 'type' "Ident" = TypeValue +TypeDeclaration -> 'type' "Ident" = TypeValue TypeValue -> TypeValueBase TypeValueSuffix* TypeValueBase -> "Ident" - FunctionTypeBase ObjectTypeBase ObjectTypeBase -> '{' PropertyTypeList '}' PropertyTypeList -> (PropertyType ';')* PropertyType -> "Ident" ':' TypeValue -FunctionTypeBase -> '(' ArgTypeList ')' '=>' TypeValue ArgTypeList -> (TypeValue ',')* TypeValueSuffix -> '['']' '?' diff --git a/Interpreter.Lib/BackEnd/Instructions/AsString.cs b/Interpreter.Lib/BackEnd/Instructions/AsString.cs deleted file mode 100644 index 333eca74..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/AsString.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using Interpreter.Lib.BackEnd.Values; -using SystemType = System.Type; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class AsString : Simple -{ - public AsString(string left, IValue right, int number) : - base(left, (null, right), "", number) - { - } - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - frame[Left] = JsonSerializer.Serialize( - right.right.Get(frame), - new JsonSerializerOptions - { - WriteIndented = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - ReferenceHandler = ReferenceHandler.IgnoreCycles, - Converters = { new DoubleValueWriteConverter() }, - NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals - } - ); - - return Jump(); - } - - protected override string ToStringRepresentation() => $"{Left} = {right.right} as string"; - - [ExcludeFromCodeCoverage] - private class DoubleValueWriteConverter : JsonConverter - { - public override double Read(ref Utf8JsonReader reader, - SystemType typeToConvert, JsonSerializerOptions options) => - throw new NotImplementedException(); - - public override void Write(Utf8JsonWriter writer, - double value, JsonSerializerOptions options) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - if (value == Math.Truncate(value)) - writer.WriteNumberValue(Convert.ToInt64(value)); - else - writer.WriteNumberValue(value); - } - } -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/BeginFunction.cs b/Interpreter.Lib/BackEnd/Instructions/BeginFunction.cs deleted file mode 100644 index 861a8760..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/BeginFunction.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class BeginFunction : Instruction -{ - private readonly FunctionInfo _function; - - public BeginFunction(int number, FunctionInfo function) : base(number) - { - _function = function; - } - - public override int Execute(VirtualMachine vm) => Number + 1; - - protected override string ToStringRepresentation() => $"BeginFunction {_function.CallId()}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/CallFunction.cs b/Interpreter.Lib/BackEnd/Instructions/CallFunction.cs deleted file mode 100644 index 30f5a128..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/CallFunction.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class CallFunction : Simple -{ - private readonly FunctionInfo _function; - private readonly int _numberOfArguments; - - public CallFunction(FunctionInfo function, int number, int numberOfArguments, string left = null) : - base(left, (null, null), "Call ", number) - { - _function = function; - _numberOfArguments = numberOfArguments + Convert.ToInt32(function.MethodOf != null); - } - - public override int Jump() => _function.Location; - - public override int Execute(VirtualMachine vm) - { - var frame = new Frame(Number + 1, vm.Frames.Peek()); - - var i = 0; - var args = new List<(string Id, object Value)>(); - while (i < _numberOfArguments) - { - args.Add(vm.Arguments.Pop()); - frame[args[i].Id] = args[i].Value; - i++; - } - - if (_function.MethodOf != null) - { - var obj = (Dictionary) frame[_function.MethodOf]; - foreach (var (key, value) in obj) - { - frame[key] = value; - } - } - - vm.CallStack.Push(new Call(Number, _function, args, Left)); - vm.Frames.Push(frame); - return _function.Location; - } - - protected override string ToStringRepresentation() => Left == null - ? $"Call {_function}, {_numberOfArguments}" - : $"{Left} = Call {_function}, {_numberOfArguments}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/CreateArray.cs b/Interpreter.Lib/BackEnd/Instructions/CreateArray.cs deleted file mode 100644 index 6dbf2330..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/CreateArray.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class CreateArray : Instruction -{ - private readonly string _id; - private readonly int _size; - - public CreateArray(int number, string id, int size) : base(number) - { - _id = id; - _size = size; - } - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - frame[_id] = new object[_size].ToList(); - return Number + 1; - } - - protected override string ToStringRepresentation() => $"array {_id} = [{_size}]"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/CreateObject.cs b/Interpreter.Lib/BackEnd/Instructions/CreateObject.cs deleted file mode 100644 index 973c5be3..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/CreateObject.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class CreateObject : Instruction -{ - private readonly string _id; - - public CreateObject(int number, string id) : base(number) - { - _id = id; - } - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - frame[_id] = new Dictionary(); - return Number + 1; - } - - protected override string ToStringRepresentation() => $"object {_id} = {{}}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/DotAssignment.cs b/Interpreter.Lib/BackEnd/Instructions/DotAssignment.cs deleted file mode 100644 index 8aaf66b0..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/DotAssignment.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class DotAssignment : Simple -{ - public DotAssignment(string left, (IValue left, IValue right) right, int number) : - base(left, right, ".", number) - { - } - - public override int 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); - return Number + 1; - } - - protected override string ToStringRepresentation() => - $"{Left}{@operator}{right.left} = {right.right}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Goto.cs b/Interpreter.Lib/BackEnd/Instructions/Goto.cs deleted file mode 100644 index e633e7e3..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Goto.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class Goto : Instruction -{ - protected int jump; - - public Goto(int jump, int number) : base(number) - { - this.jump = jump; - } - - public override int Jump() => jump; - - public override int Execute(VirtualMachine vm) => Jump(); - - public void SetJump(int newJump) => jump = newJump; - - protected override string ToStringRepresentation() => $"Goto {Jump()}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Halt.cs b/Interpreter.Lib/BackEnd/Instructions/Halt.cs deleted file mode 100644 index d9cd0002..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Halt.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public class Halt : Instruction -{ - public Halt(int number) : base(number) - { - } - - public override bool End() => true; - - public override int Execute(VirtualMachine vm) - { - vm.Frames.Pop(); - return -3; - } - - protected override string ToStringRepresentation() => "End"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/IfNotGoto.cs b/Interpreter.Lib/BackEnd/Instructions/IfNotGoto.cs deleted file mode 100644 index 64043003..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/IfNotGoto.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class IfNotGoto : Goto -{ - private readonly IValue _test; - - public IfNotGoto(IValue test, int jump, int number) : - base(jump, number) - { - _test = test; - } - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - if (!Convert.ToBoolean(_test.Get(frame))) - { - return jump; - } - return Number + 1; - } - - protected override string ToStringRepresentation() => $"IfNot {_test} Goto {Jump()}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/IndexAssignment.cs b/Interpreter.Lib/BackEnd/Instructions/IndexAssignment.cs deleted file mode 100644 index 0d37ed03..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/IndexAssignment.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class IndexAssignment : Simple -{ - public IndexAssignment(string left, (IValue left, IValue right) right, int number) : - base(left, right, "[]", number) - { - } - - public override int 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); - return Number + 1; - } - - protected override string ToStringRepresentation() => - $"{Left}[{right.left}] = {right.right}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Instruction.cs b/Interpreter.Lib/BackEnd/Instructions/Instruction.cs deleted file mode 100644 index c1688613..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Instruction.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Interpreter.Lib.BackEnd.Instructions; - -public abstract class Instruction : IComparable -{ - public int Number { get; } - - protected Instruction(int number) => - Number = number; - - public virtual int Jump() => Number + 1; - - public virtual bool End() => false; - - public abstract int Execute(VirtualMachine vm); - - public int CompareTo(Instruction other) => Number.CompareTo(other.Number); - - protected abstract string ToStringRepresentation(); - - public override string ToString() => $"{Number}: {ToStringRepresentation()}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Print.cs b/Interpreter.Lib/BackEnd/Instructions/Print.cs deleted file mode 100644 index 6fb587bb..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Print.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class Print : Instruction -{ - private readonly IValue _value; - - public Print(int number, IValue value) : base(number) - { - _value = value; - } - - public override int Execute(VirtualMachine vm) - { - vm.Writer.WriteLine(_value.Get(vm.Frames.Peek())); - return Number + 1; - } - - protected override string ToStringRepresentation() => $"Print {_value}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/PushParameter.cs b/Interpreter.Lib/BackEnd/Instructions/PushParameter.cs deleted file mode 100644 index bdacc41e..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/PushParameter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class PushParameter : Instruction -{ - private readonly string _parameter; - private readonly IValue _value; - - public PushParameter( - int number, - string parameter, - IValue value - ) : base(number) - { - _parameter = parameter; - _value = value; - } - - public override int Execute(VirtualMachine vm) - { - vm.Arguments.Push((_parameter, _value.Get(vm.Frames.Peek()))); - return Number + 1; - } - - protected override string ToStringRepresentation() => $"PushParameter {_parameter} = {_value}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/RemoveFromArray.cs b/Interpreter.Lib/BackEnd/Instructions/RemoveFromArray.cs deleted file mode 100644 index e933855e..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/RemoveFromArray.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class RemoveFromArray : Instruction -{ - private readonly string _id; - private readonly IValue _index; - - public RemoveFromArray(int number, string id, IValue index) : base(number) - { - _id = id; - _index = index; - } - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - var list = (List) frame[_id]; - list.RemoveAt(Convert.ToInt32(_index.Get(frame))); - return Number + 1; - } - - protected override string ToStringRepresentation() => - $"RemoveFrom {_id} at {_index}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Return.cs b/Interpreter.Lib/BackEnd/Instructions/Return.cs deleted file mode 100644 index 0a9b3966..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Return.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections; -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class Return : Instruction, IEnumerable -{ - private readonly IValue _value; - private readonly List _callers = new(); - - public int FunctionStart { get; } - - public Return(int functionStart, int number, IValue value = null) : base(number) - { - _value = value; - FunctionStart = functionStart; - } - - public void AddCaller(int caller) => _callers.Add(caller); - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Pop(); - var call = vm.CallStack.Pop(); - if (call.Where != null && _value != null) - { - vm.Frames.Peek()[call.Where] = _value.Get(frame); - } - - return frame.ReturnAddress; - } - - public IEnumerator GetEnumerator() => _callers.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - protected override string ToStringRepresentation() => $"Return{(_value != null ? $" {_value}" : "")}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/Instructions/Simple.cs b/Interpreter.Lib/BackEnd/Instructions/Simple.cs deleted file mode 100644 index 8ac1b483..00000000 --- a/Interpreter.Lib/BackEnd/Instructions/Simple.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.BackEnd.Instructions; - -public class Simple : Instruction -{ - public string Left { get; set; } - - protected (IValue left, IValue right) right; - protected readonly string @operator; - - public Simple( - string left, - (IValue left, IValue right) right, - string @operator, - int number - ) : - base(number) - { - Left = left; - this.right = right; - this.@operator = @operator; - } - - public IValue Source => right.right; - - public bool Assignment => @operator == ""; - - public override int Execute(VirtualMachine vm) - { - var frame = vm.Frames.Peek(); - if (right.left == null) - { - var value = right.right.Get(frame); - frame[Left] = @operator switch - { - "-" => -Convert.ToDouble(value), - "!" => !Convert.ToBoolean(value), - "~" => ((List) value).Count, - "" => value, - _ => throw new NotImplementedException() - }; - } - else - { - object lValue = right.left.Get(frame), rValue = right.right.Get(frame); - frame[Left] = @operator switch - { - "+" when lValue is string => lValue.ToString() + rValue, - "+" => Convert.ToDouble(lValue) + Convert.ToDouble(rValue), - "-" => Convert.ToDouble(lValue) - Convert.ToDouble(rValue), - "*" => Convert.ToDouble(lValue) * Convert.ToDouble(rValue), - "/" => Convert.ToDouble(lValue) / Convert.ToDouble(rValue), - "%" => Convert.ToDouble(lValue) % Convert.ToDouble(rValue), - "||" => Convert.ToBoolean(lValue) || Convert.ToBoolean(rValue), - "&&" => Convert.ToBoolean(lValue) && Convert.ToBoolean(rValue), - "==" => Equals(lValue, rValue), - "!=" => !Equals(lValue, rValue), - ">" => Convert.ToDouble(lValue) > Convert.ToDouble(rValue), - ">=" => Convert.ToDouble(lValue) >= Convert.ToDouble(rValue), - "<" => Convert.ToDouble(lValue) < Convert.ToDouble(rValue), - "<=" => Convert.ToDouble(lValue) <= Convert.ToDouble(rValue), - "." => ((Dictionary) lValue)[rValue.ToString()!], - "[]" => ((List) lValue)[Convert.ToInt32(rValue)], - "++" => ((List) lValue).Concat((List) rValue).ToList(), - _ => throw new NotImplementedException() - }; - } - if (vm.CallStack.Any()) - { - var call = vm.CallStack.Peek(); - var methodOf = call.To.MethodOf; - if (methodOf != null) - { - var methodOwner = (Dictionary) frame[methodOf]; - if (methodOwner.ContainsKey(Left)) - { - methodOwner[Left] = frame[Left]; - } - } - } - - return Jump(); - } - - protected override string ToStringRepresentation() => - right.left == null - ? $"{Left} = {@operator}{right.right}" - : $"{Left} = {right.left} {@operator} {right.right}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/BackEnd/VirtualMachine.cs b/Interpreter.Lib/BackEnd/VirtualMachine.cs deleted file mode 100644 index a88c5565..00000000 --- a/Interpreter.Lib/BackEnd/VirtualMachine.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.BackEnd; - -public record VirtualMachine( - Stack CallStack, Stack Frames, - Stack<(string Id, object Value)> Arguments, - TextWriter Writer -) -{ - public VirtualMachine() : - this(new(), new(), new(), Console.Out) { } - - public void Run(List instructions) - { - Frames.Push(new Frame()); - - var address = 0; - while (!instructions[address].End()) - { - var instruction = instructions[address]; - var jump = instruction.Execute(this); - address = jump; - } - - instructions[address].Execute(this); - } -} - -public record Call( - int From, FunctionInfo To, - List<(string Id, object Value)> Parameters, - string Where = null) -{ - public override string ToString() => - $"{From} => {To.Location}: {To.Id}({string.Join(", ", Parameters.Select(x => $"{x.Id}: {x.Value}"))})"; -} - -public record FunctionInfo(string Id, int Location = 0, string MethodOf = null) -{ - public int Location { get; set; } = Location; - - public string MethodOf { get; set; } = MethodOf; - - public string CallId() => - MethodOf == null - ? Id - : $"{MethodOf}.{Id}"; - - public override string ToString() => - $"({Location}, {CallId()})"; -} - -public class Frame -{ - private readonly Dictionary _variables = new(); - private readonly Frame _parentFrame; - - public int ReturnAddress { get; } - - public Frame(int returnAddress = 0, Frame parentFrame = null) - { - ReturnAddress = returnAddress; - _parentFrame = parentFrame; - } - - public object this[string id] - { - get => _variables.ContainsKey(id) - ? _variables[id] - : _parentFrame?[id]; - set => _variables[id] = value; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenTypeUtils.cs b/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenTypeUtils.cs deleted file mode 100644 index 8d2c6e6a..00000000 --- a/Interpreter.Lib/FrontEnd/GetTokens/Data/TokenTypes/TokenTypeUtils.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Interpreter.Lib.FrontEnd.GetTokens.Data.TokenTypes; - -public static class TokenTypeUtils -{ - public static readonly TokenType End = new EndOfProgramType(); - public static readonly TokenType Error = new ErrorType(); -} \ No newline at end of file diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs b/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs deleted file mode 100644 index ef64c670..00000000 --- a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs +++ /dev/null @@ -1,839 +0,0 @@ -using System.Text.RegularExpressions; -using Interpreter.Lib.FrontEnd.GetTokens; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.Ast; -using Interpreter.Lib.IR.Ast.Impl; -using Interpreter.Lib.IR.Ast.Nodes; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.ComplexLiterals; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Statements; -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; -using Expression = Interpreter.Lib.IR.Ast.Nodes.Expressions.Expression; - -namespace Interpreter.Lib.FrontEnd.TopDownParse.Impl; - -public class Parser : IParser -{ - private TokensStream _tokens; - private readonly ILexer _lexer; - - public Parser(ILexer lexer) => - _lexer = lexer; - - private Token Expect(string expectedTag, string expectedValue = null) - { - var current = _tokens.Current; - - if (!CurrentIs(expectedTag)) - throw new ParserException(_tokens.Current!.Segment, expectedTag, _tokens.Current); - if (_tokens.Current!.Value != (expectedValue ?? _tokens.Current.Value)) - throw new ParserException(_tokens.Current.Segment, expectedValue, _tokens.Current); - - if (CurrentIs(expectedTag) && _tokens.Current.Value == (expectedValue ?? _tokens.Current.Value)) - { - _tokens.MoveNext(); - } - - return current; - } - - private bool CurrentIs(string tag) => - _tokens.Current!.Type == _lexer.Structure.FindByTag(tag); - - private bool CurrentIsLiteral() => - CurrentIs("NullLiteral") || - CurrentIs("IntegerLiteral") || - CurrentIs("FloatLiteral") || - CurrentIs("StringLiteral") || - CurrentIs("BooleanLiteral"); - - private bool CurrentIsKeyword(string keyword) => - CurrentIs("Keyword") && - _tokens.Current!.Value == keyword; - - private bool CurrentIsOperator(string @operator) => - CurrentIs("Operator") && - _tokens.Current!.Value == @operator; - - public IAbstractSyntaxTree TopDownParse(string text) - { - _tokens = _lexer.GetTokens(text); - - var root = Script(SymbolTableUtils.GetStandardLibrary()); - Expect("EOP"); - return new AbstractSyntaxTree(root); - } - - private ScriptBody Script(SymbolTable table = null) => - new(StatementList(table ?? new SymbolTable())) - { - SymbolTable = table ?? new SymbolTable() - }; - - private IEnumerable StatementList(SymbolTable table) - { - var statementList = new List(); - while ( - CurrentIsKeyword("function") || CurrentIsKeyword("let") || CurrentIsKeyword("const") || - CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || - CurrentIs("LeftCurl") || CurrentIsKeyword("return") || CurrentIsKeyword("break") || - CurrentIsKeyword("continue") || CurrentIsKeyword("if") || CurrentIsKeyword("while") || - CurrentIsKeyword("type") - ) - { - statementList.Add(StatementListItem(table)); - } - - return statementList; - } - - private StatementListItem StatementListItem(SymbolTable table) - { - if (CurrentIsKeyword("function") || CurrentIsKeyword("let") || CurrentIsKeyword("const")) - { - return Declaration(table); - } - - return Statement(table); - } - - private Statement Statement(SymbolTable table) - { - if (CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || CurrentIsOperator("-") || - CurrentIsOperator("!")) - { - return ExpressionStatement(table); - } - - if (CurrentIs("LeftCurl")) - { - return BlockStatement(table); - } - - if (CurrentIsKeyword("return")) - { - return ReturnStatement(table); - } - - if (CurrentIsKeyword("break")) - { - return new BreakStatement - { - Segment = Expect("Keyword", "break").Segment - }; - } - - if (CurrentIsKeyword("continue")) - { - return new ContinueStatement - { - Segment = Expect("Keyword", "continue").Segment - }; - } - - if (CurrentIsKeyword("if")) - { - return IfStatement(table); - } - - if (CurrentIsKeyword("while")) - { - return WhileStatement(table); - } - - if (CurrentIsKeyword("type")) - { - return TypeStatement(table); - } - - return null; - } - - private BlockStatement BlockStatement(SymbolTable table) - { - var newTable = new SymbolTable(); - newTable.AddOpenScope(table); - - Expect("LeftCurl"); - var block = new BlockStatement(StatementList(newTable)) - { - SymbolTable = newTable - }; - Expect("RightCurl"); - - return block; - } - - private ExpressionStatement ExpressionStatement(SymbolTable table) - { - return new(Expression(table)); - } - - private ReturnStatement ReturnStatement(SymbolTable table) - { - var ret = Expect("Keyword", "return"); - if (CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || CurrentIsOperator("-") || - CurrentIsOperator("!") || CurrentIs("LeftCurl") || CurrentIs("LeftBracket")) - { - return new ReturnStatement(Expression(table)) - { - Segment = ret.Segment, - SymbolTable = table - }; - } - - return new ReturnStatement - { - Segment = ret.Segment - }; - } - - private IfStatement IfStatement(SymbolTable table) - { - var token = Expect("Keyword", "if"); - Expect("LeftParen"); - var expr = Expression(table); - Expect("RightParen"); - var then = Statement(table); - if (CurrentIsKeyword("else")) - { - Expect("Keyword", "else"); - var @else = Statement(table); - return new IfStatement(expr, then, @else) {SymbolTable = table, Segment = token.Segment}; - } - - return new IfStatement(expr, then) {SymbolTable = table, Segment = token.Segment}; - } - - private WhileStatement WhileStatement(SymbolTable table) - { - var token = Expect("Keyword", "while"); - Expect("LeftParen"); - var expr = Expression(table); - Expect("RightParen"); - var stmt = Statement(table); - return new WhileStatement(expr, stmt) {SymbolTable = table, Segment = token.Segment}; - } - - private TypeStatement TypeStatement(SymbolTable table) - { - var typeWord = Expect("Keyword", "type"); - var ident = Expect("Ident"); - Expect("Assign"); - if (CurrentIs("LeftCurl")) - { - table.AddType(new Type(ident.Value)); - } - var type = TypeValue(table); - - type.Recursive = type.ToString().Contains(ident.Value); - - if (type is ObjectType objectType && type.Recursive) - { - objectType.ResolveSelfReferences(ident.Value); - } - table.AddType(type, ident.Value); - - return new TypeStatement(ident.Value, type) - { - Segment = typeWord.Segment, - SymbolTable = table - }; - } - - private Type TypeValue(SymbolTable table) - { - if (CurrentIs("Ident")) - { - var ident = Expect("Ident"); - var typeFromTable = table.FindType(ident.Value); - if (typeFromTable == null) - { - throw new UnknownIdentifierReference( - new IdentifierReference(ident.Value) - {Segment = ident.Segment} - ); - } - - return WithSuffix(typeFromTable); - } - - if (CurrentIs("LeftCurl")) - { - Expect("LeftCurl"); - var propertyTypes = new List(); - while (CurrentIs("Ident")) - { - var ident = Expect("Ident"); - Expect("Colon"); - var propType = TypeValue(table); - propertyTypes.Add(new PropertyType(ident.Value, propType)); - Expect("SemiColon"); - } - - Expect("RightCurl"); - - return WithSuffix(new ObjectType(propertyTypes)); - } - - if (CurrentIs("LeftParen")) - { - Expect("LeftParen"); - var args = new List(); - while (CurrentIs("Ident") || CurrentIs("LeftCurl") || CurrentIs("LeftParen")) - { - args.Add(TypeValue(table)); - if (!CurrentIs("RightParen")) - { - Expect("Comma"); - } - } - Expect("RightParen"); - Expect("Arrow"); - var returnType = TypeValue(table); - return new FunctionType(returnType, args); - } - - return null; - } - - private Type WithSuffix(Type baseType) - { - var type = baseType; - while (CurrentIs("LeftBracket") || CurrentIs("QuestionMark")) - { - if (CurrentIs("LeftBracket")) - { - Expect("LeftBracket"); - Expect("RightBracket"); - type = new ArrayType(type); - } - else if (CurrentIs("QuestionMark")) - { - Expect("QuestionMark"); - type = new NullableType(type); - } - } - - return type; - } - - private Declaration Declaration(SymbolTable table) - { - if (CurrentIsKeyword("function")) - { - return FunctionDeclaration(table); - } - - if (CurrentIsKeyword("let") || CurrentIsKeyword("const")) - { - return LexicalDeclaration(table); - } - - return null; - } - - private FunctionDeclaration FunctionDeclaration(SymbolTable table) - { - var newTable = new SymbolTable(); - newTable.AddOpenScope(table); - - Expect("Keyword", "function"); - var ident = Expect("Ident"); - - Expect("LeftParen"); - var args = new List(); - if (CurrentIs("Ident")) - { - var arg = Expect("Ident").Value; - Expect("Colon"); - var type = TypeValue(table); - args.Add(new VariableSymbol(arg, type)); - } - - while (CurrentIs("Comma")) - { - Expect("Comma"); - var arg = Expect("Ident").Value; - Expect("Colon"); - var type = TypeValue(table); - args.Add(new VariableSymbol(arg, type)); - } - - Expect("RightParen"); - - var returnType = TypeUtils.JavaScriptTypes.Void; - if (CurrentIs("Colon")) - { - Expect("Colon"); - returnType = TypeValue(table); - } - - var functionSymbol = - new FunctionSymbol(ident.Value, args, - new FunctionType(returnType, args.Select(x => x.Type)) - ); - table.AddSymbol(functionSymbol); - - return new FunctionDeclaration(functionSymbol, BlockStatement(newTable)) - { - Segment = ident.Segment, - SymbolTable = newTable - }; - } - - private LexicalDeclaration LexicalDeclaration(SymbolTable table) - { - var readOnly = CurrentIsKeyword("const"); - Expect("Keyword", readOnly ? "const" : "let"); - var declaration = new LexicalDeclaration(readOnly) - { - SymbolTable = table - }; - - AddToDeclaration(declaration, table); - - while (CurrentIs("Comma")) - { - Expect("Comma"); - AddToDeclaration(declaration, table); - } - - return declaration; - } - - private void AddToDeclaration(LexicalDeclaration declaration, SymbolTable table) - { - var ident = Expect("Ident"); - if (CurrentIs("Assign")) - { - var assignSegment = Expect("Assign").Segment; - declaration.AddAssignment(ident.Value, ident.Segment, Expression(table), assignSegment); - } - else if (CurrentIs("Colon")) - { - Expect("Colon"); - var type = TypeValue(table); - if (CurrentIs("Assign")) - { - var assignSegment = Expect("Assign").Segment; - declaration.AddAssignment(ident.Value, ident.Segment, Expression(table), assignSegment, type); - } - else - { - declaration.AddAssignment( - ident.Value, - ident.Segment, - new Literal( - type, - TypeUtils.GetDefaultValue(type), - label: TypeUtils.GetDefaultValue(type) == null ? "null" : null - ) - ); - } - } - } - - private Expression Expression(SymbolTable table) - { - return AssignmentExpression(table); - } - - private Expression AssignmentExpression(SymbolTable table) - { - var lhs = LeftHandSideExpression(table); - if (CurrentIs("Assign") && !(lhs is CallExpression)) - { - var assign = Expect("Assign"); - var member = lhs is IdentifierReference reference - ? (MemberExpression) reference - : (MemberExpression) lhs; - return new AssignmentExpression(member, AssignmentExpression(table)) - {SymbolTable = table, Segment = assign.Segment}; - } - - return lhs; - } - - private Expression LeftHandSideExpression(SymbolTable table) - { - var expr = CastExpression(table); - if (expr is IdentifierReference identRef) - { - if (CurrentIs("LeftParen") || CurrentIs("LeftBracket") || CurrentIs("Dot")) - { - return CallExpression(identRef, table); - } - } - - return expr; - } - - private Expression CallExpression(IdentifierReference identRef, SymbolTable table) - { - var member = MemberExpression(identRef, table); - if (CurrentIs("LeftParen")) - { - var lp = Expect("LeftParen"); - var expressions = new List(); - if (CurrentIs("Ident") || CurrentIsLiteral() || CurrentIs("LeftParen") || CurrentIsOperator("-")) - { - expressions.Add(Expression(table)); - } - - while (CurrentIs("Comma")) - { - Expect("Comma"); - expressions.Add(Expression(table)); - } - - Expect("RightParen"); - return new CallExpression(member, expressions) - { - SymbolTable = table, - Segment = lp.Segment - }; - } - - return member; - } - - private MemberExpression MemberExpression(IdentifierReference identRef, SymbolTable table) - { - var accessChain = new List(); - while (CurrentIs("LeftBracket") || CurrentIs("Dot")) - { - Token access; - if (CurrentIs("LeftBracket")) - { - access = Expect("LeftBracket"); - var lb = access.Segment; - var expr = Expression(table); - var rb = Expect("RightBracket").Segment; - accessChain.Add( - new IndexAccess(expr, accessChain.LastOrDefault()) {Segment = lb + rb} - ); - } - else if (CurrentIs("Dot")) - { - access = Expect("Dot"); - var identToken = Expect("Ident"); - var idRef = new IdentifierReference(identToken.Value) - { - Segment = identToken.Segment, - SymbolTable = table - }; - accessChain.Add( - new DotAccess(idRef, accessChain.LastOrDefault()) {Segment = access.Segment} - ); - } - } - - return new MemberExpression(identRef, accessChain.FirstOrDefault()) - { - SymbolTable = table - }; - } - - private Expression CastExpression(SymbolTable table) - { - var cond = ConditionalExpression(table); - if (CurrentIsKeyword("as")) - { - var asKeyword = Expect("Keyword", "as"); - var type = TypeValue(table); - return new CastAsExpression(cond, type) {Segment = asKeyword.Segment}; - } - - return cond; - } - - private Expression ConditionalExpression(SymbolTable table) - { - var test = OrExpression(table); - if (CurrentIs("QuestionMark")) - { - Expect("QuestionMark"); - var consequent = AssignmentExpression(table); - Expect("Colon"); - var alternate = AssignmentExpression(table); - return new ConditionalExpression(test, consequent, alternate); - } - - return test; - } - - private Expression OrExpression(SymbolTable table) - { - var left = AndExpression(table); - while (CurrentIsOperator("||")) - { - var op = Expect("Operator"); - var right = AndExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression AndExpression(SymbolTable table) - { - var left = EqualityExpression(table); - while (CurrentIsOperator("&&")) - { - var op = Expect("Operator"); - var right = EqualityExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression EqualityExpression(SymbolTable table) - { - var left = RelationExpression(table); - while (CurrentIsOperator("==") || CurrentIsOperator("!=")) - { - var op = Expect("Operator"); - var right = RelationExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression RelationExpression(SymbolTable table) - { - var left = AdditiveExpression(table); - while (CurrentIsOperator(">") || CurrentIsOperator("<") || CurrentIsOperator(">=") || - CurrentIsOperator("<=")) - { - var op = Expect("Operator"); - var right = AdditiveExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression AdditiveExpression(SymbolTable table) - { - var left = MultiplicativeExpression(table); - while (CurrentIsOperator("+") || CurrentIsOperator("-")) - { - var op = Expect("Operator"); - var right = MultiplicativeExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression MultiplicativeExpression(SymbolTable table) - { - var left = UnaryExpression(table); - while (CurrentIsOperator("*") || CurrentIsOperator("/") || CurrentIsOperator("%") - || CurrentIsOperator("++") || CurrentIsOperator("::")) - { - var op = Expect("Operator"); - var right = UnaryExpression(table); - left = new BinaryExpression(left, op.Value, right) - { - Segment = op.Segment - }; - } - - return left; - } - - private Expression UnaryExpression(SymbolTable table) - { - if (CurrentIsOperator("-") || CurrentIsOperator("!") || CurrentIsOperator("~")) - { - var op = Expect("Operator"); - return new UnaryExpression(op.Value, UnaryExpression(table)) - { - Segment = op.Segment - }; - } - - return PrimaryExpression(table); - } - - private Expression PrimaryExpression(SymbolTable table) - { - if (CurrentIs("LeftParen")) - { - Expect("LeftParen"); - var expr = Expression(table); - Expect("RightParen"); - return expr; - } - - if (CurrentIs("Ident")) - { - var ident = Expect("Ident"); - var id = new IdentifierReference(ident.Value) - { - Segment = ident.Segment, - SymbolTable = table - }; - - return id; - } - - if (CurrentIsLiteral()) - { - return Literal(); - } - - if (CurrentIs("LeftCurl")) - { - return ObjectLiteral(table); - } - - if (CurrentIs("LeftBracket")) - { - return ArrayLiteral(table); - } - - return null; - } - - private Literal Literal() - { - var segment = _tokens.Current!.Segment; - if (CurrentIs("StringLiteral")) - { - var str = Expect("StringLiteral"); - return new Literal( - TypeUtils.JavaScriptTypes.String, - Regex.Unescape(str.Value.Trim('"')), - segment, - str.Value - .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), segment), - "BooleanLiteral" => new Literal(TypeUtils.JavaScriptTypes.Boolean, - bool.Parse(Expect("BooleanLiteral").Value), segment), - _ => new Literal(TypeUtils.JavaScriptTypes.Undefined, new TypeUtils.Undefined()) - }; - } - - private ObjectLiteral ObjectLiteral(SymbolTable table) - { - var newTable = new SymbolTable(); - newTable.AddOpenScope(table); - Expect("LeftCurl"); - var properties = new List(); - var methods = new List(); - while (CurrentIs("Ident")) - { - var idToken = Expect("Ident"); - var id = new IdentifierReference(idToken.Value) - { - Segment = idToken.Segment, - SymbolTable = newTable - }; - if (CurrentIs("Colon")) - { - Expect("Colon"); - var expr = Expression(newTable); - properties.Add(new Property(id, expr)); - } - else if (CurrentIs("Arrow")) - { - Expect("Arrow"); - Expect("LeftParen"); - var args = new List(); - while (CurrentIs("Ident")) - { - var name = Expect("Ident").Value; - Expect("Colon"); - var type = TypeValue(newTable); - args.Add(new VariableSymbol(name, type)); - if (!CurrentIs("RightParen")) - { - Expect("Comma"); - } - } - Expect("RightParen"); - var returnType = TypeUtils.JavaScriptTypes.Void; - if (CurrentIs("Colon")) - { - Expect("Colon"); - returnType = TypeValue(newTable); - } - - var functionSymbol = new FunctionSymbol(idToken.Value, args, - new FunctionType(returnType, args.Select(a => a.Type)) - ); - newTable.AddSymbol(functionSymbol); - var bodyTable = new SymbolTable(); - bodyTable.AddOpenScope(newTable); - methods.Add(new FunctionDeclaration(functionSymbol, BlockStatement(bodyTable)) - { - Segment = idToken.Segment, - SymbolTable = bodyTable - }); - } - - Expect("SemiColon"); - } - Expect("RightCurl"); - return new ObjectLiteral(properties, methods) - { - SymbolTable = newTable - }; - } - - private ArrayLiteral ArrayLiteral(SymbolTable table) - { - var lb = Expect("LeftBracket").Segment; - var expressions = new List(); - while (CurrentIs("Ident") || CurrentIsLiteral() || - CurrentIs("LeftParen") || CurrentIsOperator("-") || - CurrentIsOperator("!") || CurrentIs("LeftCurl") || - CurrentIs("LeftBracket")) - { - expressions.Add(Expression(table)); - if (!CurrentIs("RightBracket")) - { - Expect("Comma"); - } - } - var rb = Expect("RightBracket").Segment; - return new ArrayLiteral(expressions) {Segment = lb + rb}; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/GlobalUsings.cs b/Interpreter.Lib/GlobalUsings.cs deleted file mode 100644 index ab06ac66..00000000 --- a/Interpreter.Lib/GlobalUsings.cs +++ /dev/null @@ -1,3 +0,0 @@ -// Global using directives - -global using Type = Interpreter.Lib.IR.CheckSemantics.Types.Type; \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/IAbstractSyntaxTree.cs b/Interpreter.Lib/IR/Ast/IAbstractSyntaxTree.cs deleted file mode 100644 index 15e5f494..00000000 --- a/Interpreter.Lib/IR/Ast/IAbstractSyntaxTree.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.IR.Ast; - -public interface IAbstractSyntaxTree -{ - List GetInstructions(); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs b/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs deleted file mode 100644 index a04f5e1b..00000000 --- a/Interpreter.Lib/IR/Ast/Impl/AbstractSyntaxTree.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Text; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast.Nodes; - -namespace Interpreter.Lib.IR.Ast.Impl; - -public class AbstractSyntaxTree : IAbstractSyntaxTree -{ - private readonly AbstractSyntaxTreeNode _root; - - public AbstractSyntaxTree(AbstractSyntaxTreeNode root) - { - _root = root; - } - - private void Check() => - GetAllNodes().ToList().ForEach(node => node.SemanticCheck()); - - private IEnumerable GetAllNodes() => - _root.GetAllNodes(); - - public List GetInstructions() - { - Check(); - - var start = 0; - var result = new List(); - foreach (var node in _root) - { - var instructions = node.ToInstructions(start); - result.AddRange(instructions); - start += instructions.Count; - } - - result.Sort(); - result.Add(new Halt(result.Count)); - - var calls = result.OfType().GroupBy(i => i.Jump()); - foreach (var call in calls) - { - var returns = result.OfType() - .Where(r => r.FunctionStart == call.Key); - foreach (var ret in returns) - { - foreach (var caller in call) - { - ret.AddCaller(caller.Number + 1); - } - } - } - return result; - } - - public override string ToString() - { - var tree = new StringBuilder("digraph ast {\n"); - _root.GetAllNodes().ForEach(node => - { - tree.Append('\t').Append(node).Append('\n'); - node.ToList().ForEach(child => tree.Append($"\t{node.GetHashCode()}->{child.GetHashCode()}\n")); - }); - return tree.Append("}\n").ToString(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/AbstractSyntaxTreeNode.cs b/Interpreter.Lib/IR/Ast/Nodes/AbstractSyntaxTreeNode.cs deleted file mode 100644 index 0c241ad1..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/AbstractSyntaxTreeNode.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Collections; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.CheckSemantics.Variables; - -namespace Interpreter.Lib.IR.Ast.Nodes; - -public abstract class AbstractSyntaxTreeNode : IEnumerable -{ - 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; - } - - internal List GetAllNodes() - { - var result = new List - { - this - }; - foreach (var child in this) - { - result.AddRange(child.GetAllNodes()); - } - - return result; - } - - public bool ChildOf() where T : AbstractSyntaxTreeNode - { - var parent = Parent; - while (parent != null) - { - if (parent is T) - { - return true; - } - parent = parent.Parent; - } - - return false; - } - - public void SemanticCheck() - { - if (CanEvaluate && !ChildOf()) - { - NodeCheck(); - } - } - - internal virtual Type NodeCheck() => null; - - public virtual List ToInstructions(int start) => new (); - - public abstract IEnumerator GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - protected abstract string NodeRepresentation(); - - public override string ToString() => $"{GetHashCode()} [label=\"{NodeRepresentation()}\"]"; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Declarations/Declaration.cs b/Interpreter.Lib/IR/Ast/Nodes/Declarations/Declaration.cs deleted file mode 100644 index 426a64fb..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Declarations/Declaration.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes.Declarations; - -public abstract class Declaration : StatementListItem -{ - public override bool IsDeclaration() => true; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Declarations/FunctionDeclaration.cs b/Interpreter.Lib/IR/Ast/Nodes/Declarations/FunctionDeclaration.cs deleted file mode 100644 index 7d578fde..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Declarations/FunctionDeclaration.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Declarations; - -public class FunctionDeclaration : Declaration -{ - private readonly FunctionSymbol _function; - - private readonly BlockStatement _statements; - - public FunctionDeclaration(FunctionSymbol function, BlockStatement statements) - { - _function = function; - function.Body = this; - - _statements = statements; - _statements.Parent = this; - } - - public bool HasReturnStatement() => _statements.HasReturnStatement(); - - 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 FunctionSymbol GetSymbol() => _function; - - public override IEnumerator GetEnumerator() - { - yield return _statements; - } - - protected override string NodeRepresentation() => $"function {_function.Id}"; - - public override List ToInstructions(int start) - { - var instructions = new List(); - if (_statements.Any()) - { - _function.CallInfo.Location = start + 1; - - var body = new List - { - new BeginFunction(_function.CallInfo.Location, _function.CallInfo) - }; - body.AddRange(_statements.ToInstructions(_function.CallInfo.Location + 1)); - if (!_statements.HasReturnStatement()) - { - body.Add(new Return(_function.CallInfo.Location, body.Last().Number + 1)); - } - - instructions.Add(new Goto(body.Last().Number + 1, start)); - - instructions.AddRange(body); - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Declarations/LexicalDeclaration.cs b/Interpreter.Lib/IR/Ast/Nodes/Declarations/LexicalDeclaration.cs deleted file mode 100644 index 056519e4..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Declarations/LexicalDeclaration.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.FrontEnd.GetTokens.Data; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Declarations; - -public class LexicalDeclaration : Declaration -{ - private readonly DeclarationType _declarationType; - private readonly List _assignments = new(); - - public LexicalDeclaration(bool readOnly) - { - _declarationType = readOnly ? DeclarationType.Const : DeclarationType.Let; - } - - public void AddAssignment(string id, Segment identSegment, Expression expression, Segment assignSegment = null, Type destinationType = null) - { - var identRef = new IdentifierReference(id) - { - SymbolTable = SymbolTable, - Segment = identSegment - }; - var assignment = - new AssignmentExpression( - new MemberExpression(identRef, null), - expression, - destinationType - ) - { - SymbolTable = SymbolTable, - Segment = assignSegment, - Parent = this - }; - _assignments.Add(assignment); - } - - public bool Const() => _declarationType == DeclarationType.Const; - - public override IEnumerator GetEnumerator() => _assignments.GetEnumerator(); - - protected override string NodeRepresentation() => _declarationType.ToString(); - - public override List ToInstructions(int start) - { - var instructions = new List(); - var offset = start; - foreach (var aInstructions in _assignments.Select(assignment => assignment.ToInstructions(offset))) - { - instructions.AddRange(aInstructions); - offset += aInstructions.Count; - } - - return instructions; - } - - private enum DeclarationType - { - Let, - Const - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/AccessExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/AccessExpression.cs deleted file mode 100644 index 9ffd5e11..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/AccessExpression.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; - -public abstract class AccessExpression : Expression -{ - public AccessExpression Next { get; private set; } - - protected AccessExpression(AccessExpression prev) - { - if (prev != null) - { - Parent = prev; - prev.Next = this; - } - } - - public AccessExpression Tail - { - get - { - var head = this; - while (head.HasNext()) - { - head = head.Next; - } - - return head; - } - } - - public abstract Type Check(Type prev); - - public bool HasNext() => Next != null; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/DotAccess.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/DotAccess.cs deleted file mode 100644 index b2ea92b8..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/DotAccess.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; - -public class DotAccess : AccessExpression -{ - private readonly IdentifierReference _id; - - public DotAccess(IdentifierReference id, AccessExpression prev = null) : base(prev) - { - _id = id; - _id.Parent = this; - } - - public string Id => _id.Id; - - public override Type Check(Type prev) - { - if (prev is ObjectType objectType) - { - var fieldType = objectType[_id.Id]; - if (fieldType != null) - { - return HasNext() ? Next.Check(fieldType) : fieldType; - } - - throw new ObjectAccessException(Segment, objectType, _id.Id); - } - - return null; - } - - public override IEnumerator GetEnumerator() - { - yield return _id; - if (HasNext()) - { - yield return Next; - } - } - - protected override string NodeRepresentation() => "."; - - public override List ToInstructions(int start, string temp) - { - if (HasNext()) - { - var left = "_t" + start; - var nextInstructions = Next.ToInstructions(start + 1, left); - nextInstructions.Insert(0, - new Simple(left, (new Name(temp), new Constant(_id.Id, _id.Id)), ".", start) - ); - return nextInstructions; - } - - return new(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/IndexAccess.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/IndexAccess.cs deleted file mode 100644 index f733a7a1..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AccessExpressions/IndexAccess.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; - -public class IndexAccess : AccessExpression -{ - private readonly Expression _expression; - - public IndexAccess(Expression expression, AccessExpression prev = null) : base(prev) - { - _expression = expression; - _expression.Parent = this; - } - - public PrimaryExpression Expression => _expression as PrimaryExpression; - - public override IEnumerator GetEnumerator() - { - yield return _expression; - if (HasNext()) - { - yield return Next; - } - } - - public override Type Check(Type prev) - { - if (prev is ArrayType arrayType) - { - var indexType = _expression.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 List ToInstructions(int start, string temp) - { - if (HasNext()) - { - if (_expression is PrimaryExpression prim) - { - var left = "_t" + start; - var nextInstructions = Next.ToInstructions(start + 1, left); - nextInstructions.Insert(0, - new Simple(left, (new Name(temp), prim.ToValue()), "[]", start) - ); - return nextInstructions; - } - - throw new NotImplementedException(); - } - - return new(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AssignmentExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/AssignmentExpression.cs deleted file mode 100644 index b98f1299..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/AssignmentExpression.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class AssignmentExpression : Expression -{ - private readonly MemberExpression _destination; - private readonly Expression _source; - private readonly Type _destinationType; - - public AssignmentExpression(MemberExpression destination, Expression source, Type destinationType = null) - { - _destination = destination; - destination.Parent = this; - - _source = source; - source.Parent = this; - - _destinationType = destinationType; - } - - internal override Type NodeCheck() - { - var id = _destination.Id; - var type = _source.NodeCheck(); - if (Parent is LexicalDeclaration declaration) - { - if (declaration.Const() && type.Equals(TypeUtils.JavaScriptTypes.Undefined)) - { - throw new ConstWithoutInitializer(_destination); - } - - if (SymbolTable.ContainsSymbol(_destination.Id)) - { - throw new DeclarationAlreadyExists(_destination); - } - - 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.Const(), _source.SymbolTable) - { - Table = _source.SymbolTable - }); - } - else - { - SymbolTable.AddSymbol(new VariableSymbol(id, typeOfSymbol, declaration.Const())); - } - } - else - { - var symbol = SymbolTable.FindSymbol(id); - if (symbol != null) - { - if (symbol.ReadOnly) - { - throw new AssignmentToConst(_destination); - } - - if (!_destination.NodeCheck().Equals(type)) - { - throw new IncompatibleTypesOfOperands(Segment, symbol.Type, type); - } - } - } - - return type; - } - - public override List ToInstructions(int start) - { - var instructions = new List(); - var destInstructions = _destination.ToInstructions(start, _destination.Id); - var srcInstructions = _source.ToInstructions(start + destInstructions.Count, _destination.Id); - - instructions.AddRange(destInstructions); - instructions.AddRange(srcInstructions); - start += instructions.Count; - - if (_source is MemberExpression member && member.Any()) - { - var access = (member.First() as AccessExpression)?.Tail; - var dest = destInstructions.Any() - ? destInstructions.OfType().Last().Left - : _destination.Id; - var src = srcInstructions.Any() - ? srcInstructions.OfType().Last().Left - : member.Id; - var instruction = access switch - { - DotAccess dot => new Simple(dest, (new Name(src), new Constant(dot.Id, dot.Id)), ".", start), - IndexAccess index => new Simple(dest, (new Name(src), index.Expression.ToValue()), "[]", start), - _ => throw new NotImplementedException() - }; - instructions.Add(instruction); - start++; - } - - var last = instructions.OfType().LastOrDefault(); - if (last != null) - { - if (_source is AssignmentExpression) - { - instructions.Add(new Simple( - _destination.Id, - (null, new Name(last.Left)), - "", last.Jump() - )); - start++; - } - else - { - last.Left = _destination.Id; - } - } - - if (_destination.Any()) - { - var access = (_destination.First() as AccessExpression)?.Tail; - var lastIndex = instructions.Count - 1; - last = instructions.OfType().Last(); - if (last.Assignment) - { - instructions.RemoveAt(lastIndex); - start--; - } - else - { - last.Left = "_t" + last.Number; - } - - var dest = destInstructions.Any() - ? destInstructions.OfType().Last().Left - : _destination.Id; - var src = !last.Assignment - ? new Name(last.Left) - : last.Source; - Instruction instruction = access switch - { - DotAccess dot => new DotAssignment(dest, (new Constant(dot.Id, @$"\""{dot.Id}\"""), src), start), - IndexAccess index => new IndexAssignment(dest, (index.Expression.ToValue(), src), start), - _ => throw new NotImplementedException() - }; - instructions.Add(instruction); - } - - return instructions; - } - - public override IEnumerator GetEnumerator() - { - yield return _destination; - yield return _source; - } - - protected override string NodeRepresentation() => "="; - - public override List ToInstructions(int start, string temp) => ToInstructions(start); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/BinaryExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/BinaryExpression.cs deleted file mode 100644 index 3d3963ea..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/BinaryExpression.cs +++ /dev/null @@ -1,209 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class BinaryExpression : Expression -{ - private readonly Expression _left; - - private readonly string _operator; - - private readonly Expression _right; - - public BinaryExpression(Expression left, string @operator, Expression right) - { - _left = left; - _left.Parent = this; - - _operator = @operator; - - _right = 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; - yield return _right; - } - - protected override string NodeRepresentation() => _operator; - - public override List ToInstructions(int start) - { - if (_left is IdentifierReference arr && _right.Primary() && _operator == "::") - { - return new List - { - new RemoveFromArray(start, arr.Id, ((PrimaryExpression) _right).ToValue()) - }; - } - - throw new NotImplementedException(); - } - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - (IValue left, IValue right) newRight = (null, null); - - var lInstructions = new List(); - var rInstructions = new List(); - - if (_left.Primary()) - { - newRight.left = ((PrimaryExpression) _left).ToValue(); - } - else - { - lInstructions.AddRange(_left.ToInstructions(start, temp)); - if (_left is MemberExpression member && member.Any()) - { - var i = start + lInstructions.Count; - var dest = "_t" + i; - var src = lInstructions.Any() - ? lInstructions.OfType().Last().Left - : member.Id; - var instruction = member.AccessChain.Tail switch - { - DotAccess dot => new Simple(dest, (new Name(src), new Constant(dot.Id, dot.Id)), ".", i), - IndexAccess index => new Simple(dest, (new Name(src), index.Expression.ToValue()), "[]", i), - _ => throw new NotImplementedException() - }; - lInstructions.Add(instruction); - } - newRight.left = new Name(lInstructions.OfType().Last().Left); - } - - if (_right.Primary()) - { - newRight.right = ((PrimaryExpression) _right).ToValue(); - } - else - { - var c = _left.Primary() - ? start - : lInstructions.Last().Number + 1; - rInstructions.AddRange(_right.ToInstructions(c, temp)); - if (_right is MemberExpression member && member.Any()) - { - var i = c + rInstructions.Count; - var dest = "_t" + i; - var src = rInstructions.Any() - ? rInstructions.OfType().Last().Left - : member.Id; - var instruction = member.AccessChain.Tail switch - { - DotAccess dot => new Simple(dest, (new Name(src), new Constant(dot.Id, dot.Id)), ".", i), - IndexAccess index => new Simple(dest, (new Name(src), index.Expression.ToValue()), "[]", i), - _ => throw new NotImplementedException() - }; - rInstructions.Add(instruction); - } - newRight.right = new Name(rInstructions.OfType().Last().Left); - } - - instructions.AddRange(lInstructions); - instructions.AddRange(rInstructions); - - var number = instructions.Any() ? instructions.Last().Number + 1 : start; - - instructions.Add - ( - new Simple( - temp + number, - newRight, _operator, number - ) - ); - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/CallExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/CallExpression.cs deleted file mode 100644 index 60d46166..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/CallExpression.cs +++ /dev/null @@ -1,195 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class CallExpression : Expression -{ - private readonly MemberExpression _ident; - private readonly List _expressions; - - public CallExpression(MemberExpression ident, IEnumerable expressions) - { - _ident = ident; - _ident.Parent = this; - - _expressions = new List(expressions); - _expressions.ForEach(expr => expr.Parent = this); - } - - private FunctionSymbol GetFunction() - { - if (_ident.Any()) - { - var table = SymbolTable.FindSymbol(_ident.Id).Table; - var chain = _ident.AccessChain; - while (chain.HasNext()) - { - table = chain switch - { - DotAccess dot => table.FindSymbol(dot.Id).Table, - IndexAccess => throw new NotImplementedException(), - _ => throw new NotImplementedException() - }; - chain = chain.Next; - } - - return table.FindSymbol(((DotAccess) chain).Id); - } - - return SymbolTable.FindSymbol(_ident.Id); - } - - internal override Type NodeCheck() - { - if (_ident.Any()) - { - _ident.NodeCheck(); - } - else - { - IdentifierReference idRef = _ident; - idRef.NodeCheck(); - } - - var function = GetFunction(); - if (function == null) - { - throw new SymbolIsNotCallable(_ident.Id, Segment); - } - - if (!function.Type.ReturnType.Equals(TypeUtils.JavaScriptTypes.Void)) - { - if (!function.Body.HasReturnStatement()) - { - throw new FunctionWithoutReturnStatement(function.Body.Segment); - } - } - - function.Body.SetArguments(this, _expressions); - - 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._ident.Id == _ident.Id)) - { - node.NodeCheck(); - } - } - - function.Body.Clear(); - return TypeUtils.JavaScriptTypes.Void; - } - - public override IEnumerator GetEnumerator() - { - var nodes = new List - { - _ident - }; - nodes.AddRange(_expressions); - return nodes.GetEnumerator(); - } - - protected override string NodeRepresentation() => "()"; - - private List Print(int start) - { - var instructions = new List(); - var expression = _expressions.First(); - if (!expression.Primary()) - { - instructions.AddRange(expression.ToInstructions(start, "_t")); - instructions.Add(new Print( - instructions.Last().Number + 1, - new Name(instructions.OfType().Last().Left) - )); - } - else - { - instructions.Add(new Print(start, ((PrimaryExpression) expression).ToValue())); - } - - return instructions; - } - - public override List ToInstructions(int start) - { - return _ident.Id switch - { - "print" when !_ident.Any() => Print(start), - _ => ToInstructions(start, null) - }; - } - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - FunctionSymbol function; - if (!_ident.Any()) - { - function = SymbolTable.FindSymbol(_ident.Id); - } - else - { - function = GetFunction(); - instructions.AddRange(_ident.ToInstructions(start, temp)); - function.CallInfo.MethodOf = instructions.Any() - ? instructions.OfType().Last().Left - : function.CallInfo.MethodOf; - instructions.Add( - new PushParameter( - start + instructions.Count, - "this", new Name(function.CallInfo.MethodOf)) - ); - } - if (function.Body.First().Any()) - { - _expressions.Zip(function.Parameters).ToList<(Expression expr, Symbol param)>() - .ForEach(item => - { - var (expr, symbol) = item; - var paramInstructions = expr.Primary() - ? new List() - : expr.ToInstructions(start, "_t"); - var pushNumber = start + instructions.Count + paramInstructions.Count; - var pushValue = expr.Primary() - ? ((PrimaryExpression) expr).ToValue() - : new Name(paramInstructions.OfType().Last().Left); - paramInstructions.Add( - new PushParameter(pushNumber, symbol.Id, pushValue) - ); - instructions.AddRange(paramInstructions); - }); - var left = temp != null - ? temp + (start + instructions.Count) - : null; - instructions.Add( - new CallFunction( - function.CallInfo, - start + instructions.Count, - function.Parameters.Count, left - )); - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/CastAsExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/CastAsExpression.cs deleted file mode 100644 index 5c9f5503..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/CastAsExpression.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class CastAsExpression : Expression -{ - private readonly Expression _expression; - private readonly Type _cast; - - public CastAsExpression(Expression expression, Type cast) - { - _expression = expression; - _expression.Parent = this; - - _cast = cast; - } - - internal override Type NodeCheck() => - TypeUtils.JavaScriptTypes.String; - - public override IEnumerator GetEnumerator() - { - yield return _expression; - } - - protected override string NodeRepresentation() => $"as {_cast}"; - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - var castNumber = start; - - if (!_expression.Primary()) - { - instructions.AddRange(_expression.ToInstructions(start, "_t")); - castNumber = instructions.Last().Number + 1; - } - - instructions.Add(new AsString( - "_t" + castNumber, - _expression.Primary() - ? ((PrimaryExpression) _expression).ToValue() - : new Name(instructions.OfType().Last().Left), - castNumber - )); - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs deleted file mode 100644 index 8d555a68..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ArrayLiteral.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.ComplexLiterals; - -public class ArrayLiteral : Expression -{ - private readonly List _expressions; - - public ArrayLiteral(IEnumerable expressions) - { - _expressions = new List(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(); - - protected override string NodeRepresentation() => "[]"; - - public override List ToInstructions(int start, string temp) - { - if (Parent is not AssignmentExpression) - { - temp = "_t" + start; - } - var instructions = new List - { - new CreateArray(start, temp, _expressions.Count) - }; - var j = 1; - for (var i = 0; i < _expressions.Count; i++) - { - var expr = _expressions[i]; - var index = new Constant(i, i.ToString()); - if (expr is PrimaryExpression prim) - { - instructions.Add(new IndexAssignment(temp, (index, prim.ToValue()), start + j)); - j++; - } - else - { - var propInstructions = expr.ToInstructions(start + j, "_t" + (start + j)); - j += propInstructions.Count; - var left = propInstructions.OfType().Last().Left; - propInstructions.Add(new IndexAssignment(temp, (index, new Name(left)), start + j)); - j++; - instructions.AddRange(propInstructions); - } - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs deleted file mode 100644 index 4f59bed5..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ComplexLiterals/ObjectLiteral.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.ComplexLiterals; - -public class ObjectLiteral : Expression -{ - private readonly List _properties; - private readonly List _methods; - - public ObjectLiteral(IEnumerable properties, IEnumerable methods) - { - _properties = new List(properties); - _properties.ForEach(prop => prop.Parent = this); - - _methods = new List(methods); - _methods.ForEach(m => 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.Id, propType)); - prop.Id.SymbolTable.AddSymbol(propType is ObjectType objectType - ? new ObjectSymbol(prop.Id.Id, objectType) {Table = prop.Expression.SymbolTable} - : new VariableSymbol(prop.Id.Id, propType) - ); - }); - _methods.ForEach(m => - { - var symbol = m.GetSymbol(); - 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(); - - protected override string NodeRepresentation() => "{}"; - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - _methods.ForEach(method => - { - var mInstructions = method.ToInstructions(start); - instructions.AddRange(mInstructions); - start += mInstructions.Count; - }); - - instructions.Add(new CreateObject(start, temp)); - var i = 1; - foreach (var (id, expr) in _properties) - { - if (expr is PrimaryExpression prim) - { - instructions.Add(new DotAssignment(temp, (new Constant(id, @$"\""{id}\"""), prim.ToValue()), start + i)); - i++; - } - else - { - var propInstructions = expr.ToInstructions(start + i, "_t" + (start + i)); - i += propInstructions.Count; - var left = propInstructions.OfType().Last().Left; - propInstructions.Add(new DotAssignment(temp, (new Constant(id, @$"\""{id}\"""), new Name(left)), start + i)); - i++; - instructions.AddRange(propInstructions); - } - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ConditionalExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/ConditionalExpression.cs deleted file mode 100644 index 2eafabaa..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/ConditionalExpression.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class ConditionalExpression : Expression -{ - private readonly Expression _test, _consequent, _alternate; - - public ConditionalExpression(Expression test, Expression consequent, Expression alternate) - { - _test = test; - _consequent = consequent; - _alternate = alternate; - - _test.Parent = this; - _consequent.Parent = this; - _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; - yield return _consequent; - yield return _alternate; - } - - protected override string NodeRepresentation() => "?:"; - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - IValue ifNotTest; - if (!_test.Primary()) - { - var testInstructions = _test.ToInstructions(start, "_t"); - ifNotTest = new Name(testInstructions.OfType().Last().Left); - instructions.AddRange(testInstructions); - } - else - { - ifNotTest = ((PrimaryExpression) _test).ToValue(); - } - - var cOffset = start + instructions.Count + 1; - var consequentInstructions = _consequent.ToInstructions(cOffset, temp); - - var aOffset = consequentInstructions.Last().Number + 2; - var alternateInstructions = _alternate.ToInstructions(aOffset, temp); - - instructions.Add( - new IfNotGoto( - ifNotTest, alternateInstructions.First().Number, cOffset - 1 - ) - ); - instructions.AddRange(consequentInstructions); - instructions.OfType().Last().Left = temp; - - instructions.Add( - new Goto(alternateInstructions.Last().Number + 1, aOffset - 1) - ); - instructions.AddRange(alternateInstructions); - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/Expression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/Expression.cs deleted file mode 100644 index a4a678a8..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/Expression.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public abstract class Expression : AbstractSyntaxTreeNode -{ - protected Expression() - { - CanEvaluate = true; - } - - public bool Primary() => !this.Any(); - - public abstract List ToInstructions(int start, string temp); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/MemberExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/MemberExpression.cs deleted file mode 100644 index 596f8302..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/MemberExpression.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class MemberExpression : Expression -{ - private readonly IdentifierReference _id; - - public AccessExpression AccessChain { get; } - - public MemberExpression(IdentifierReference id, AccessExpression accessChain) - { - _id = id; - _id.Parent = this; - - AccessChain = accessChain; - if (accessChain != null) - { - AccessChain.Parent = this; - } - } - - public string Id => _id.Id; - - internal override Type NodeCheck() - { - if (AccessChain == null) - { - return _id.NodeCheck(); - } - - var symbol = SymbolTable.FindSymbol(_id.Id); - if (symbol == null) - { - throw new UnknownIdentifierReference(_id); - } - - return AccessChain.Check(symbol.Type); - } - - public override IEnumerator GetEnumerator() - { - if (AccessChain != null) - { - yield return AccessChain; - } - } - - protected override string NodeRepresentation() => Id; - - public override List ToInstructions(int start, string temp) - { - if (AccessChain != null && AccessChain.HasNext()) - { - return AccessChain.ToInstructions(start, _id.Id); - } - - return new(); - } - - public static implicit operator IdentifierReference(MemberExpression member) => - member._id; - - public static explicit operator MemberExpression(IdentifierReference idRef) => - new (idRef, null); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs deleted file mode 100644 index 7fd61bf9..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/IdentifierReference.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -public class IdentifierReference : PrimaryExpression -{ - public string Id { get; } - - public IdentifierReference(string id) - { - Id = id; - } - - internal override Type NodeCheck() - { - if (!ChildOf()) - { - var symbol = SymbolTable.FindSymbol(Id); - return symbol switch - { - VariableSymbol v => v.Type, - FunctionSymbol f => f.Type, - _ => throw new UnknownIdentifierReference(this) - }; - } - - return null; - } - - protected override string NodeRepresentation() => Id; - - public override IValue ToValue() => new Name(Id); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/Literal.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/Literal.cs deleted file mode 100644 index b0286598..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/Literal.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.FrontEnd.GetTokens.Data; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -public class Literal : PrimaryExpression -{ - private readonly Type _type; - private readonly object _value; - private readonly string _label; - - public Literal(Type type, object value, Segment segment = null, string label = null) - { - _type = type; - _label = label ?? value.ToString(); - _value = value; - Segment = segment; - } - - internal override Type NodeCheck() => _type; - - protected override string NodeRepresentation() => _label; - - public override IValue ToValue() => new Constant(_value, _label); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs deleted file mode 100644 index 15b785a4..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/PrimaryExpressions/PrimaryExpression.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -public abstract class PrimaryExpression : Expression -{ - public override IEnumerator GetEnumerator() - { - yield break; - } - - public abstract IValue ToValue(); - - public override List ToInstructions(int start, string temp) => - new() - { - new Simple(temp, (null, ToValue()), "", start) - }; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Expressions/UnaryExpression.cs b/Interpreter.Lib/IR/Ast/Nodes/Expressions/UnaryExpression.cs deleted file mode 100644 index 4b2a4a1e..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Expressions/UnaryExpression.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.AccessExpressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Expressions; - -public class UnaryExpression : Expression -{ - private readonly string _operator; - - private readonly Expression _expression; - - public UnaryExpression(string @operator, Expression expression) - { - _operator = @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; - } - - protected override string NodeRepresentation() => _operator; - - public override List ToInstructions(int start, string temp) - { - var instructions = new List(); - - (IValue left, IValue right) right = (null, null); - if (_expression.Primary()) - { - right.right = ((PrimaryExpression) _expression).ToValue(); - } - else - { - instructions.AddRange(_expression.ToInstructions(start, temp)); - if (_expression is MemberExpression member && member.Any()) - { - var i = start + instructions.Count; - var dest = "_t" + i; - var src = instructions.Any() - ? instructions.OfType().Last().Left - : member.Id; - var instruction = member.AccessChain.Tail switch - { - DotAccess dot => new Simple(dest, (new Name(src), new Constant(dot.Id, dot.Id)), ".", i), - IndexAccess index => new Simple(dest, (new Name(src), index.Expression.ToValue()), "[]", i), - _ => throw new NotImplementedException() - }; - instructions.Add(instruction); - } - right.right = new Name(instructions.OfType().Last().Left); - } - - var number = instructions.Any() ? instructions.Last().Number + 1 : start; - - instructions.Add(new Simple( - temp + number, right, _operator, number - )); - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/ScriptBody.cs b/Interpreter.Lib/IR/Ast/Nodes/ScriptBody.cs deleted file mode 100644 index b2fb2be3..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/ScriptBody.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes; - -public class ScriptBody : AbstractSyntaxTreeNode -{ - private readonly List _statementList; - - public ScriptBody(IEnumerable statementList) - { - _statementList = new List(statementList); - _statementList.ForEach(item => item.Parent = this); - } - - public override IEnumerator GetEnumerator() => _statementList.GetEnumerator(); - - protected override string NodeRepresentation() => "Script"; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/StatementListItem.cs b/Interpreter.Lib/IR/Ast/Nodes/StatementListItem.cs deleted file mode 100644 index 7adf45aa..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/StatementListItem.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes; - -public abstract class StatementListItem : AbstractSyntaxTreeNode -{ - public virtual bool IsStatement() => false; - - public virtual bool IsDeclaration() => false; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/BlockStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/BlockStatement.cs deleted file mode 100644 index 004e0ed3..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/BlockStatement.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class BlockStatement : Statement -{ - private readonly List _statementList; - - public BlockStatement(IEnumerable statementList) - { - _statementList = new List(statementList); - _statementList.ForEach(item => item.Parent = this); - } - - public bool HasReturnStatement() - { - var has = _statementList.Any(item => item is ReturnStatement); - if (!has) - { - has = _statementList - .Where(item => item.IsStatement()) - .OfType() - .Any(ifStmt => ifStmt.HasReturnStatement()); - } - - return has; - } - - public override IEnumerator GetEnumerator() => _statementList.GetEnumerator(); - - protected override string NodeRepresentation() => "{}"; - - public override List ToInstructions(int start) - { - var blockInstructions = new List(); - var offset = start; - foreach (var item in _statementList) - { - var itemInstructions = item.ToInstructions(offset); - blockInstructions.AddRange(itemInstructions); - if (item is ReturnStatement) - { - break; - } - - offset += itemInstructions.Count; - } - - return blockInstructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/BreakStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/BreakStatement.cs deleted file mode 100644 index c1cfb42b..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/BreakStatement.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class BreakStatement : InsideLoopStatement -{ - protected override string NodeRepresentation() => "break"; - - public override List ToInstructions(int start) => - new() - { - new Goto(-1, start) - }; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/ContinueStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/ContinueStatement.cs deleted file mode 100644 index d4374d10..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/ContinueStatement.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class ContinueStatement : InsideLoopStatement -{ - protected override string NodeRepresentation() => "continue"; - - public override List ToInstructions(int start) => - new() - { - new Goto(-2, start) - }; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/ExpressionStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/ExpressionStatement.cs deleted file mode 100644 index bba3d9b0..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/ExpressionStatement.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class ExpressionStatement : Statement -{ - private readonly Expression _expression; - - public ExpressionStatement(Expression expression) - { - _expression = expression; - expression.Parent = this; - } - - public override IEnumerator GetEnumerator() - { - yield return _expression; - } - - protected override string NodeRepresentation() => nameof(ExpressionStatement); - - public override List ToInstructions(int start) => _expression.ToInstructions(start); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/IfStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/IfStatement.cs deleted file mode 100644 index f18fe08c..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/IfStatement.cs +++ /dev/null @@ -1,126 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class IfStatement : Statement -{ - private readonly Expression _test; - private readonly Statement _then; - private readonly Statement _else; - - public IfStatement(Expression test, Statement then, Statement @else = null) - { - _test = test; - _test.Parent = this; - - _then = then; - _then.Parent = this; - - if (@else != null) - { - _else = @else; - _else.Parent = this; - } - - CanEvaluate = true; - } - - public bool HasReturnStatement() - { - var thenResult = _then is ReturnStatement; - if (!thenResult) - { - if (_then is BlockStatement block) - { - thenResult = block.HasReturnStatement(); - } - } - - var elseResult = _else == null || _else is ReturnStatement; - if (!elseResult) - { - if (_else is BlockStatement block) - { - elseResult = block.HasReturnStatement(); - } - } - - return thenResult && elseResult; - } - - public override IEnumerator GetEnumerator() - { - yield return _test; - yield return _then; - if (_else != null) - { - yield return _else; - } - } - - internal override Type NodeCheck() - { - var testType = _test.NodeCheck(); - if (!testType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - throw new NotBooleanTestExpression(Segment, testType); - } - - return testType; - } - - protected override string NodeRepresentation() => "if"; - - public override List ToInstructions(int start) - { - var instructions = new List(); - if (_then.Any() && (_else == null || _else.Any())) - { - IValue ifNotTest; - if (!_test.Primary()) - { - var testInstructions = _test.ToInstructions(start, "_t"); - ifNotTest = new Name(testInstructions.OfType().Last().Left); - instructions.AddRange(testInstructions); - } - else - { - ifNotTest = ((PrimaryExpression) _test).ToValue(); - } - - var tOffset = start + instructions.Count + 1; - var thenInstructions = _then.ToInstructions(tOffset); - - var eOffset = thenInstructions.Any() - ? thenInstructions.Last().Number + 2 - : tOffset + 1; - var elseInstructions = _else?.ToInstructions(eOffset); - - instructions.Add( - new IfNotGoto( - ifNotTest, elseInstructions?.First().Number ?? eOffset - 1, tOffset - 1 - ) - ); - - instructions.AddRange(thenInstructions); - - if (elseInstructions != null) - { - instructions.Add( - new Goto( - elseInstructions.Last().Number + 1, - eOffset - 1 - ) - ); - instructions.AddRange(elseInstructions); - } - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/InsideLoopStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/InsideLoopStatement.cs deleted file mode 100644 index 77744c3a..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/InsideLoopStatement.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Exceptions; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public abstract class InsideLoopStatement : Statement -{ - protected InsideLoopStatement() - { - CanEvaluate = true; - } - - internal override Type NodeCheck() - { - if (!ChildOf()) - { - throw new OutsideOfLoop(Segment, NodeRepresentation()); - } - return null; - } - - public override IEnumerator GetEnumerator() - { - yield break; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/ReturnStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/ReturnStatement.cs deleted file mode 100644 index a69cb44f..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/ReturnStatement.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class ReturnStatement : Statement -{ - private readonly Expression _expression; - - public ReturnStatement(Expression expression = null) - { - _expression = expression; - CanEvaluate = true; - if (expression != null) - { - _expression.Parent = this; - } - } - - internal override Type NodeCheck() - { - if (!ChildOf()) - { - throw new ReturnOutsideFunction(Segment); - } - - return _expression?.NodeCheck() ?? TypeUtils.JavaScriptTypes.Void; - } - - public override IEnumerator GetEnumerator() - { - if (_expression == null) - { - yield break; - } - - yield return _expression; - } - - protected override string NodeRepresentation() => "return"; - - private FunctionSymbol GetCallee() - { - var parent = Parent; - while (parent != null) - { - if (parent is FunctionDeclaration declaration) - { - return declaration.GetSymbol(); - } - - parent = parent.Parent; - } - - return null; - } - - public override List ToInstructions(int start) - { - var instructions = new List(); - if (_expression == null) - { - instructions.Add(new Return(GetCallee().CallInfo.Location, start)); - } - else - { - if (_expression.Primary()) - { - instructions.Add(new Return( - GetCallee().CallInfo.Location, start, ((PrimaryExpression) _expression).ToValue()) - ); - } - else - { - var eInstructions = _expression.ToInstructions(start, "_t"); - var last = eInstructions.OfType().Last(); - instructions.AddRange(eInstructions); - instructions.Add(new Return( - GetCallee().CallInfo.Location, last.Number + 1, new Name(last.Left) - )); - } - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/Statement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/Statement.cs deleted file mode 100644 index 2a4f7f0d..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/Statement.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public abstract class Statement : StatementListItem -{ - public override bool IsStatement() => true; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/TypeStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/TypeStatement.cs deleted file mode 100644 index 07563b27..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/TypeStatement.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class TypeStatement : Statement -{ - private readonly string _typeId; - private readonly Type _typeValue; - - public TypeStatement(string typeId, Type typeValue) - { - _typeId = typeId; - _typeValue = typeValue; - } - - public override IEnumerator GetEnumerator() - { - yield break; - } - - protected override string NodeRepresentation() => - $"type {_typeId} = {_typeValue}"; -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/Ast/Nodes/Statements/WhileStatement.cs b/Interpreter.Lib/IR/Ast/Nodes/Statements/WhileStatement.cs deleted file mode 100644 index 77f4e052..00000000 --- a/Interpreter.Lib/IR/Ast/Nodes/Statements/WhileStatement.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Interpreter.Lib.IR.CheckSemantics.Exceptions; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.Ast.Nodes.Statements; - -public class WhileStatement : Statement -{ - private readonly Expression _condition; - private readonly Statement _statement; - - public WhileStatement(Expression condition, Statement statement) - { - _condition = condition; - _condition.Parent = this; - - _statement = statement; - _statement.Parent = this; - - CanEvaluate = true; - } - - public override IEnumerator GetEnumerator() - { - yield return _condition; - yield return _statement; - } - - internal override Type NodeCheck() - { - var condType = _condition.NodeCheck(); - if (!condType.Equals(TypeUtils.JavaScriptTypes.Boolean)) - { - throw new NotBooleanTestExpression(Segment, condType); - } - - return condType; - } - - protected override string NodeRepresentation() => "while"; - - public override List ToInstructions(int start) - { - var instructions = new List(); - IValue ifNotTest; - if (!_condition.Primary()) - { - var conditionInstructions = _condition.ToInstructions(start, "_t"); - ifNotTest = new Name(conditionInstructions.OfType().Last().Left); - instructions.AddRange(conditionInstructions); - } - else - { - ifNotTest = ((PrimaryExpression) _condition).ToValue(); - } - - var cOffset = start + instructions.Count + 1; - var loopBody = _statement.ToInstructions(cOffset); - if (loopBody.Any()) - { - instructions.Add(new IfNotGoto(ifNotTest, loopBody.Last().Number + 2, cOffset - 1)); - instructions.AddRange(loopBody); - instructions.Add(new Goto(start, loopBody.Last().Number + 1)); - - loopBody - .OfType() - .Where(g => g.Jump() < 0) - .ToList() - .ForEach(j => - { - if (j.Jump() == -1) - { - j.SetJump(loopBody.Last().Number + 2); - } - else if (j.Jump() == -2) - { - j.SetJump(start); - } - }); - } - else - { - instructions.Clear(); - } - - return instructions; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs deleted file mode 100644 index 353b87ea..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/AssignmentToConst.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class AssignmentToConst : SemanticException -{ - public AssignmentToConst(IdentifierReference ident) : - base(ident.Segment,$"Cannot assign to const: {ident.Id}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs deleted file mode 100644 index 2a2dd640..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/CannotDefineType.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class CannotDefineType : SemanticException -{ - public CannotDefineType(Segment segment) : - base(segment, "Cannot define type") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs deleted file mode 100644 index 9d451dd1..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class ConstWithoutInitializer : SemanticException -{ - public ConstWithoutInitializer(IdentifierReference ident) : - base(ident.Segment, $"Const without initializer: {ident.Id}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs deleted file mode 100644 index ddb751f9..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationAlreadyExists.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class DeclarationAlreadyExists : SemanticException -{ - public DeclarationAlreadyExists(IdentifierReference ident) : - base(ident.Segment, $"Declaration already exists: {ident.Id}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/OutsideOfLoop.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/OutsideOfLoop.cs deleted file mode 100644 index 2049c6cf..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/OutsideOfLoop.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class OutsideOfLoop : SemanticException -{ - public OutsideOfLoop(Segment segment, string keyword) : - base(segment, $"\"{keyword}\" outside of loop") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs deleted file mode 100644 index 5f3609e5..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/SymbolIsNotCallable.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class SymbolIsNotCallable: SemanticException -{ - public SymbolIsNotCallable(string symbol, Segment segment) : - base(segment, $"Symbol is not callable: {symbol}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs deleted file mode 100644 index 99397033..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/UnknownIdentifierReference.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -public class UnknownIdentifierReference : SemanticException -{ - public UnknownIdentifierReference(IdentifierReference ident) : - base(ident.Segment, $"Unknown identifier reference: {ident.Id}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs deleted file mode 100644 index 5ba7fdee..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/ArrayType.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public class ArrayType : Type -{ - public Type Type { get; set; } - - public ArrayType(Type type) : base($"{type}[]") - { - Type = 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) - { - if (ReferenceEquals(this, obj)) return true; - if (obj == null || GetType() != obj.GetType()) return false; - var that = (ArrayType) obj; - return Equals(Type, that.Type); - } - - public override int GetHashCode() => - // ReSharper disable once NonReadonlyMemberInGetHashCode - Type.GetHashCode(); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs deleted file mode 100644 index 98f3296b..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/FunctionType.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Text; -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public class FunctionType : Type -{ - public Type ReturnType { get; set; } - - public List Arguments { get; } - - public FunctionType(Type returnType, IEnumerable arguments) - { - ReturnType = returnType; - Arguments = new List(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; - if (obj == null || GetType() != obj.GetType()) return false; - var that = (FunctionType) obj; - return ReturnType.Equals(that.ReturnType) && - Arguments.Count == that.Arguments.Count && - Arguments.Zip(that.Arguments) - .All(pair => pair.First.Equals(pair.Second)); - } - - public override int GetHashCode() => - HashCode.Combine( - // ReSharper disable once NonReadonlyMemberInGetHashCode - ReturnType, - Arguments - .Select(arg => arg.GetHashCode()) - .Aggregate(36, HashCode.Combine) - ); - - public override string ToString() => - new StringBuilder() - .Append('(') - .AppendJoin(", ", Arguments) - .Append(')') - .Append(" => ") - .Append(ReturnType) - .ToString(); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs deleted file mode 100644 index 489d0a4e..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/NullableType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public class NullableType : Type -{ - public Type Type { get; set; } - - public NullableType(Type type) : base($"{type}?") - { - Type = type; - } - - 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) - { - if (obj is NullableType that) - { - return Type.Equals(that.Type); - } - return obj is NullType; - } - - public override int GetHashCode() => - // ReSharper disable once NonReadonlyMemberInGetHashCode - Type.GetHashCode(); -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs b/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs deleted file mode 100644 index 57f30446..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/ObjectType.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public class ObjectType : NullableType -{ - private readonly Dictionary _properties; - private readonly ObjectTypeHasher _hasher; - private readonly ObjectTypePrinter _serializer; - - public ObjectType(IEnumerable properties) - { - _properties = properties - .OrderBy(x => x.Id) - .ToDictionary( - x => x.Id, - x => x.Type - ); - _hasher = new ObjectTypeHasher(this); - _serializer = new ObjectTypePrinter(this); - } - - public Type this[string id] - { - get => _properties.ContainsKey(id) - ? _properties[id] - : null; - set => _properties[id] = value; - } - - public IEnumerable Keys => _properties.Keys; - - public void ResolveSelfReferences(string self) => - new ReferenceResolver(this, self) - .Visit(this); - - 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 (obj is ObjectType that) - { - return ReferenceEquals(this, that) || _properties.Count == that._properties.Count && - _properties - .Zip(that._properties) - .All(pair => - pair.First.Key == pair.Second.Key && - pair.First.Value.Equals(pair.Second.Value) - ); - } - - return obj is NullType; - } - - public override int GetHashCode() => - _hasher.Visit(this); - - public override string ToString() => - _serializer.Visit(this); -} - -public record PropertyType(string Id, Type Type); \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs b/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs deleted file mode 100644 index 4b1d7aa5..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Type.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Types.Visitors; -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types; - -public class Type : - IVisitable, - IVisitable, - IVisitable -{ - private readonly string _name; - - 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; - if (obj == null || GetType() != obj.GetType()) return false; - var that = (Type) obj; - return Equals(_name, that._name); - } - - public override int GetHashCode() => - _name.GetHashCode(); - - public override string ToString() => _name; - - public static implicit operator Type(string alias) => new(alias); - - public static bool operator ==(Type left, Type right) => Equals(left, right); - - public static bool operator !=(Type left, Type right) => !(left == right); -} \ No newline at end of file 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 ef33b5ef..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypeHasher.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Visitor.NET.Lib.Core; - -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 1f11d91a..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ObjectTypePrinter.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Text; -using Visitor.NET.Lib.Core; - -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/Types/Visitors/ReferenceResolver.cs b/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs deleted file mode 100644 index 483654f0..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Types/Visitors/ReferenceResolver.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Visitor.NET.Lib.Core; - -namespace Interpreter.Lib.IR.CheckSemantics.Types.Visitors; - -public class ReferenceResolver : - IVisitor, - IVisitor, - IVisitor, - IVisitor, - IVisitor -{ - private readonly ObjectType _reference; - private readonly string _refId; - private readonly HashSet _visited; - - public ReferenceResolver(ObjectType reference, string refId) - { - _reference = reference; - _refId = refId; - _visited = new(); - } - - public Unit Visit(ObjectType visitable) - { - if (_visited.Contains(visitable)) - return default; - _visited.Add(visitable); - - foreach (var key in visitable.Keys) - if (_refId == visitable[key]) - visitable[key] = _reference; - else - visitable[key].Accept(this); - return default; - } - - public Unit Visit(Type visitable) => default; - - public Unit Visit(ArrayType visitable) - { - if (visitable.Type == _refId) - visitable.Type = _reference; - else - visitable.Type.Accept(this); - return default; - } - - public Unit Visit(FunctionType visitable) - { - if (visitable.ReturnType == _refId) - visitable.ReturnType = _reference; - else - visitable.ReturnType.Accept(this); - - for (var i = 0; i < visitable.Arguments.Count; i++) - { - var argType = visitable.Arguments[i]; - if (argType == _refId) - visitable.Arguments[i] = _reference; - else - argType.Accept(this); - } - - return default; - } - - public Unit Visit(NullableType visitable) - { - if (visitable.Type == _refId) - visitable.Type = _reference; - else - visitable.Type.Accept(this); - return default; - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs deleted file mode 100644 index 2a7d33f4..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/SymbolTable.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -namespace Interpreter.Lib.IR.CheckSemantics.Variables; - -public class SymbolTable -{ - private readonly Dictionary _symbols = new(); - private readonly Dictionary _types = new(); - - private SymbolTable _openScope; - - public void AddOpenScope(SymbolTable table) - { - _openScope = table; - } - - public void AddSymbol(Symbol symbol) => _symbols[symbol.Id] = symbol; - - public void AddType(Type type, string typeId = null) => - _types[typeId ?? type.ToString()] = type; - - public Type FindType(string typeId) - { - var hasInsideTheScope = _types.TryGetValue(typeId, out var type); - return !hasInsideTheScope ? _openScope?.FindType(typeId) : type; - } - - /// - /// Поиск эффективного символа - /// - public T FindSymbol(string id) where T : Symbol - { - var hasInsideTheScope = _symbols.TryGetValue(id, out var symbol); - return !hasInsideTheScope ? _openScope?.FindSymbol(id) : symbol as T; - } - - /// - /// Проверяет наличие собственного символа - /// - 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 b9b228da..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.Nodes; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.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.AddType(TypeUtils.JavaScriptTypes.Number); - library.AddType(TypeUtils.JavaScriptTypes.Boolean); - library.AddType(TypeUtils.JavaScriptTypes.String); - library.AddType(TypeUtils.JavaScriptTypes.Null); - library.AddType(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 deleted file mode 100644 index a7144623..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/FunctionSymbol.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text; -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -public class FunctionSymbol : Symbol -{ - 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) : - base(id, type) - { - Parameters = new List(parameters); - CallInfo = new FunctionInfo(id); - Type = type; - } - - public override string ToString() - { - var sb = new StringBuilder($"function {Id}("); - sb.AppendJoin(',', Parameters); - sb.Append($") => {Type.ReturnType}"); - return sb.ToString(); - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs deleted file mode 100644 index efb9672e..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/ObjectSymbol.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Types; - -namespace Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -public class ObjectSymbol : VariableSymbol -{ - public override ObjectType Type { get; } - - public SymbolTable Table { get; init; } - - public ObjectSymbol(string id, ObjectType objectType, bool readOnly = false, SymbolTable table = null) : - base(id, objectType, readOnly) - { - Type = objectType; - if (table != null) - { - foreach (var key in objectType.Keys) - { - if (objectType[key] is FunctionType) - { - var function = table.FindSymbol(key); - function.CallInfo.MethodOf = id; - } - } - } - } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs b/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs deleted file mode 100644 index 87b487c8..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Variables/Symbols/Symbol.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; - -public abstract class Symbol -{ - // ReSharper disable once VirtualMemberNeverOverridden.Global - public virtual string Id { get; } - - public virtual Type Type { get; } - - protected Symbol(string id, Type type) => - (Id, Type) = (id, type); -} \ No newline at end of file diff --git a/Interpreter.Tests/GlobalUsings.cs b/Interpreter.Tests/GlobalUsings.cs deleted file mode 100644 index 9f96c142..00000000 --- a/Interpreter.Tests/GlobalUsings.cs +++ /dev/null @@ -1,3 +0,0 @@ -// Global using directives - -global using Type = Interpreter.Lib.IR.CheckSemantics.Types.Type; \ No newline at end of file diff --git a/Interpreter.Tests/MockExtensions.cs b/Interpreter.Tests/MockExtensions.cs deleted file mode 100644 index 1b88106b..00000000 --- a/Interpreter.Tests/MockExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.BackEnd.Instructions; -using Microsoft.Extensions.Options; -using Moq; - -namespace Interpreter.Tests; - -public static class MockExtensions -{ - public static Mock Trackable(this Mock halt) - { - halt.Setup(x => x.Execute(It.IsAny())) - .Returns(-3).Verifiable(); - halt.Setup(x => x.End()).Returns(true); - return halt; - } - - public static IOptions ToOptions - (this Mock commandLineSettings) => - Options.Create(commandLineSettings.Object); -} \ No newline at end of file diff --git a/Interpreter.Tests/Stubs/SemanticExceptionStub.cs b/Interpreter.Tests/Stubs/SemanticExceptionStub.cs deleted file mode 100644 index c1cc2463..00000000 --- a/Interpreter.Tests/Stubs/SemanticExceptionStub.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Interpreter.Lib.IR.CheckSemantics.Exceptions; - -namespace Interpreter.Tests.Stubs; - -public class SemanticExceptionStub : SemanticException { } \ No newline at end of file diff --git a/Interpreter.Tests/TestData/InstructionsData.cs b/Interpreter.Tests/TestData/InstructionsData.cs deleted file mode 100644 index 2eb25f8b..00000000 --- a/Interpreter.Tests/TestData/InstructionsData.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Collections; -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; - -namespace Interpreter.Tests.TestData; - -public class InstructionsData : IEnumerable -{ - public IEnumerator GetEnumerator() - { - yield return new object[] - { - new AsString("str", new Name("num"), 0), - "0: str = num as string" - }; - yield return new object[] - { - new BeginFunction(1, new FunctionInfo("func", 1)), - "1: BeginFunction func" - }; - yield return new object[] - { - new CallFunction(new FunctionInfo("func"), 2, 0), - "2: Call (0, func), 0" - }; - yield return new object[] - { - new CallFunction(new FunctionInfo("func"), 2, 0, "ret"), - "2: ret = Call (0, func), 0" - }; - yield return new object[] - { - new CreateArray(3, "arr", 5), - "3: array arr = [5]" - }; - yield return new object[] - { - new CreateObject(4, "obj"), - "4: object obj = {}" - }; - yield return new object[] - { - new DotAssignment("obj", (new Constant("prop", "prop"), new Constant(3, "3")), 5), - "5: obj.prop = 3" - }; - yield return new object[] - { - new Goto(10, 6), - "6: Goto 10" - }; - yield return new object[] - { - new Halt(7), - "7: End" - }; - yield return new object[] - { - new IfNotGoto(new Name("test"), 17, 8), - "8: IfNot test Goto 17" - }; - yield return new object[] - { - new IndexAssignment("arr", (new Constant(1, "1"), new Constant(1, "1")), 9), - "9: arr[1] = 1" - }; - yield return new object[] - { - new Print(10, new Name("str")), - "10: Print str" - }; - yield return new object[] - { - new PushParameter(11, "param", new Name("value")), - "11: PushParameter param = value" - }; - yield return new object[] - { - new RemoveFromArray(12, "arr", new Constant(0, "0")), - "12: RemoveFrom arr at 0" - }; - yield return new object[] - { - new Return(3, 13), - "13: Return" - }; - yield return new object[] - { - new Return(3, 13, new Name("result")), - "13: Return result" - }; - yield return new object[] - { - new Simple("a", (new Name("b"), new Name("c")), "+", 14), - "14: a = b + c" - }; - yield return new object[] - { - new Simple("b", (null, new Name("c")), "-", 14), - "14: b = -c" - }; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/BackEnd/FunctionInfoTests.cs b/Interpreter.Tests/Unit/BackEnd/FunctionInfoTests.cs deleted file mode 100644 index f0fc3116..00000000 --- a/Interpreter.Tests/Unit/BackEnd/FunctionInfoTests.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Interpreter.Lib.BackEnd; -using Xunit; - -namespace Interpreter.Tests.Unit.BackEnd; - -public class FunctionInfoTests -{ - [Theory] - [InlineData("func", null, "func")] - [InlineData("func", "obj", "obj.func")] - public void CallIdCorrectTest(string id, string methodOf, string expected) => - Assert.Equal(expected, new FunctionInfo(id, 0, methodOf).CallId()); -} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/BackEnd/InstructionsTests.cs b/Interpreter.Tests/Unit/BackEnd/InstructionsTests.cs deleted file mode 100644 index 6111c5d7..00000000 --- a/Interpreter.Tests/Unit/BackEnd/InstructionsTests.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Tests.TestData; -using Moq; -using Xunit; - -namespace Interpreter.Tests.Unit.BackEnd; - -public class InstructionsTests -{ - [Theory] - [ClassData(typeof(InstructionsData))] - public void ToStringCorrectTest(Instruction instruction, string expected) => - Assert.Equal(expected, instruction.ToString()); - - [Fact] - public void ComparisonDependsOnAddressTest() - { - var instruction1 = new Mock(1).Object; - var instruction2 = new Mock(2).Object; - - Assert.Equal(1, instruction2.CompareTo(instruction1)); - } - - [Fact] - public void GotoJumpChangedTest() - { - var @goto = new Goto(0, 1); - @goto.SetJump(5); - Assert.Equal(5, @goto.Jump()); - } - - [Fact] - public void ReturnCallersAddedTest() - { - var @return = new Return(7, 19); - @return.AddCaller(@return.FunctionStart - 2); - Assert.NotEmpty(@return); - } -} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/BackEnd/VirtualMachineTests.cs b/Interpreter.Tests/Unit/BackEnd/VirtualMachineTests.cs deleted file mode 100644 index 28a8234e..00000000 --- a/Interpreter.Tests/Unit/BackEnd/VirtualMachineTests.cs +++ /dev/null @@ -1,131 +0,0 @@ -#nullable enable -using Interpreter.Lib.BackEnd; -using Interpreter.Lib.BackEnd.Instructions; -using Interpreter.Lib.BackEnd.Values; -using Moq; -using Xunit; - -namespace Interpreter.Tests.Unit.BackEnd; - -public class VirtualMachineTests -{ - private readonly VirtualMachine _vm; - - public VirtualMachineTests() - { - _vm = new(new(), new(), new(), TextWriter.Null); - } - - [Fact] - public void CorrectPrintToOutTest() - { - var writer = new Mock(); - writer.Setup(x => x.WriteLine(It.IsAny())) - .Verifiable(); - - var vm = new VirtualMachine(new(), new Stack(new[] { new Frame() }), new(), writer.Object); - var print = new Print(0, new Constant(223, "223")); - - print.Execute(vm); - writer.Verify(x => x.WriteLine( - It.Is(v => v!.Equals(223)) - ), Times.Once()); - } - - [Fact] - public void ProgramWithoutHaltWillNotRunTest() - { - var program = new List(); - Assert.Throws(() => _vm.Run(program)); - - program.Add(new Halt(0)); - Assert.Null(Record.Exception(() => _vm.Run(program))); - } - - [Fact] - public void VirtualMachineFramesClearedAfterExecutionTest() - { - var program = new List() - { - new Simple("a", (new Constant(1, "1"), new Constant(2, "2")), "+", 0), - new AsString("b", new Name("a"), 1), - new Halt(2) - }; - - _vm.Run(program); - Assert.Empty(_vm.Frames); - } - - [Fact] - public void VirtualMachineHandlesRecursionTest() - { - var halt = new Mock(12).Trackable(); - var factorial = new FunctionInfo("fact", 1); - var program = new List - { - new Goto(10, 0), - new BeginFunction(1, factorial), - new Simple("_t2", (new Name("n"), new Constant(2, "2")), "<", 2), - new IfNotGoto(new Name("_t2"), 5, 3), - new Return(1, 4, new Name("n")), - new Simple("_t5", (new Name("n"), new Constant(1, "1")), "-", 5), - new PushParameter(6, "n", new Name("_t5")), - new CallFunction(factorial, 7, 1, "f"), - new Simple("_t8", (new Name("n"), new Name("f")), "*", 8), - new Return(1, 9, new Name("_t8")), - new PushParameter(10, "n", new Constant(6, "6")), - new CallFunction(factorial, 11, 1, "fa6"), - halt.Object - }; - - _vm.Run(program); - Assert.Empty(_vm.CallStack); - Assert.Empty(_vm.Arguments); - halt.Verify(x => x.Execute( - It.Is( - vm => Convert.ToInt32(vm.Frames.Peek()["fa6"]) == 720 - ) - ), Times.Once()); - _vm.Frames.Pop(); - } - - [Fact] - public void CreateArrayReservesCertainSpaceTest() - { - var vm = new VirtualMachine(); - vm.Frames.Push(new Frame()); - - var createArray = new CreateArray(0, "arr", 6); - createArray.Execute(vm); - Assert.Equal(6, ((List) vm.Frames.Peek()["arr"]).Count); - - var indexAssignment = new IndexAssignment("arr", (new Constant(0, "0"), new Constant(0, "0")), 1); - indexAssignment.Execute(vm); - Assert.Equal(0, ((List) vm.Frames.Peek()["arr"])[0]); - - var removeFromArray = new RemoveFromArray(2, "arr", new Constant(5, "5")); - removeFromArray.Execute(vm); - Assert.Equal(5, ((List) vm.Frames.Peek()["arr"]).Count); - } - - [Fact] - public void ObjectCreationTest() - { - var halt = new Mock(2).Trackable(); - var program = new List - { - new CreateObject(0, "obj"), - new DotAssignment("obj", (new Constant("prop", "prop"), new Constant(null, "null")), 1), - halt.Object - }; - - _vm.Run(program); - halt.Verify(x => x.Execute( - It.Is( - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - vm => ((Dictionary)vm.Frames.Peek()["obj"])["prop"] == null - ) - ), Times.Once()); - _vm.Frames.Pop(); - } -} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/IR/AstNodeTests.cs b/Interpreter.Tests/Unit/IR/AstNodeTests.cs deleted file mode 100644 index 95344cb0..00000000 --- a/Interpreter.Tests/Unit/IR/AstNodeTests.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes; -using Interpreter.Lib.IR.Ast.Nodes.Declarations; -using Interpreter.Lib.IR.Ast.Nodes.Statements; -using Interpreter.Lib.IR.CheckSemantics.Types; -using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; -using Moq; -using Xunit; - -namespace Interpreter.Tests.Unit.IR; - -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)); - - Assert.True(lexicalDecl.ChildOf()); - } -} \ No newline at end of file diff --git a/Interpreter.Tests/Unit/IR/ExpressionTests.cs b/Interpreter.Tests/Unit/IR/ExpressionTests.cs deleted file mode 100644 index 30663b57..00000000 --- a/Interpreter.Tests/Unit/IR/ExpressionTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Interpreter.Lib.IR.Ast.Nodes.Expressions; -using Interpreter.Lib.IR.Ast.Nodes.Expressions.PrimaryExpressions; -using Xunit; - -namespace Interpreter.Tests.Unit.IR; - -public class ExpressionTests -{ - [Fact] - public void BinaryExpressionTest() - { - var number = new Type("number"); - - var left = new Literal(number, 0); - var right = new Literal(number, 1); - - var binExpr = new BinaryExpression(left, "-", right); - - var ex = Record.Exception(() => binExpr.SemanticCheck()); - Assert.Null(ex); - } -} \ No newline at end of file diff --git a/Interpreter/Services/Providers/ILexerProvider.cs b/Interpreter/Services/Providers/ILexerProvider.cs deleted file mode 100644 index 0f34a033..00000000 --- a/Interpreter/Services/Providers/ILexerProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens; - -namespace Interpreter.Services.Providers; - -public interface ILexerProvider -{ - ILexer CreateLexer(); -} \ No newline at end of file diff --git a/Interpreter/Services/Providers/IParserProvider.cs b/Interpreter/Services/Providers/IParserProvider.cs deleted file mode 100644 index cd7b7101..00000000 --- a/Interpreter/Services/Providers/IParserProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Interpreter.Lib.FrontEnd.TopDownParse; - -namespace Interpreter.Services.Providers; - -public interface IParserProvider -{ - IParser CreateParser(); -} \ No newline at end of file diff --git a/Interpreter/Services/Providers/IStructureProvider.cs b/Interpreter/Services/Providers/IStructureProvider.cs deleted file mode 100644 index 037c97e6..00000000 --- a/Interpreter/Services/Providers/IStructureProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Interpreter.Lib.FrontEnd.GetTokens.Data; - -namespace Interpreter.Services.Providers; - -public interface IStructureProvider -{ - Structure CreateStructure(); -} \ No newline at end of file diff --git a/Readme.md b/Readme.md index de8ec1ab..a204709d 100644 --- a/Readme.md +++ b/Readme.md @@ -2,8 +2,8 @@ Package | Line Rate | Health -------- | --------- | ------ -Interpreter.Lib | 40% | ❌ -Interpreter | 100% | ✔ +HydraScript.Lib | 40% | ❌ +HydraScript | 100% | ✔ **Summary** | **43%** (925 / 2173) | ❌ _Minimum allowed line rate is `80%`_ @@ -14,9 +14,9 @@ _Minimum allowed line rate is `80%`_ За основу был взят стандарт [ECMA-262](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/) -[Лексическая структура](Interpreter/TokenTypes.cs) +[Лексическая структура](HydraScript/TokenTypes.cs) -[Грамматика](Interpreter/grammar.txt) +[Грамматика](HydraScript/grammar.txt) [Рабочие примеры](samples) @@ -164,7 +164,7 @@ let s = v2d as string - .NET 7 SDK ### Сборка -После клонирования репозитория идём в папку проекта `Interpreter`. +После клонирования репозитория идём в папку проекта `HydraScript`. Там выполняем команду: ```dotnet publish -r -p:PublishSingleFile=true -p:DebugType=embedded --self-contained false -o ``` @@ -174,13 +174,13 @@ let s = v2d as string ### Запуск ``` -Interpreter 1.2.6 -Copyright (C) 2022 Interpreter +HydraScript 1.2.6 +Copyright (C) 2024 HydraScript USAGE: Simple interpretation call: - Interpreter file.js + HydraScript file.js Request dump: - Interpreter --dump file.js + HydraScript --dump file.js -d, --dump (Default: false) Show dump data of interpreter diff --git a/samples/equals.js b/samples/equals.js index c512345e..09724ff7 100644 --- a/samples/equals.js +++ b/samples/equals.js @@ -1,20 +1,17 @@ type withEquals = { prop: number; - equals: (withEquals) => boolean; } -let obj1 = { +function equals(obj: withEquals, that: withEquals) { + return obj.prop == that.prop +} + +let obj1: withEquals = { prop: 1; - equals => (that: withEquals): boolean { - return prop == (that.prop) - }; } -let obj2 = { +let obj2: withEquals = { prop: 2; - equals => (that: withEquals): boolean { - return prop == (that.prop) - }; } let res = obj1.equals(obj2) diff --git a/samples/forwardref.js b/samples/forwardref.js new file mode 100644 index 00000000..5c73092e --- /dev/null +++ b/samples/forwardref.js @@ -0,0 +1,15 @@ +type A = { + b: B; +} + +type B = { + a: A; +} + +let a: A = { + b: { + a: null; + }; +} + +print(a as string) \ No newline at end of file diff --git a/samples/linkedlist.js b/samples/linkedlist.js index 439ff2bf..f3aa7f2f 100644 --- a/samples/linkedlist.js +++ b/samples/linkedlist.js @@ -4,8 +4,27 @@ type node = { } type list = { head: node; - append: (number,) => void; - getOdd: () => number[]; +} + +function append(lst: list, item: number) { + let tail: node = lst.head + while (tail.next != null) { + tail = tail.next + } + tail.next = makeNode(item) +} + +function getOdd(lst: list): number[] { + let result: number[] + let n = lst.head + while (n != null) { + if (n.data % 2 != 0) { + let i = n.data + result = result ++ [i] + } + n = n.next + } + return result } function makeNode(item: number): node { @@ -17,25 +36,6 @@ function makeNode(item: number): node { let linkedList: list = { head: makeNode(1); - append => (item: number) { - let tail: node = head - while ((tail.next) != null) { - tail = tail.next - } - tail.next = makeNode(item) - }; - getOdd => (): number[] { - let result: number[] - let n = head - while (n != null) { - if ((n.data) % 2 != 0) { - let i = n.data - result = result ++ [i,] - } - n = n.next - } - return result - }; } linkedList.append(3) diff --git a/samples/settable.js b/samples/settable.js index f9b94258..0219a6f3 100644 --- a/samples/settable.js +++ b/samples/settable.js @@ -1,16 +1,16 @@ type settable = { prop: string; - setprop: (string) => void; +} + +function setprop(obj: settable, str: string) { + obj.prop = str + if (obj.prop == "1") { + print("prop is one") + } } let obj: settable = { prop: "prop"; - setprop => (str: string) { - prop = str - if (prop == "1") { - print("prop is one") - } - }; } obj.setprop("1") diff --git a/samples/summator.js b/samples/summator.js index 893aee84..029e6803 100644 --- a/samples/summator.js +++ b/samples/summator.js @@ -1,9 +1,15 @@ -let summator = { +type summable{ + x: number; + y: number; +} + +function sum(obj: summable): number { + return obj.x + obj.y +} + +let summator: summable = { x: 1; y: 2; - sum => (): number { - return x + y - }; } let s = summator.sum() diff --git a/samples/this.js b/samples/this.js index 6d577351..5b8a3aea 100644 --- a/samples/this.js +++ b/samples/this.js @@ -1,11 +1,18 @@ -let obj = { +type ObjType = { + num: number; + flag: boolean; + str: string; +} + +function toString(obj: ObjType): string { + let s = "object obj:\n" + return s + (obj as string) +} + +let obj: ObjType = { num: 1; flag: true; str: "field"; - toString => (): string { - let s = "object obj:\n" - return s + (this as string) - }; } print(obj.toString()) \ No newline at end of file diff --git a/samples/typeresolving.js b/samples/typeresolving.js new file mode 100644 index 00000000..19730899 --- /dev/null +++ b/samples/typeresolving.js @@ -0,0 +1,14 @@ +type A = { + a: B; +} +{ + type C = string + type D = number[] + type E = A[] + type R = { + prop: R; +} +} +type B = { + b: A; +} \ No newline at end of file diff --git a/samples/vec2d.js b/samples/vec2d.js index bc20bd18..2086ccea 100644 --- a/samples/vec2d.js +++ b/samples/vec2d.js @@ -18,5 +18,6 @@ function vlensquared(v: vec2d): number { let v = makeVec(3, 4) let l = vlensquared(v) - +print(l as string) +l = v.vlensquared() print(l as string) \ No newline at end of file