All but interpreter support for getting and setting struct fields.
All but interpreter support for getting and setting struct fields.
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() {