Added support for forwards.
authorDavid Anderson <dvander@alliedmods.net>
Sun Jul 08 16:49:17 2012 -0700 (2012-07-08)
changeset 63dd57743d220e
parent 62 e04c5be84792
child 64 11c81eb30246
Added support for forwards.
jitcraft/BytecodeCompiler.cpp
jitcraft/Messages.tbl
jitcraft/NameBinding.cpp
jitcraft/NameBinding.h
jitcraft/Parser.cpp
jitcraft/Parser.h
jitcraft/Scanner.cpp
jitcraft/Scopes.cpp
jitcraft/Scopes.h
jitcraft/SemanticAnalysis.cpp
jitcraft/Token.h
jitcraft/Types.cpp
jitcraft/Types.h
     1.1 --- a/jitcraft/BytecodeCompiler.cpp	Sun Jul 08 15:23:48 2012 -0700
     1.2 +++ b/jitcraft/BytecodeCompiler.cpp	Sun Jul 08 16:49:17 2012 -0700
     1.3 @@ -654,6 +654,12 @@
     1.4  void
     1.5  BytecodeCompiler::visit(FunctionStatement *node)
     1.6  {
     1.7 +    // If the function has no body, then it's just a declaration.
     1.8 +    if (!node->body()) {
     1.9 +        assert(node->fun()->isForward() || node->fun()->isPublic());
    1.10 +        return;
    1.11 +    }
    1.12 +
    1.13      BytecodeCompiler child(zone_, tree_, module_);
    1.14      Local<Function> fun(zone_, child.compileFunction(module_, node));
    1.15      if (!fun)
     2.1 --- a/jitcraft/Messages.tbl	Sun Jul 08 15:23:48 2012 -0700
     2.2 +++ b/jitcraft/Messages.tbl	Sun Jul 08 16:49:17 2012 -0700
     2.3 @@ -41,3 +41,6 @@
     2.4  MSG(CantOpenFile,                   SyntaxError,            "cannot open file")
     2.5  MSG(ErrorSeekingFile,               SyntaxError,            "error seeking file")
     2.6  MSG(ErrorReadingFile,               SyntaxError,            "error reading file")
     2.7 +MSG(ExpectedGlobal,                 SyntaxError,            "expected global variable or function")
     2.8 +MSG(ForwardNotImplemented,          SyntaxError,            "forward '%s' not implemented")
     2.9 +MSG(ForwardDeclareMismatches,       SyntaxError,            "declaration does not match original forward signature")
    2.10 \ No newline at end of file
     3.1 --- a/jitcraft/NameBinding.cpp	Sun Jul 08 15:23:48 2012 -0700
     3.2 +++ b/jitcraft/NameBinding.cpp	Sun Jul 08 16:49:17 2012 -0700
     3.3 @@ -29,8 +29,10 @@
     3.4  {
     3.5  }
     3.6  
     3.7 -NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos)
     3.8 -  : BoundName(scope, name, pos)
     3.9 +NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
    3.10 +                             TokenKind token)
    3.11 +  : BoundName(scope, name, pos),
    3.12 +    token_(token)
    3.13  {
    3.14  }
    3.15  
     4.1 --- a/jitcraft/NameBinding.h	Sun Jul 08 15:23:48 2012 -0700
     4.2 +++ b/jitcraft/NameBinding.h	Sun Jul 08 16:49:17 2012 -0700
     4.3 @@ -37,6 +37,8 @@
     4.4      Scope *scope_;
     4.5      ScopedRoot<String> name_;
     4.6      ScopedRoot<Type> type_;
     4.7 +
     4.8 +  protected:
     4.9      SourcePosition pos_;
    4.10  
    4.11    public:
    4.12 @@ -83,9 +85,11 @@
    4.13  class NamedFunction : public BoundName
    4.14  {
    4.15      unsigned slot_;
    4.16 +    TokenKind token_;
    4.17 +    ScopedRoot<Type> forwardType_;
    4.18  
    4.19    public:
    4.20 -    NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos);
    4.21 +    NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
    4.22  
    4.23      Kind kind() const {
    4.24          return FUNCTION;
    4.25 @@ -93,6 +97,22 @@
    4.26      void allocate(unsigned slot) {
    4.27          slot_ = slot;
    4.28      }
    4.29 +    bool isForward() const {
    4.30 +        return token_ == TOK_FORWARD;
    4.31 +    }
    4.32 +    bool isPublic() const {
    4.33 +        return token_ == TOK_PUBLIC;
    4.34 +    }
    4.35 +    void setForwardType(Handle<Type> type) {
    4.36 +        forwardType_ = type;
    4.37 +    }
    4.38 +    Type *forwardType() {
    4.39 +        return forwardType_;
    4.40 +    }
    4.41 +    void setImplemented(const SourcePosition &at) {
    4.42 +        token_ = TOK_PUBLIC;
    4.43 +        pos_ = at;
    4.44 +    }
    4.45      unsigned slot() const {
    4.46          return slot_;
    4.47      }
     5.1 --- a/jitcraft/Parser.cpp	Sun Jul 08 15:23:48 2012 -0700
     5.2 +++ b/jitcraft/Parser.cpp	Sun Jul 08 16:49:17 2012 -0700
     5.3 @@ -46,6 +46,12 @@
     5.4  }
     5.5  
     5.6  bool
     5.7 +Parser::matchSemicolon()
     5.8 +{
     5.9 +    return expect(TOK_SEMICOLON);
    5.10 +}
    5.11 +
    5.12 +bool
    5.13  Parser::expect(TokenKind kind)
    5.14  {
    5.15      TokenKind got = scanner_.scan();
    5.16 @@ -96,7 +102,8 @@
    5.17  void
    5.18  Parser::redeclarationError(BoundName *other)
    5.19  {
    5.20 -    cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->pos().line, other->pos().col);
    5.21 +    cc_.reportError(scanner_.begin(), Message_RedeclaredName, other->name()->chars(),
    5.22 +                    other->pos().line, other->pos().col);
    5.23  }
    5.24  
    5.25  Expression *
    5.26 @@ -842,7 +849,7 @@
    5.27  }
    5.28  
    5.29  Statement *
    5.30 -Parser::function()
    5.31 +Parser::function(TokenKind token)
    5.32  {
    5.33      Local<String> name(zone_, expectName());
    5.34      if (!name)
    5.35 @@ -853,13 +860,29 @@
    5.36      // The function name goes into the outer (global) scope.
    5.37      assert(!scope_->enclosing());
    5.38  
    5.39 +    NamedFunction *fun;
    5.40      if (BoundName *other = scope_->localLookup(name)) {
    5.41 -        redeclarationError(other);
    5.42 -        return NULL;
    5.43 +        // We allow a redeclaration if the new type is a public, and the old
    5.44 +        // type was a forward. However, the forward must come first.
    5.45 +        if (other->kind() != BoundName::FUNCTION) {
    5.46 +            redeclarationError(other);
    5.47 +            return NULL;
    5.48 +        }
    5.49 +
    5.50 +        fun = other->toNamedFunction();
    5.51 +        if (!fun->isForward() || token != TOK_PUBLIC) {
    5.52 +            redeclarationError(other);
    5.53 +            return NULL;
    5.54 +        }
    5.55 +        
    5.56 +        // We've got the same name, but the original is a forward, so let it
    5.57 +        // slide and re-use the original declaration.
    5.58 +        fun->setImplemented(scanner_.begin());
    5.59 +    } else {
    5.60 +        fun = scope_->declareFunction(name, scanner_.begin(), token);
    5.61 +        if (!fun)
    5.62 +            return NULL;
    5.63      }
    5.64 -    NamedFunction *fun = scope_->declareFunction(name, scanner_.begin());
    5.65 -    if (!fun)
    5.66 -        return NULL;
    5.67  
    5.68      Scope *scope = enterScope(Scope::FUNCTION);
    5.69      if (!scope)
    5.70 @@ -897,9 +920,12 @@
    5.71              return NULL;
    5.72      }
    5.73  
    5.74 -    Statement *body = block();
    5.75 -    if (!body)
    5.76 -        return NULL;
    5.77 +    Statement *body = NULL;
    5.78 +    if (token != TOK_FORWARD) {
    5.79 +        body = block();
    5.80 +        if (!body)
    5.81 +            return NULL;
    5.82 +    }
    5.83  
    5.84      scope_ = scope_->enclosing();
    5.85      return new (pool_) FunctionStatement(pos, scope, fun, body, parameters);
    5.86 @@ -924,18 +950,30 @@
    5.87              break;
    5.88  
    5.89            case TOK_NAME:
    5.90 -            if ((statement = function()) == NULL)
    5.91 +            if ((statement = function(TOK_NAME)) == NULL)
    5.92                  return NULL;
    5.93              break;
    5.94  
    5.95 +          case TOK_FORWARD:
    5.96 +          case TOK_PUBLIC:
    5.97 +          {
    5.98 +            TokenKind kind = scanner_.scan();
    5.99 +            if ((statement = function(kind)) == NULL)
   5.100 +                return NULL;
   5.101 +            if (kind == TOK_FORWARD && !matchSemicolon())
   5.102 +                return NULL;
   5.103 +            break;
   5.104 +          }
   5.105 +
   5.106            case TOK_ENUM:
   5.107              if ((statement = enum_()) == NULL)
   5.108                  return NULL;
   5.109 -            // :TODO: require semicolon
   5.110 +            if (!matchSemicolon())
   5.111 +                return NULL;
   5.112              break;
   5.113  
   5.114            default:
   5.115 -            fprintf(stderr, "expected function or global variable\n");
   5.116 +            cc_.reportError(scanner_.begin(), Message_ExpectedGlobal);
   5.117              return NULL;
   5.118          }
   5.119  
   5.120 @@ -991,7 +1029,8 @@
   5.121          prefix();
   5.122          fprintf(fp_, "[ FunctionStatement (%s)\n", node->fun()->name()->chars());
   5.123          indent();
   5.124 -        node->body()->accept(this);
   5.125 +        if (node->body())
   5.126 +            node->body()->accept(this);
   5.127          unindent();
   5.128      }
   5.129      void visit(ExpressionStatement *node) {
     6.1 --- a/jitcraft/Parser.h	Sun Jul 08 15:23:48 2012 -0700
     6.2 +++ b/jitcraft/Parser.h	Sun Jul 08 16:49:17 2012 -0700
     6.3 @@ -39,6 +39,7 @@
     6.4      void redeclarationError(BoundName *name);
     6.5      bool match(TokenKind kind);
     6.6      bool expect(TokenKind kind);
     6.7 +    bool matchSemicolon();
     6.8  
     6.9      Scope *enterScope(Scope::Kind kind);
    6.10  
    6.11 @@ -66,7 +67,7 @@
    6.12      Statement *enum_();
    6.13      Statement *if_();
    6.14      Statement *block(Scope *scope = NULL);
    6.15 -    Statement *function();
    6.16 +    Statement *function(TokenKind tok);
    6.17      Statement *expressionStatement();
    6.18      Statement *while_();
    6.19      Statement *do_();
     7.1 --- a/jitcraft/Scanner.cpp	Sun Jul 08 15:23:48 2012 -0700
     7.2 +++ b/jitcraft/Scanner.cpp	Sun Jul 08 16:49:17 2012 -0700
     7.3 @@ -365,6 +365,10 @@
     7.4          return TOK_BREAK;
     7.5      if (literal_ == "continue")
     7.6          return TOK_CONTINUE;
     7.7 +    if (literal_ == "forward")
     7.8 +        return TOK_FORWARD;
     7.9 +    if (literal_ == "public")
    7.10 +        return TOK_PUBLIC;
    7.11      return (c == ':') ? TOK_LABEL : TOK_NAME;
    7.12  }
    7.13  
     8.1 --- a/jitcraft/Scopes.cpp	Sun Jul 08 15:23:48 2012 -0700
     8.2 +++ b/jitcraft/Scopes.cpp	Sun Jul 08 16:49:17 2012 -0700
     8.3 @@ -111,12 +111,12 @@
     8.4  }
     8.5  
     8.6  NamedFunction *
     8.7 -Scope::declareFunction(Handle<String> name, const SourcePosition &pos)
     8.8 +Scope::declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token)
     8.9  {
    8.10      assert(!localLookup(name));
    8.11      assert(kind() == GLOBAL);
    8.12  
    8.13 -    NamedFunction *fun = new (pool_) NamedFunction(this, name, pos);
    8.14 +    NamedFunction *fun = new (pool_) NamedFunction(this, name, pos, token);
    8.15      if (!names_.append(fun))
    8.16          return NULL;
    8.17      return fun;
     9.1 --- a/jitcraft/Scopes.h	Sun Jul 08 15:23:48 2012 -0700
     9.2 +++ b/jitcraft/Scopes.h	Sun Jul 08 16:49:17 2012 -0700
     9.3 @@ -81,7 +81,7 @@
     9.4      BoundName *localLookup(Handle<String> name);
     9.5      BoundName *lookup(Handle<String> name);
     9.6  
     9.7 -    NamedFunction *declareFunction(Handle<String> name, const SourcePosition &pos);
     9.8 +    NamedFunction *declareFunction(Handle<String> name, const SourcePosition &pos, TokenKind token);
     9.9      Variable *declareVariable(Handle<String> name, const SourcePosition &pos);
    9.10      Variable *declareArgument(Handle<String> name, const SourcePosition &pos);
    9.11      NamedEnum *declareEnum(Handle<String> name, const SourcePosition &pos);
    10.1 --- a/jitcraft/SemanticAnalysis.cpp	Sun Jul 08 15:23:48 2012 -0700
    10.2 +++ b/jitcraft/SemanticAnalysis.cpp	Sun Jul 08 16:49:17 2012 -0700
    10.3 @@ -558,8 +558,20 @@
    10.4      Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args));
    10.5      if (!funtype)
    10.6          return false;
    10.7 +    
    10.8 +    // If the function already has a type, it was forward declared before, and
    10.9 +    // now this is our chance to type check the second declaration.
   10.10 +    if (node->fun()->type()) {
   10.11 +        Local<Type> forward(zone_, node->fun()->type());
   10.12 +        if (!Type::Compare(funtype, forward)) {
   10.13 +            cc_.reportError(node->pos(), Message_ForwardDeclareMismatches);
   10.14 +            return false;
   10.15 +        }
   10.16 +        node->fun()->setForwardType(forward);
   10.17 +    }
   10.18  
   10.19      node->fun()->setType(funtype);
   10.20 +
   10.21      return true;
   10.22  }
   10.23  
   10.24 @@ -568,7 +580,8 @@
   10.25  {
   10.26      function_ = node->fun()->type();
   10.27      scope_ = node->scope();
   10.28 -    node->body()->accept(this);
   10.29 +    if (node->body())
   10.30 +        node->body()->accept(this);
   10.31      scope_ = NULL;
   10.32      function_ = NULL;
   10.33  }
   10.34 @@ -689,6 +702,13 @@
   10.35          return;
   10.36      }
   10.37  
   10.38 +    // Currently, only calls from a NameProxy are possible.
   10.39 +    NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
   10.40 +    if (fun->isForward()) {
   10.41 +        cc_.reportError(node->pos(), Message_ForwardNotImplemented, fun->name()->chars());
   10.42 +        return;
   10.43 +    }
   10.44 +
   10.45      for (unsigned i = 0; i < node->arguments()->length(); i++) {
   10.46          // Note: we don't compute references unless the callee needs a
   10.47          // reference type.
    11.1 --- a/jitcraft/Token.h	Sun Jul 08 15:23:48 2012 -0700
    11.2 +++ b/jitcraft/Token.h	Sun Jul 08 16:49:17 2012 -0700
    11.3 @@ -54,6 +54,8 @@
    11.4      _(DO,                 "<do>")                       \
    11.5      _(BREAK,              "<break>")                    \
    11.6      _(CONTINUE,           "<continue>")                 \
    11.7 +    _(FORWARD,            "<forward>")                  \
    11.8 +    _(PUBLIC,             "<public>")                   \
    11.9      _(PLUS,               "+")                          \
   11.10      _(MINUS,              "-")                          \
   11.11      _(STAR,               "*")                          \
    12.1 --- a/jitcraft/Types.cpp	Sun Jul 08 15:23:48 2012 -0700
    12.2 +++ b/jitcraft/Types.cpp	Sun Jul 08 16:49:17 2012 -0700
    12.3 @@ -109,3 +109,44 @@
    12.4      type->parameters_ = parameters;
    12.5      return type;
    12.6  }
    12.7 +
    12.8 +bool
    12.9 +Type::Compare(Type *left, Type *right)
   12.10 +{
   12.11 +    if (left->kind() != right->kind())
   12.12 +        return false;
   12.13 +
   12.14 +    switch (left->kind()) {
   12.15 +      case Type::PRIMITIVE:
   12.16 +        return (left->primitive() == right->primitive() &&
   12.17 +                left->tag() == right->tag());
   12.18 +
   12.19 +      case Type::ARRAY:
   12.20 +      {
   12.21 +        if (left->levels() != right->levels())
   12.22 +          return false;
   12.23 +        if (left->elements() != right->elements())
   12.24 +          return false;
   12.25 +        return Compare(left->contained(), right->contained());
   12.26 +      }
   12.27 +
   12.28 +      case Type::FUNCTION:
   12.29 +      {
   12.30 +        if (!Compare(left->returnType(), right->returnType()))
   12.31 +            return false;
   12.32 +        if (left->parameters()->length() != right->parameters()->length())
   12.33 +            return false;
   12.34 +        for (unsigned i = 0; i < left->parameters()->length(); i++) {
   12.35 +            Type *leftparam = left->parameterAt(i);
   12.36 +            Type *rightparam = right->parameterAt(i);
   12.37 +            if (!Compare(leftparam, rightparam))
   12.38 +                return false;
   12.39 +        }
   12.40 +        return true;
   12.41 +      }
   12.42 +
   12.43 +      default:
   12.44 +        assert(left->kind() == Type::REFERENCE);
   12.45 +        return Compare(left->contained(), right->contained());
   12.46 +    }
   12.47 +}
    13.1 --- a/jitcraft/Types.h	Sun Jul 08 15:23:48 2012 -0700
    13.2 +++ b/jitcraft/Types.h	Sun Jul 08 16:49:17 2012 -0700
    13.3 @@ -60,6 +60,8 @@
    13.4      static Type *NewReference(Zone *zone, Handle<Type> contained);
    13.5      static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters);
    13.6  
    13.7 +    static bool Compare(Type *left, Type *right);
    13.8 +
    13.9      static Type *cast(Object *obj) {
   13.10          assert(!obj || obj->is(MapKind_Type));
   13.11          return (Type *)obj;