diff --git a/ast.cc b/ast.cc index d9a6e79..b54d306 100644 --- a/ast.cc +++ b/ast.cc @@ -60,7 +60,7 @@ void EvalVisitor::visit(Binary* expr) { Boolean* b1 = dynamic_cast(v1.value); Boolean* b2 = dynamic_cast(v2.value); Variable* lv = dynamic_cast(expr->left); - Expr* rv = v2.value; + Literal* rv = v2.value; switch (expr->op.tokenType) { case PLUS: if (n1 && n2) { @@ -182,6 +182,14 @@ void ExecVisitor::visit(VarDecl* s) { context.define(s->identifier, v.getValue()); } +void ExecVisitor::visit(FunDecl* s) { + if (context.count(s->identifier)) { + std::cerr << "redefine function " << s->identifier; + exit(-1); + } + context.define(s->identifier, new Function(s)); +} + void ExecVisitor::visit(BlockStmt* s) { ExecVisitor v = wrap(); for (auto d : s->decls) { diff --git a/ast.h b/ast.h index ea92e4f..9ce607d 100644 --- a/ast.h +++ b/ast.h @@ -14,6 +14,7 @@ class Variable; class Declaration; class VarDecl; +class FunDecl; class Statement; class PrintStmt; @@ -31,6 +32,7 @@ class DeclVisitor { virtual void visit(ExprStmt* st) = 0; virtual void visit(PrintStmt* st) = 0; virtual void visit(VarDecl* d) = 0; + virtual void visit(FunDecl* d) = 0; virtual void visit(BlockStmt* d) = 0; virtual void visit(IfStmt* d) = 0; virtual void visit(WhileStmt* d) = 0; @@ -50,6 +52,7 @@ class ExecVisitor : public DeclVisitor { virtual void visit(ExprStmt* st) override; virtual void visit(PrintStmt* st) override; virtual void visit(VarDecl* d) override; + virtual void visit(FunDecl* d) override; virtual void visit(BlockStmt* d) override; virtual void visit(IfStmt* d) override; virtual void visit(WhileStmt* d) override; @@ -197,6 +200,22 @@ class VarDecl : public Declaration { friend class ExecVisitor; }; +typedef std::vector Args; +class FunDecl : public Declaration { + protected: + std::string identifier; + Args args; + BlockStmt* body; + + public: + FunDecl(std::string id, Args args, BlockStmt* body) + : identifier(id), args(args), body(body){}; + operator std::string() override { return "function " + identifier; }; + + void accept(DeclVisitor* v) { v->visit(this); } + friend class ExecVisitor; +}; + class Binary : public Expr { protected: Expr* left; @@ -277,6 +296,21 @@ class Boolean : public Literal { void accept(ExprVisitor* v) { v->visit(this); } friend class EvalVisitor; }; + +class Function : public Literal { + protected: + FunDecl* fun; + + public: + Function(FunDecl* fun) : fun(fun){}; + operator std::string() { return std::string(*fun); }; + + bool isTruthy() { return fun != nullptr; } + + void accept(ExprVisitor* v) { v->visit(this); } + friend class EvalVisitor; +}; + class Variable : public Expr { protected: std::string name; diff --git a/context.h b/context.h index 4319890..319ece9 100644 --- a/context.h +++ b/context.h @@ -4,28 +4,28 @@ #include #include -class Expr; +class Literal; enum class ReturnReason { NORMAL, RETURN, BREAK, CONTINUE }; class ExecContext { ExecContext* parent; - typedef std::map Rec; - std::shared_ptr rec; + typedef std::map VarRec; + std::shared_ptr varRec; ReturnReason* reason; bool localCount(std::string); - void setOrCreateVar(std::string, Expr* expr); + void setOrCreateVar(std::string, Literal* expr); public: ExecContext(ExecContext* parent = nullptr, ReturnReason* reason = nullptr) : parent(parent), reason(reason) { - rec = std::make_shared(); + varRec = std::make_shared(); } bool count(std::string); - void define(std::string, Expr* expr); - void set(std::string, Expr* expr); - Expr* get(std::string); + void define(std::string, Literal* expr); + void set(std::string, Literal* expr); + Literal* get(std::string); void setReason(ReturnReason r); ReturnReason getReason(); diff --git a/parser.cc b/parser.cc index 30b7f9c..7207f88 100644 --- a/parser.cc +++ b/parser.cc @@ -67,6 +67,10 @@ Declaration* Parser::decl() { d = varDecl(); break; + case FUNCTION: + d = funDecl(); + break; + default: d = stmt(); break; @@ -229,6 +233,35 @@ VarDecl* Parser::varDecl() { return s; } +Args Parser::args() { + Args args; + + args.push_back(consume(IDENTIFIER, "Expect an identifier")); + while (match(1, COMMA)) { + advance(); + args.push_back(consume(IDENTIFIER, "Expect an identifier")); + } + + return args; +} + +FunDecl* Parser::funDecl() { + consume(FUNCTION, "Expect a `function` declaration"); + Token id = consume(IDENTIFIER, "Expect an identifier for function name"); + consume(LEFT_PAREN, "Expect `(` as argument list begins"); + + Args a; + if (!match(1, RIGHT_PAREN)) { + a = args(); + } + + consume(RIGHT_PAREN, "Expect `)` as argument list ends"); + + BlockStmt* b = blockStmt(); + + return new FunDecl(id.lexeme, a, b); +} + Expr* Parser::expression() { return assignment(); } Expr* Parser::assignment() { diff --git a/parser.h b/parser.h index 2b82cd7..671bf28 100644 --- a/parser.h +++ b/parser.h @@ -28,6 +28,8 @@ class Parser { BlockStmt* forStmt(); // FOR '(' VAR_DECL EXPRESSION; EXPRESSION ')' WhileStmt* whileStmt(); // WHILE '(' EXPRESSION ')' STMT VarDecl* varDecl(); // VAR IDENTIFIER (EQUAL EXPRESSION)? ; + FunDecl* funDecl(); // FUN IDENTIFIER '(' ARGS? ')' BLOCK + Args args(); // ID (, ID)* Expr* expression(); Expr* assignment(); diff --git a/testfile b/testfile index 68be3cf..1d8fbfe 100644 --- a/testfile +++ b/testfile @@ -1,9 +1,10 @@ +function printOne() { + print 1; +} print "loop begins!"; -for (var i = 0; i != 3; i = i + 1) - print i; for (var i = 0; i < 10; i = i + 1) { print i*i; - if (i*i > 10) { - print "wow big"; + { + if (i*i>50) break; } } diff --git a/token.h b/token.h index 970bbff..d4d05f0 100644 --- a/token.h +++ b/token.h @@ -39,7 +39,7 @@ enum TokenType { CLASS, ELSE, FALSE, - FUN, + FUNCTION, FOR, IF, NIL,