Jelajahi Sumber

get and set property

runningwater 2 tahun lalu
induk
melakukan
10e713c78c
6 mengubah file dengan 64 tambahan dan 5 penghapusan
  1. 2 0
      chunk.h
  2. 3 3
      common.h
  3. 13 1
      compiler.c
  4. 2 0
      debug.c
  5. 6 0
      test/class.lox
  6. 38 1
      vm.c

+ 2 - 0
chunk.h

@@ -45,6 +45,8 @@ typedef enum {
   OP_RETURN,       ///<OP_RETURN>
   OP_CLOSURE,
   OP_CLOSE_UPVALUE,
+  OP_SET_PROPERTY,
+  OP_GET_PROPERTY,
   OP_CLASS,
 } OpCode;
 

+ 3 - 3
common.h

@@ -13,10 +13,10 @@
 #include <string.h>
 
 #define DEBUG_PRINT_CODE
-//#define DEBUG_TRACE_EXECUTION
-//#define DEBUG_STACK_INFO
+#define DEBUG_TRACE_EXECUTION
+#define DEBUG_STACK_INFO
 
-#define DEBUG_STRESS_GC
+//#define DEBUG_STRESS_GC
 #define DEBUG_LOG_GC
 
 #define UINT8_COUNT (UINT8_MAX + 1)

+ 13 - 1
compiler.c

@@ -707,13 +707,25 @@ static void literal(__attribute__((unused)) bool canAssign) {
     default: return;// Unreachable
   }
 }
+static void dot(bool canAssign) {
+  // eclair.filling = "pastry creme";
+  consume(TOKEN_IDENTIFIER, "Expect property name after '.'.");
+  uint8_t name = identifierConstant(&parser.previous);
+
+  if (canAssign && match(TOKEN_EQUAL)) {
+    expression();
+    emitBytes(OP_SET_PROPERTY, name);
+  } else {
+    emitBytes(OP_GET_PROPERTY, name);
+  }
+}
 ParseRule rules[] = {
     [TOKEN_LEFT_PAREN] = {grouping, call, PREC_CALL},
     [TOKEN_RIGHT_PAREN] = {NULL, NULL, PREC_NONE},
     [TOKEN_LEFT_BRACE] = {NULL, NULL, PREC_NONE},
     [TOKEN_RIGHT_BRACE] = {NULL, NULL, PREC_NONE},
     [TOKEN_COMMA] = {NULL, NULL, PREC_NONE},
-    [TOKEN_DOT] = {NULL, NULL, PREC_NONE},
+    [TOKEN_DOT] = {NULL, dot, PREC_CALL},
     [TOKEN_MINUS] = {unary, binary, PREC_TERM},
     [TOKEN_PLUS] = {NULL, binary, PREC_TERM},
     [TOKEN_SEMICOLON] = {NULL, NULL, PREC_NONE},

+ 2 - 0
debug.c

@@ -79,6 +79,8 @@ int disassembleInstruction(Chunk *chunk, int offset) {
     case OP_SET_UPVALUE: return byteInstruction("OP_SET_UPVALUE", chunk, offset);
     case OP_CLOSE_UPVALUE: return simpleInstruction("OP_CLOSE_UPVALUE", offset);
     case OP_CLASS: return constantInstruction("OP_CLASS", chunk, offset);
+    case OP_GET_PROPERTY: return constantInstruction("OP_GET_PROPERTY", chunk, offset);
+    case OP_SET_PROPERTY: return constantInstruction("OP_SET_PROPERTY", chunk, offset);
     case OP_RETURN: return simpleInstruction("OP_RETURN", offset);
     default:
       printf("Unknown opcode %d\n", instruction);

+ 6 - 0
test/class.lox

@@ -0,0 +1,6 @@
+class Pair {}
+
+var pair = Pair();
+pair.first = 1;
+pair.second = 2;
+print pair.first + pair.second; // 3.

+ 38 - 1
vm.c

@@ -345,6 +345,37 @@ static InterpretResult run() {
         frame = &vm.frames[vm.frameCount - 1];
         break;
       }
+      case OP_GET_PROPERTY: {
+        if (!IS_INSTANCE(peek(0))) {
+          runtimeError("Only instance have properties.");
+          return INTERPRET_RUNTIME_ERROR;
+        }
+
+        ObjInstance *instance = AS_INSTANCE(peek(0));
+        ObjString *name = READ_STRING();
+
+        Value value;
+        if (tableGet(&instance->fields, name, &value)) {
+          pop();// Instance
+          push(value);
+          break;
+        }
+        runtimeError("Undefined property '%s'.", name->chars);
+        return INTERPRET_RUNTIME_ERROR;
+      }
+      case OP_SET_PROPERTY: {
+        if (!IS_INSTANCE(peek(1))) {
+          runtimeError("Only instances have fields.");
+          return INTERPRET_RUNTIME_ERROR;
+        }
+
+        ObjInstance *instance = AS_INSTANCE(peek(1));
+        tableSet(&instance->fields, READ_STRING(), peek(0));
+        Value value = pop();
+        pop();
+        push(value);
+        break;
+      }
       case OP_CLOSURE: {
         ObjFunction *function = AS_FUNCTION(READ_CONSTANT());
         ObjClosure *closure = newClosure(function);
@@ -437,5 +468,11 @@ void push(Value value) {
 Value pop() {
   vm.stackTop--;
   //! NOTE: 出栈后,里面的值没有清除
-  return *vm.stackTop;
+  Value value =  *vm.stackTop;
+#ifdef DEBUG_TRACE_EXECUTION
+  printf("pop stack: ");
+  printValue(value);
+  printf("\n");
+#endif
+  return value;
 }