# HG changeset patch # User David Anderson # Date 1341791357 25200 # Node ID dd57743d220eb9105f21f8b9c931afad2cbc9eca # Parent e04c5be84792ba94da5b1e379a1c9f4f10ca7695 Added support for forwards. diff -r e04c5be84792 -r dd57743d220e jitcraft/BytecodeCompiler.cpp --- a/jitcraft/BytecodeCompiler.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/BytecodeCompiler.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -654,6 +654,12 @@ void BytecodeCompiler::visit(FunctionStatement *node) { + // If the function has no body, then it's just a declaration. + if (!node->body()) { + assert(node->fun()->isForward() || node->fun()->isPublic()); + return; + } + BytecodeCompiler child(zone_, tree_, module_); Local fun(zone_, child.compileFunction(module_, node)); if (!fun) diff -r e04c5be84792 -r dd57743d220e jitcraft/Messages.tbl --- a/jitcraft/Messages.tbl Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Messages.tbl Sun Jul 08 16:49:17 2012 -0700 @@ -41,3 +41,6 @@ MSG(CantOpenFile, SyntaxError, "cannot open file") MSG(ErrorSeekingFile, SyntaxError, "error seeking file") MSG(ErrorReadingFile, SyntaxError, "error reading file") +MSG(ExpectedGlobal, SyntaxError, "expected global variable or function") +MSG(ForwardNotImplemented, SyntaxError, "forward '%s' not implemented") +MSG(ForwardDeclareMismatches, SyntaxError, "declaration does not match original forward signature") \ No newline at end of file diff -r e04c5be84792 -r dd57743d220e jitcraft/NameBinding.cpp --- a/jitcraft/NameBinding.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/NameBinding.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -29,8 +29,10 @@ { } -NamedFunction::NamedFunction(Scope *scope, Handle name, const SourcePosition &pos) - : BoundName(scope, name, pos) +NamedFunction::NamedFunction(Scope *scope, Handle name, const SourcePosition &pos, + TokenKind token) + : BoundName(scope, name, pos), + token_(token) { } diff -r e04c5be84792 -r dd57743d220e jitcraft/NameBinding.h --- a/jitcraft/NameBinding.h Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/NameBinding.h Sun Jul 08 16:49:17 2012 -0700 @@ -37,6 +37,8 @@ Scope *scope_; ScopedRoot name_; ScopedRoot type_; + + protected: SourcePosition pos_; public: @@ -83,9 +85,11 @@ class NamedFunction : public BoundName { unsigned slot_; + TokenKind token_; + ScopedRoot forwardType_; public: - NamedFunction(Scope *scope, Handle name, const SourcePosition &pos); + NamedFunction(Scope *scope, Handle name, const SourcePosition &pos, TokenKind token); Kind kind() const { return FUNCTION; @@ -93,6 +97,22 @@ void allocate(unsigned slot) { slot_ = slot; } + bool isForward() const { + return token_ == TOK_FORWARD; + } + bool isPublic() const { + return token_ == TOK_PUBLIC; + } + void setForwardType(Handle type) { + forwardType_ = type; + } + Type *forwardType() { + return forwardType_; + } + void setImplemented(const SourcePosition &at) { + token_ = TOK_PUBLIC; + pos_ = at; + } unsigned slot() const { return slot_; } diff -r e04c5be84792 -r dd57743d220e jitcraft/Parser.cpp --- a/jitcraft/Parser.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Parser.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -46,6 +46,12 @@ } bool +Parser::matchSemicolon() +{ + return expect(TOK_SEMICOLON); +} + +bool Parser::expect(TokenKind kind) { TokenKind got = scanner_.scan(); @@ -96,7 +102,8 @@ void Parser::redeclarationError(BoundName *other) { - cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->pos().line, other->pos().col); + cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(), + other->pos().line, other->pos().col); } Expression * @@ -842,7 +849,7 @@ } Statement * -Parser::function() +Parser::function(TokenKind token) { Local name(zone_, expectName()); if (!name) @@ -853,13 +860,29 @@ // The function name goes into the outer (global) scope. assert(!scope_->enclosing()); + NamedFunction *fun; if (BoundName *other = scope_->localLookup(name)) { - redeclarationError(other); - return NULL; + // We allow a redeclaration if the new type is a public, and the old + // type was a forward. However, the forward must come first. + if (other->kind() != BoundName::FUNCTION) { + redeclarationError(other); + return NULL; + } + + fun = other->toNamedFunction(); + if (!fun->isForward() || token != TOK_PUBLIC) { + redeclarationError(other); + return NULL; + } + + // We've got the same name, but the original is a forward, so let it + // slide and re-use the original declaration. + fun->setImplemented(scanner_.begin()); + } else { + fun = scope_->declareFunction(name, scanner_.begin(), token); + if (!fun) + return NULL; } - NamedFunction *fun = scope_->declareFunction(name, scanner_.begin()); - if (!fun) - return NULL; Scope *scope = enterScope(Scope::FUNCTION); if (!scope) @@ -897,9 +920,12 @@ return NULL; } - Statement *body = block(); - if (!body) - return NULL; + Statement *body = NULL; + if (token != TOK_FORWARD) { + body = block(); + if (!body) + return NULL; + } scope_ = scope_->enclosing(); return new (pool_) FunctionStatement(pos, scope, fun, body, parameters); @@ -924,18 +950,30 @@ break; case TOK_NAME: - if ((statement = function()) == NULL) + if ((statement = function(TOK_NAME)) == NULL) return NULL; break; + case TOK_FORWARD: + case TOK_PUBLIC: + { + TokenKind kind = scanner_.scan(); + if ((statement = function(kind)) == NULL) + return NULL; + if (kind == TOK_FORWARD && !matchSemicolon()) + return NULL; + break; + } + case TOK_ENUM: if ((statement = enum_()) == NULL) return NULL; - // :TODO: require semicolon + if (!matchSemicolon()) + return NULL; break; default: - fprintf(stderr, "expected function or global variable\n"); + cc_.reportError(scanner_.begin(), Message_ExpectedGlobal); return NULL; } @@ -991,7 +1029,8 @@ prefix(); fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars()); indent(); - node->body()->accept(this); + if (node->body()) + node->body()->accept(this); unindent(); } void visit(ExpressionStatement *node) { diff -r e04c5be84792 -r dd57743d220e jitcraft/Parser.h --- a/jitcraft/Parser.h Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Parser.h Sun Jul 08 16:49:17 2012 -0700 @@ -39,6 +39,7 @@ void redeclarationError(BoundName *name); bool match(TokenKind kind); bool expect(TokenKind kind); + bool matchSemicolon(); Scope *enterScope(Scope::Kind kind); @@ -66,7 +67,7 @@ Statement *enum_(); Statement *if_(); Statement *block(Scope *scope = NULL); - Statement *function(); + Statement *function(TokenKind tok); Statement *expressionStatement(); Statement *while_(); Statement *do_(); diff -r e04c5be84792 -r dd57743d220e jitcraft/Scanner.cpp --- a/jitcraft/Scanner.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Scanner.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -365,6 +365,10 @@ return TOK_BREAK; if (literal_ == "continue") return TOK_CONTINUE; + if (literal_ == "forward") + return TOK_FORWARD; + if (literal_ == "public") + return TOK_PUBLIC; return (c == ':') ? TOK_LABEL : TOK_NAME; } diff -r e04c5be84792 -r dd57743d220e jitcraft/Scopes.cpp --- a/jitcraft/Scopes.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Scopes.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -111,12 +111,12 @@ } NamedFunction * -Scope::declareFunction(Handle name, const SourcePosition &pos) +Scope::declareFunction(Handle name, const SourcePosition &pos, TokenKind token) { assert(!localLookup(name)); assert(kind() == GLOBAL); - NamedFunction *fun = new (pool_) NamedFunction(this, name, pos); + NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token); if (!names_.append(fun)) return NULL; return fun; diff -r e04c5be84792 -r dd57743d220e jitcraft/Scopes.h --- a/jitcraft/Scopes.h Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Scopes.h Sun Jul 08 16:49:17 2012 -0700 @@ -81,7 +81,7 @@ BoundName *localLookup(Handle name); BoundName *lookup(Handle name); - NamedFunction *declareFunction(Handle name, const SourcePosition &pos); + NamedFunction *declareFunction(Handle name, const SourcePosition &pos, TokenKind token); Variable *declareVariable(Handle name, const SourcePosition &pos); Variable *declareArgument(Handle name, const SourcePosition &pos); NamedEnum *declareEnum(Handle name, const SourcePosition &pos); diff -r e04c5be84792 -r dd57743d220e jitcraft/SemanticAnalysis.cpp --- a/jitcraft/SemanticAnalysis.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/SemanticAnalysis.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -558,8 +558,20 @@ Local funtype(zone_, zone_->types()->newFunction(returnType, args)); if (!funtype) return false; + + // If the function already has a type, it was forward declared before, and + // now this is our chance to type check the second declaration. + if (node->fun()->type()) { + Local forward(zone_, node->fun()->type()); + if (!Type::Compare(funtype, forward)) { + cc_.reportError(node->pos(), Message_ForwardDeclareMismatches); + return false; + } + node->fun()->setForwardType(forward); + } node->fun()->setType(funtype); + return true; } @@ -568,7 +580,8 @@ { function_ = node->fun()->type(); scope_ = node->scope(); - node->body()->accept(this); + if (node->body()) + node->body()->accept(this); scope_ = NULL; function_ = NULL; } @@ -689,6 +702,13 @@ return; } + // Currently, only calls from a NameProxy are possible. + NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction(); + if (fun->isForward()) { + cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars()); + return; + } + for (unsigned i = 0; i < node->arguments()->length(); i++) { // Note: we don't compute references unless the callee needs a // reference type. diff -r e04c5be84792 -r dd57743d220e jitcraft/Token.h --- a/jitcraft/Token.h Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Token.h Sun Jul 08 16:49:17 2012 -0700 @@ -54,6 +54,8 @@ _(DO, "") \ _(BREAK, "") \ _(CONTINUE, "") \ + _(FORWARD, "") \ + _(PUBLIC, "") \ _(PLUS, "+") \ _(MINUS, "-") \ _(STAR, "*") \ diff -r e04c5be84792 -r dd57743d220e jitcraft/Types.cpp --- a/jitcraft/Types.cpp Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Types.cpp Sun Jul 08 16:49:17 2012 -0700 @@ -109,3 +109,44 @@ type->parameters_ = parameters; return type; } + +bool +Type::Compare(Type *left, Type *right) +{ + if (left->kind() != right->kind()) + return false; + + switch (left->kind()) { + case Type::PRIMITIVE: + return (left->primitive() == right->primitive() && + left->tag() == right->tag()); + + case Type::ARRAY: + { + if (left->levels() != right->levels()) + return false; + if (left->elements() != right->elements()) + return false; + return Compare(left->contained(), right->contained()); + } + + case Type::FUNCTION: + { + if (!Compare(left->returnType(), right->returnType())) + return false; + if (left->parameters()->length() != right->parameters()->length()) + return false; + for (unsigned i = 0; i < left->parameters()->length(); i++) { + Type *leftparam = left->parameterAt(i); + Type *rightparam = right->parameterAt(i); + if (!Compare(leftparam, rightparam)) + return false; + } + return true; + } + + default: + assert(left->kind() == Type::REFERENCE); + return Compare(left->contained(), right->contained()); + } +} diff -r e04c5be84792 -r dd57743d220e jitcraft/Types.h --- a/jitcraft/Types.h Sun Jul 08 15:23:48 2012 -0700 +++ b/jitcraft/Types.h Sun Jul 08 16:49:17 2012 -0700 @@ -60,6 +60,8 @@ static Type *NewReference(Zone *zone, Handle contained); static Type *NewFunction(Zone *zone, Handle returnType, Handle parameters); + static bool Compare(Type *left, Type *right); + static Type *cast(Object *obj) { assert(!obj || obj->is(MapKind_Type)); return (Type *)obj;