Forráskód Böngészése

class declaration and instances of classes

runningwater 2 éve
szülő
commit
3ed01d1ad6
7 módosított fájl, 86 hozzáadás és 4 törlés
  1. 1 0
      chunk.h
  2. 15 1
      compiler.c
  3. 1 0
      debug.c
  4. 21 0
      memory.c
  5. 17 0
      object.c
  6. 23 3
      object.h
  7. 8 0
      vm.c

+ 1 - 0
chunk.h

@@ -45,6 +45,7 @@ typedef enum {
   OP_RETURN,       ///<OP_RETURN>
   OP_CLOSURE,
   OP_CLOSE_UPVALUE,
+  OP_CLASS,
 } OpCode;
 
 //============================================================================

+ 15 - 1
compiler.c

@@ -74,6 +74,7 @@ Compiler *current = NULL;
 
 static void parsePrecedence(Precedence);
 static uint8_t parseVariable(const char *);
+static void declareVariable();
 static void defineVariable(uint8_t);
 static uint8_t identifierConstant(Token *name);
 static bool identifiersEqual(Token *a, Token *b);
@@ -210,6 +211,17 @@ static void function(FunctionType type) {
     emitByte(compiler.upvalues[i].index);
   }
 }
+static void classDeclaration() {
+  consume(TOKEN_IDENTIFIER, "Expect class name.");
+  uint8_t nameConstant = identifierConstant(&parser.previous);
+  declareVariable();
+
+  emitBytes(OP_CLASS, nameConstant);
+  defineVariable(nameConstant);
+
+  consume(TOKEN_LEFT_BRACE, "Expect '{' before class body.");
+  consume(TOKEN_RIGHT_BRACE, "Expect '}' after class body.");
+}
 static void funDeclaration() {
   uint8_t global = parseVariable("Expect function name.");
   markInitialized();
@@ -385,7 +397,9 @@ static void synchronize() {
 ///               | varDecl
 ///               | statement ;
 static void declaration() {
-  if (match(TOKEN_FUN)) {
+  if (match(TOKEN_CLASS)) {
+    classDeclaration();
+  } else if (match(TOKEN_FUN)) {
     funDeclaration();
   } else if (match(TOKEN_VAR)) {
     varDeclaration();

+ 1 - 0
debug.c

@@ -78,6 +78,7 @@ int disassembleInstruction(Chunk *chunk, int offset) {
     case OP_GET_UPVALUE: return byteInstruction("OP_GET_UPVALUE", chunk, 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_RETURN: return simpleInstruction("OP_RETURN", offset);
     default:
       printf("Unknown opcode %d\n", instruction);

+ 21 - 0
memory.c

@@ -76,6 +76,16 @@ static void freeObject(Obj *object) {
     case OBJ_UPVALUE:
       FREE(ObjUpvalue, object);
       break;
+    case OBJ_CLASS: {
+      FREE(ObjClass, object);
+      break;
+    }
+    case OBJ_INSTANCE: {
+      ObjInstance *instance = (ObjInstance *) object;
+      freeTable(&instance->fields);
+      FREE(ObjInstance, object);
+      break;
+    }
   }
 }
 void freeObjects() {
@@ -113,6 +123,17 @@ void blackenObject(Obj *object) {
 #endif
 
   switch (object->type) {
+    case OBJ_INSTANCE: {
+      ObjInstance *instance = (ObjInstance *) object;
+      markObject((Obj *) instance->klass);
+      markTable(&instance->fields);
+      break;
+    }
+    case OBJ_CLASS: {
+      ObjClass *klass = (ObjClass *) object;
+      markObject((Obj *) klass->name);
+      break;
+    }
     case OBJ_CLOSURE: {
       ObjClosure *closure = (ObjClosure *) object;
       markObject((Obj *) closure->function);

+ 17 - 0
object.c

@@ -71,6 +71,12 @@ void printObject(Value value) {
     case OBJ_UPVALUE:
       printf("upvalue");
       break;
+    case OBJ_CLASS:
+      printf("%s", AS_CLASS(value)->name->chars);
+      break;
+    case OBJ_INSTANCE:
+      printf("%s instance", AS_INSTANCE(value)->klass->name->chars);
+      break;
   }
 }
 ObjFunction *newFunction() {
@@ -117,6 +123,17 @@ ObjUpvalue *newUpvalue(Value *slot) {
   upvalue->next = NULL;
   return upvalue;
 }
+ObjClass *newClass(ObjString *name) {
+  ObjClass *klass = ALLOCATE_OBJ(ObjClass, OBJ_CLASS);
+  klass->name = name;
+  return klass;
+}
+ObjInstance *newInstance(ObjClass *klass) {
+  ObjInstance *instance = ALLOCATE_OBJ(ObjInstance, OBJ_INSTANCE);
+  instance->klass = klass;
+  initTable(&instance->fields);
+  return instance;
+}
 /// 分配内存空间
 /// \param size 空间大小
 /// \param type 对象类型

+ 23 - 3
object.h

@@ -13,26 +13,33 @@
 
 #include "chunk.h"
 #include "common.h"
+#include "table.h"
 #include "value.h"
 
 #define OBJ_TYPE(value) (AS_OBJ(value)->type)
 
+#define IS_CLASS(value) isObjType(value, OBJ_CLASS)
 #define IS_CLOSURE(value) isObjType(value, OBJ_CLOSURE)
 #define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION)
+#define IS_INSTANCE(value) isObjType(value, OBJ_INSTANCE)
 #define IS_NATIVE(value) isObjType(value, OBJ_NATIVE)
 #define IS_STRING(value) isObjType(value, OBJ_STRING)
 
+#define AS_CLASS(value) ((ObjClass *) AS_OBJ(value))
 #define AS_CLOSURE(value) ((ObjClosure *) AS_OBJ(value))
 #define AS_FUNCTION(value) ((ObjFunction *) AS_OBJ(value))
+#define AS_INSTANCE(value) ((ObjInstance *) AS_OBJ(value))
 #define AS_NATIVE(value) (((ObjNative *) AS_OBJ(value))->function)
 #define AS_STRING(value) ((ObjString *) AS_OBJ(value))
 #define AS_CSTRING(value) (((ObjString *) AS_OBJ(value))->chars)
 
 typedef enum {
-  OBJ_STRING,
-  OBJ_FUNCTION,
-  OBJ_NATIVE,
+  OBJ_CLASS,
   OBJ_CLOSURE,
+  OBJ_NATIVE,
+  OBJ_FUNCTION,
+  OBJ_INSTANCE,
+  OBJ_STRING,
   OBJ_UPVALUE,
 } ObjType;
 
@@ -78,8 +85,21 @@ typedef struct {
   int upvalueCount;
 } ObjClosure;
 
+typedef struct {
+  struct Obj obj;
+  ObjString *name;
+} ObjClass;
+
+typedef struct {
+  struct Obj obj;
+  ObjClass *klass;
+  Table fields;
+} ObjInstance;
+
+ObjClass *newClass(ObjString *name);
 ObjClosure *newClosure(ObjFunction *function);
 ObjFunction *newFunction();
+ObjInstance *newInstance(ObjClass *klass);
 ObjNative *newNative(NativeFn function);
 ObjString *takeString(char *chars, int length);
 ObjString *copyString(const char *chars, int length);

+ 8 - 0
vm.c

@@ -107,6 +107,11 @@ static bool callValue(Value callee, int argCount) {
         push(result);
         return true;
       }
+      case OBJ_CLASS: {
+        ObjClass *klass = AS_CLASS(callee);
+        vm.stackTop[-argCount - 1] = OBJ_VAL(newInstance(klass));
+        return true;
+      }
       default:
         break;// Non-callable object type.
     }
@@ -235,6 +240,9 @@ static InterpretResult run() {
         pop();
         break;
       }
+      case OP_CLASS:
+        push(OBJ_VAL(newClass(READ_STRING())));
+        break;
       case OP_GET_GLOBAL: {
         ObjString *name = READ_STRING();
         Value value;