All but interpreter support for getting and setting struct fields.
authorDavid Anderson <dvander@alliedmods.net>
Sat Aug 04 20:12:20 2012 -0700 (2012-08-04)
changeset 148c0740249963c
parent 147 9c544823d090
child 149 b01ee7446984
All but interpreter support for getting and setting struct fields.
src/AST.h
src/BytecodeCompiler.cpp
src/BytecodeCompiler.h
src/Messages.tbl
src/Opcodes.cpp
src/Parser.cpp
src/Parser.h
src/Scanner.cpp
src/SemanticAnalysis.cpp
src/SemanticAnalysis.h
src/Token.h
src/Types.cpp
src/Types.h
     1.1 --- a/src/AST.h	Sat Aug 04 19:33:06 2012 -0700
     1.2 +++ b/src/AST.h	Sat Aug 04 20:12:20 2012 -0700
     1.3 @@ -42,6 +42,7 @@
     1.4      _(CallExpression)           \
     1.5      _(IfStatement)              \
     1.6      _(IndexExpression)          \
     1.7 +    _(FieldExpression)          \
     1.8      _(EnumStatement)            \
     1.9      _(WhileStatement)           \
    1.10      _(BreakStatement)           \
    1.11 @@ -465,6 +466,43 @@
    1.12      }
    1.13  };
    1.14  
    1.15 +class FieldExpression : public Expression
    1.16 +{
    1.17 +    Expression *left_;
    1.18 +    ScopedRoot<String> field_;
    1.19 +    unsigned fieldIndex_;
    1.20 +
    1.21 +  public:
    1.22 +    FieldExpression(const SourcePosition &pos, Expression *left, Handle<String> field)
    1.23 +      : Expression(pos),
    1.24 +        left_(left),
    1.25 +        field_(field),
    1.26 +        fieldIndex_(unsigned(-1))
    1.27 +    {
    1.28 +    }
    1.29 +
    1.30 +    Kind kind() const {
    1.31 +        return kFieldExpression;
    1.32 +    }
    1.33 +    Expression *left() const {
    1.34 +        return left_;
    1.35 +    }
    1.36 +    String *field() const {
    1.37 +        return field_;
    1.38 +    }
    1.39 +    void setFieldIndex(unsigned index) {
    1.40 +        assert(fieldIndex_ == unsigned(-1));
    1.41 +        fieldIndex_ = index;
    1.42 +    }
    1.43 +    unsigned fieldIndex() const {
    1.44 +        assert(fieldIndex_ != unsigned(-1));
    1.45 +        return fieldIndex_;
    1.46 +    }
    1.47 +    void accept(AstVisitor *visitor) {
    1.48 +        visitor->visit(this);
    1.49 +    }
    1.50 +};
    1.51 +
    1.52  class CallExpression : public Expression
    1.53  {
    1.54      Expression *callee_;
     2.1 --- a/src/BytecodeCompiler.cpp	Sat Aug 04 19:33:06 2012 -0700
     2.2 +++ b/src/BytecodeCompiler.cpp	Sat Aug 04 20:12:20 2012 -0700
     2.3 @@ -228,6 +228,17 @@
     2.4                  __ get(var);
     2.5              }
     2.6          }
     2.7 +    } else if (node->lvalue()->isFieldExpression()) {
     2.8 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
     2.9 +        __ note_position(expr->pos());
    2.10 +
    2.11 +        expr->left()->accept(this);
    2.12 +
    2.13 +        if (node->token() != TOK_ASSIGN) {
    2.14 +            __ dup();
    2.15 +            __ getfield(expr->fieldIndex(), expr->type());
    2.16 +        }
    2.17 +
    2.18      } else {
    2.19          IndexExpression *index = node->lvalue()->toIndexExpression();
    2.20          __ note_position(index->pos());
    2.21 @@ -276,6 +287,9 @@
    2.22              __ setref(var->type()->contained());
    2.23          else
    2.24              __ set(var);
    2.25 +    } else if (node->lvalue()->isFieldExpression()) {
    2.26 +        FieldExpression *expr = node->lvalue()->toFieldExpression();
    2.27 +        __ setfield(expr->fieldIndex(), expr->type());
    2.28      } else {
    2.29          IndexExpression *index = node->lvalue()->toIndexExpression();
    2.30          // :TODO: get rid of the BOUNDS instruction, embed it in g/setarray*?
    2.31 @@ -506,6 +520,13 @@
    2.32  }
    2.33  
    2.34  void
    2.35 +BytecodeCompiler::visit(FieldExpression *node)
    2.36 +{
    2.37 +    node->left()->accept(this);
    2.38 +    __ getfield(node->fieldIndex(), node->type());
    2.39 +}
    2.40 +
    2.41 +void
    2.42  BytecodeCompiler::visit(ReturnStatement *node)
    2.43  {
    2.44      if (node->expression()) {
     3.1 --- a/src/BytecodeCompiler.h	Sat Aug 04 19:33:06 2012 -0700
     3.2 +++ b/src/BytecodeCompiler.h	Sat Aug 04 20:12:20 2012 -0700
     3.3 @@ -144,6 +144,7 @@
     3.4      void visit(UnaryExpression *node);
     3.5      void visit(TernaryExpression *node);
     3.6      void visit(StructureStatement *node);
     3.7 +    void visit(FieldExpression *node);
     3.8  };
     3.9  
    3.10  }
     4.1 --- a/src/Messages.tbl	Sat Aug 04 19:33:06 2012 -0700
     4.2 +++ b/src/Messages.tbl	Sat Aug 04 20:12:20 2012 -0700
     4.3 @@ -59,9 +59,10 @@
     4.4  MSG(UsedVoidReturn,                 SyntaxError,            "return value expected, but function does not return a value")
     4.5  MSG(FunctionDoesNotReturnValue,     SyntaxError,            "cannot use the result of a function with no return value")
     4.6  MSG(IdentifierNotFound,             SyntaxError,            "identifier '%s' could not be found")
     4.7 -MSG(TypeMismatchDuringInvoke,       SyntaxError,            "incoming type '%s' does not match signature type '%s'")
     4.8 +MSG(TypeMismatchDuringInvoke,       TypeError,              "incoming type '%s' does not match signature type '%s'")
     4.9  MSG(CannotInvokeReturnType,         SyntaxError,            "cannot invoke function with return type '%s'")
    4.10  MSG(TypeNotFound,                   SyntaxError,            "type '%s' could not be found")
    4.11  MSG(IdentifierIsNotAType,           SyntaxError,            "identifier '%s' cannot be used as a type")
    4.12 -MSG(TypeMismatch,                   SyntaxError,            "type mismatch (expected '%s', got '%s')")
    4.13 +MSG(TypeMismatch,                   TypeError,              "type mismatch (expected '%s', got '%s')")
    4.14 +MSG(PropertyNotFound,               TypeError,              "property '%s' not found on type '%s'")
    4.15  
     5.1 --- a/src/Opcodes.cpp	Sat Aug 04 19:33:06 2012 -0700
     5.2 +++ b/src/Opcodes.cpp	Sat Aug 04 20:12:20 2012 -0700
     5.3 @@ -288,6 +288,8 @@
     5.4            case OP_SETGLOBAL_I:
     5.5            case OP_SETGLOBAL_F:
     5.6            case OP_SETGLOBAL_O:
     5.7 +          case OP_GETFIELD:
     5.8 +          case OP_SETFIELD:
     5.9              fprintf(fp, "%u", READ_UINT32(pc));
    5.10              break;
    5.11  
     6.1 --- a/src/Parser.cpp	Sat Aug 04 19:33:06 2012 -0700
     6.2 +++ b/src/Parser.cpp	Sat Aug 04 20:12:20 2012 -0700
     6.3 @@ -239,6 +239,19 @@
     6.4  }
     6.5  
     6.6  Expression *
     6.7 +Parser::field(Expression *left)
     6.8 +{
     6.9 +    expect(TOK_DOT);
    6.10 +
    6.11 +    SourcePosition pos = scanner_.begin();
    6.12 +    Local<String> name(zone_, expectName());
    6.13 +    if (!name)
    6.14 +        return NULL;
    6.15 +
    6.16 +    return new (pool_) FieldExpression(pos, left, name);
    6.17 +}
    6.18 +
    6.19 +Expression *
    6.20  Parser::primary()
    6.21  {
    6.22      Expression *expr = prefix();
    6.23 @@ -248,14 +261,17 @@
    6.24      for (;;) {
    6.25          switch (scanner_.peek()) {
    6.26            case TOK_LPAREN:
    6.27 -            expr = call(expr);
    6.28 -            if (!expr)
    6.29 +            if ((expr = call(expr)) == NULL)
    6.30                  return NULL;
    6.31              break;
    6.32  
    6.33            case TOK_LBRACKET:
    6.34 -            expr = index(expr);
    6.35 -            if (!expr)
    6.36 +            if ((expr = index(expr)) == NULL)
    6.37 +                return NULL;
    6.38 +            break;
    6.39 +
    6.40 +          case TOK_DOT:
    6.41 +            if ((expr = field(expr)) == NULL)
    6.42                  return NULL;
    6.43              break;
    6.44  
    6.45 @@ -1493,7 +1509,14 @@
    6.46      }
    6.47      void visit(StructureStatement *node) {
    6.48          prefix();
    6.49 -        fprintf(fp_, "[ StructureStatement\n");
    6.50 +        fprintf(fp_, "[ StructureStatement %s\n", node->decl()->name()->chars());
    6.51 +    }
    6.52 +    void visit(FieldExpression *node) {
    6.53 +        prefix();
    6.54 +        fprintf(fp_, "[ FieldExpression %s\n", node->field()->chars());
    6.55 +        indent();
    6.56 +        node->left()->accept(this);
    6.57 +        unindent();
    6.58      }
    6.59  };
    6.60  
     7.1 --- a/src/Parser.h	Sat Aug 04 19:33:06 2012 -0700
     7.2 +++ b/src/Parser.h	Sat Aug 04 20:12:20 2012 -0700
     7.3 @@ -58,6 +58,7 @@
     7.4  
     7.5      Expression *primitive();
     7.6      Expression *call(Expression *callee);
     7.7 +    Expression *field(Expression *left);
     7.8      Expression *index(Expression *left);
     7.9      Expression *prefix();
    7.10      Expression *primary();
     8.1 --- a/src/Scanner.cpp	Sat Aug 04 19:33:06 2012 -0700
     8.2 +++ b/src/Scanner.cpp	Sat Aug 04 20:12:20 2012 -0700
     8.3 @@ -464,9 +464,11 @@
     8.4                  c = getChar();
     8.5                  if (c == '.')
     8.6                      return TOK_ELLIPSES;
     8.7 +                cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
     8.8 +                return TOK_ERROR;
     8.9              }
    8.10 -            cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
    8.11 -            return TOK_ERROR;
    8.12 +            putChar(c);
    8.13 +            return TOK_DOT;
    8.14  
    8.15            case '*':
    8.16              c = getChar();
    8.17 @@ -542,6 +544,7 @@
    8.18              putChar(c);
    8.19              return TOK_ASSIGN;
    8.20  
    8.21 +
    8.22            case '<':
    8.23              c = getChar();
    8.24              if (c == '=')
     9.1 --- a/src/SemanticAnalysis.cpp	Sat Aug 04 19:33:06 2012 -0700
     9.2 +++ b/src/SemanticAnalysis.cpp	Sat Aug 04 20:12:20 2012 -0700
     9.3 @@ -275,6 +275,10 @@
     9.4          }
     9.5      }
     9.6  
     9.7 +    // Note that unlike IndexExpression, FieldExpression uses its actual
     9.8 +    // result type, rather than its parent array type, which can be recovered
     9.9 +    // from its left-hand side expression.
    9.10 +
    9.11      return expression->type();
    9.12  }
    9.13  
    9.14 @@ -300,7 +304,7 @@
    9.15        case PrimitiveType_Int32:
    9.16          return "int";
    9.17        case PrimitiveType_Float:
    9.18 -        return "float";
    9.19 +        return "Float";
    9.20        default:
    9.21          return "<unknown>";
    9.22      }
    9.23 @@ -390,6 +394,19 @@
    9.24          return type->contained();
    9.25      }
    9.26  
    9.27 +    if (expression->isFieldExpression()) {
    9.28 +        Type *type = visitAndApplyType(expression);
    9.29 +        if (!type)
    9.30 +            return NULL;
    9.31 +
    9.32 +        // if (expression->toFieldExpression()->left()->type()->isConst()) {
    9.33 +        //     cc_.reportError(expression->pos(), Message_ReferenceIsConstant);
    9.34 +        //     return NULL;
    9.35 +        // }
    9.36 +
    9.37 +        return type;
    9.38 +    }
    9.39 +
    9.40      if (!expression->isNameProxy()) {
    9.41          cc_.reportError(expression->pos(), Message_ExpectedLValue);
    9.42          return NULL;
    9.43 @@ -1105,6 +1122,7 @@
    9.44          // a reference.
    9.45          if (expression->isIndexExpression())
    9.46              given = given->contained();
    9.47 +        assert(!expression->isFieldExpression());
    9.48  
    9.49          bool mustComputeReference;
    9.50          if (i >= type->parameters()->length()) {
    9.51 @@ -1188,6 +1206,33 @@
    9.52  }
    9.53  
    9.54  void
    9.55 +SemanticAnalysis::visit(FieldExpression *node)
    9.56 +{
    9.57 +    Local<Type> left(zone_, visitForLoad(node->left()));
    9.58 +    if (!left)
    9.59 +        return;
    9.60 +
    9.61 +    if (!left->isStruct()) {
    9.62 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
    9.63 +                        GetTypeName(left));
    9.64 +        return;
    9.65 +    }
    9.66 +
    9.67 +    Local<String> field(zone_, node->field());
    9.68 +
    9.69 +    unsigned offset;
    9.70 +    Local<Descriptor> desc(zone_, left->lookupField(field, &offset));
    9.71 +    if (!desc) {
    9.72 +        cc_.reportError(node->pos(), Message_PropertyNotFound, node->field()->chars(),
    9.73 +                        GetTypeName(left));
    9.74 +        return;
    9.75 +    }
    9.76 +
    9.77 +    node->setFieldIndex(offset);
    9.78 +    node->setType(desc->type());
    9.79 +}
    9.80 +
    9.81 +void
    9.82  SemanticAnalysis::visit(EnumStatement *node)
    9.83  {
    9.84      Local<Type> type(zone_, node->decl()->type());
    10.1 --- a/src/SemanticAnalysis.h	Sat Aug 04 19:33:06 2012 -0700
    10.2 +++ b/src/SemanticAnalysis.h	Sat Aug 04 20:12:20 2012 -0700
    10.3 @@ -204,6 +204,7 @@
    10.4      void visit(TernaryExpression *node);
    10.5      void visit(BooleanLiteral *node);
    10.6      void visit(StructureStatement *node);
    10.7 +    void visit(FieldExpression *node);
    10.8  };
    10.9  
   10.10  const char *GetTypeName(Type *type);
    11.1 --- a/src/Token.h	Sat Aug 04 19:33:06 2012 -0700
    11.2 +++ b/src/Token.h	Sat Aug 04 20:12:20 2012 -0700
    11.3 @@ -116,6 +116,7 @@
    11.4      _(QMARK,              "?")                          \
    11.5      _(COLON,              ":")                          \
    11.6      _(UNDERSCORE,         "_")                          \
    11.7 +    _(DOT,                ".")                          \
    11.8      _(EOF,                "<end-of-file>")
    11.9  
   11.10  enum TokenKind
    12.1 --- a/src/Types.cpp	Sat Aug 04 19:33:06 2012 -0700
    12.2 +++ b/src/Types.cpp	Sat Aug 04 20:12:20 2012 -0700
    12.3 @@ -20,6 +20,7 @@
    12.4  #include "Types.h"
    12.5  #include "Zone.h"
    12.6  #include "Strings.h"
    12.7 +#include "Structures.h"
    12.8  #include "Heap-inl.h"
    12.9  
   12.10  using namespace ke;
   12.11 @@ -221,3 +222,20 @@
   12.12          return Compare(left->contained(), right->contained());
   12.13      }
   12.14  }
   12.15 +
   12.16 +Descriptor *
   12.17 +Type::lookupField(Handle<String> name, unsigned *index)
   12.18 +{
   12.19 +    assert(isStruct());
   12.20 +
   12.21 +    for (unsigned i = 0; i < fields_->length(); i++) {
   12.22 +        Descriptor *desc = Descriptor::cast(fields_->at(i));
   12.23 +        if (desc->name() == name) {
   12.24 +            *index = i;
   12.25 +            return desc;
   12.26 +        }
   12.27 +    }
   12.28 +
   12.29 +    return NULL;
   12.30 +}
   12.31 +
    13.1 --- a/src/Types.h	Sat Aug 04 19:33:06 2012 -0700
    13.2 +++ b/src/Types.h	Sat Aug 04 20:12:20 2012 -0700
    13.3 @@ -26,6 +26,7 @@
    13.4  namespace ke {
    13.5  
    13.6  class String;
    13.7 +class Descriptor;
    13.8  
    13.9  enum PrimitiveType
   13.10  {
   13.11 @@ -189,6 +190,11 @@
   13.12          assert(isEnum() || isStruct());
   13.13          return name_;
   13.14      }
   13.15 +    FixedArray *fields() {
   13.16 +        assert(isStruct());
   13.17 +        return fields_;
   13.18 +    }
   13.19 +    Descriptor *lookupField(Handle<String> name, unsigned *index);
   13.20  
   13.21      // Objects of this type can be created with this cached map.
   13.22      Map *newMap() {