2013-10-22 21:16:39 +02:00
|
|
|
#ifndef wren_vm_h
|
|
|
|
|
#define wren_vm_h
|
|
|
|
|
|
2013-11-28 17:11:50 +01:00
|
|
|
#include "wren_common.h"
|
|
|
|
|
#include "wren_value.h"
|
2013-11-17 02:51:30 +01:00
|
|
|
|
2013-10-24 00:32:59 +02:00
|
|
|
// TODO(bob): Make these externally controllable.
|
2013-10-22 21:16:39 +02:00
|
|
|
#define STACK_SIZE 1024
|
2013-10-24 00:32:59 +02:00
|
|
|
#define MAX_CALL_FRAMES 256
|
2013-10-22 21:16:39 +02:00
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
// Load the constant at index [arg].
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_CONSTANT,
|
2013-10-22 21:16:39 +02:00
|
|
|
|
2013-11-06 00:40:21 +01:00
|
|
|
// Push null onto the stack.
|
|
|
|
|
CODE_NULL,
|
|
|
|
|
|
2013-11-04 06:38:58 +01:00
|
|
|
// Push false onto the stack.
|
|
|
|
|
CODE_FALSE,
|
|
|
|
|
|
|
|
|
|
// Push true onto the stack.
|
|
|
|
|
CODE_TRUE,
|
|
|
|
|
|
feat: add class parsing and object type system with ObjBlock, ObjClass, and ObjNum structs
Introduce token types TOKEN_CLASS and TOKEN_META for class declaration parsing in the compiler. Refactor the internal object model from a single Obj union to distinct ObjNum, ObjBlock, and ObjClass structs, replacing the old Block type with ObjBlock throughout the compiler, VM, and main entry point. Implement makeClass() and makeBlock() factory functions, update makeNum() to return ObjNum*, and add CODE_CLASS and CODE_DUP bytecodes to support class definition at compile time. Modify the symbol table and method dispatch to use a Method union (primitive or block) stored in ObjClass, and update the VM's callBlock signature and newVM initialization accordingly.
2013-10-24 07:50:04 +02:00
|
|
|
// Define a new empty class and push it.
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_CLASS,
|
feat: add class parsing and object type system with ObjBlock, ObjClass, and ObjNum structs
Introduce token types TOKEN_CLASS and TOKEN_META for class declaration parsing in the compiler. Refactor the internal object model from a single Obj union to distinct ObjNum, ObjBlock, and ObjClass structs, replacing the old Block type with ObjBlock throughout the compiler, VM, and main entry point. Implement makeClass() and makeBlock() factory functions, update makeNum() to return ObjNum*, and add CODE_CLASS and CODE_DUP bytecodes to support class definition at compile time. Modify the symbol table and method dispatch to use a Method union (primitive or block) stored in ObjClass, and update the VM's callBlock signature and newVM initialization accordingly.
2013-10-24 07:50:04 +02:00
|
|
|
|
2013-11-13 20:05:03 +01:00
|
|
|
// Pop a superclass off the stack, then push a new class that extends it.
|
|
|
|
|
CODE_SUBCLASS,
|
|
|
|
|
|
2013-10-25 06:32:17 +02:00
|
|
|
// Add a method for symbol [arg1] with body stored in constant [arg2] to the
|
|
|
|
|
// class on the top of stack. Does not modify the stack.
|
2013-11-20 16:20:16 +01:00
|
|
|
CODE_METHOD_INSTANCE,
|
|
|
|
|
|
|
|
|
|
// Add a method for symbol [arg1] with body stored in constant [arg2] to the
|
|
|
|
|
// metaclass of the class on the top of stack. Does not modify the stack.
|
|
|
|
|
CODE_METHOD_STATIC,
|
|
|
|
|
|
|
|
|
|
// Add a constructor method for symbol [arg1] with body stored in constant
|
|
|
|
|
// [arg2] to the metaclass of the class on the top of stack. Does not modify
|
|
|
|
|
// the stack.
|
|
|
|
|
CODE_METHOD_CTOR,
|
2013-10-25 06:32:17 +02:00
|
|
|
|
2013-11-24 22:38:31 +01:00
|
|
|
// Create a new list with [arg] elements. The top [arg] values on the stack
|
|
|
|
|
// are the elements in forward order. Removes the elements and then pushes
|
|
|
|
|
// the new list.
|
|
|
|
|
CODE_LIST,
|
2013-10-24 00:32:59 +02:00
|
|
|
|
2013-10-27 01:01:44 +02:00
|
|
|
// Pushes the value in local slot [arg].
|
2013-10-24 00:32:59 +02:00
|
|
|
CODE_LOAD_LOCAL,
|
|
|
|
|
|
feat: add class parsing and object type system with ObjBlock, ObjClass, and ObjNum structs
Introduce token types TOKEN_CLASS and TOKEN_META for class declaration parsing in the compiler. Refactor the internal object model from a single Obj union to distinct ObjNum, ObjBlock, and ObjClass structs, replacing the old Block type with ObjBlock throughout the compiler, VM, and main entry point. Implement makeClass() and makeBlock() factory functions, update makeNum() to return ObjNum*, and add CODE_CLASS and CODE_DUP bytecodes to support class definition at compile time. Modify the symbol table and method dispatch to use a Method union (primitive or block) stored in ObjClass, and update the VM's callBlock signature and newVM initialization accordingly.
2013-10-24 07:50:04 +02:00
|
|
|
// Stores the top of stack in local slot [arg]. Does not pop it.
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_STORE_LOCAL,
|
2013-10-24 00:32:59 +02:00
|
|
|
|
2013-10-26 05:32:42 +02:00
|
|
|
// Pushes the value in global slot [arg].
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_LOAD_GLOBAL,
|
2013-10-26 05:32:42 +02:00
|
|
|
|
|
|
|
|
// Stores the top of stack in global slot [arg]. Does not pop it.
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_STORE_GLOBAL,
|
2013-10-26 05:32:42 +02:00
|
|
|
|
2013-11-23 23:55:05 +01:00
|
|
|
// Pushes the value of the field in slot [arg] for the current receiver.
|
|
|
|
|
CODE_LOAD_FIELD,
|
|
|
|
|
|
|
|
|
|
// Stores the top of stack in field slot [arg] in the current receiver.
|
|
|
|
|
CODE_STORE_FIELD,
|
|
|
|
|
|
2013-11-24 22:38:31 +01:00
|
|
|
// Push a copy of the top of stack.
|
|
|
|
|
CODE_DUP,
|
|
|
|
|
|
|
|
|
|
// Pop and discard the top of stack.
|
|
|
|
|
CODE_POP,
|
|
|
|
|
|
2013-10-27 01:01:44 +02:00
|
|
|
// Invoke the method with symbol [arg]. The number indicates the number of
|
|
|
|
|
// arguments (not including the receiver).
|
|
|
|
|
CODE_CALL_0,
|
|
|
|
|
CODE_CALL_1,
|
|
|
|
|
CODE_CALL_2,
|
|
|
|
|
CODE_CALL_3,
|
|
|
|
|
CODE_CALL_4,
|
|
|
|
|
CODE_CALL_5,
|
|
|
|
|
CODE_CALL_6,
|
|
|
|
|
CODE_CALL_7,
|
|
|
|
|
CODE_CALL_8,
|
|
|
|
|
CODE_CALL_9,
|
|
|
|
|
CODE_CALL_10,
|
2013-11-06 00:40:21 +01:00
|
|
|
|
2013-11-19 16:35:25 +01:00
|
|
|
// Jump the instruction pointer [arg] forward.
|
2013-11-06 00:40:21 +01:00
|
|
|
CODE_JUMP,
|
|
|
|
|
|
2013-11-19 16:35:25 +01:00
|
|
|
// Jump the instruction pointer [arg] backward. Pop and discard the top of
|
2013-11-18 07:38:59 +01:00
|
|
|
// the stack.
|
|
|
|
|
CODE_LOOP,
|
|
|
|
|
|
2013-11-19 16:35:25 +01:00
|
|
|
// Pop and if not truthy then jump the instruction pointer [arg] forward.
|
2013-11-06 00:40:21 +01:00
|
|
|
CODE_JUMP_IF,
|
|
|
|
|
|
2013-11-19 16:35:25 +01:00
|
|
|
// If the top of the stack is false, jump [arg] forward. Otherwise, pop and
|
|
|
|
|
// continue.
|
|
|
|
|
CODE_AND,
|
|
|
|
|
|
2013-11-20 03:24:58 +01:00
|
|
|
// If the top of the stack is non-false, jump [arg] forward. Otherwise, pop
|
|
|
|
|
// and continue.
|
|
|
|
|
CODE_OR,
|
|
|
|
|
|
feat: add `is` operator for type checking and refactor primitives registration
Add TOKEN_IS token and CODE_IS bytecode to support runtime type checking via the `is` keyword. Refactor primitive registration by replacing `registerPrimitives` with `loadCore`, which compiles a core library string to define built-in classes (Bool, Class, Function, Num, Null, String, IO) and then attaches primitive methods to them. Update Primitive typedef to remove unused numArgs parameter, and add findGlobal helper to retrieve globals by name. Include test files for class syntax, class instantiation, and the new `is` operator.
2013-11-08 02:07:32 +01:00
|
|
|
// Pop [a] then [b] and push true if [b] is an instance of [a].
|
|
|
|
|
CODE_IS,
|
2013-11-10 23:21:14 +01:00
|
|
|
|
2013-10-22 21:16:39 +02:00
|
|
|
// The current block is done and should be exited.
|
2013-10-27 01:01:44 +02:00
|
|
|
CODE_END
|
2013-10-22 21:16:39 +02:00
|
|
|
} Code;
|
|
|
|
|
|
2013-10-23 22:51:41 +02:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
// TODO(bob): Make this dynamically sized.
|
2013-10-24 00:32:59 +02:00
|
|
|
char* names[MAX_SYMBOLS];
|
|
|
|
|
int count;
|
|
|
|
|
} SymbolTable;
|
|
|
|
|
|
2013-11-29 18:14:19 +01:00
|
|
|
// A pinned object is an Obj that has been temporarily made an explicit GC root.
|
|
|
|
|
// This is for temporary or new objects that are not otherwise reachable but
|
|
|
|
|
// should not be collected.
|
|
|
|
|
//
|
|
|
|
|
// They are organized as linked list of these objects stored on the stack. The
|
|
|
|
|
// WrenVM has a pointer to the head of the list and walks it if a collection
|
|
|
|
|
// occurs. This implies that pinned objects need to have stack semantics: only
|
|
|
|
|
// the most recently pinned object can be unpinned.
|
|
|
|
|
typedef struct sPinnedObj
|
|
|
|
|
{
|
|
|
|
|
// The pinned object.
|
|
|
|
|
Obj* obj;
|
|
|
|
|
|
|
|
|
|
// The next pinned object.
|
|
|
|
|
struct sPinnedObj* previous;
|
|
|
|
|
} PinnedObj;
|
|
|
|
|
|
2013-11-25 16:47:02 +01:00
|
|
|
struct WrenVM
|
2013-10-24 00:32:59 +02:00
|
|
|
{
|
2013-11-09 20:18:27 +01:00
|
|
|
SymbolTable methods;
|
2013-10-24 22:01:24 +02:00
|
|
|
|
2013-11-04 06:38:58 +01:00
|
|
|
ObjClass* boolClass;
|
2013-10-24 22:01:24 +02:00
|
|
|
ObjClass* classClass;
|
2013-11-06 15:52:28 +01:00
|
|
|
ObjClass* fnClass;
|
2013-11-24 22:38:31 +01:00
|
|
|
ObjClass* listClass;
|
2013-11-06 00:40:21 +01:00
|
|
|
ObjClass* nullClass;
|
feat: add class parsing and object type system with ObjBlock, ObjClass, and ObjNum structs
Introduce token types TOKEN_CLASS and TOKEN_META for class declaration parsing in the compiler. Refactor the internal object model from a single Obj union to distinct ObjNum, ObjBlock, and ObjClass structs, replacing the old Block type with ObjBlock throughout the compiler, VM, and main entry point. Implement makeClass() and makeBlock() factory functions, update makeNum() to return ObjNum*, and add CODE_CLASS and CODE_DUP bytecodes to support class definition at compile time. Modify the symbol table and method dispatch to use a Method union (primitive or block) stored in ObjClass, and update the VM's callBlock signature and newVM initialization accordingly.
2013-10-24 07:50:04 +02:00
|
|
|
ObjClass* numClass;
|
2013-11-13 20:05:03 +01:00
|
|
|
ObjClass* objectClass;
|
2013-10-26 05:40:24 +02:00
|
|
|
ObjClass* stringClass;
|
2013-10-26 05:32:42 +02:00
|
|
|
|
2013-11-04 06:38:58 +01:00
|
|
|
// The singleton values.
|
2013-10-31 15:04:44 +01:00
|
|
|
Value unsupported;
|
|
|
|
|
|
2013-10-26 05:32:42 +02:00
|
|
|
SymbolTable globalSymbols;
|
|
|
|
|
// TODO(bob): Using a fixed array is gross here.
|
|
|
|
|
Value globals[MAX_SYMBOLS];
|
2013-11-12 17:32:35 +01:00
|
|
|
|
|
|
|
|
// TODO(bob): Support more than one fiber.
|
|
|
|
|
Fiber* fiber;
|
|
|
|
|
|
|
|
|
|
// Memory management data:
|
|
|
|
|
|
|
|
|
|
// How many bytes of object data have been allocated so far.
|
|
|
|
|
size_t totalAllocated;
|
|
|
|
|
|
|
|
|
|
// The number of total allocated bytes that will trigger the next GC.
|
|
|
|
|
size_t nextGC;
|
|
|
|
|
|
|
|
|
|
// The first object in the linked list of all currently allocated objects.
|
|
|
|
|
Obj* first;
|
|
|
|
|
|
2013-11-29 18:14:19 +01:00
|
|
|
// The head of the list of pinned objects. Will be `NULL` if nothing is
|
|
|
|
|
// pinned.
|
|
|
|
|
PinnedObj* pinned;
|
2013-10-31 15:04:44 +01:00
|
|
|
};
|
2013-10-23 22:51:41 +02:00
|
|
|
|
2013-11-05 16:56:59 +01:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
// Index of the current (really next-to-be-executed) instruction in the
|
|
|
|
|
// block's bytecode.
|
|
|
|
|
int ip;
|
|
|
|
|
|
2013-11-06 15:52:28 +01:00
|
|
|
// The function being executed.
|
|
|
|
|
ObjFn* fn;
|
2013-11-05 16:56:59 +01:00
|
|
|
|
2013-11-09 20:18:27 +01:00
|
|
|
// Index of the first stack slot used by this call frame. This will contain
|
|
|
|
|
// the receiver, followed by the function's parameters, then local variables
|
|
|
|
|
// and temporaries.
|
|
|
|
|
int stackStart;
|
2013-11-05 16:56:59 +01:00
|
|
|
} CallFrame;
|
|
|
|
|
|
|
|
|
|
struct sFiber
|
|
|
|
|
{
|
|
|
|
|
Value stack[STACK_SIZE];
|
|
|
|
|
int stackSize;
|
|
|
|
|
|
|
|
|
|
CallFrame frames[MAX_CALL_FRAMES];
|
|
|
|
|
int numFrames;
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-27 03:02:10 +01:00
|
|
|
void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize);
|
|
|
|
|
|
2013-11-25 16:47:02 +01:00
|
|
|
// TODO(bob): Make these static or prefix their names.
|
2013-10-23 22:51:41 +02:00
|
|
|
|
2013-10-24 00:32:59 +02:00
|
|
|
// Initializes the symbol table.
|
|
|
|
|
void initSymbolTable(SymbolTable* symbols);
|
|
|
|
|
|
2013-11-18 18:19:03 +01:00
|
|
|
// Removes any symbols added after [count] symbols were defined.
|
|
|
|
|
void truncateSymbolTable(SymbolTable* symbols, int count);
|
|
|
|
|
|
2013-10-24 00:32:59 +02:00
|
|
|
// Frees all dynamically allocated memory used by the symbol table, but not the
|
|
|
|
|
// SymbolTable itself.
|
|
|
|
|
void clearSymbolTable(SymbolTable* symbols);
|
|
|
|
|
|
|
|
|
|
// Adds name to the symbol table. Returns the index of it in the table. Returns
|
|
|
|
|
// -1 if the symbol is already present.
|
|
|
|
|
int addSymbol(SymbolTable* symbols, const char* name, size_t length);
|
|
|
|
|
|
|
|
|
|
// Adds name to the symbol table. Returns the index of it in the table. Will
|
|
|
|
|
// use an existing symbol if already present.
|
|
|
|
|
int ensureSymbol(SymbolTable* symbols, const char* name, size_t length);
|
|
|
|
|
|
|
|
|
|
// Looks up name in the symbol table. Returns its index if found or -1 if not.
|
|
|
|
|
int findSymbol(SymbolTable* symbols, const char* name, size_t length);
|
2013-10-23 22:51:41 +02:00
|
|
|
|
2013-10-25 06:32:17 +02:00
|
|
|
// Given an index in the symbol table, returns its name.
|
|
|
|
|
const char* getSymbolName(SymbolTable* symbols, int symbol);
|
|
|
|
|
|
feat: add `is` operator for type checking and refactor primitives registration
Add TOKEN_IS token and CODE_IS bytecode to support runtime type checking via the `is` keyword. Refactor primitive registration by replacing `registerPrimitives` with `loadCore`, which compiles a core library string to define built-in classes (Bool, Class, Function, Num, Null, String, IO) and then attaches primitive methods to them. Update Primitive typedef to remove unused numArgs parameter, and add findGlobal helper to retrieve globals by name. Include test files for class syntax, class instantiation, and the new `is` operator.
2013-11-08 02:07:32 +01:00
|
|
|
// Returns the global variable named [name].
|
2013-11-25 16:47:02 +01:00
|
|
|
Value findGlobal(WrenVM* vm, const char* name);
|
feat: add `is` operator for type checking and refactor primitives registration
Add TOKEN_IS token and CODE_IS bytecode to support runtime type checking via the `is` keyword. Refactor primitive registration by replacing `registerPrimitives` with `loadCore`, which compiles a core library string to define built-in classes (Bool, Class, Function, Num, Null, String, IO) and then attaches primitive methods to them. Update Primitive typedef to remove unused numArgs parameter, and add findGlobal helper to retrieve globals by name. Include test files for class syntax, class instantiation, and the new `is` operator.
2013-11-08 02:07:32 +01:00
|
|
|
|
2013-11-25 16:47:02 +01:00
|
|
|
Value interpret(WrenVM* vm, ObjFn* fn);
|
2013-10-22 21:16:39 +02:00
|
|
|
|
2013-11-06 15:52:28 +01:00
|
|
|
// Push [fn] onto [fiber]'s callstack and invoke it. Expects [numArgs]
|
2013-11-05 16:56:59 +01:00
|
|
|
// arguments (including the receiver) to be on the top of the stack already.
|
2013-11-06 15:52:28 +01:00
|
|
|
void callFunction(Fiber* fiber, ObjFn* fn, int numArgs);
|
2013-11-05 16:56:59 +01:00
|
|
|
|
2013-11-29 18:14:19 +01:00
|
|
|
// Mark [obj] as a GC root so that it doesn't get collected. Initializes
|
|
|
|
|
// [pinned], which must be then passed to [unpinObj].
|
|
|
|
|
void pinObj(WrenVM* vm, Obj* obj, PinnedObj* pinned);
|
2013-11-12 17:32:35 +01:00
|
|
|
|
2013-11-29 18:14:19 +01:00
|
|
|
// Remove the most recently pinned object from the list of pinned GC roots.
|
|
|
|
|
void unpinObj(WrenVM* vm);
|
2013-11-12 17:32:35 +01:00
|
|
|
|
2013-10-22 21:16:39 +02:00
|
|
|
#endif
|