Pārlūkot izejas kodu

native functions

runningwater 2 gadi atpakaļ
vecāks
revīzija
2509d833e3
6 mainītis faili ar 61 papildinājumiem un 2 dzēšanām
  1. 1 1
      common.h
  2. 3 0
      memory.c
  3. 14 0
      object.c
  4. 12 1
      object.h
  5. 8 0
      test/fib.lox
  6. 23 0
      vm.c

+ 1 - 1
common.h

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

+ 3 - 0
memory.c

@@ -31,6 +31,9 @@ void *reallocate(void *pointer, size_t oldSize, size_t newSize) {
 }
 static void freeObject(Obj *object) {
   switch (object->type) {
+    case OBJ_NATIVE:
+      FREE(ObjNative, object);
+      break;
     case OBJ_FUNCTION: {
       ObjFunction *function = (ObjFunction *) object;
       freeChunk(&function->chunk);

+ 14 - 0
object.c

@@ -49,8 +49,13 @@ static void printFunction(ObjFunction *function) {
   }
   printf("<fn %s>", function->name->chars);
 }
+/// 打印对象
+/// \param value
 void printObject(Value value) {
   switch (OBJ_TYPE(value)) {
+    case OBJ_NATIVE:
+      printf("<native fn>");
+      break;
     case OBJ_FUNCTION:
       printFunction(AS_FUNCTION(value));
       break;
@@ -77,6 +82,15 @@ ObjString *takeString(char *chars, int length) {
 
   return allocateString(chars, length, hash);
 }
+ObjNative *newNative(NativeFn function) {
+  ObjNative *native = ALLOCATE_OBJ(ObjNative, OBJ_NATIVE);
+  native->function = function;
+  return native;
+}
+/// 分配内在空间
+/// \param size 空间大小
+/// \param type 对象类型
+/// \return Obj*
 static Obj *allocateObject(size_t size, ObjType type) {
   Obj *object = (Obj *) reallocate(NULL, 0, size);
   object->type = type;

+ 12 - 1
object.h

@@ -17,16 +17,19 @@
 
 #define OBJ_TYPE(value) (AS_OBJ(value)->type)
 
-#define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION);
+#define IS_FUNCTION(value) isObjType(value, OBJ_FUNCTION)
+#define IS_NATIVE(value) isObjType(value, OBJ_NATIVE)
 #define IS_STRING(value) isObjType(value, OBJ_STRING)
 
 #define AS_FUNCTION(value) ((ObjFunction *) 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,
 } ObjType;
 
 struct Obj {
@@ -41,6 +44,13 @@ typedef struct {
   ObjString *name;
 } ObjFunction;
 
+typedef Value (*NativeFn)(int argCount, Value *args);
+
+typedef struct {
+  struct Obj obj;
+  NativeFn function;
+} ObjNative;
+
 struct ObjString {
   struct Obj obj;
   int length;
@@ -49,6 +59,7 @@ struct ObjString {
 };
 
 ObjFunction *newFunction();
+ObjNative *newNative(NativeFn function);
 ObjString *takeString(char *chars, int length);
 ObjString *copyString(const char *chars, int length);
 void printObject(Value value);

+ 8 - 0
test/fib.lox

@@ -0,0 +1,8 @@
+fun fib(n) {
+  if (n < 2) return n;
+  return fib(n - 2) + fib(n - 1);
+}
+
+var start = clock();
+print fib(35);
+print clock() - start;

+ 23 - 0
vm.c

@@ -13,6 +13,7 @@
 #include "debug.h"
 #include "memory.h"
 #include <stdarg.h>
+#include <time.h>
 
 VM vm;
 
@@ -44,11 +45,26 @@ static void runtimeError(const char *format, ...) {
   resetStack();
 }
 
+static void defineNative(const char *name, NativeFn function) {
+  push(OBJ_VAL(copyString(name, (int) strlen(name))));
+  push(OBJ_VAL(newNative(function)));
+  tableSet(&vm.globals, AS_STRING(vm.stack[0]), vm.stack[1]);
+  pop();
+  pop();
+}
+
+static Value clockNative(int argCount, Value *args) {
+  return NUMBER_VAL((double) clock() / CLOCKS_PER_SEC);
+}
+
 void initVM() {
   resetStack();
   vm.objects = NULL;
   initTable(&vm.globals);
   initTable(&vm.strings);
+
+  /// Native Function define.
+  defineNative("clock", clockNative);
 }
 
 static Value peek(int distance) {
@@ -76,6 +92,13 @@ static bool callValue(Value callee, int argCount) {
     switch (OBJ_TYPE(callee)) {
       case OBJ_FUNCTION:
         return call(AS_FUNCTION(callee), argCount);
+      case OBJ_NATIVE: {
+        NativeFn fn = AS_NATIVE(callee);
+        Value result = fn(argCount, vm.stackTop - argCount);
+        vm.stackTop -= argCount + 1;
+        push(result);
+        return true;
+      }
       default:
         break;// Non-callable object type.
     }