diff --git a/bootstrap/emit.cc b/bootstrap/emit.cc index dcada32..dba673e 100644 --- a/bootstrap/emit.cc +++ b/bootstrap/emit.cc @@ -20,9 +20,9 @@ std::any EmitVisitor::visitFunction(xlangParser::FunctionContext *ctx) { output << std::endl << "export function w $" << ctx->Identifier()->getSymbol()->getText() << "("; - if (auto arg_list = ctx->argumentList()) { - for (const auto arg : arg_list->Identifier()) { - output << "w %_" << arg->getSymbol()->getText() << ", "; + if (auto param_list = ctx->parameterList()) { + for (const auto param : param_list->Identifier()) { + output << "w %_" << param->getSymbol()->getText() << ", "; } } output << ")" << std::endl << "{" << std::endl << "@start" << std::endl; @@ -36,7 +36,7 @@ std::any EmitVisitor::visitFunction(xlangParser::FunctionContext *ctx) { std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) { if (auto identifier = ctx->Identifier()) { tmpcount = 0; - visitExpr(ctx->expr()); + visitValue(ctx->value()); output << " %_" << identifier->getSymbol()->getText() << " = w copy " << last << std::endl; return {}; @@ -73,14 +73,14 @@ std::any EmitVisitor::visitStatement(xlangParser::StatementContext *ctx) { } if (ctx->Return()) { tmpcount = 0; - visitExpr(ctx->expr()); + visitValue(ctx->value()); output << " ret " << last << std::endl; output << "@dead" << blockcount++ << std::endl; return {}; } if (ctx->Print()) { tmpcount = 0; - visitExpr(ctx->expr()); + visitValue(ctx->value()); output << " call $printf(l $printformat, ..., w " << last << ")" << std::endl; return {}; @@ -129,7 +129,7 @@ std::any EmitVisitor::visitBoolean(xlangParser::BooleanContext *ctx) { last = "0"; return {}; } - visitCondition(ctx->condition()); + visitChildren(ctx); return {}; } @@ -169,27 +169,29 @@ std::any EmitVisitor::visitFactor(xlangParser::FactorContext *ctx) { last = integer->getSymbol()->getText(); return {}; } - if (auto identifier = ctx->Identifier()) { - if (ctx->LeftParen()) { - std::vector args; - if (auto expr_list = ctx->exprList()) { - for (auto expr : expr_list->expr()) { - visitExpr(expr); - args.emplace_back(last); - } + visitChildren(ctx); + return {}; +} + +std::any EmitVisitor::visitVariable(xlangParser::VariableContext *ctx) { + auto name = ctx->Identifier()->getSymbol()->getText(); + + if (ctx->LeftParen()) { + std::vector args; + if (auto arg_list = ctx->argumentList()) { + for (auto value : arg_list->value()) { + visitValue(value); + args.emplace_back(last); } - output << " " << tmp() << " = w call $" - << identifier->getSymbol()->getText() << "("; - for (auto arg : args) { - output << "w " << arg << ", "; - } - output << ")" << std::endl; - } else { - last = "%_" + identifier->getSymbol()->getText(); } - return {}; + output << " " << tmp() << " = w call $" << name << "("; + for (auto arg : args) { + output << "w " << arg << ", "; + } + output << ")" << std::endl; + } else { + last = "%_" + name; } - visitExpr(ctx->expr()); return {}; } diff --git a/bootstrap/emit.hh b/bootstrap/emit.hh index e86c9c0..889e4f8 100644 --- a/bootstrap/emit.hh +++ b/bootstrap/emit.hh @@ -26,6 +26,7 @@ class EmitVisitor : public xlangBaseVisitor { std::any visitExpr(xlangParser::ExprContext *ctx) override; std::any visitTerm(xlangParser::TermContext *ctx) override; std::any visitFactor(xlangParser::FactorContext *ctx) override; + std::any visitVariable(xlangParser::VariableContext *ctx) override; }; } // namespace xlang diff --git a/bootstrap/typecheck.cc b/bootstrap/typecheck.cc index f7b4cb3..274e305 100644 --- a/bootstrap/typecheck.cc +++ b/bootstrap/typecheck.cc @@ -26,8 +26,8 @@ std::any TypeCheckVisitor::visitFile(xlangParser::FileContext *ctx) { "duplicate function '" + name + "'"); continue; } - if (auto arg_list = function->argumentList()) { - function_arity[name] = arg_list->Identifier().size(); + if (auto param_list = function->parameterList()) { + function_arity[name] = param_list->Identifier().size(); } else { function_arity[name] = 0; } @@ -38,9 +38,9 @@ std::any TypeCheckVisitor::visitFile(xlangParser::FileContext *ctx) { std::any TypeCheckVisitor::visitFunction(xlangParser::FunctionContext *ctx) { scope.emplace_back(); - if (auto arg_list = ctx->argumentList()) { - for (const auto arg : arg_list->Identifier()) { - scope.back().emplace(arg->getSymbol()->getText()); + if (auto param_list = ctx->parameterList()) { + for (const auto param : param_list->Identifier()) { + scope.back().emplace(param->getSymbol()->getText()); } } visitBlock(ctx->block()); @@ -57,7 +57,7 @@ std::any TypeCheckVisitor::visitBlock(xlangParser::BlockContext *ctx) { std::any TypeCheckVisitor::visitStatement(xlangParser::StatementContext *ctx) { if (auto identifier = ctx->Identifier()) { - visitExpr(ctx->expr()); + visitValue(ctx->value()); scope.back().emplace(identifier->getSymbol()->getText()); return {}; } @@ -65,45 +65,46 @@ std::any TypeCheckVisitor::visitStatement(xlangParser::StatementContext *ctx) { return {}; } -std::any TypeCheckVisitor::visitFactor(xlangParser::FactorContext *ctx) { - if (auto identifier = ctx->Identifier()) { - auto token = identifier->getSymbol(); - auto name = token->getText(); - if (ctx->LeftParen()) { - if (function_arity.find(name) != function_arity.end()) { - if (auto expr_list = ctx->exprList()) { - auto arity = function_arity[name]; - auto arg_num = expr_list->expr().size(); - if (arity != arg_num) { - errorlistener.typeError( - token->getLine(), token->getCharPositionInLine(), - "function '" + name + "' expects " + std::to_string(arity) + - " arguments, but got " + std::to_string(arg_num)); - } - } else { - if (auto arity = function_arity[name]) { - errorlistener.typeError( - token->getLine(), token->getCharPositionInLine(), - "function '" + name + "' expects " + std::to_string(arity) + - " arguments, but got none"); - } +std::any TypeCheckVisitor::visitVariable(xlangParser::VariableContext *ctx) { + auto token = ctx->Identifier()->getSymbol(); + auto name = token->getText(); + auto line = token->getLine(); + auto charPositionInLine = token->getCharPositionInLine(); + + if (ctx->LeftParen()) { + auto it = function_arity.find(name); + + if (it == function_arity.end()) { + errorlistener.typeError(line, charPositionInLine, + "unknown function '" + name + "'"); + } else { + auto arity = it->second; + + if (auto arg_list = ctx->argumentList()) { + auto arg_num = arg_list->value().size(); + + if (arity != arg_num) { + errorlistener.typeError( + line, charPositionInLine, + "function '" + name + "' expects " + std::to_string(arity) + + " arguments, but got " + std::to_string(arg_num)); } } else { - errorlistener.typeError(token->getLine(), - token->getCharPositionInLine(), - "unknown function '" + name + "'"); - } - visitChildren(ctx); - } else { - if (!inScope(name)) { - errorlistener.typeError(token->getLine(), - token->getCharPositionInLine(), - "variable '" + name + "' is not in scope"); + if (arity) { + errorlistener.typeError(line, charPositionInLine, + "function '" + name + "' expects " + + std::to_string(arity) + + " arguments, but got none"); + } } } - return {}; + visitChildren(ctx); + } else { + if (!inScope(name)) { + errorlistener.typeError(line, charPositionInLine, + "variable '" + name + "' is not in scope"); + } } - visitChildren(ctx); return {}; } diff --git a/bootstrap/typecheck.hh b/bootstrap/typecheck.hh index b60290f..cf84daf 100644 --- a/bootstrap/typecheck.hh +++ b/bootstrap/typecheck.hh @@ -23,7 +23,7 @@ class TypeCheckVisitor : public xlangBaseVisitor { std::any visitFunction(xlangParser::FunctionContext *ctx) override; std::any visitBlock(xlangParser::BlockContext *ctx) override; std::any visitStatement(xlangParser::StatementContext *ctx) override; - std::any visitFactor(xlangParser::FactorContext *ctx) override; + std::any visitVariable(xlangParser::VariableContext *ctx) override; }; } // namespace xlang diff --git a/bootstrap/xlang.g4 b/bootstrap/xlang.g4 index 6b23f6c..d2b7513 100644 --- a/bootstrap/xlang.g4 +++ b/bootstrap/xlang.g4 @@ -1,15 +1,18 @@ grammar xlang; file : function+ EOF; -function : Identifier LeftParen argumentList? RightParen block; -argumentList : Identifier (Comma Identifier)*; +function : Identifier LeftParen parameterList? RightParen block; +parameterList : Identifier (Comma Identifier)*; block : LeftBrace statement* RightBrace; -statement : Identifier Assign expr Semicolon +statement : Identifier Assign value Semicolon | If condition block (Else block)? | While condition block - | Return expr Semicolon - | Print expr Semicolon + | Return value Semicolon + | Print value Semicolon ; +value : expr + | condition + ; condition : condition (And|Or|Xor) boolean | boolean ; @@ -17,6 +20,7 @@ boolean : Not boolean | expr (Less|LessEqual|Greater|GreaterEqual|Equal|NotEqual) expr | True | False + | variable | LeftParen condition RightParen ; expr : expr (Plus|Minus|BitAnd|BitOr|BitXor|ShiftLeft|ShiftRight) term @@ -28,11 +32,13 @@ term : term (Mul|Div) factor factor : Minus factor | BitNot factor | Integer - | Identifier - | Identifier LeftParen exprList? RightParen + | variable | LeftParen expr RightParen ; -exprList : expr (Comma expr)*; +variable : Identifier + | Identifier LeftParen argumentList? RightParen + ; +argumentList : value (Comma value)*; If : 'if'; Else : 'else';