diff --git a/CMakeLists.txt b/CMakeLists.txt index b48677a..bacaf73 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,4 +30,4 @@ add_executable( enact src/h/AstPrinter.h src/Analyser.cpp src/h/Analyser.h - src/h/Compiler.h src/Compiler.cpp src/h/Natives.h src/Natives.cpp src/h/GC.h src/GC.cpp src/h/Flags.h src/Flags.cpp) + src/h/Compiler.h src/Compiler.cpp src/h/Natives.h src/Natives.cpp src/h/GC.h src/GC.cpp src/h/Flags.h src/Flags.cpp src/h/Typename.h src/Typename.cpp) diff --git a/src/Analyser.cpp b/src/Analyser.cpp index 3056ec9..f193df0 100755 --- a/src/Analyser.cpp +++ b/src/Analyser.cpp @@ -4,7 +4,7 @@ #include "h/Analyser.h" #include "h/Enact.h" -void Analyser::analyse(std::vector program) { +std::vector> Analyser::analyse(std::vector> program) { m_hadError = false; beginScope(); @@ -15,7 +15,7 @@ void Analyser::analyse(std::vector program) { declareVariable("dis", Variable{std::make_shared(STRING_TYPE, std::vector{DYNAMIC_TYPE}), true}); for (auto &stmt : program) { - analyse(stmt); + analyse(*stmt); } // Analyse all function bodies in the global scope @@ -23,18 +23,20 @@ void Analyser::analyse(std::vector program) { analyseFunctionBody(function); } endScope(); + + return program; } -void Analyser::analyse(Stmt stmt) { +void Analyser::analyse(Stmt& stmt) { try { - stmt->accept(this); + stmt.accept(this); } catch (const AnalysisError &error) { m_hadError = true; } } -void Analyser::analyse(Expr expr) { - expr->accept(this); +void Analyser::analyse(Expr& expr) { + expr.accept(this); } bool Analyser::hadError() { @@ -49,8 +51,8 @@ Analyser::AnalysisError Analyser::errorAt(const Token &token, const std::string void Analyser::visitBlockStmt(BlockStmt &stmt) { beginScope(); - for (Stmt &statement : stmt.statements) { - analyse(statement); + for (auto& statement : stmt.statements) { + analyse(*statement); } endScope(); } @@ -72,14 +74,14 @@ void Analyser::visitEachStmt(EachStmt &stmt) { } void Analyser::visitExpressionStmt(ExpressionStmt &stmt) { - analyse(stmt.expr); + analyse(*stmt.expr); } void Analyser::visitForStmt(ForStmt &stmt) { beginScope(); - analyse(stmt.initializer); + analyse(*stmt.initializer); - analyse(stmt.condition); + analyse(*stmt.condition); if (!stmt.condition->getType()->maybeBool()) { throw errorAt(stmt.keyword, "Expected for loop condition of type 'bool', not '" + stmt.condition->getType()->toString() + "'."); @@ -87,13 +89,13 @@ void Analyser::visitForStmt(ForStmt &stmt) { m_insideLoop = true; beginScope(); - for (Stmt &statement : stmt.body) { - analyse(statement); + for (auto& statement : stmt.body) { + analyse(*statement); } endScope(); m_insideLoop = false; - analyse(stmt.increment); + analyse(*stmt.increment); endScope(); } @@ -110,11 +112,11 @@ void Analyser::visitFunctionStmt(FunctionStmt &stmt) { } void Analyser::visitGivenStmt(GivenStmt &stmt) { - analyse(stmt.value); + analyse(*stmt.value); Type valueType = stmt.value->getType(); for (const GivenCase &case_ : stmt.cases) { - analyse(case_.value); + analyse(*case_.value); if (!case_.value->getType()->looselyEquals(*valueType)) { throw errorAt(case_.keyword, "Given value of type '" + valueType->toString() + "' cannot be compared with case of type '" + @@ -123,8 +125,8 @@ void Analyser::visitGivenStmt(GivenStmt &stmt) { beginScope(); - for (const Stmt &bodyStmt : case_.body) { - analyse(bodyStmt); + for (auto& bodyStmt : case_.body) { + analyse(*bodyStmt); } endScope(); @@ -132,7 +134,7 @@ void Analyser::visitGivenStmt(GivenStmt &stmt) { } void Analyser::visitIfStmt(IfStmt &stmt) { - analyse(stmt.condition); + analyse(*stmt.condition); if (!stmt.condition->getType()->maybeBool()) { throw errorAt(stmt.keyword, "Expected if statement condition of type 'bool', not '" @@ -140,14 +142,14 @@ void Analyser::visitIfStmt(IfStmt &stmt) { } beginScope(); - for (Stmt &statement : stmt.thenBlock) { - analyse(statement); + for (auto& statement : stmt.thenBlock) { + analyse(*statement); } endScope(); beginScope(); - for (Stmt &statement : stmt.elseBlock) { - analyse(statement); + for (auto& statement : stmt.elseBlock) { + analyse(*statement); } endScope(); } @@ -157,7 +159,7 @@ void Analyser::visitReturnStmt(ReturnStmt &stmt) { throw errorAt(stmt.keyword, "Return is only allowed inside functions."); } - analyse(stmt.value); + analyse(*stmt.value); Type returnType = m_currentFunctions.back().getReturnType(); if (!returnType->looselyEquals(*stmt.value->getType())) { @@ -187,23 +189,23 @@ void Analyser::visitStructStmt(StructStmt &stmt) { } } - // In the AST, fields are represented as a name paired with a type (NamedTypename). + // In the AST, fields are represented as a name paired with a type (Field). // We must now find the types that the typenames are referring to, and create // NamedTypes containing them. std::unordered_map fields; std::vector fieldTypes; - for (const NamedTypename &field : stmt.fields) { + for (const Field& field : stmt.fields) { // Check if the field has the same name as another field if (fields.count(field.name.lexeme) > 0) { throw errorAt(field.name, "Struct field '" + field.name.lexeme + "' cannot have the same name as another field."); } - if (m_types.count(field.typeName) > 0) { - fields.insert(std::pair(field.name.lexeme, m_types[field.typeName])); - fieldTypes.push_back(m_types[field.typeName]); + if (m_types.count(field.typeName->name()) > 0) { + fields.insert(std::pair(field.name.lexeme, m_types[field.typeName->name()])); + fieldTypes.push_back(m_types[field.typeName->name()]); } else { - throw errorAt(field.name, "Undeclared field type '" + field.typeName + "'."); + throw errorAt(field.name, "Undeclared field type '" + field.typeName->name() + "'."); } } @@ -211,7 +213,7 @@ void Analyser::visitStructStmt(StructStmt &stmt) { // properly. We take the methods as they are represented in the AST (a pointer to // a FunctionStmt) and convert them to NamedTypes. std::unordered_map methods; - for (const std::shared_ptr &method : stmt.methods) { + for (auto& method : stmt.methods) { // Check if the method has the same name as a field if (methods.count(method->name.lexeme) > 0 || fields.count(method->name.lexeme) > 0) { throw errorAt(method->name, "Struct method '" + method->name.lexeme + @@ -250,7 +252,7 @@ void Analyser::visitStructStmt(StructStmt &stmt) { Type thisType = std::make_shared(stmt.name.lexeme, traits, fields, methods, assocFunctions); m_types.insert(std::make_pair(stmt.name.lexeme, thisType)); - for (const std::shared_ptr &function : stmt.assocFunctions) { + for (auto& function : stmt.assocFunctions) { assocFunctions.insert(std::pair(function->name.lexeme, getFunctionType(*function))); } @@ -267,11 +269,11 @@ void Analyser::visitStructStmt(StructStmt &stmt) { beginScope(); // Next, we'll declare all fields and methods: - for (const auto &field : fields) { + for (const auto& field : fields) { declareVariable(field.first, Variable{field.second, false}); } - for (const auto &method : methods) { + for (const auto& method : methods) { declareVariable(method.first, Variable{method.second, true}); } @@ -279,16 +281,16 @@ void Analyser::visitStructStmt(StructStmt &stmt) { declareVariable("this", Variable{thisType, false}); // Now we can analyse the methods: - for (const std::shared_ptr &method : stmt.methods) { - analyse(method); + for (auto& method : stmt.methods) { + analyse(*method); } // End the struct scope. endScope(); // Look at the assoc functions (remember, they are outside of the struct scope): - for (const std::shared_ptr &function : stmt.assocFunctions) { - analyse(function); + for (auto& function : stmt.assocFunctions) { + analyse(*function); } } @@ -298,7 +300,7 @@ void Analyser::visitTraitStmt(TraitStmt &stmt) { } std::unordered_map methods; - for (const std::shared_ptr &method : stmt.methods) { + for (auto& method : stmt.methods) { if (methods.count(method->name.lexeme) > 0) { throw errorAt(method->name, "Trait method '" + method->name.lexeme + "' cannot have the same name as another method."); @@ -311,7 +313,7 @@ void Analyser::visitTraitStmt(TraitStmt &stmt) { } void Analyser::visitWhileStmt(WhileStmt &stmt) { - analyse(stmt.condition); + analyse(*stmt.condition); if (!stmt.condition->getType()->maybeBool()) { throw errorAt(stmt.keyword, "Expected while loop condition of type 'bool', not '" @@ -320,29 +322,39 @@ void Analyser::visitWhileStmt(WhileStmt &stmt) { m_insideLoop = true; beginScope(); - for (Stmt &statement : stmt.body) { - analyse(statement); + for (auto& statement : stmt.body) { + analyse(*statement); } endScope(); m_insideLoop = false; } void Analyser::visitVariableStmt(VariableStmt &stmt) { - analyse(stmt.initializer); + analyse(*stmt.initializer); - std::string typeName = stmt.typeName; + std::unique_ptr typeName = stmt.typeName->clone(); - if (stmt.typeName.empty()) { + if (typeName->name().empty()) { // Infer the type from the initializer - typeName = stmt.initializer->getType()->toString(); + typeName = stmt.initializer->getType()->toTypename(); } - if (!stmt.initializer->getType()->looselyEquals(*lookUpType(typeName, stmt.name))) { - throw errorAt(stmt.name, "Cannot initialize variable of type '" + typeName + + if (!stmt.initializer->getType()->looselyEquals(*lookUpType(*typeName))) { + throw errorAt(stmt.name, "Cannot initialize variable of type '" + typeName->name() + "' with value of type '" + stmt.initializer->getType()->toString() + "'."); } - declareVariable(stmt.name.lexeme, Variable{lookUpType(typeName, stmt.name), stmt.isConst}); + declareVariable(stmt.name.lexeme, Variable{lookUpType(*typeName), stmt.isConst}); +} + +void Analyser::visitAllotExpr(AllotExpr& expr) { + analyse(*expr.target); + analyse(*expr.value); + + if (!expr.target->getType()->looselyEquals(*expr.value->getType())) { + throw errorAt(expr.oper, "Cannot assign variable of type '" + expr.target->getType()->toString() + + "' with value of type '" + expr.value->getType()->toString() + "'."); + } } void Analyser::visitAnyExpr(AnyExpr &expr) { @@ -351,13 +363,13 @@ void Analyser::visitAnyExpr(AnyExpr &expr) { void Analyser::visitArrayExpr(ArrayExpr &expr) { std::vector elementTypes{}; - for (Expr &element : expr.value) { - analyse(element); + for (auto& element : expr.value) { + analyse(*element); elementTypes.push_back(element->getType()); } - if (!expr.typeName.empty()) { - Type elementType = lookUpType(expr.typeName, expr.square); + if (!expr.typeName->name().empty()) { + Type elementType = lookUpType(*expr.typeName); for (Type &type : elementTypes) { if (!elementType->looselyEquals(*type)) { @@ -384,25 +396,23 @@ void Analyser::visitArrayExpr(ArrayExpr &expr) { } void Analyser::visitAssignExpr(AssignExpr &expr) { - analyse(expr.left); - analyse(expr.right); + analyse(*expr.target); + analyse(*expr.value); - if (!expr.left->getType()->looselyEquals(*expr.right->getType())) { - throw errorAt(expr.oper, "Cannot assign variable of type '" + expr.left->getType()->toString() + - "' with value of type '" + expr.right->getType()->toString() + "'."); + if (!expr.target->getType()->looselyEquals(*expr.value->getType())) { + throw errorAt(expr.oper, "Cannot assign variable of type '" + expr.target->getType()->toString() + + "' with value of type '" + expr.value->getType()->toString() + "'."); } - if (typeid(*expr.left) == typeid(VariableExpr)) { - auto name = std::static_pointer_cast(expr.left)->name; - if (lookUpVariable(name).isConst) { - throw errorAt(name, "Cannot assign to constant variable."); - } + auto name = expr.target->name; + if (lookUpVariable(name).isConst) { + throw errorAt(name, "Cannot assign to constant variable."); } } void Analyser::visitBinaryExpr(BinaryExpr &expr) { - analyse(expr.left); - analyse(expr.right); + analyse(*expr.left); + analyse(*expr.right); Type left = expr.left->getType(); Type right = expr.right->getType(); @@ -478,9 +488,9 @@ void Analyser::visitBooleanExpr(BooleanExpr &expr) { } void Analyser::visitCallExpr(CallExpr &expr) { - analyse(expr.callee); + analyse(*expr.callee); for (auto& argument : expr.arguments) { - analyse(argument); + analyse(*argument); } Type type = expr.callee->getType(); @@ -517,8 +527,12 @@ void Analyser::visitCallExpr(CallExpr &expr) { } } -void Analyser::visitFieldExpr(FieldExpr &expr) { - analyse(expr.object); +void Analyser::visitFloatExpr(FloatExpr &expr) { + expr.setType(m_types["float"]); +} + +void Analyser::visitGetExpr(GetExpr &expr) { + analyse(*expr.object); Type objectType = expr.object->getType(); @@ -561,17 +575,13 @@ void Analyser::visitFieldExpr(FieldExpr &expr) { } } -void Analyser::visitFloatExpr(FloatExpr &expr) { - expr.setType(m_types["float"]); -} - void Analyser::visitIntegerExpr(IntegerExpr &expr) { expr.setType(m_types["int"]); } void Analyser::visitLogicalExpr(LogicalExpr &expr) { - analyse(expr.left); - analyse(expr.right); + analyse(*expr.left); + analyse(*expr.right); Type left = expr.left->getType(); Type right = expr.right->getType(); @@ -593,8 +603,8 @@ void Analyser::visitStringExpr(StringExpr &expr) { } void Analyser::visitSubscriptExpr(SubscriptExpr &expr) { - analyse(expr.object); - analyse(expr.index); + analyse(*expr.object); + analyse(*expr.index); if (!expr.object->getType()->maybeArray()) { throw errorAt(expr.square, "Only arrays can be subscripted."); @@ -613,13 +623,13 @@ void Analyser::visitSubscriptExpr(SubscriptExpr &expr) { } void Analyser::visitTernaryExpr(TernaryExpr &expr) { - analyse(expr.condition); + analyse(*expr.condition); if (!expr.condition->getType()->maybeBool()) { throw errorAt(expr.oper, "Conditional operator condition must be a boolean."); } - analyse(expr.thenExpr); - analyse(expr.elseExpr); + analyse(*expr.thenExpr); + analyse(*expr.elseExpr); if (!expr.thenExpr->getType()->looselyEquals(*expr.elseExpr->getType())) { throw errorAt(expr.oper, "Mismatched types in conditional operation: '" + expr.thenExpr->getType()->toString() @@ -628,7 +638,7 @@ void Analyser::visitTernaryExpr(TernaryExpr &expr) { } void Analyser::visitUnaryExpr(UnaryExpr &expr) { - analyse(expr.operand); + analyse(*expr.operand); switch (expr.oper.type) { case TokenType::BANG: if (!(expr.operand->getType()->maybeBool())) { @@ -672,8 +682,8 @@ void Analyser::analyseFunctionBody(FunctionStmt &stmt) { declareVariable(stmt.params[i].name.lexeme, Variable{functionType->getArgumentTypes()[i]}); } - for (Stmt &statement : stmt.body) { - analyse(statement); + for (auto& statement : stmt.body) { + analyse(*statement); } m_currentFunctions.pop_back(); @@ -682,10 +692,10 @@ void Analyser::analyseFunctionBody(FunctionStmt &stmt) { Type Analyser::getFunctionType(const FunctionStmt &stmt) { Type returnType; - if (stmt.returnTypeName.empty()) { + if (stmt.returnTypename->name().empty()) { returnType = NOTHING_TYPE; } else { - returnType = lookUpType(stmt.returnTypeName, stmt.name); + returnType = lookUpType(*stmt.returnTypename); } if (stmt.params.size() > 255) { @@ -693,82 +703,39 @@ Type Analyser::getFunctionType(const FunctionStmt &stmt) { } std::vector parameterTypes; - for (const NamedTypename ¶meter : stmt.params) { - parameterTypes.push_back(lookUpType(parameter.typeName, parameter.name)); + for (const Param& parameter : stmt.params) { + parameterTypes.push_back(lookUpType(*parameter.typeName)); } return std::make_shared(returnType, parameterTypes); } -Type Analyser::lookUpType(const Token &name) { - return lookUpType(name.lexeme, name); -} - -Type Analyser::lookUpType(const std::string &name, const Token &where) { - if (!name.empty()) { - if (name[0] == '[' && name[name.size() - 1] == ']') { - std::string elementTypeName = name.substr(1, name.size() - 2); - return std::make_shared(lookUpType(elementTypeName, where)); +Type Analyser::lookUpType(const Typename& name) { + switch (name.kind()) { + case Typename::Kind::BASIC: + if (m_types.count(name.name()) > 0) { + return m_types[name.name()]; + } else if (name.name() == "") { + return m_types["nothing"]; + } + break; + case Typename::Kind::ARRAY: { + auto arrName = dynamic_cast(name); + return std::make_shared(lookUpType(arrName.elementTypename())); } - } - - if (name.size() >= 4 && - name[0] == 'f' && - name[1] == 'u' && - name[2] == 'n' && - (name[3] == ' ' || name[3] == '(')) { - return lookUpFunctionType(name, where); - } - - if (m_types.count(name) > 0) { - return m_types[name]; - } - - throw errorAt(where, "Undefined type '" + name + "'."); -} - -Type Analyser::lookUpFunctionType(const std::string& name, const Token& where) { - int current = 3; + case Typename::Kind::FUNCTION: { + auto funName = static_cast(name); - while (name[current] == ' ' || name[current] == '(') ++current; - - int openBrackets = 1; - std::vector paramTypes; - while (openBrackets != 0) { - std::string paramTypeName; - do { - if (name[current] == ' ') { - ++current; - continue; - } - if (name[current] == ',') { - if (openBrackets > 1) { - paramTypeName.push_back(name[current]); - ++current; - continue; - } else { - ++current; - break; - } + std::vector argTypes{}; + for (const auto& argName : funName.argumentTypenames()) { + argTypes.push_back(lookUpType(*argName)); } - if (name[current] == '(') ++openBrackets; - if (name[current] == ')') --openBrackets; - if (openBrackets == 0) continue; - paramTypeName.push_back(name[current]); - ++current; - } while (openBrackets != 0); - paramTypes.push_back(lookUpType(paramTypeName, where)); - } - std::string returnTypeName; - while (++current < name.size()) { - if (name[current] == ' ') continue; - returnTypeName.push_back(name[current]); + return std::make_shared(lookUpType(funName.returnTypename()), std::move(argTypes)); + } } - if (returnTypeName.empty()) returnTypeName = "nothing"; - Type returnType = lookUpType(returnTypeName, where); - return std::make_shared(returnType, paramTypes); + throw errorAt(name.where(), "Undefined type '" + name.name() + "'."); } Analyser::Variable &Analyser::lookUpVariable(const Token &name) { diff --git a/src/AstPrinter.cpp b/src/AstPrinter.cpp index 7b1b8b1..0280bbf 100755 --- a/src/AstPrinter.cpp +++ b/src/AstPrinter.cpp @@ -1,23 +1,23 @@ #include #include "h/AstPrinter.h" -void AstPrinter::print(Stmt stmt) { +void AstPrinter::print(Stmt& stmt) { std::cout << evaluate(stmt) << "\n"; } -std::string AstPrinter::evaluate(Stmt stmt) { - return stmt->accept(this); +std::string AstPrinter::evaluate(Stmt& stmt) { + return stmt.accept(this); } -std::string AstPrinter::evaluate(Expr expr) { - return expr->accept(this); +std::string AstPrinter::evaluate(Expr& expr) { + return expr.accept(this); } std::string AstPrinter::visitBlockStmt(BlockStmt& stmt) { std::stringstream s; s << "Stmt::Block [\n"; - for (auto &statement : stmt.statements) { - s << evaluate(statement) << "\n"; + for (auto& statement : stmt.statements) { + s << evaluate(*statement) << "\n"; } s << "]"; return s.str(); @@ -33,25 +33,25 @@ std::string AstPrinter::visitContinueStmt(ContinueStmt& stmt) { std::string AstPrinter::visitEachStmt(EachStmt& stmt) { std::stringstream s; - s << "Stmt::Each " << stmt.name.lexeme << " in " << evaluate(stmt.object) << " [\n"; - for (auto &statement : stmt.body) { - s << evaluate(statement) << "\n"; + s << "Stmt::Each " << stmt.name.lexeme << " in " << evaluate(*stmt.object) << " [\n"; + for (auto& statement : stmt.body) { + s << evaluate(*statement) << "\n"; } s << "]"; return s.str(); } std::string AstPrinter::visitExpressionStmt(ExpressionStmt& stmt) { - return "Stmt::Expression " + evaluate(stmt.expr); + return "Stmt::Expression " + evaluate(*stmt.expr); } std::string AstPrinter::visitForStmt(ForStmt& stmt) { std::stringstream s; - s << "Stmt::For " << evaluate(stmt.initializer) << "; " - << evaluate(stmt.condition) << "; " - << evaluate(stmt.increment) << " [\n"; - for (auto &statement : stmt.body) { - s << evaluate(statement) << "\n"; + s << "Stmt::For " << evaluate(*stmt.initializer) << "; " + << evaluate(*stmt.condition) << "; " + << evaluate(*stmt.increment) << " [\n"; + for (auto& statement : stmt.body) { + s << evaluate(*statement) << "\n"; } s << "]"; return s.str(); @@ -62,15 +62,15 @@ std::string AstPrinter::visitFunctionStmt(FunctionStmt& stmt) { s << "Stmt::Function " << stmt.name.lexeme << " ("; std::string separator = ""; - for (auto ¶m : stmt.params) { - s << separator << param.name.lexeme << " " << param.typeName; + for (auto& param : stmt.params) { + s << separator << param.name.lexeme << " " << param.typeName->name(); separator = ", "; } - s << ") " << stmt.returnTypeName << " [\n"; + s << ") " << stmt.returnTypename->name() << " [\n"; - for (auto &statement : stmt.body) { - s << evaluate(statement) << "\n"; + for (auto& statement : stmt.body) { + s << evaluate(*statement) << "\n"; } s << "]"; @@ -80,11 +80,11 @@ std::string AstPrinter::visitFunctionStmt(FunctionStmt& stmt) { std::string AstPrinter::visitGivenStmt(GivenStmt& stmt) { std::stringstream s; - s << "Stmt::Given " << evaluate(stmt.value) << " [\n"; - for (auto &case_ : stmt.cases) { - s << "when " << evaluate(case_.value) << " [\n"; - for (auto &statement: case_.body) { - s << evaluate(statement) << "\n"; + s << "Stmt::Given " << evaluate(*stmt.value) << " [\n"; + for (auto& case_ : stmt.cases) { + s << "when " << evaluate(*case_.value) << " [\n"; + for (auto& statement: case_.body) { + s << evaluate(*statement) << "\n"; } s << "]\n"; } @@ -94,20 +94,20 @@ std::string AstPrinter::visitGivenStmt(GivenStmt& stmt) { std::string AstPrinter::visitIfStmt(IfStmt& stmt) { std::stringstream s; - s << "Stmt::If " << evaluate(stmt.condition) << " [\n"; - for (auto &statement : stmt.thenBlock) { - s << evaluate(statement) << "\n"; + s << "Stmt::If " << evaluate(*stmt.condition) << " [\n"; + for (auto& statement : stmt.thenBlock) { + s << evaluate(*statement) << "\n"; } s << "] else [\n"; - for (auto &statement : stmt.elseBlock) { - s << evaluate(statement) << "\n"; + for (auto& statement : stmt.elseBlock) { + s << evaluate(*statement) << "\n"; } s << "]"; return s.str(); } std::string AstPrinter::visitReturnStmt(ReturnStmt& stmt) { - return "Stmt::Return " + evaluate(stmt.value); + return "Stmt::Return " + evaluate(*stmt.value); } std::string AstPrinter::visitStructStmt(StructStmt& stmt) { @@ -115,7 +115,7 @@ std::string AstPrinter::visitStructStmt(StructStmt& stmt) { s << "Stmt::Struct " << stmt.name.lexeme << " "; std::string separator = ""; - for (auto &trait : stmt.traits) { + for (auto& trait : stmt.traits) { s << separator << "is " << trait.lexeme; separator = ", "; } @@ -123,15 +123,15 @@ std::string AstPrinter::visitStructStmt(StructStmt& stmt) { s << "[\n"; for (auto &field : stmt.fields) { - s << "field " << field.name.lexeme << " " << field.typeName << "\n"; + s << "field " << field.name.lexeme << " " << field.typeName->name() << "\n"; } for (auto &method : stmt.methods) { - s << evaluate(method) << "\n"; + s << evaluate(*method) << "\n"; } for (auto &function : stmt.assocFunctions) { - s << "assoc " << evaluate(function) << "\n"; + s << "assoc " << evaluate(*function) << "\n"; } s << "]"; @@ -143,8 +143,8 @@ std::string AstPrinter::visitTraitStmt(TraitStmt& stmt) { std::stringstream s; s << "Stmt::Trait " << stmt.name.lexeme << " [\n"; - for (auto &method : stmt.methods) { - s << evaluate(method) << "\n"; + for (auto& method : stmt.methods) { + s << evaluate(*method) << "\n"; } s << "]"; @@ -154,16 +154,20 @@ std::string AstPrinter::visitTraitStmt(TraitStmt& stmt) { std::string AstPrinter::visitWhileStmt(WhileStmt& stmt) { std::stringstream s; - s << "Stmt::While " << evaluate(stmt.condition) << " then [\n"; - for (auto &statement : stmt.body) { - s << evaluate(statement) << "\n"; + s << "Stmt::While " << evaluate(*stmt.condition) << " then [\n"; + for (auto& statement : stmt.body) { + s << evaluate(*statement) << "\n"; } s << "]"; return s.str(); } std::string AstPrinter::visitVariableStmt(VariableStmt& stmt) { - return "Stmt::Var " + stmt.name.lexeme + " " + evaluate(stmt.initializer); + return "Stmt::Var " + stmt.name.lexeme + " " + evaluate(*stmt.initializer); +} + +std::string AstPrinter::visitAllotExpr(AllotExpr& expr) { + return "(= " + evaluate(*expr.target) + " " + evaluate(*expr.value) + ")"; } std::string AstPrinter::visitAnyExpr(AnyExpr& expr) { @@ -175,8 +179,8 @@ std::string AstPrinter::visitArrayExpr(ArrayExpr& expr) { s << "["; std::string separator = ""; - for (auto &element : expr.value) { - s << separator << evaluate(element); + for (auto& element : expr.value) { + s << separator << evaluate(*element); separator = ", "; } @@ -185,11 +189,11 @@ std::string AstPrinter::visitArrayExpr(ArrayExpr& expr) { } std::string AstPrinter::visitAssignExpr(AssignExpr& expr) { - return "(= " + evaluate(expr.left) + " " + evaluate(expr.right) + ")"; + return "(= " + evaluate(*expr.target) + " " + evaluate(*expr.value) + ")"; } std::string AstPrinter::visitBinaryExpr(BinaryExpr& expr) { - return "(" + expr.oper.lexeme + " " + evaluate(expr.left) + " " + evaluate(expr.right) + ")"; + return "(" + expr.oper.lexeme + " " + evaluate(*expr.left) + " " + evaluate(*expr.right) + ")"; } std::string AstPrinter::visitBooleanExpr(BooleanExpr& expr) { @@ -198,28 +202,28 @@ std::string AstPrinter::visitBooleanExpr(BooleanExpr& expr) { std::string AstPrinter::visitCallExpr(CallExpr& expr) { std::stringstream s; - s << "(() " << evaluate(expr.callee); - for (auto &arg : expr.arguments) { - s << " " << evaluate(arg); + s << "(() " << evaluate(*expr.callee); + for (auto& arg : expr.arguments) { + s << " " << evaluate(*arg); } s << ")"; return s.str(); } -std::string AstPrinter::visitFieldExpr(FieldExpr& expr) { - return "(. " + evaluate(expr.object) + " " + expr.name.lexeme + ")"; -} - std::string AstPrinter::visitFloatExpr(FloatExpr& expr) { return std::to_string(expr.value); } +std::string AstPrinter::visitGetExpr(GetExpr& expr) { + return "(. " + evaluate(*expr.object) + " " + expr.name.lexeme + ")"; +} + std::string AstPrinter::visitIntegerExpr(IntegerExpr& expr) { return std::to_string(expr.value); } std::string AstPrinter::visitLogicalExpr(LogicalExpr& expr) { - return "(" + expr.oper.lexeme + " " + evaluate(expr.left) + " " + evaluate(expr.right) + ")"; + return "(" + expr.oper.lexeme + " " + evaluate(*expr.left) + " " + evaluate(*expr.right) + ")"; } std::string AstPrinter::visitNilExpr(NilExpr& expr) { @@ -233,15 +237,15 @@ std::string AstPrinter::visitStringExpr(StringExpr& expr) { } std::string AstPrinter::visitSubscriptExpr(SubscriptExpr& expr) { - return "([] " + evaluate(expr.object) + " " + evaluate(expr.index) + ")"; + return "([] " + evaluate(*expr.object) + " " + evaluate(*expr.index) + ")"; } std::string AstPrinter::visitTernaryExpr(TernaryExpr& expr) { - return "(?: " + evaluate(expr.condition) + " " + evaluate(expr.thenExpr) + " " + evaluate(expr.elseExpr) + ")"; + return "(?: " + evaluate(*expr.condition) + " " + evaluate(*expr.thenExpr) + " " + evaluate(*expr.elseExpr) + ")"; } std::string AstPrinter::visitUnaryExpr(UnaryExpr& expr) { - return "(" + expr.oper.lexeme + " " + evaluate(expr.operand) + ")"; + return "(" + expr.oper.lexeme + " " + evaluate(*expr.operand) + ")"; } std::string AstPrinter::visitVariableExpr(VariableExpr& expr) { diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 2e16a5c..5603117 100755 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -86,9 +86,12 @@ std::pair Chunk::disassembleInstruction(size_t index) const case OpCode::TRUE: case OpCode::FALSE: case OpCode::NIL: + case OpCode::CHECK_INT: case OpCode::CHECK_NUMERIC: case OpCode::CHECK_BOOL: case OpCode::CHECK_REFERENCE: + case OpCode::CHECK_INDEXABLE: + case OpCode::CHECK_ALLOTABLE: case OpCode::NEGATE: case OpCode::NOT: case OpCode::COPY: @@ -99,6 +102,8 @@ std::pair Chunk::disassembleInstruction(size_t index) const case OpCode::LESS: case OpCode::GREATER: case OpCode::EQUAL: + case OpCode::GET_ARRAY_INDEX: + case OpCode::SET_ARRAY_INDEX: case OpCode::POP: case OpCode::CLOSE_UPVALUE: case OpCode::RETURN: { @@ -109,6 +114,7 @@ std::pair Chunk::disassembleInstruction(size_t index) const } // Byte instructions + case OpCode::ARRAY: case OpCode::CHECK_CALLABLE: case OpCode::GET_LOCAL: case OpCode::SET_LOCAL: @@ -133,6 +139,7 @@ std::pair Chunk::disassembleInstruction(size_t index) const } // Long instructions + case OpCode::ARRAY_LONG: case OpCode::GET_LOCAL_LONG: case OpCode::SET_LOCAL_LONG: case OpCode::GET_UPVALUE_LONG: @@ -354,10 +361,13 @@ std::string opCodeToString(OpCode code) { case OpCode::TRUE: return "TRUE"; case OpCode::FALSE: return "FALSE"; case OpCode::NIL: return "NIL"; + case OpCode::CHECK_INT: return "CHECK_INT"; case OpCode::CHECK_NUMERIC: return "CHECK_NUMERIC"; case OpCode::CHECK_BOOL: return "CHECK_BOOL"; case OpCode::CHECK_REFERENCE: return "CHECK_REFERENCE"; case OpCode::CHECK_CALLABLE: return "CHECK_CALLABLE"; + case OpCode::CHECK_INDEXABLE: return "CHECK_INDEXABLE"; + case OpCode::CHECK_ALLOTABLE: return "CHECK_ALLOTABLE"; case OpCode::CHECK_TYPE: return "CHECK_TYPE"; case OpCode::CHECK_TYPE_LONG: return "CHECK_TYPE_LONG"; case OpCode::NEGATE: return "NEGATE"; @@ -370,6 +380,10 @@ std::string opCodeToString(OpCode code) { case OpCode::LESS: return "LESS"; case OpCode::GREATER: return "GREATER"; case OpCode::EQUAL: return "EQUAL"; + case OpCode::ARRAY: return "ARRAY"; + case OpCode::ARRAY_LONG: return "ARRAY_LONG"; + case OpCode::GET_ARRAY_INDEX: return "GET_ARRAY_INDEX"; + case OpCode::SET_ARRAY_INDEX: return "SET_ARRAY_INDEX"; case OpCode::POP: return "POP"; case OpCode::GET_LOCAL: return "GET_LOCAL"; case OpCode::GET_LOCAL_LONG: return "GET_LOCAL_LONG"; diff --git a/src/Compiler.cpp b/src/Compiler.cpp index 35270e7..c5c705a 100755 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -44,29 +44,29 @@ FunctionObject* Compiler::end() { return m_currentFunction; } -void Compiler::compile(std::vector ast) { +void Compiler::compile(std::vector> ast) { for (auto& stmt : ast) { - compile(stmt); + compile(*stmt); } } -void Compiler::compile(Stmt stmt) { +void Compiler::compile(Stmt& stmt) { try { - stmt->accept(this); + stmt.accept(this); } catch (CompileError& error) { Enact::reportErrorAt(error.getToken(), error.getMessage()); m_hadError = true; } } -void Compiler::compile(Expr expr) { - expr->accept(this); +void Compiler::compile(Expr& expr) { + expr.accept(this); } void Compiler::visitBlockStmt(BlockStmt &stmt) { beginScope(); - for (const Stmt& statement : stmt.statements) { - compile(statement); + for (auto& statement : stmt.statements) { + compile(*statement); } endScope(); } @@ -84,17 +84,17 @@ void Compiler::visitEachStmt(EachStmt &stmt) { } void Compiler::visitExpressionStmt(ExpressionStmt &stmt) { - compile(stmt.expr); + compile(*stmt.expr); emitByte(OpCode::POP); } void Compiler::visitForStmt(ForStmt &stmt) { beginScope(); - compile(stmt.initializer); + compile(*stmt.initializer); size_t loopStartIndex = currentChunk().getCount(); - compile(stmt.condition); + compile(*stmt.condition); if (stmt.condition->getType()->isDynamic()) { emitByte(OpCode::CHECK_BOOL); } @@ -104,12 +104,12 @@ void Compiler::visitForStmt(ForStmt &stmt) { emitByte(OpCode::POP); beginScope(); - for (Stmt& statement : stmt.body) { - compile(statement); + for (auto& statement : stmt.body) { + compile(*statement); } endScope(); - compile(stmt.increment); + compile(*stmt.increment); endScope(); // Pop the increment @@ -129,12 +129,12 @@ void Compiler::visitFunctionStmt(FunctionStmt &stmt) { Compiler compiler{this}; compiler.init(FunctionKind::FUNCTION, stmt.type, stmt.name.lexeme); - for (const NamedTypename& param : stmt.params) { + for (const Param& param : stmt.params) { compiler.addLocal(param.name); compiler.m_locals.back().initialized = true; } - compiler.compile(stmt.body); + compiler.compile(std::move(stmt.body)); FunctionObject* function = compiler.end(); uint32_t constantIndex = currentChunk().addConstant(Value{function}); @@ -166,8 +166,8 @@ void Compiler::visitGivenStmt(GivenStmt &stmt) { std::vector exitJumps; for (GivenCase& case_ : stmt.cases) { - compile(stmt.value); - compile(case_.value); + compile(*stmt.value); + compile(*case_.value); emitByte(OpCode::EQUAL); size_t jumpToNext = emitJump(OpCode::JUMP_IF_FALSE); @@ -175,8 +175,8 @@ void Compiler::visitGivenStmt(GivenStmt &stmt) { emitByte(OpCode::POP); beginScope(); - for (Stmt& statement : case_.body) { - compile(statement); + for (auto& statement : case_.body) { + compile(*statement); } endScope(); @@ -195,7 +195,7 @@ void Compiler::visitGivenStmt(GivenStmt &stmt) { } void Compiler::visitIfStmt(IfStmt &stmt) { - compile(stmt.condition); + compile(*stmt.condition); if (stmt.condition->getType()->isDynamic()) { emitByte(OpCode::CHECK_BOOL); } @@ -207,8 +207,8 @@ void Compiler::visitIfStmt(IfStmt &stmt) { emitByte(OpCode::POP); beginScope(); - for (Stmt& statement : stmt.thenBlock) { - compile(statement); + for (auto& statement : stmt.thenBlock) { + compile(*statement); } endScope(); @@ -222,8 +222,8 @@ void Compiler::visitIfStmt(IfStmt &stmt) { emitByte(OpCode::POP); beginScope(); - for (Stmt& statement : stmt.elseBlock) { - compile(statement); + for (auto& statement : stmt.elseBlock) { + compile(*statement); } endScope(); @@ -232,7 +232,7 @@ void Compiler::visitIfStmt(IfStmt &stmt) { } void Compiler::visitReturnStmt(ReturnStmt &stmt) { - compile(stmt.value); + compile(*stmt.value); emitByte(OpCode::RETURN); } @@ -247,7 +247,7 @@ void Compiler::visitTraitStmt(TraitStmt &stmt) { void Compiler::visitWhileStmt(WhileStmt &stmt) { size_t loopStartIndex = currentChunk().getCount(); - compile(stmt.condition); + compile(*stmt.condition); if (stmt.condition->getType()->isDynamic()) { emitByte(OpCode::CHECK_BOOL); } @@ -257,8 +257,8 @@ void Compiler::visitWhileStmt(WhileStmt &stmt) { emitByte(OpCode::POP); beginScope(); - for (Stmt& statement : stmt.body) { - compile(statement); + for (auto& statement : stmt.body) { + compile(*statement); } endScope(); @@ -271,39 +271,80 @@ void Compiler::visitWhileStmt(WhileStmt &stmt) { void Compiler::visitVariableStmt(VariableStmt &stmt) { addLocal(stmt.name); - compile(stmt.initializer); + compile(*stmt.initializer); m_locals.back().initialized = true; } +void Compiler::visitAllotExpr(AllotExpr& expr) { + compile(*expr.value); + compile(*expr.target->object); + + if (expr.target->object->getType()->isDynamic()) { + emitByte(OpCode::CHECK_INDEXABLE); + emitByte(OpCode::CHECK_ALLOTABLE); + } + + compile(*expr.target->index); + if (expr.target->index->getType()->isDynamic()) { + emitByte(OpCode::CHECK_INT); + } + + emitByte(OpCode::SET_ARRAY_INDEX); +} + void Compiler::visitAnyExpr(AnyExpr &expr) { // TODO: Throw CompileError "Not implemented." } void Compiler::visitArrayExpr(ArrayExpr &expr) { - throw errorAt(expr.square, "Not implemented."); + for (auto& value : expr.value) { + compile(*value); + } + + uint32_t length = expr.value.size(); + + auto* type = GC::allocateObject(expr.getType()); + uint32_t typeConstant = currentChunk().addConstant(Value{type}); + + if (length <= UINT8_MAX && typeConstant <= UINT8_MAX) { + emitByte(OpCode::ARRAY); + emitByte(static_cast(length)); + emitByte(static_cast(typeConstant)); + } else { + emitByte(OpCode::ARRAY_LONG); + emitLong(length); + emitLong(typeConstant); + } } void Compiler::visitAssignExpr(AssignExpr &expr) { - compile(expr.right); + compile(*expr.value); - if (typeid(*expr.left) == typeid(VariableExpr)) { - auto variableExpr = std::static_pointer_cast(expr.left); + uint32_t index; + OpCode byteOp; + OpCode longOp; - uint32_t index = resolveLocal(variableExpr->name); - if (index <= UINT8_MAX) { - emitByte(OpCode::SET_LOCAL); - emitByte(static_cast(index)); - } else { - emitByte(OpCode::SET_LOCAL_LONG); - emitLong(index); - } + try { + index = resolveLocal(expr.target->name); + byteOp = OpCode::SET_LOCAL; + longOp = OpCode::SET_LOCAL_LONG; + } catch (CompileError&) { + index = resolveUpvalue(expr.target->name); + byteOp = OpCode::SET_UPVALUE; + longOp = OpCode::SET_UPVALUE_LONG; + } + + if (index <= UINT8_MAX) { + emitByte(byteOp); + emitByte(static_cast(index)); } else { - throw errorAt(expr.oper, "Not implemented."); + emitByte(longOp); + emitLong(index); } } void Compiler::visitBinaryExpr(BinaryExpr &expr) { - compile(expr.left); + compile(*expr.left); if (expr.oper.type != TokenType::EQUAL && expr.oper.type != TokenType::BANG_EQUAL @@ -311,7 +352,7 @@ void Compiler::visitBinaryExpr(BinaryExpr &expr) { emitByte(OpCode::CHECK_NUMERIC); } - compile(expr.right); + compile(*expr.right); if (expr.oper.type != TokenType::EQUAL && expr.oper.type != TokenType::BANG_EQUAL @@ -350,12 +391,12 @@ void Compiler::visitBooleanExpr(BooleanExpr &expr) { } void Compiler::visitCallExpr(CallExpr &expr) { - compile(expr.callee); + compile(*expr.callee); bool needRuntimeCheck = expr.callee->getType()->isDynamic(); for (int i = 0; i < expr.arguments.size(); ++i) { - compile(expr.arguments[i]); + compile(*expr.arguments[i]); if (expr.arguments[i]->getType()->isDynamic()) { needRuntimeCheck = true; } @@ -370,21 +411,21 @@ void Compiler::visitCallExpr(CallExpr &expr) { emitByte(static_cast(expr.arguments.size())); } -void Compiler::visitFieldExpr(FieldExpr &expr) { - throw errorAt(expr.oper, "Not implemented."); -} - void Compiler::visitFloatExpr(FloatExpr &expr) { emitConstant(Value{expr.value}); } +void Compiler::visitGetExpr(GetExpr &expr) { + throw errorAt(expr.oper, "Not implemented."); +} + void Compiler::visitIntegerExpr(IntegerExpr &expr) { emitConstant(Value{expr.value}); } void Compiler::visitLogicalExpr(LogicalExpr &expr) { // Always compile the left operand - compile(expr.left); + compile(*expr.left); size_t jumpIndex = 0; @@ -396,7 +437,7 @@ void Compiler::visitLogicalExpr(LogicalExpr &expr) { emitByte(OpCode::POP); - compile(expr.right); + compile(*expr.right); patchJump(jumpIndex, expr.oper); } @@ -411,7 +452,17 @@ void Compiler::visitStringExpr(StringExpr &expr) { } void Compiler::visitSubscriptExpr(SubscriptExpr &expr) { - throw errorAt(expr.square, "Not implemented."); + compile(*expr.object); + if (expr.object->getType()->isDynamic()) { + emitByte(OpCode::CHECK_INDEXABLE); + } + + compile(*expr.index); + if (expr.index->getType()->isDynamic()) { + emitByte(OpCode::CHECK_INT); + } + + emitByte(OpCode::GET_ARRAY_INDEX); } void Compiler::visitTernaryExpr(TernaryExpr &expr) { @@ -419,7 +470,7 @@ void Compiler::visitTernaryExpr(TernaryExpr &expr) { } void Compiler::visitUnaryExpr(UnaryExpr &expr) { - compile(expr.operand); + compile(*expr.operand); switch (expr.oper.type) { case TokenType::MINUS: { @@ -449,24 +500,25 @@ void Compiler::visitUnaryExpr(UnaryExpr &expr) { } void Compiler::visitVariableExpr(VariableExpr &expr) { + uint32_t index; + OpCode byteOp; + OpCode longOp; + try { - uint32_t index = resolveLocal(expr.name); - if (index <= UINT8_MAX) { - emitByte(OpCode::GET_LOCAL); - emitByte(static_cast(index)); - } else { - emitByte(OpCode::GET_LOCAL_LONG); - emitLong(index); - } - return; - } catch (CompileError& error) {} + index = resolveLocal(expr.name); + byteOp = OpCode::GET_LOCAL; + longOp = OpCode::GET_LOCAL_LONG; + } catch (CompileError& error) { + index = resolveUpvalue(expr.name); + byteOp = OpCode::GET_UPVALUE; + longOp = OpCode::GET_UPVALUE_LONG; + } - uint32_t index = resolveUpvalue(expr.name); if (index <= UINT8_MAX) { - emitByte(OpCode::GET_UPVALUE); + emitByte(byteOp); emitByte(static_cast(index)); } else { - emitByte(OpCode::GET_UPVALUE_LONG); + emitByte(longOp); emitLong(index); } } diff --git a/src/Enact.cpp b/src/Enact.cpp index f4ee08d..76c92fb 100755 --- a/src/Enact.cpp +++ b/src/Enact.cpp @@ -40,25 +40,25 @@ InterpretResult Enact::run(const std::string& source) { { // Free up memory for the VM Parser parser{m_source}; - std::vector statements = parser.parse(); + std::vector> statements = parser.parse(); Analyser analyser{}; - analyser.analyse(statements); + statements = analyser.analyse(std::move(statements)); if (parser.hadError()) return InterpretResult::PARSE_ERROR; if (analyser.hadError()) return InterpretResult::ANALYSIS_ERROR; if (getFlags().flagEnabled(Flag::DEBUG_PRINT_AST)) { AstPrinter astPrinter; - for (const Stmt &stmt : statements) { - astPrinter.print(stmt); + for (const auto& stmt : statements) { + astPrinter.print(*stmt); std::cout << "\n"; } } Compiler compiler{}; compiler.init(FunctionKind::SCRIPT, std::make_shared(NOTHING_TYPE, std::vector{}), ""); - compiler.compile(statements); + compiler.compile(std::move(statements)); script = compiler.end(); if (compiler.hadError()) return InterpretResult::COMPILE_ERROR; } diff --git a/src/Object.cpp b/src/Object.cpp index 7090eed..dd803c9 100755 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -66,18 +66,29 @@ StringObject* StringObject::clone() const { return GC::allocateObject(*this); } -ArrayObject::ArrayObject() : Object{ObjectType::ARRAY}, m_vector{} { +ArrayObject::ArrayObject(Type type) : Object{ObjectType::ARRAY}, m_type{type}, m_vector{} { } -ArrayObject::ArrayObject(std::vector vector) : Object{ObjectType::ARRAY}, m_vector{std::move(vector)} { +ArrayObject::ArrayObject(size_t length, Type type) : Object{ObjectType::ARRAY}, m_vector{length}, m_type{type} { } -std::optional ArrayObject::at(size_t index) const { - if (index >= m_vector.size()) { - return {}; - } +ArrayObject::ArrayObject(std::vector vector, Type type) : Object{ObjectType::ARRAY}, m_vector{std::move(vector)}, m_type{type} { +} + +size_t ArrayObject::length() const { + return m_vector.size(); +} + +Value& ArrayObject::at(size_t index) { + return m_vector[index]; +} + +const Value& ArrayObject::at(size_t index) const { + return m_vector[index]; +} - return {m_vector[index]}; +void ArrayObject::append(Value value) { + m_vector.push_back(value); } const std::vector& ArrayObject::asVector() const { @@ -85,24 +96,22 @@ const std::vector& ArrayObject::asVector() const { } std::string ArrayObject::toString() const { - std::string output{"["}; + std::stringstream output{}; std::string separator{}; + + output << "["; for (const Value& item : asVector()) { - output += separator; - output += item.toString(); + output << separator; + output << item.toString(); separator = ", "; } - return output; + output << "]"; + + return output.str(); } Type ArrayObject::getType() const { - Type elementType = DYNAMIC_TYPE; - - for (const auto& element : m_vector) { - elementType = element.getType(); - } - - return std::make_shared(elementType); + return m_type; } ArrayObject* ArrayObject::clone() const { diff --git a/src/Parser.cpp b/src/Parser.cpp index 61fc9e4..4f4f675 100755 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -9,7 +9,7 @@ const ParseRule& Parser::getParseRule(TokenType type) { return m_parseRules[(size_t)type]; } -Expr Parser::parsePrecedence(Precedence precedence) { +std::unique_ptr Parser::parsePrecedence(Precedence precedence) { advance(); PrefixFn prefixRule = getParseRule(m_previous.type).prefix; if (prefixRule == nullptr) { @@ -18,87 +18,90 @@ Expr Parser::parsePrecedence(Precedence precedence) { return nullptr; } - Expr expr = (this->*(prefixRule))(); + std::unique_ptr expr = (this->*(prefixRule))(); while (precedence <= getParseRule(m_current.type).precedence) { advance(); InfixFn infixRule = getParseRule(m_previous.type).infix; - expr = (this->*(infixRule))(expr); + expr = (this->*(infixRule))(std::move(expr)); } return expr; } -Expr Parser::expression() { +std::unique_ptr Parser::expression() { return parsePrecedence(Precedence::ASSIGNMENT); } -Expr Parser::grouping() { - Expr expr = expression(); +std::unique_ptr Parser::grouping() { + std::unique_ptr expr = expression(); expect(TokenType::RIGHT_PAREN, "Expected ')' after expression."); return expr; } -Expr Parser::variable() { +std::unique_ptr Parser::variable() { if (m_previous.lexeme != "_") { - return std::make_shared(m_previous); + return std::make_unique(m_previous); } else { - return std::make_shared(); + return std::make_unique(); } } -Expr Parser::number() { +std::unique_ptr Parser::number() { if (m_previous.type == TokenType::INTEGER) { int value = std::stoi(m_previous.lexeme); - return std::make_shared(value); + return std::make_unique(value); } double value = std::stod(m_previous.lexeme); - return std::make_shared(value); + return std::make_unique(value); } -Expr Parser::literal() { +std::unique_ptr Parser::literal() { switch (m_previous.type) { - case TokenType::TRUE: return std::make_shared(true); - case TokenType::FALSE: return std::make_shared(false); - case TokenType::NIL: return std::make_shared(); + case TokenType::TRUE: return std::make_unique(true); + case TokenType::FALSE: return std::make_unique(false); + case TokenType::NIL: return std::make_unique(); } } -Expr Parser::string() { - return std::make_shared(m_previous.lexeme.substr(1, m_previous.lexeme.size() - 2)); +std::unique_ptr Parser::string() { + return std::make_unique(m_previous.lexeme.substr(1, m_previous.lexeme.size() - 2)); } -Expr Parser::array() { +std::unique_ptr Parser::array() { Token square = m_previous; - std::string typeName{}; + std::unique_ptr typeName; - std::vector elements; + std::vector> elements; if (!consume(TokenType::RIGHT_SQUARE)) { do { elements.push_back(expression()); } while (consume(TokenType::COMMA)); expect(TokenType::RIGHT_SQUARE, "Expected end of array."); + + // Typename can be empty + typeName = expectTypename(true); } else { - // Empty literal must have a typename - typeName = consumeTypeName(); + // Typename cannot be empty + typeName = expectTypename(); } - return std::make_shared(elements, square, typeName); + return std::make_unique(std::move(elements), square, std::move(typeName)); } -Expr Parser::unary() { +std::unique_ptr Parser::unary() { Token oper = m_previous; - Expr expr = parsePrecedence(Precedence::UNARY); + std::unique_ptr expr = parsePrecedence(Precedence::UNARY); - return std::make_shared(expr, oper); + return std::make_unique(std::move(expr), oper); } -Expr Parser::call(Expr callee) { +std::unique_ptr Parser::call(std::unique_ptr callee) { Token leftParen = m_previous; - std::vector arguments; + std::vector> arguments; if (!consume(TokenType::RIGHT_PAREN)) { do { @@ -110,67 +113,75 @@ Expr Parser::call(Expr callee) { if (arguments.size() > 255) throw errorAt(leftParen, "Too many arguments. Max is 255."); - return std::make_shared(callee, arguments, leftParen); + return std::make_unique(std::move(callee), std::move(arguments), leftParen); } -Expr Parser::subscript(Expr object) { +std::unique_ptr Parser::subscript(std::unique_ptr object) { Token square = m_previous; - Expr index = expression(); + std::unique_ptr index = expression(); expect(TokenType::RIGHT_SQUARE, "Expected ']' after subscript index."); - return std::make_shared(object, index, square); + return std::make_unique(std::move(object), std::move(index), square); } -Expr Parser::binary(Expr left) { +std::unique_ptr Parser::binary(std::unique_ptr left) { Token oper = m_previous; const ParseRule &rule = getParseRule(oper.type); - Expr right = parsePrecedence((Precedence)((int)rule.precedence + 1)); + std::unique_ptr right = parsePrecedence((Precedence)((int)rule.precedence + 1)); switch (oper.type) { case TokenType::AND: case TokenType::OR: - return std::make_shared(left, right, oper); + return std::make_unique(std::move(left), std::move(right), oper); default: - return std::make_shared(left, right, oper); + return std::make_unique(std::move(left), std::move(right), oper); } } -Expr Parser::assignment(Expr left) { +std::unique_ptr Parser::assignment(std::unique_ptr target) { Token oper = m_previous; - Expr right = parsePrecedence(Precedence::ASSIGNMENT); + std::unique_ptr value = parsePrecedence(Precedence::ASSIGNMENT); - if (typeid(*left) == typeid(VariableExpr) || - typeid(*left) == typeid(FieldExpr) || - typeid(*left) == typeid(SubscriptExpr)) { - return std::make_shared(left, right, oper); + if (typeid(*target) == typeid(VariableExpr)) { + auto variableTarget = std::unique_ptr{ + static_cast(target.release()) + }; + return std::make_unique(std::move(variableTarget), std::move(value), oper); + } else if (typeid(*target) == typeid(SubscriptExpr)) { + auto subscriptTarget = std::unique_ptr{ + static_cast(target.release()) + }; + return std::make_unique(std::move(subscriptTarget), std::move(value), oper); + } else if (typeid(*target) == typeid(GetExpr)) { + throw errorAt(oper, "Not implemented."); } throw errorAt(oper, "Invalid assignment target."); } -Expr Parser::field(Expr object) { +std::unique_ptr Parser::field(std::unique_ptr object) { Token oper = m_previous; expect(TokenType::IDENTIFIER, "Expected field name after '.'."); Token name = m_previous; - return std::make_shared(object, name, oper); + return std::make_unique(std::move(object), name, oper); } -Expr Parser::ternary(Expr condition) { - Expr thenBranch = parsePrecedence(Precedence::CONDITIONAL); +std::unique_ptr Parser::ternary(std::unique_ptr condition) { + std::unique_ptr thenBranch = parsePrecedence(Precedence::CONDITIONAL); expect(TokenType::COLON, "Expected ':' after then value of conditional expression."); Token oper = m_previous; - Expr elseBranch = parsePrecedence(Precedence::ASSIGNMENT); + std::unique_ptr elseBranch = parsePrecedence(Precedence::ASSIGNMENT); - return std::make_shared(condition, thenBranch, elseBranch, oper); + return std::make_unique(std::move(condition), std::move(thenBranch), std::move(elseBranch), oper); } -Stmt Parser::declaration() { +std::unique_ptr Parser::declaration() { ignoreNewline(); try { if (consume(TokenType::FUN)) return functionDeclaration(); @@ -185,29 +196,29 @@ Stmt Parser::declaration() { } } -Stmt Parser::functionDeclaration(bool mustParseBody) { +std::unique_ptr Parser::functionDeclaration(bool mustParseBody) { expect(TokenType::IDENTIFIER, "Expected function name."); Token name = m_previous; expect(TokenType::LEFT_PAREN, "Expected '(' after function name."); - std::vector params; + std::vector params; if (!consume(TokenType::RIGHT_PAREN)) { do { expect(TokenType::IDENTIFIER, "Expected parameter name."); - params.push_back(NamedTypename{m_previous, consumeTypeName()}); + params.push_back(Param{m_previous, expectTypename()}); } while (consume(TokenType::COMMA)); expect(TokenType::RIGHT_PAREN, "Expected end of parameter list."); } // Get the return type - std::string typeName = consumeTypeName(true); + std::unique_ptr returnTypename = expectTypename(true); - std::vector body; + std::vector> body; if (!mustParseBody && consumeSeparator()) { - return std::make_shared(name, typeName, params, body); + return std::make_unique(name, std::move(returnTypename), std::move(params), std::move(body), nullptr); } expect(TokenType::COLON, "Expected ':' before function body."); @@ -221,10 +232,10 @@ Stmt Parser::functionDeclaration(bool mustParseBody) { expectSeparator("Expected newline or ';' after function declaration."); - return std::make_shared(name, typeName, params, body); + return std::make_unique(name, std::move(returnTypename), std::move(params), std::move(body), nullptr); } -Stmt Parser::structDeclaration() { +std::unique_ptr Parser::structDeclaration() { expect(TokenType::IDENTIFIER, "Expected struct name."); Token name = m_previous; @@ -242,28 +253,32 @@ Stmt Parser::structDeclaration() { expect(TokenType::COLON, "Expected ':' before struct body."); ignoreNewline(); - std::vector fields; - std::vector> methods; - std::vector> assocFunctions; + std::vector fields; + std::vector> methods; + std::vector> assocFunctions; while (!check(TokenType::END) && !isAtEnd()) { ignoreNewline(); if (consume(TokenType::IDENTIFIER)) { // Field declaration Token fieldName = m_previous; - std::string fieldType = consumeTypeName(); + std::unique_ptr fieldType = expectTypename(); - fields.push_back(NamedTypename{fieldName, fieldType}); + fields.push_back(Field{fieldName, std::move(fieldType)}); expectSeparator("Expected newline or ';' after field declaration."); } else if (consume(TokenType::FUN)) { // Method declaration - std::shared_ptr method = std::static_pointer_cast(functionDeclaration()); - methods.push_back(method); + auto method = std::unique_ptr{ + static_cast(functionDeclaration().release()) + }; + methods.push_back(std::move(method)); } else if (consume(TokenType::ASSOC)) { // Associated function declaration - auto function = std::static_pointer_cast(functionDeclaration()); - assocFunctions.push_back(function); + auto function = std::unique_ptr{ + static_cast(functionDeclaration().release()) + }; + assocFunctions.push_back(std::move(function)); } else { throw errorAtCurrent("Expected field or method declaration."); } @@ -272,22 +287,24 @@ Stmt Parser::structDeclaration() { expect(TokenType::END, "Expected 'end' at end of struct declaration."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(name, traits, fields, methods, assocFunctions); + return std::make_unique(name, traits, std::move(fields), std::move(methods), std::move(assocFunctions)); } -Stmt Parser::traitDeclaration() { +std::unique_ptr Parser::traitDeclaration() { expect(TokenType::IDENTIFIER, "Expected trait name."); Token name = m_previous; expect(TokenType::COLON, "Expected ':' after trait name."); ignoreNewline(); - std::vector> methods; + std::vector> methods; while (!check(TokenType::END) && !isAtEnd()) { ignoreNewline(); if (consume(TokenType::FUN)) { - auto method = std::static_pointer_cast(functionDeclaration(false)); - methods.push_back(method); + auto method = std::unique_ptr{ + static_cast(functionDeclaration(false).release()) + }; + methods.push_back(std::move(method)); } else { throw errorAtCurrent("Expected method declaration."); } @@ -296,25 +313,25 @@ Stmt Parser::traitDeclaration() { expect(TokenType::END, "Expected 'end' at end of trait declaration."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(name, methods); + return std::make_unique(name, std::move(methods)); } -Stmt Parser::variableDeclaration(bool isConst) { +std::unique_ptr Parser::variableDeclaration(bool isConst) { expect(TokenType::IDENTIFIER, "Expected variable name."); Token name = m_previous; - std::string typeName { consumeTypeName(true) }; + std::unique_ptr typeName{expectTypename(true)}; expect(TokenType::EQUAL, "Expected '=' after variable name/type."); - Expr initializer = expression(); + std::unique_ptr initializer = expression(); expectSeparator("Expected newline or ';' after variable declaration."); - return std::make_shared(name, typeName, initializer, isConst); + return std::make_unique(name, std::move(typeName), std::move(initializer), isConst); } -Stmt Parser::statement() { +std::unique_ptr Parser::statement() { if (consume(TokenType::BLOCK)) return blockStatement(); if (consume(TokenType::IF)) return ifStatement(); if (consume(TokenType::WHILE)) return whileStatement(); @@ -327,11 +344,11 @@ Stmt Parser::statement() { return expressionStatement(); } -Stmt Parser::blockStatement() { +std::unique_ptr Parser::blockStatement() { expect(TokenType::COLON, "Expected ':' before block body."); ignoreNewline(); - std::vector statements; + std::vector> statements; while (!check(TokenType::END) && !isAtEnd()) { statements.push_back(declaration()); } @@ -339,22 +356,22 @@ Stmt Parser::blockStatement() { expect(TokenType::END, "Expected 'end' at end of block."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(statements); + return std::make_unique(std::move(statements)); } -Stmt Parser::ifStatement() { +std::unique_ptr Parser::ifStatement() { Token keyword = m_previous; - Expr condition = expression(); + std::unique_ptr condition = expression(); expect(TokenType::COLON, "Expected ':' after if condition."); ignoreNewline(); - std::vector thenBlock; + std::vector> thenBlock; while (!check(TokenType::END) && !check(TokenType::ELSE) && !isAtEnd()) { thenBlock.push_back(declaration()); } - std::vector elseBlock; + std::vector> elseBlock; if (consume(TokenType::ELSE)) { expect(TokenType::COLON, "Expected ':' after start of else block."); @@ -367,18 +384,18 @@ Stmt Parser::ifStatement() { expect(TokenType::END, "Expected 'end' at end of if statement."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(condition, thenBlock, elseBlock, keyword); + return std::make_unique(std::move(condition), std::move(thenBlock), std::move(elseBlock), keyword); } -Stmt Parser::whileStatement() { +std::unique_ptr Parser::whileStatement() { Token keyword = m_previous; - Expr condition = expression(); + std::unique_ptr condition = expression(); expect(TokenType::COLON, "Expected ':' after while condition."); ignoreNewline(); - std::vector body; + std::vector> body; while (!check(TokenType::END) && !isAtEnd()) { body.push_back(declaration()); } @@ -386,15 +403,15 @@ Stmt Parser::whileStatement() { expect(TokenType::END, "Expected 'end' at end of while loop."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(condition, body, keyword); + return std::make_unique(std::move(condition), std::move(body), keyword); } -Stmt Parser::forStatement() { +std::unique_ptr Parser::forStatement() { Token keyword = m_previous; - Stmt initializer; + std::unique_ptr initializer; if (consume(TokenType::SEMICOLON)) { - initializer = std::make_shared(std::make_shared()); + initializer = std::make_unique(std::make_unique()); } else if (consume(TokenType::VAR)) { initializer = variableDeclaration(false); } else if (consume(TokenType::CONST)) { @@ -403,26 +420,26 @@ Stmt Parser::forStatement() { initializer = expressionStatement(); } - Expr condition; + std::unique_ptr condition; if (!consume(TokenType::SEMICOLON)) { condition = expression(); expect(TokenType::SEMICOLON, "Expected ';' after for loop condition."); } else { - condition = std::make_shared(true); + condition = std::make_unique(true); } - Expr increment; + std::unique_ptr increment; if (!check(TokenType::COLON)) { increment = expression(); } else { - increment = std::make_shared(); + increment = std::make_unique(); } expect(TokenType::COLON, "Expected ':' before body of for loop."); ignoreNewline(); - std::vector body; + std::vector> body; while (!check(TokenType::END) && !isAtEnd()) { body.push_back(declaration()); } @@ -430,21 +447,21 @@ Stmt Parser::forStatement() { expect(TokenType::END, "Expected 'end' at end of for loop."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(initializer, condition, increment, body, keyword); + return std::make_unique(std::move(initializer), std::move(condition), std::move(increment), std::move(body), keyword); } -Stmt Parser::eachStatement() { +std::unique_ptr Parser::eachStatement() { expect(TokenType::IDENTIFIER, "Expected item name after 'each'."); Token name = m_previous; expect(TokenType::IN, "Expected 'in' after each loop item name."); - Expr object = expression(); + std::unique_ptr object = expression(); expect(TokenType::COLON, "Expected ':' before each loop body."); ignoreNewline(); - std::vector body; + std::vector> body; while (!check(TokenType::END) && !isAtEnd()) { body.push_back(declaration()); } @@ -452,11 +469,11 @@ Stmt Parser::eachStatement() { expect(TokenType::END, "Expected 'end' at end of each loop."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(name, object, body); + return std::make_unique(name, std::move(object), std::move(body)); } -Stmt Parser::givenStatement() { - Expr value = expression(); +std::unique_ptr Parser::givenStatement() { + std::unique_ptr value = expression(); expect(TokenType::COLON, "Expected ':' before given statement body."); std::vector cases; @@ -466,69 +483,69 @@ Stmt Parser::givenStatement() { if (consume(TokenType::WHEN)) { Token keyword = m_previous; - Expr caseValue = expression(); + std::unique_ptr caseValue = expression(); expect(TokenType::COLON, "Expected ':' before case body"); - std::vector caseBody; + std::vector> caseBody; while (!check(TokenType::WHEN) && !check(TokenType::ELSE) && !check(TokenType::END) && !isAtEnd()) { caseBody.push_back(declaration()); } - cases.push_back(GivenCase{caseValue, caseBody, keyword}); + cases.push_back(GivenCase{std::move(caseValue), std::move(caseBody), keyword}); } else if (consume(TokenType::ELSE)) { Token keyword = m_previous; expect(TokenType::COLON, "Expected ':' before 'else' case body."); - std::vector caseBody; + std::vector> caseBody; while (!check(TokenType::WHEN) && !check(TokenType::END) && !isAtEnd()) { caseBody.push_back(declaration()); } - Expr caseValue = std::make_shared(); + std::unique_ptr caseValue = std::make_unique(); - cases.push_back(GivenCase{caseValue, caseBody, keyword}); + cases.push_back(GivenCase{std::move(caseValue), std::move(caseBody), keyword}); } } expect(TokenType::END, "Expected 'end' at end of given statement."); expectSeparator("Expected newline or ';' after 'end'."); - return std::make_shared(value, cases); + return std::make_unique(std::move(value), std::move(cases)); } -Stmt Parser::returnStatement() { +std::unique_ptr Parser::returnStatement() { Token keyword = m_previous; - Expr value = expression(); + std::unique_ptr value = expression(); expectSeparator("Expected newline or ';' after return statement."); - return std::make_shared(keyword, value); + return std::make_unique(keyword, std::move(value)); } -Stmt Parser::breakStatement() { +std::unique_ptr Parser::breakStatement() { expectSeparator("Expected newline or ';' after break statement."); - return std::make_shared(m_previous); + return std::make_unique(m_previous); } -Stmt Parser::continueStatement() { +std::unique_ptr Parser::continueStatement() { expectSeparator("Expected newline or ';' after continue statement."); - return std::make_shared(m_previous); + return std::make_unique(m_previous); } -Stmt Parser::expressionStatement() { - Expr expr = expression(); +std::unique_ptr Parser::expressionStatement() { + std::unique_ptr expr = expression(); expectSeparator("Expected newline or ';' after expression."); - return std::make_shared(expr); + return std::make_unique(std::move(expr)); } -std::vector Parser::parse() { +std::vector> Parser::parse() { advance(); - std::vector statements{}; + std::vector> statements{}; while (!isAtEnd()) { - Stmt stmt = declaration(); - if (stmt) statements.push_back(stmt); + std::unique_ptr stmt = declaration(); + if (stmt) statements.push_back(std::move(stmt)); } return statements; @@ -597,59 +614,50 @@ void Parser::expectSeparator(const std::string &message) { throw errorAtCurrent(message); } -std::string Parser::consumeTypeName(bool emptyAllowed) { - if (consume(TokenType::FUN)) { - std::string typeName; - - expect(TokenType::LEFT_PAREN, "Expected '(' after 'fun' in function type."); - typeName += "fun ("; +std::unique_ptr Parser::expectTypename(bool emptyAllowed) { + std::unique_ptr typeName; - std::string separator = ""; - if (!consume(TokenType::RIGHT_PAREN)) { - do { - typeName += separator; - typeName += consumeTypeName(); - separator = ", "; - } while (consume(TokenType::COMMA)); - - expect(TokenType::RIGHT_PAREN, "Expected end of parameter list."); - } - typeName += ")"; + bool isEnclosed = consume(TokenType::LEFT_PAREN); - // Get the return type - typeName += consumeTypeName(true); - return typeName; + if (consume(TokenType::FUN)) { + typeName = expectFunctionTypename(); + } else if (consume(TokenType::IDENTIFIER)) { + typeName = std::make_unique(m_previous); + } else if (!emptyAllowed) { + throw error("Expected a typename."); } - // May be enclosed in square brackets to signify list type - if (consume(TokenType::LEFT_SQUARE)) { - std::string typeName; + if (typeName && consume(TokenType::LEFT_SQUARE)) { + expect(TokenType::RIGHT_SQUARE, "Expected ']' to complete list typename."); + typeName = std::make_unique(std::move(typeName)); + } - typeName += "["; + if (isEnclosed && !consume(TokenType::RIGHT_PAREN)) { + throw error("Expected ')' after typename."); + } - std::string elementType = consumeTypeName(); - if (elementType.empty()) { - undoAdvance(); - return ""; - } + if (!typeName && emptyAllowed) { + typeName = std::make_unique("", m_previous); + } - typeName += elementType; + return typeName; +} - expect(TokenType::RIGHT_SQUARE, "Expected ']' after list type name."); +std::unique_ptr Parser::expectFunctionTypename() { + expect(TokenType::LEFT_PAREN, "Expected '(' after 'fun' in function type."); - typeName += "]"; - return typeName; - } + std::vector> argumentTypenames; + if (!consume(TokenType::RIGHT_PAREN)) { + do { + argumentTypenames.push_back(expectTypename()); + } while (consume(TokenType::COMMA)); - if (consume(TokenType::IDENTIFIER)) { - return m_previous.lexeme; + expect(TokenType::RIGHT_PAREN, "Expected end of parameter list in function type."); } - if (!emptyAllowed) { - throw error("Expected a typename."); - } + std::unique_ptr returnTypename = expectTypename(true); - return ""; + return std::make_unique(std::move(returnTypename), std::move(argumentTypenames)); } void Parser::synchronise() { diff --git a/src/Type.cpp b/src/Type.cpp index 5f108b1..f74b57b 100755 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -69,6 +69,9 @@ bool TypeBase::operator!=(const TypeBase &type) const { } bool TypeBase::looselyEquals(const TypeBase &type) const { + if (this->isArray() && type.isArray()) { + return this->as()->getElementType()->looselyEquals(*type.as()->getElementType()); + } if (this->isTrait() && type.isStruct()) { return type.as()->getTrait(*this) != std::nullopt; } @@ -80,48 +83,7 @@ bool TypeBase::looselyEquals(const TypeBase &type) const { } std::string TypeBase::toString() const { - switch (m_kind) { - case TypeKind::PRIMITIVE: { - auto primType = this->as(); - switch (primType->getPrimitiveKind()) { - case PrimitiveKind::INT: return "int"; - case PrimitiveKind::FLOAT: return "float"; - case PrimitiveKind::BOOL: return "bool"; - case PrimitiveKind::STRING: return "string"; - case PrimitiveKind::NOTHING: return "nothing"; - case PrimitiveKind::DYNAMIC: return "any"; - default: return ""; - } - } - case TypeKind::ARRAY: { - auto arrType = this->as(); - return "[" + arrType->getElementType()->toString() + "]"; - } - case TypeKind::FUNCTION: { - auto funType = this->as(); - - std::stringstream ret{}; - ret << "fun ("; - std::string separator = ""; - for (const Type& argType : funType->getArgumentTypes()) { - ret << separator << argType->toString(); - separator = ", "; - } - - ret << ") " << funType->getReturnType()->toString(); - - return ret.str(); - } - case TypeKind::TRAIT: { - return this->as()->getName(); - } - case TypeKind::STRUCT: { - return this->as()->getName(); - } - - // Unreachable - default: return ""; - } + return toTypename()->name(); } bool TypeBase::isPrimitive() const { @@ -224,7 +186,6 @@ bool TypeBase::maybeStruct() const { // Primitive types - PrimitiveType::PrimitiveType(PrimitiveKind kind) : TypeBase{TypeKind::PRIMITIVE}, m_kind{kind} {} @@ -233,6 +194,18 @@ PrimitiveKind PrimitiveType::getPrimitiveKind() const { return m_kind; } +std::unique_ptr PrimitiveType::toTypename() const { + std::string name; + switch (m_kind) { + case PrimitiveKind::INT: name = "int"; break; + case PrimitiveKind::FLOAT: name = "float"; break; + case PrimitiveKind::BOOL: name = "bool"; break; + case PrimitiveKind::STRING: name = "string"; break; + case PrimitiveKind::DYNAMIC: name = "any"; break; + case PrimitiveKind::NOTHING: name = "nothing"; break; + } + return std::make_unique(Token{TokenType::IDENTIFIER, name, 0, 0}); +} ArrayType::ArrayType(Type elementType) : TypeBase{TypeKind::ARRAY}, @@ -242,6 +215,10 @@ const Type ArrayType::getElementType() const { return m_elementType; } +std::unique_ptr ArrayType::toTypename() const { + return std::make_unique(m_elementType->toTypename()); +} + FunctionType::FunctionType(Type returnType, std::vector argumentTypes) : TypeBase{TypeKind::FUNCTION}, m_returnType{returnType}, @@ -255,6 +232,14 @@ const std::vector& FunctionType::getArgumentTypes() const { return m_argumentTypes; } +std::unique_ptr FunctionType::toTypename() const { + std::vector> argumentTypenames; + for (Type type : m_argumentTypes) { + argumentTypenames.push_back(type->toTypename()); + } + return std::make_unique(m_returnType->toTypename(), std::move(argumentTypenames)); +} + TraitType::TraitType(std::string name, std::unordered_map methods) : TypeBase{TypeKind::TRAIT}, m_name{name}, @@ -276,6 +261,10 @@ std::optional TraitType::getMethod(const std::string &name) const { return {}; } +std::unique_ptr TraitType::toTypename() const { + return std::make_unique(m_name, Token{TokenType::IDENTIFIER, m_name, 0, 0}); +} + StructType::StructType(std::string name, std::vector traits, std::unordered_map fields, std::unordered_map methods, @@ -343,6 +332,10 @@ std::optional StructType::getAssocFunction(const std::string &name) const return {}; } +std::unique_ptr StructType::toTypename() const { + return std::make_unique(m_name, Token{TokenType::IDENTIFIER, m_name, 0, 0}); +} + ConstructorType::ConstructorType(StructType structType) : TypeBase{TypeKind::CONSTRUCTOR}, m_structType{structType}, @@ -356,3 +349,7 @@ const StructType &ConstructorType::getStructType() const { const FunctionType &ConstructorType::getFunctionType() const { return m_functionType; } + +std::unique_ptr ConstructorType::toTypename() const { + return m_functionType.toTypename(); +} diff --git a/src/Typename.cpp b/src/Typename.cpp new file mode 100644 index 0000000..99f09c5 --- /dev/null +++ b/src/Typename.cpp @@ -0,0 +1,113 @@ +#include +#include "h/Typename.h" + +BasicTypename::BasicTypename(Token name) : + m_name{name.lexeme}, + m_where{std::move(name)} {} + +BasicTypename::BasicTypename(std::string name, Token where) : + m_name{std::move(name)}, + m_where{std::move(where)} {} + +BasicTypename::BasicTypename(const BasicTypename& typeName) : + BasicTypename{typeName.m_name, typeName.m_where} {} + +std::unique_ptr BasicTypename::clone() const { + return std::make_unique(m_name, m_where); +} + +Typename::Kind BasicTypename::kind() const { + return Kind::BASIC; +} + +const std::string& BasicTypename::name() const { + return m_name; +} + +const Token& BasicTypename::where() const { + return m_where; +} + +ArrayTypename::ArrayTypename(std::unique_ptr elementTypename) : + m_elementTypename{std::move(elementTypename)}, + m_name{m_elementTypename->name() + "[]"} {} + +ArrayTypename::ArrayTypename(const ArrayTypename &typeName) : + ArrayTypename{typeName.m_elementTypename->clone()} {} + +std::unique_ptr ArrayTypename::clone() const { + return std::make_unique(m_elementTypename->clone()); +} + +const Typename& ArrayTypename::elementTypename() const { + return *m_elementTypename; +} + +Typename::Kind ArrayTypename::kind() const { + return Kind::ARRAY; +} + +const std::string& ArrayTypename::name() const { + return m_name; +} + +const Token& ArrayTypename::where() const { + return m_elementTypename->where(); +} + + +FunctionTypename::FunctionTypename(std::unique_ptr returnTypename, + std::vector> argumentTypenames) : + m_returnTypename{std::move(returnTypename)}, + m_argumentTypenames{std::move(argumentTypenames)} { + std::stringstream name{}; + name << "fun ("; + + std::string separator{}; + for (auto const& typeName : m_argumentTypenames) { + name << separator; + name << typeName->name(); + separator = ", "; + } + + name << ") " << m_returnTypename->name(); + + m_name = name.str(); +} + +FunctionTypename::FunctionTypename(const FunctionTypename &typeName) : + m_returnTypename{typeName.m_returnTypename->clone()}, + m_argumentTypenames{} { + for (auto& argTypeName : m_argumentTypenames) { + m_argumentTypenames.push_back(argTypeName->clone()); + } +} + +std::unique_ptr FunctionTypename::clone() const { + std::vector> argumentTypenames{}; + for (auto& typeName : m_argumentTypenames) { + argumentTypenames.push_back(typeName->clone()); + } + + return std::make_unique(m_returnTypename->clone(), std::move(argumentTypenames)); +} + +const Typename& FunctionTypename::returnTypename() const { + return *m_returnTypename; +} + +const std::vector>& FunctionTypename::argumentTypenames() const { + return m_argumentTypenames; +} + +Typename::Kind FunctionTypename::kind() const { + return Kind::FUNCTION; +} + +const std::string& FunctionTypename::name() const { + return m_name; +} + +const Token& FunctionTypename::where() const { + return m_returnTypename->where(); +} diff --git a/src/VM.cpp b/src/VM.cpp index ee5d3d8..9a7f918 100755 --- a/src/VM.cpp +++ b/src/VM.cpp @@ -69,6 +69,16 @@ InterpretResult VM::run(FunctionObject* function) { case OpCode::FALSE: push(Value{false}); break; case OpCode::NIL: push(Value{}); break; + case OpCode::CHECK_INT: { + Value value = peek(0); + if (!value.getType()->isInt()) { + runtimeError("Expected a value of type 'int', but got a value of type '" + + value.getType()->toString() + "' instead."); + + return InterpretResult::RUNTIME_ERROR; + } + break; + } case OpCode::CHECK_NUMERIC: { Value value = peek(0); if (!value.getType()->isNumeric()) { @@ -134,6 +144,26 @@ InterpretResult VM::run(FunctionObject* function) { } break; } + case OpCode::CHECK_INDEXABLE: { + Value array = peek(0); + if (!array.getType()->isArray()) { + runtimeError("Expected an array, but got a value of type '" + array.getType()->toString() + + "' instead."); + return InterpretResult::RUNTIME_ERROR; + } + break; + } + case OpCode::CHECK_ALLOTABLE: { + Type shouldBe = peek(0).getType()->as()->getElementType(); + Type valueType = peek(1).getType(); + + if (!valueType->looselyEquals(*shouldBe)) { + runtimeError("Expected a value of type '" + shouldBe->toString() + + "' to assign in array, but got a value of type '" + valueType->toString() + "' instead."); + return InterpretResult::RUNTIME_ERROR; + } + break; + } case OpCode::CHECK_TYPE: { Type shouldBe = READ_CONSTANT().asObject()->getType(); Value value = peek(0); @@ -182,6 +212,60 @@ InterpretResult VM::run(FunctionObject* function) { break; } + + case OpCode::ARRAY: { + uint8_t length = READ_BYTE(); + Type type = READ_CONSTANT().asObject()->as()->getContainedType(); + auto* array = GC::allocateObject(length, type); + if (length != 0) { + for (uint8_t i = length; i-- > 0;) { + array->at(i) = pop(); + } + } + push(Value{array}); + break; + } + case OpCode::ARRAY_LONG: { + uint32_t length = READ_LONG(); + Type type = READ_CONSTANT_LONG().asObject()->as()->getContainedType(); + auto* array = GC::allocateObject(length, type); + if (length != 0) { + for (uint32_t i = length; i-- > 0;) { + array->at(i) = pop(); + } + } + push(Value{array}); + break; + } + + case OpCode::GET_ARRAY_INDEX: { + int index = pop().asInt(); + ArrayObject* array = pop().asObject()->as(); + + if (index >= array->length()) { + runtimeError("Array index '" + std::to_string(index) + "' is out of bounds for array of " + + "length '" + std::to_string(array->asVector().size()) + "'."); + return InterpretResult::RUNTIME_ERROR; + } + + push(array->at(index)); + break; + } + case OpCode::SET_ARRAY_INDEX: { + int index = pop().asInt(); + ArrayObject* array = pop().asObject()->as(); + Value newValue = peek(0); + + if (index >= array->length()) { + runtimeError("Array index '" + std::to_string(index) + "' is out of bounds for array of " + + "length '" + std::to_string(array->asVector().size()) + "'."); + return InterpretResult::RUNTIME_ERROR; + } + + array->at(index) = newValue; + break; + } + case OpCode::POP: pop(); break; case OpCode::GET_LOCAL: push(slots[READ_BYTE()]); break; @@ -385,7 +469,7 @@ UpvalueObject* VM::captureUpvalue(uint32_t location) { if (upvalue != nullptr && upvalue->getLocation() == location) return upvalue; - UpvalueObject* createdUpvalue = GC::allocateObject(location); + auto* createdUpvalue = GC::allocateObject(location); createdUpvalue->setNext(upvalue); if (prevUpvalue == nullptr) { diff --git a/src/ast/Expr.h b/src/ast/Expr.h index 5dccba0..263fe11 100755 --- a/src/ast/Expr.h +++ b/src/ast/Expr.h @@ -4,15 +4,15 @@ #ifndef ENACT_EXPR_H #define ENACT_EXPR_H -#include "../h/Token.h" #include "../h/Type.h" +#include "../h/Typename.h" #include #include template class ExprVisitor; -class ExprBase { +class Expr { Type m_type = nullptr; public: virtual void setType(Type t) { m_type = t; } @@ -20,21 +20,21 @@ class ExprBase { ENACT_ASSERT(m_type != nullptr, "Expr::getType(): Tried to get uninitialized type."); return m_type; } - virtual ~ExprBase() = default; + virtual ~Expr() = default; virtual std::string accept(ExprVisitor *visitor) = 0; virtual void accept(ExprVisitor *visitor) = 0; }; -typedef std::shared_ptr Expr; - +class AllotExpr; +class AnyExpr; class ArrayExpr; class AssignExpr; class BinaryExpr; class BooleanExpr; class CallExpr; -class FieldExpr; class FloatExpr; +class GetExpr; class IntegerExpr; class LogicalExpr; class NilExpr; @@ -42,19 +42,20 @@ class StringExpr; class SubscriptExpr; class TernaryExpr; class UnaryExpr; -class AnyExpr; class VariableExpr; template class ExprVisitor { public: + virtual R visitAllotExpr(AllotExpr& expr) = 0; + virtual R visitAnyExpr(AnyExpr& expr) = 0; virtual R visitArrayExpr(ArrayExpr& expr) = 0; virtual R visitAssignExpr(AssignExpr& expr) = 0; virtual R visitBinaryExpr(BinaryExpr& expr) = 0; virtual R visitBooleanExpr(BooleanExpr& expr) = 0; virtual R visitCallExpr(CallExpr& expr) = 0; - virtual R visitFieldExpr(FieldExpr& expr) = 0; virtual R visitFloatExpr(FloatExpr& expr) = 0; + virtual R visitGetExpr(GetExpr& expr) = 0; virtual R visitIntegerExpr(IntegerExpr& expr) = 0; virtual R visitLogicalExpr(LogicalExpr& expr) = 0; virtual R visitNilExpr(NilExpr& expr) = 0; @@ -62,18 +63,54 @@ class ExprVisitor { virtual R visitSubscriptExpr(SubscriptExpr& expr) = 0; virtual R visitTernaryExpr(TernaryExpr& expr) = 0; virtual R visitUnaryExpr(UnaryExpr& expr) = 0; - virtual R visitAnyExpr(AnyExpr& expr) = 0; virtual R visitVariableExpr(VariableExpr& expr) = 0; }; -class ArrayExpr : public ExprBase { +class AllotExpr : public Expr { +public: + std::unique_ptr target; + std::unique_ptr value; + Token oper; + + AllotExpr(std::unique_ptr target,std::unique_ptr value,Token oper) : + target{std::move(target)}, + value{std::move(value)}, + oper{oper} {} + ~AllotExpr() override = default; + + std::string accept(ExprVisitor *visitor) override { + return visitor->visitAllotExpr(*this); + } + + void accept(ExprVisitor *visitor) override { + return visitor->visitAllotExpr(*this); + } +}; + +class AnyExpr : public Expr { +public: + AnyExpr() = default; + ~AnyExpr() override = default; + + std::string accept(ExprVisitor *visitor) override { + return visitor->visitAnyExpr(*this); + } + + void accept(ExprVisitor *visitor) override { + return visitor->visitAnyExpr(*this); + } +}; + +class ArrayExpr : public Expr { public: - std::vector value; + std::vector> value; Token square; - std::string typeName; + std::unique_ptr typeName; - ArrayExpr(std::vector value,Token square,std::string typeName) : - value{value},square{square},typeName{typeName} {} + ArrayExpr(std::vector> value,Token square,std::unique_ptr typeName) : + value{std::move(value)}, + square{square}, + typeName{std::move(typeName)} {} ~ArrayExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -85,14 +122,16 @@ class ArrayExpr : public ExprBase { } }; -class AssignExpr : public ExprBase { +class AssignExpr : public Expr { public: - Expr left; - Expr right; + std::unique_ptr target; + std::unique_ptr value; Token oper; - AssignExpr(Expr left,Expr right,Token oper) : - left{left},right{right},oper{oper} {} + AssignExpr(std::unique_ptr target,std::unique_ptr value,Token oper) : + target{std::move(target)}, + value{std::move(value)}, + oper{oper} {} ~AssignExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -104,14 +143,16 @@ class AssignExpr : public ExprBase { } }; -class BinaryExpr : public ExprBase { +class BinaryExpr : public Expr { public: - Expr left; - Expr right; + std::unique_ptr left; + std::unique_ptr right; Token oper; - BinaryExpr(Expr left,Expr right,Token oper) : - left{left},right{right},oper{oper} {} + BinaryExpr(std::unique_ptr left,std::unique_ptr right,Token oper) : + left{std::move(left)}, + right{std::move(right)}, + oper{oper} {} ~BinaryExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -123,12 +164,12 @@ class BinaryExpr : public ExprBase { } }; -class BooleanExpr : public ExprBase { +class BooleanExpr : public Expr { public: bool value; BooleanExpr(bool value) : - value{value} {} + value{value} {} ~BooleanExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -140,14 +181,16 @@ class BooleanExpr : public ExprBase { } }; -class CallExpr : public ExprBase { +class CallExpr : public Expr { public: - Expr callee; - std::vector arguments; + std::unique_ptr callee; + std::vector> arguments; Token paren; - CallExpr(Expr callee,std::vector arguments,Token paren) : - callee{callee},arguments{arguments},paren{paren} {} + CallExpr(std::unique_ptr callee,std::vector> arguments,Token paren) : + callee{std::move(callee)}, + arguments{std::move(arguments)}, + paren{paren} {} ~CallExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -159,48 +202,50 @@ class CallExpr : public ExprBase { } }; -class FieldExpr : public ExprBase { +class FloatExpr : public Expr { public: - Expr object; - Token name; - Token oper; + double value; - FieldExpr(Expr object,Token name,Token oper) : - object{object},name{name},oper{oper} {} - ~FieldExpr() override = default; + FloatExpr(double value) : + value{value} {} + ~FloatExpr() override = default; std::string accept(ExprVisitor *visitor) override { - return visitor->visitFieldExpr(*this); + return visitor->visitFloatExpr(*this); } void accept(ExprVisitor *visitor) override { - return visitor->visitFieldExpr(*this); + return visitor->visitFloatExpr(*this); } }; -class FloatExpr : public ExprBase { +class GetExpr : public Expr { public: - double value; + std::unique_ptr object; + Token name; + Token oper; - FloatExpr(double value) : - value{value} {} - ~FloatExpr() override = default; + GetExpr(std::unique_ptr object,Token name,Token oper) : + object{std::move(object)}, + name{name}, + oper{oper} {} + ~GetExpr() override = default; std::string accept(ExprVisitor *visitor) override { - return visitor->visitFloatExpr(*this); + return visitor->visitGetExpr(*this); } void accept(ExprVisitor *visitor) override { - return visitor->visitFloatExpr(*this); + return visitor->visitGetExpr(*this); } }; -class IntegerExpr : public ExprBase { +class IntegerExpr : public Expr { public: int value; IntegerExpr(int value) : - value{value} {} + value{value} {} ~IntegerExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -212,14 +257,16 @@ class IntegerExpr : public ExprBase { } }; -class LogicalExpr : public ExprBase { +class LogicalExpr : public Expr { public: - Expr left; - Expr right; + std::unique_ptr left; + std::unique_ptr right; Token oper; - LogicalExpr(Expr left,Expr right,Token oper) : - left{left},right{right},oper{oper} {} + LogicalExpr(std::unique_ptr left,std::unique_ptr right,Token oper) : + left{std::move(left)}, + right{std::move(right)}, + oper{oper} {} ~LogicalExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -231,7 +278,7 @@ class LogicalExpr : public ExprBase { } }; -class NilExpr : public ExprBase { +class NilExpr : public Expr { public: NilExpr() = default; ~NilExpr() override = default; @@ -245,12 +292,12 @@ class NilExpr : public ExprBase { } }; -class StringExpr : public ExprBase { +class StringExpr : public Expr { public: std::string value; StringExpr(std::string value) : - value{value} {} + value{value} {} ~StringExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -262,14 +309,16 @@ class StringExpr : public ExprBase { } }; -class SubscriptExpr : public ExprBase { +class SubscriptExpr : public Expr { public: - Expr object; - Expr index; + std::unique_ptr object; + std::unique_ptr index; Token square; - SubscriptExpr(Expr object,Expr index,Token square) : - object{object},index{index},square{square} {} + SubscriptExpr(std::unique_ptr object,std::unique_ptr index,Token square) : + object{std::move(object)}, + index{std::move(index)}, + square{square} {} ~SubscriptExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -281,15 +330,18 @@ class SubscriptExpr : public ExprBase { } }; -class TernaryExpr : public ExprBase { +class TernaryExpr : public Expr { public: - Expr condition; - Expr thenExpr; - Expr elseExpr; + std::unique_ptr condition; + std::unique_ptr thenExpr; + std::unique_ptr elseExpr; Token oper; - TernaryExpr(Expr condition,Expr thenExpr,Expr elseExpr,Token oper) : - condition{condition},thenExpr{thenExpr},elseExpr{elseExpr},oper{oper} {} + TernaryExpr(std::unique_ptr condition,std::unique_ptr thenExpr,std::unique_ptr elseExpr,Token oper) : + condition{std::move(condition)}, + thenExpr{std::move(thenExpr)}, + elseExpr{std::move(elseExpr)}, + oper{oper} {} ~TernaryExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -301,13 +353,14 @@ class TernaryExpr : public ExprBase { } }; -class UnaryExpr : public ExprBase { +class UnaryExpr : public Expr { public: - Expr operand; + std::unique_ptr operand; Token oper; - UnaryExpr(Expr operand,Token oper) : - operand{operand},oper{oper} {} + UnaryExpr(std::unique_ptr operand,Token oper) : + operand{std::move(operand)}, + oper{oper} {} ~UnaryExpr() override = default; std::string accept(ExprVisitor *visitor) override { @@ -319,26 +372,12 @@ class UnaryExpr : public ExprBase { } }; -class AnyExpr : public ExprBase { -public: - AnyExpr() = default; - ~AnyExpr() override = default; - - std::string accept(ExprVisitor *visitor) override { - return visitor->visitAnyExpr(*this); - } - - void accept(ExprVisitor *visitor) override { - return visitor->visitAnyExpr(*this); - } -}; - -class VariableExpr : public ExprBase { +class VariableExpr : public Expr { public: Token name; VariableExpr(Token name) : - name{name} {} + name{name} {} ~VariableExpr() override = default; std::string accept(ExprVisitor *visitor) override { diff --git a/src/ast/Stmt.h b/src/ast/Stmt.h index 3b9d941..70f4829 100755 --- a/src/ast/Stmt.h +++ b/src/ast/Stmt.h @@ -10,16 +10,14 @@ template class StmtVisitor; -class StmtBase { +class Stmt { public: - virtual ~StmtBase() = default; + virtual ~Stmt() = default; virtual std::string accept(StmtVisitor *visitor) = 0; virtual void accept(StmtVisitor *visitor) = 0; }; -typedef std::shared_ptr Stmt; - class BlockStmt; class BreakStmt; class ContinueStmt; @@ -54,12 +52,12 @@ class StmtVisitor { virtual R visitVariableStmt(VariableStmt& stmt) = 0; }; -class BlockStmt : public StmtBase { +class BlockStmt : public Stmt { public: - std::vector statements; + std::vector> statements; - BlockStmt(std::vector statements) : - statements{statements} {} + BlockStmt(std::vector> statements) : + statements{std::move(statements)} {} ~BlockStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -71,12 +69,12 @@ class BlockStmt : public StmtBase { } }; -class BreakStmt : public StmtBase { +class BreakStmt : public Stmt { public: Token keyword; BreakStmt(Token keyword) : - keyword{keyword} {} + keyword{keyword} {} ~BreakStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -88,12 +86,12 @@ class BreakStmt : public StmtBase { } }; -class ContinueStmt : public StmtBase { +class ContinueStmt : public Stmt { public: Token keyword; ContinueStmt(Token keyword) : - keyword{keyword} {} + keyword{keyword} {} ~ContinueStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -105,14 +103,16 @@ class ContinueStmt : public StmtBase { } }; -class EachStmt : public StmtBase { +class EachStmt : public Stmt { public: Token name; - Expr object; - std::vector body; + std::unique_ptr object; + std::vector> body; - EachStmt(Token name,Expr object,std::vector body) : - name{name},object{object},body{body} {} + EachStmt(Token name, std::unique_ptr object, std::vector> body) : + name{name}, + object{std::move(object)}, + body{std::move(body)} {} ~EachStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -124,12 +124,12 @@ class EachStmt : public StmtBase { } }; -class ExpressionStmt : public StmtBase { +class ExpressionStmt : public Stmt { public: - Expr expr; + std::unique_ptr expr; - ExpressionStmt(Expr expr) : - expr{expr} {} + ExpressionStmt(std::unique_ptr expr) : + expr{std::move(expr)} {} ~ExpressionStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -141,16 +141,20 @@ class ExpressionStmt : public StmtBase { } }; -class ForStmt : public StmtBase { +class ForStmt : public Stmt { public: - Stmt initializer; - Expr condition; - Expr increment; - std::vector body; + std::unique_ptr initializer; + std::unique_ptr condition; + std::unique_ptr increment; + std::vector> body; Token keyword; - ForStmt(Stmt initializer,Expr condition,Expr increment,std::vector body,Token keyword) : - initializer{initializer},condition{condition},increment{increment},body{body},keyword{keyword} {} + ForStmt(std::unique_ptr initializer, std::unique_ptr condition, std::unique_ptr increment, std::vector> body, Token keyword) : + initializer{std::move(initializer)}, + condition{std::move(condition)}, + increment{std::move(increment)}, + body{std::move(body)}, + keyword{keyword} {} ~ForStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -162,16 +166,20 @@ class ForStmt : public StmtBase { } }; -class FunctionStmt : public StmtBase { +class FunctionStmt : public Stmt { public: Token name; - std::string returnTypeName; - std::vector params; - std::vector body; - Type type = nullptr; - - FunctionStmt(Token name,std::string returnTypeName,std::vector params,std::vector body) : - name{name},returnTypeName{returnTypeName},params{params},body{body} {} + std::unique_ptr returnTypename; + std::vector params; + std::vector> body; + Type type; + + FunctionStmt(Token name, std::unique_ptr returnTypename, std::vector&& params, std::vector> body, Type type) : + name{name}, + returnTypename{std::move(returnTypename)}, + params{std::move(params)}, + body{std::move(body)}, + type{type} {} ~FunctionStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -183,13 +191,14 @@ class FunctionStmt : public StmtBase { } }; -class GivenStmt : public StmtBase { +class GivenStmt : public Stmt { public: - Expr value; + std::unique_ptr value; std::vector cases; - GivenStmt(Expr value,std::vector cases) : - value{value},cases{cases} {} + GivenStmt(std::unique_ptr value, std::vector&& cases) : + value{std::move(value)}, + cases{std::move(cases)} {} ~GivenStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -201,15 +210,18 @@ class GivenStmt : public StmtBase { } }; -class IfStmt : public StmtBase { +class IfStmt : public Stmt { public: - Expr condition; - std::vector thenBlock; - std::vector elseBlock; + std::unique_ptr condition; + std::vector> thenBlock; + std::vector> elseBlock; Token keyword; - IfStmt(Expr condition,std::vector thenBlock,std::vector elseBlock,Token keyword) : - condition{condition},thenBlock{thenBlock},elseBlock{elseBlock},keyword{keyword} {} + IfStmt(std::unique_ptr condition, std::vector> thenBlock, std::vector> elseBlock, Token keyword) : + condition{std::move(condition)}, + thenBlock{std::move(thenBlock)}, + elseBlock{std::move(elseBlock)}, + keyword{keyword} {} ~IfStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -221,13 +233,14 @@ class IfStmt : public StmtBase { } }; -class ReturnStmt : public StmtBase { +class ReturnStmt : public Stmt { public: Token keyword; - Expr value; + std::unique_ptr value; - ReturnStmt(Token keyword,Expr value) : - keyword{keyword},value{value} {} + ReturnStmt(Token keyword, std::unique_ptr value) : + keyword{keyword}, + value{std::move(value)} {} ~ReturnStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -239,16 +252,20 @@ class ReturnStmt : public StmtBase { } }; -class StructStmt : public StmtBase { +class StructStmt : public Stmt { public: Token name; std::vector traits; - std::vector fields; - std::vector> methods; - std::vector> assocFunctions; - - StructStmt(Token name,std::vector traits,std::vector fields,std::vector> methods,std::vector> assocFunctions) : - name{name},traits{traits},fields{fields},methods{methods},assocFunctions{assocFunctions} {} + std::vector fields; + std::vector> methods; + std::vector> assocFunctions; + + StructStmt(Token name, std::vector traits, std::vector&& fields, std::vector> methods, std::vector> assocFunctions) : + name{name}, + traits{traits}, + fields{std::move(fields)}, + methods{std::move(methods)}, + assocFunctions{std::move(assocFunctions)} {} ~StructStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -260,13 +277,14 @@ class StructStmt : public StmtBase { } }; -class TraitStmt : public StmtBase { +class TraitStmt : public Stmt { public: Token name; - std::vector> methods; + std::vector> methods; - TraitStmt(Token name,std::vector> methods) : - name{name},methods{methods} {} + TraitStmt(Token name, std::vector> methods) : + name{name}, + methods{std::move(methods)} {} ~TraitStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -278,14 +296,16 @@ class TraitStmt : public StmtBase { } }; -class WhileStmt : public StmtBase { +class WhileStmt : public Stmt { public: - Expr condition; - std::vector body; + std::unique_ptr condition; + std::vector> body; Token keyword; - WhileStmt(Expr condition,std::vector body,Token keyword) : - condition{condition},body{body},keyword{keyword} {} + WhileStmt(std::unique_ptr condition, std::vector> body, Token keyword) : + condition{std::move(condition)}, + body{std::move(body)}, + keyword{keyword} {} ~WhileStmt() override = default; std::string accept(StmtVisitor *visitor) override { @@ -297,15 +317,18 @@ class WhileStmt : public StmtBase { } }; -class VariableStmt : public StmtBase { +class VariableStmt : public Stmt { public: Token name; - std::string typeName; - Expr initializer; + std::unique_ptr typeName; + std::unique_ptr initializer; bool isConst; - VariableStmt(Token name,std::string typeName,Expr initializer,bool isConst) : - name{name},typeName{typeName},initializer{initializer},isConst{isConst} {} + VariableStmt(Token name, std::unique_ptr typeName, std::unique_ptr initializer, bool isConst) : + name{name}, + typeName{std::move(typeName)}, + initializer{std::move(initializer)}, + isConst{isConst} {} ~VariableStmt() override = default; std::string accept(StmtVisitor *visitor) override { diff --git a/src/ast/generate.py b/src/ast/generate.py index 7b0ea00..0791cef 100755 --- a/src/ast/generate.py +++ b/src/ast/generate.py @@ -1,3 +1,6 @@ +# THIS SCRIPT IS DEPRECATED +# It will NOT generate a correct AST + # This script generates the AST classes found in Expr.h/cpp and Stmt.h/cpp. @@ -116,13 +119,15 @@ def generate_tree(name, type_fields, visitor_types, includes): generate_tree( "Expr", { - "Array": ["std::vector value", "Token square", "std::string typeName"], - "Assign": ["Expr left", "Expr right", "Token oper"], + "Allot": ["std::shared_ptr target", "Expr value", "Token oper"], + "Any": [], + "Array": ["std::vector value", "Token square", "std::unique_ptr typeName"], + "Assign": ["std::shared_ptr target", "Expr value", "Token oper"], "Binary": ["Expr left", "Expr right", "Token oper"], "Boolean": ["bool value"], "Call": ["Expr callee", "std::vector arguments", "Token paren"], - "Field": ["Expr object", "Token name", "Token oper"], "Float": ["double value"], + "Get": ["Expr object", "Token name", "Token oper"], "Integer": ["int value"], "Logical": ["Expr left", "Expr right", "Token oper"], "Nil": [], @@ -130,11 +135,10 @@ def generate_tree(name, type_fields, visitor_types, includes): "Subscript":["Expr object", "Expr index", "Token square"], "Ternary": ["Expr condition", "Expr thenExpr", "Expr elseExpr", "Token oper"], "Unary": ["Expr operand", "Token oper"], - "Any": [], "Variable": ["Token name"] }, ["std::string", "void"], - ['"../h/Token.h"', '"../h/Type.h"', "", ""] + ['"../h/Type.h"', '"../h/Typename.h"', "", ""] ) generate_tree( @@ -145,15 +149,15 @@ def generate_tree(name, type_fields, visitor_types, includes): "Continue": ["Token keyword"], "Each": ["Token name", "Expr object", "std::vector body"], "Expression": ["Expr expr"], - "For": ["Stmt initializer", "Expr condition", "Expr increment", "std::vector body"], - "Function": ["Token name", "std::string returnTypeName", "std::vector params", "std::vector body"], + "For": ["Stmt initializer", "Expr condition", "Expr increment", "std::vector body", "Token keyword"], + "Function": ["Token name", "std::unique_ptr returnTypename", "std::vector> params", "std::vector body", "Type type"], "Given": ["Expr value", "std::vector cases"], "If": ["Expr condition", "std::vector thenBlock", "std::vector elseBlock", "Token keyword"], "Return": ["Token keyword", "Expr value"], - "Struct": ["Token name", "std::vector traits", "std::vector fields", "std::vector> methods", "std::vector> assocFunctions"], + "Struct": ["Token name", "std::vector traits", "std::vector> fields", "std::vector> methods", "std::vector> assocFunctions"], "Trait": ["Token name", "std::vector> methods"], - "While": ["Expr condition", "std::vector body"], - "Variable": ["Token name", "std::string typeName", "Expr initializer", "bool isConst"], + "While": ["Expr condition", "std::vector body", "Token keyword"], + "Variable": ["Token name", "Typename typeName", "Expr initializer", "bool isConst"], }, ["std::string", "void"], ['"Expr.h"', '"../h/trivialStructs.h"'] diff --git a/src/h/Analyser.h b/src/h/Analyser.h index 6df0479..0b4c4dd 100755 --- a/src/h/Analyser.h +++ b/src/h/Analyser.h @@ -39,10 +39,10 @@ class Analyser : private StmtVisitor, private ExprVisitor { std::vector m_currentFunctions = {}; // Keep track of functions that need to be analysed later - std::vector m_globalFunctions; + std::vector> m_globalFunctions; - void analyse(Stmt stmt); - void analyse(Expr expr); + void analyse(Stmt& stmt); + void analyse(Expr& expr); AnalysisError errorAt(const Token &token, const std::string &message); @@ -61,14 +61,15 @@ class Analyser : private StmtVisitor, private ExprVisitor { void visitWhileStmt(WhileStmt& stmt) override; void visitVariableStmt(VariableStmt& stmt) override; + void visitAllotExpr(AllotExpr& expr) override; void visitAnyExpr(AnyExpr& expr) override; void visitArrayExpr(ArrayExpr& expr) override; void visitAssignExpr(AssignExpr& expr) override; void visitBinaryExpr(BinaryExpr& expr) override; void visitBooleanExpr(BooleanExpr& expr) override; void visitCallExpr(CallExpr& expr) override; - void visitFieldExpr(FieldExpr& expr) override; void visitFloatExpr(FloatExpr& expr) override; + void visitGetExpr(GetExpr& expr) override; void visitIntegerExpr(IntegerExpr& expr) override; void visitLogicalExpr(LogicalExpr& expr) override; void visitNilExpr(NilExpr& expr) override; @@ -82,9 +83,7 @@ class Analyser : private StmtVisitor, private ExprVisitor { Type getFunctionType(const FunctionStmt &stmt); - Type lookUpType(const Token& name); - Type lookUpType(const std::string& name, const Token& where); - Type lookUpFunctionType(const std::string& name, const Token& where); + Type lookUpType(const Typename& name); Variable& lookUpVariable(const Token& name); void declareVariable(const std::string& name, const Variable& variable); @@ -93,7 +92,7 @@ class Analyser : private StmtVisitor, private ExprVisitor { void endScope(); public: - void analyse(std::vector program); + std::vector> analyse(std::vector> program); bool hadError(); }; diff --git a/src/h/AstPrinter.h b/src/h/AstPrinter.h index 5490799..91b5141 100755 --- a/src/h/AstPrinter.h +++ b/src/h/AstPrinter.h @@ -22,14 +22,15 @@ class AstPrinter : private StmtVisitor, private ExprVisitor, private ExprVisitor, private ExprVisitor { std::vector m_upvalues{}; - void compile(Stmt stmt); - void compile(Expr expr); + void compile(Stmt& stmt); + void compile(Expr& expr); void visitBlockStmt(BlockStmt& stmt) override; void visitBreakStmt(BreakStmt& stmt) override; @@ -53,14 +53,15 @@ class Compiler : private StmtVisitor, private ExprVisitor { void visitWhileStmt(WhileStmt& stmt) override; void visitVariableStmt(VariableStmt& stmt) override; + void visitAllotExpr(AllotExpr& expr) override; void visitAnyExpr(AnyExpr& expr) override; void visitArrayExpr(ArrayExpr& expr) override; void visitAssignExpr(AssignExpr& expr) override; void visitBinaryExpr(BinaryExpr& expr) override; void visitBooleanExpr(BooleanExpr& expr) override; void visitCallExpr(CallExpr& expr) override; - void visitFieldExpr(FieldExpr& expr) override; void visitFloatExpr(FloatExpr& expr) override; + void visitGetExpr(GetExpr& expr) override; void visitIntegerExpr(IntegerExpr& expr) override; void visitLogicalExpr(LogicalExpr& expr) override; void visitNilExpr(NilExpr& expr) override; @@ -117,7 +118,7 @@ class Compiler : private StmtVisitor, private ExprVisitor { void init(FunctionKind functionKind, Type functionType, const std::string& name); FunctionObject* end(); - void compile(std::vector ast); + void compile(std::vector> ast); bool hadError(); }; diff --git a/src/h/Object.h b/src/h/Object.h index 2b0c33b..f6b338a 100755 --- a/src/h/Object.h +++ b/src/h/Object.h @@ -115,14 +115,21 @@ class Value; class ArrayObject : public Object { std::vector m_vector; + Type m_type; public: - explicit ArrayObject(); - explicit ArrayObject(std::vector vector); + explicit ArrayObject(Type type); + explicit ArrayObject(size_t length, Type type); + explicit ArrayObject(std::vector vector, Type type); ~ArrayObject() override = default; - std::optional at(size_t index) const; + size_t length() const; + + Value& at(size_t index); + const Value& at(size_t index) const; + + void append(Value value); const std::vector& asVector() const; diff --git a/src/h/Parser.h b/src/h/Parser.h index 9fd412b..92f72ec 100755 --- a/src/h/Parser.h +++ b/src/h/Parser.h @@ -8,6 +8,7 @@ #include "Chunk.h" #include "Scanner.h" #include "Token.h" +#include "Typename.h" #include "../ast/Stmt.h" @@ -27,8 +28,8 @@ enum class Precedence { }; class Parser; -typedef Expr (Parser::*PrefixFn)(); -typedef Expr (Parser::*InfixFn)(Expr); +typedef std::unique_ptr (Parser::*PrefixFn)(); +typedef std::unique_ptr (Parser::*InfixFn)(std::unique_ptr); struct ParseRule { PrefixFn prefix; @@ -67,26 +68,26 @@ class Parser { ParseError error(const std::string &message); const ParseRule& getParseRule(TokenType type); - Expr parsePrecedence(Precedence precedence); + std::unique_ptr parsePrecedence(Precedence precedence); - Expr expression(); + std::unique_ptr expression(); // Prefix parse rules - Expr grouping(); - Expr variable(); - Expr number(); - Expr literal(); - Expr string(); - Expr array(); - Expr unary(); + std::unique_ptr grouping(); + std::unique_ptr variable(); + std::unique_ptr number(); + std::unique_ptr literal(); + std::unique_ptr string(); + std::unique_ptr array(); + std::unique_ptr unary(); // Infix parse rules - Expr call(Expr callee); - Expr subscript(Expr object); - Expr binary(Expr left); - Expr assignment(Expr left); - Expr field(Expr object); - Expr ternary(Expr condition); + std::unique_ptr call(std::unique_ptr callee); + std::unique_ptr subscript(std::unique_ptr object); + std::unique_ptr binary(std::unique_ptr left); + std::unique_ptr assignment(std::unique_ptr target); + std::unique_ptr field(std::unique_ptr object); + std::unique_ptr ternary(std::unique_ptr condition); std::array m_parseRules = { ParseRule{&Parser::grouping, &Parser::call, Precedence::CALL}, // LEFT_PAREN @@ -148,32 +149,33 @@ class Parser { }; // Declarations - Stmt declaration(); - Stmt functionDeclaration(bool mustParseBody = true); - Stmt structDeclaration(); - Stmt traitDeclaration(); - Stmt variableDeclaration(bool isConst); + std::unique_ptr declaration(); + std::unique_ptr functionDeclaration(bool mustParseBody = true); + std::unique_ptr structDeclaration(); + std::unique_ptr traitDeclaration(); + std::unique_ptr variableDeclaration(bool isConst); // Statements - Stmt statement(); - Stmt blockStatement(); - Stmt ifStatement(); - Stmt whileStatement(); - Stmt forStatement(); - Stmt eachStatement(); - Stmt givenStatement(); - Stmt returnStatement(); - Stmt breakStatement(); - Stmt continueStatement(); - Stmt expressionStatement(); - - std::string consumeTypeName(bool emptyAllowed = false); + std::unique_ptr statement(); + std::unique_ptr blockStatement(); + std::unique_ptr ifStatement(); + std::unique_ptr whileStatement(); + std::unique_ptr forStatement(); + std::unique_ptr eachStatement(); + std::unique_ptr givenStatement(); + std::unique_ptr returnStatement(); + std::unique_ptr breakStatement(); + std::unique_ptr continueStatement(); + std::unique_ptr expressionStatement(); + + std::unique_ptr expectTypename(bool emptyAllowed = false); + std::unique_ptr expectFunctionTypename(); void synchronise(); public: explicit Parser(std::string source); - std::vector parse(); + std::vector> parse(); bool hadError(); }; diff --git a/src/h/Type.h b/src/h/Type.h index 3e7458a..e0e44c4 100755 --- a/src/h/Type.h +++ b/src/h/Type.h @@ -2,6 +2,7 @@ #define ENACT_TYPE_H #include "Token.h" +#include "Typename.h" #include #include #include @@ -67,6 +68,7 @@ class TypeBase { // dynamic, or convertible to each other. virtual bool looselyEquals(const TypeBase &type) const; + virtual std::unique_ptr toTypename() const = 0; virtual std::string toString() const; // Primitive type groups @@ -125,6 +127,8 @@ class PrimitiveType : public TypeBase { ~PrimitiveType() override = default; PrimitiveKind getPrimitiveKind() const; + + std::unique_ptr toTypename() const override; }; // Array types @@ -135,6 +139,8 @@ class ArrayType : public TypeBase { ~ArrayType() override = default; const Type getElementType() const; + + std::unique_ptr toTypename() const override; }; // Function types @@ -147,6 +153,8 @@ class FunctionType : public TypeBase { const Type getReturnType() const; const std::vector& getArgumentTypes() const; + + std::unique_ptr toTypename() const override; }; @@ -165,6 +173,8 @@ class TraitType : public TypeBase { const std::unordered_map& getMethods() const; std::optional getMethod(const std::string& name) const; + + std::unique_ptr toTypename() const override; }; // Struct types @@ -195,6 +205,8 @@ class StructType : public TypeBase { std::optional getFieldOrMethod(const std::string& name) const; std::optional getAssocFunction(const std::string& name) const; + + std::unique_ptr toTypename() const override; }; // Struct constructor types @@ -207,6 +219,8 @@ class ConstructorType : public TypeBase { const StructType& getStructType() const; const FunctionType& getFunctionType() const; + + std::unique_ptr toTypename() const override; }; #endif //ENACT_TYPE_H diff --git a/src/h/Typename.h b/src/h/Typename.h new file mode 100644 index 0000000..4bdea0b --- /dev/null +++ b/src/h/Typename.h @@ -0,0 +1,77 @@ +#ifndef ENACT_TYPENAME_H +#define ENACT_TYPENAME_H + +#include +#include "Token.h" + +class Typename { +public: + enum class Kind { + BASIC, + ARRAY, + FUNCTION + }; + + virtual ~Typename() = default; + + virtual std::unique_ptr clone() const = 0; + + virtual Kind kind() const = 0; + virtual const std::string& name() const = 0; + virtual const Token& where() const = 0; +}; + +class BasicTypename : public Typename { + std::string m_name; + Token m_where; + +public: + explicit BasicTypename(Token name); + explicit BasicTypename(std::string name, Token where); + BasicTypename(const BasicTypename& typeName); + + std::unique_ptr clone() const override; + + Kind kind() const override; + const std::string& name() const override; + const Token& where() const override; +}; + +class ArrayTypename : public Typename { + std::unique_ptr m_elementTypename; + std::string m_name; + +public: + explicit ArrayTypename(std::unique_ptr elementTypename); + ArrayTypename(const ArrayTypename& typeName); + + std::unique_ptr clone() const override; + + const Typename& elementTypename() const; + + Kind kind() const override; + const std::string& name() const override; + const Token& where() const override; +}; + +class FunctionTypename : public Typename { + std::unique_ptr m_returnTypename; + std::vector> m_argumentTypenames; + std::string m_name{}; + +public: + FunctionTypename(std::unique_ptr returnTypename, + std::vector> argumentTypenames); + FunctionTypename(const FunctionTypename& typeName); + + std::unique_ptr clone() const override; + + const Typename& returnTypename() const; + const std::vector>& argumentTypenames() const; + + Kind kind() const override; + const std::string& name() const override; + const Token& where() const override; +}; + +#endif //ENACT_TYPENAME_H diff --git a/src/h/trivialStructs.h b/src/h/trivialStructs.h index 16bb53a..2c5085f 100755 --- a/src/h/trivialStructs.h +++ b/src/h/trivialStructs.h @@ -3,25 +3,22 @@ #include "../ast/Stmt.h" -class StmtBase; -typedef std::shared_ptr Stmt; +class Stmt; struct GivenCase { - Expr value; - std::vector body; + std::unique_ptr value; + std::vector> body; Token keyword; }; -// A name (token) associated with a typename (string). -struct NamedTypename { +struct Param { Token name; - std::string typeName; + std::unique_ptr typeName; }; -// A name (token) associated with a type. -struct NamedType { +struct Field { Token name; - Type type; + std::unique_ptr typeName; };