mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
import statement refactored to a builtin function
This commit is contained in:
parent
21c57a6d39
commit
2b132409e2
36
README.md
36
README.md
@ -1 +1,35 @@
|
|||||||
# MiniScript
|
## MiniScript Language
|
||||||
|
|
||||||
|
MiniScript is a simple embeddable, functional, dynamic-typed, bytecode-interpreted, scripting language written in C. It uses the [mark-and-sweep](https://en.wikipedia.org/wiki/Tracing_garbage_collection) method for garbage collection. MiniScript is is syntactically similar to Ruby. The frontend and expression parsing techniques were written using [Wren Language](https://wren.io/) and their wonderful book [craftinginterpreters](http://www.craftinginterpreters.com/) as a reference.
|
||||||
|
|
||||||
|
### What MiniScript looks like
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
|
||||||
|
## Find and return the maximum value in the array.
|
||||||
|
def get_max(arr)
|
||||||
|
ret = arr[0]
|
||||||
|
for i in 1..arr.length
|
||||||
|
ret = max(ret, arr[i])
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
## Return an array where each element returns true with function [fn] and
|
||||||
|
## belongs to [arr].
|
||||||
|
def filter(arr, fn)
|
||||||
|
ret = []
|
||||||
|
for elem in arr
|
||||||
|
if fn(elem)
|
||||||
|
array_append(ret, elem)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
array = [42, null, 3.14, "String", 0..10, [100]]
|
||||||
|
nums = filter(array, is_num)
|
||||||
|
print(get_max(nums))
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -87,7 +87,6 @@ typedef enum {
|
|||||||
//TK_XOREQ, // ^=
|
//TK_XOREQ, // ^=
|
||||||
|
|
||||||
// Keywords.
|
// Keywords.
|
||||||
TK_IMPORT, // import
|
|
||||||
TK_DEF, // def
|
TK_DEF, // def
|
||||||
TK_NATIVE, // native (C function declaration)
|
TK_NATIVE, // native (C function declaration)
|
||||||
TK_END, // end
|
TK_END, // end
|
||||||
@ -146,7 +145,6 @@ typedef struct {
|
|||||||
|
|
||||||
// List of keywords mapped into their identifiers.
|
// List of keywords mapped into their identifiers.
|
||||||
static _Keyword _keywords[] = {
|
static _Keyword _keywords[] = {
|
||||||
{ "import", 6, TK_IMPORT },
|
|
||||||
{ "def", 3, TK_DEF },
|
{ "def", 3, TK_DEF },
|
||||||
{ "native", 6, TK_NATIVE },
|
{ "native", 6, TK_NATIVE },
|
||||||
{ "end", 3, TK_END },
|
{ "end", 3, TK_END },
|
||||||
@ -719,13 +717,6 @@ typedef struct {
|
|||||||
|
|
||||||
NameDefnType type;
|
NameDefnType type;
|
||||||
|
|
||||||
// Could be found in one of the imported script or in it's imported script
|
|
||||||
// recursively. If true [_extern] will be the script ID.
|
|
||||||
bool is_extern;
|
|
||||||
|
|
||||||
// Extern script's index.
|
|
||||||
int _extern;
|
|
||||||
|
|
||||||
// Index in the variable/function buffer/array.
|
// Index in the variable/function buffer/array.
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
@ -740,7 +731,6 @@ static NameSearchResult compilerSearchName(Compiler* compiler,
|
|||||||
|
|
||||||
NameSearchResult result;
|
NameSearchResult result;
|
||||||
result.type = NAME_NOT_DEFINED;
|
result.type = NAME_NOT_DEFINED;
|
||||||
result.is_extern = false;
|
|
||||||
|
|
||||||
// Search through builtin functions.
|
// Search through builtin functions.
|
||||||
int index = findBuiltinFunction(name, length);
|
int index = findBuiltinFunction(name, length);
|
||||||
@ -781,8 +771,6 @@ static NameSearchResult compilerSearchName(Compiler* compiler,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: search in imported scripts.
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -863,7 +851,6 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
|||||||
/* TK_DIVEQ */ NO_RULE, // exprAssignment, PREC_ASSIGNMENT
|
/* TK_DIVEQ */ NO_RULE, // exprAssignment, PREC_ASSIGNMENT
|
||||||
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||||
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
||||||
/* TK_IMPORT */ NO_RULE,
|
|
||||||
/* TK_DEF */ NO_RULE,
|
/* TK_DEF */ NO_RULE,
|
||||||
/* TK_EXTERN */ NO_RULE,
|
/* TK_EXTERN */ NO_RULE,
|
||||||
/* TK_END */ NO_RULE,
|
/* TK_END */ NO_RULE,
|
||||||
@ -967,34 +954,17 @@ static void exprName(Compiler* compiler, bool can_assign) {
|
|||||||
case NAME_GLOBAL_VAR:
|
case NAME_GLOBAL_VAR:
|
||||||
if (can_assign && match(&compiler->parser, TK_EQ)) {
|
if (can_assign && match(&compiler->parser, TK_EQ)) {
|
||||||
compileExpression(compiler);
|
compileExpression(compiler);
|
||||||
if (result.is_extern) {
|
_emitStoreVariable(compiler, result.index, true);
|
||||||
emitOpcode(compiler, OP_STORE_GLOBAL_EXT);
|
|
||||||
emitShort(compiler, result._extern);
|
|
||||||
emitShort(compiler, result.index);
|
|
||||||
} else {
|
|
||||||
_emitStoreVariable(compiler, result.index, true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (result.is_extern) {
|
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
||||||
emitOpcode(compiler, OP_PUSH_GLOBAL_EXT);
|
emitShort(compiler, result.index);
|
||||||
emitShort(compiler, result._extern);
|
|
||||||
emitShort(compiler, result.index);
|
|
||||||
} else {
|
|
||||||
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
|
||||||
emitShort(compiler, result.index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case NAME_FUNCTION:
|
case NAME_FUNCTION:
|
||||||
if (result.is_extern) {
|
emitOpcode(compiler, OP_PUSH_FN);
|
||||||
emitOpcode(compiler, OP_PUSH_FN_EXT);
|
emitShort(compiler, result.index);
|
||||||
emitShort(compiler, result._extern);
|
|
||||||
emitShort(compiler, result.index);
|
|
||||||
} else {
|
|
||||||
emitOpcode(compiler, OP_PUSH_FN);
|
|
||||||
emitShort(compiler, result.index);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case NAME_BUILTIN:
|
case NAME_BUILTIN:
|
||||||
@ -1329,6 +1299,10 @@ static void compileFunction(Compiler* compiler, bool is_native) {
|
|||||||
|
|
||||||
consume(parser, TK_END, "Expected 'end' after function definition end.");
|
consume(parser, TK_END, "Expected 'end' after function definition end.");
|
||||||
|
|
||||||
|
emitOpcode(compiler, OP_PUSH_NULL);
|
||||||
|
emitOpcode(compiler, OP_RETURN);
|
||||||
|
emitOpcode(compiler, OP_END);
|
||||||
|
|
||||||
compilerExitBlock(compiler); // Parameter depth.
|
compilerExitBlock(compiler); // Parameter depth.
|
||||||
compiler->function = compiler->script->body;
|
compiler->function = compiler->script->body;
|
||||||
}
|
}
|
||||||
@ -1511,9 +1485,6 @@ Script* compileSource(MSVM* vm, const char* path) {
|
|||||||
} else if (match(parser, TK_DEF)) {
|
} else if (match(parser, TK_DEF)) {
|
||||||
compileFunction(&compiler, false);
|
compileFunction(&compiler, false);
|
||||||
|
|
||||||
} else if (match(parser, TK_IMPORT)) {
|
|
||||||
// TODO: import statement must be first of all other.
|
|
||||||
TODO;
|
|
||||||
} else {
|
} else {
|
||||||
compileStatement(&compiler);
|
compileStatement(&compiler);
|
||||||
}
|
}
|
||||||
|
66
src/core.c
66
src/core.c
@ -13,7 +13,7 @@ typedef struct {
|
|||||||
} _BuiltinFn;
|
} _BuiltinFn;
|
||||||
|
|
||||||
// Count of builtin function +1 for termination.
|
// Count of builtin function +1 for termination.
|
||||||
#define BUILTIN_COUNT 10
|
#define BUILTIN_COUNT 50
|
||||||
|
|
||||||
// Array of all builtin functions.
|
// Array of all builtin functions.
|
||||||
_BuiltinFn builtins[BUILTIN_COUNT];
|
_BuiltinFn builtins[BUILTIN_COUNT];
|
||||||
@ -47,6 +47,33 @@ Function* getBuiltinFunction(int index) {
|
|||||||
return &builtins[index].fn;
|
return &builtins[index].fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FN_IS_PRIMITE_TYPE(name, check) \
|
||||||
|
void coreIs##name(MSVM* vm) { \
|
||||||
|
vm->rbp[0] = VAR_BOOL(check(vm->rbp[1])); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FN_IS_OBJ_TYPE(name, _enum) \
|
||||||
|
void coreIs##name(MSVM* vm) { \
|
||||||
|
Var arg1 = vm->rbp[1]; \
|
||||||
|
if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == _enum) { \
|
||||||
|
vm->rbp[0] = VAR_TRUE; \
|
||||||
|
} else { \
|
||||||
|
vm->rbp[0] = VAR_FALSE; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
FN_IS_PRIMITE_TYPE(Null, IS_NULL)
|
||||||
|
FN_IS_PRIMITE_TYPE(Bool, IS_BOOL)
|
||||||
|
FN_IS_PRIMITE_TYPE(Num, IS_NUM)
|
||||||
|
|
||||||
|
FN_IS_OBJ_TYPE(String, OBJ_STRING)
|
||||||
|
FN_IS_OBJ_TYPE(Array, OBJ_ARRAY)
|
||||||
|
FN_IS_OBJ_TYPE(Map, OBJ_MAP)
|
||||||
|
FN_IS_OBJ_TYPE(Range, OBJ_RANGE)
|
||||||
|
FN_IS_OBJ_TYPE(Function, OBJ_FUNC)
|
||||||
|
FN_IS_OBJ_TYPE(Script, OBJ_SCRIPT)
|
||||||
|
FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
|
||||||
|
|
||||||
void coreToString(MSVM* vm) {
|
void coreToString(MSVM* vm) {
|
||||||
Var arg1 = vm->rbp[1];
|
Var arg1 = vm->rbp[1];
|
||||||
vm->rbp[0] = VAR_OBJ(&toString(vm, arg1)->_super);
|
vm->rbp[0] = VAR_OBJ(&toString(vm, arg1)->_super);
|
||||||
@ -66,12 +93,35 @@ void corePrint(MSVM* vm) {
|
|||||||
vm->config.write_fn(vm, "\n");
|
vm->config.write_fn(vm, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void coreImport(MSVM* vm) {
|
||||||
|
Var arg1 = vm->rbp[1];
|
||||||
|
if (IS_OBJ(arg1) && AS_OBJ(arg1)->type == OBJ_STRING) {
|
||||||
|
TODO;
|
||||||
|
} else {
|
||||||
|
msSetRuntimeError(vm, "Expected a String argument.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void initializeCore(MSVM* vm) {
|
void initializeCore(MSVM* vm) {
|
||||||
|
|
||||||
|
int i = 0; //< Iterate through builtins.
|
||||||
|
|
||||||
// Initialize builtin functions.
|
// Initialize builtin functions.
|
||||||
int i = 0;
|
initializeBuiltinFN(vm, &builtins[i++], "is_null", 1, coreIsNull);
|
||||||
initializeBuiltinFN(vm, &builtins[i++], "print", 1, corePrint);
|
initializeBuiltinFN(vm, &builtins[i++], "is_bool", 1, coreIsBool);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_num", 1, coreIsNum);
|
||||||
|
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_string", 1, coreIsString);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_array", 1, coreIsArray);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_map", 1, coreIsMap);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_range", 1, coreIsRange);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_function", 1, coreIsFunction);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_script", 1, coreIsScript);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "is_userobj", 1, coreIsUserObj);
|
||||||
|
|
||||||
initializeBuiltinFN(vm, &builtins[i++], "to_string", 1, coreToString);
|
initializeBuiltinFN(vm, &builtins[i++], "to_string", 1, coreToString);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "print", 1, corePrint);
|
||||||
|
initializeBuiltinFN(vm, &builtins[i++], "import", 1, coreImport);
|
||||||
|
|
||||||
// Sentinal to mark the end of the array.
|
// Sentinal to mark the end of the array.
|
||||||
initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL);
|
initializeBuiltinFN(vm, &builtins[i], NULL, 0, NULL);
|
||||||
@ -112,11 +162,12 @@ Var varAdd(MSVM* vm, Var v1, Var v2) {
|
|||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: string addition/ array addition etc.
|
TODO; //string addition/ array addition etc.
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var varSubtract(MSVM* vm, Var v1, Var v2) {
|
Var varSubtract(MSVM* vm, Var v1, Var v2) {
|
||||||
|
TODO;
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,9 +181,16 @@ Var varMultiply(MSVM* vm, Var v1, Var v2) {
|
|||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TODO;
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var varDivide(MSVM* vm, Var v1, Var v2) {
|
Var varDivide(MSVM* vm, Var v1, Var v2) {
|
||||||
|
TODO;
|
||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value) {
|
||||||
|
TODO;
|
||||||
|
return false;
|
||||||
}
|
}
|
@ -24,5 +24,11 @@ Var varSubtract(MSVM* vm, Var v1, Var v2);
|
|||||||
Var varMultiply(MSVM* vm, Var v1, Var v2);
|
Var varMultiply(MSVM* vm, Var v1, Var v2);
|
||||||
Var varDivide(MSVM* vm, Var v1, Var v2);
|
Var varDivide(MSVM* vm, Var v1, Var v2);
|
||||||
|
|
||||||
|
// Functions //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Parameter [iterator] should be VAR_NULL before starting the iteration.
|
||||||
|
// If an element is obtained by iteration it'll return true otherwise returns
|
||||||
|
// false indicating that the iteration is over.
|
||||||
|
bool varIterate(MSVM* vm, Var seq, Var* iterator, Var* value);
|
||||||
|
|
||||||
#endif // CORE_H
|
#endif // CORE_H
|
||||||
|
@ -64,23 +64,11 @@ OPCODE(PUSH_GLOBAL, 2, 1)
|
|||||||
// params: 2 bytes (uint16_t) index.
|
// params: 2 bytes (uint16_t) index.
|
||||||
OPCODE(STORE_GLOBAL, 2, -1)
|
OPCODE(STORE_GLOBAL, 2, -1)
|
||||||
|
|
||||||
// Push imported script's global value on the stack.
|
|
||||||
// params: 2 bytes script index and 2 bytes index.
|
|
||||||
OPCODE(PUSH_GLOBAL_EXT, 4, 1)
|
|
||||||
|
|
||||||
// Pop and store the value to imported script's global.
|
|
||||||
// params: 4 bytes script ID and 2 bytes index.
|
|
||||||
OPCODE(STORE_GLOBAL_EXT, 6, -1)
|
|
||||||
|
|
||||||
// Push the script's function on the stack. It could later be called. But a
|
// Push the script's function on the stack. It could later be called. But a
|
||||||
// function can't be stored i.e. can't assign a function with something else.
|
// function can't be stored i.e. can't assign a function with something else.
|
||||||
// params: 2 bytes index.
|
// params: 2 bytes index.
|
||||||
OPCODE(PUSH_FN, 2, 1)
|
OPCODE(PUSH_FN, 2, 1)
|
||||||
|
|
||||||
// Push an imported script's function.
|
|
||||||
// params: 2 bytes script index and 2 bytes index.
|
|
||||||
OPCODE(PUSH_FN_EXT, 4, 1)
|
|
||||||
|
|
||||||
// Push a built in function.
|
// Push a built in function.
|
||||||
// params: 2 bytes index of the script.
|
// params: 2 bytes index of the script.
|
||||||
OPCODE(PUSH_BUILTIN_FN, 2, 1)
|
OPCODE(PUSH_BUILTIN_FN, 2, 1)
|
||||||
@ -106,22 +94,6 @@ OPCODE(POP, 0, -1)
|
|||||||
//OPCODE(CALL_8, 2, -8)
|
//OPCODE(CALL_8, 2, -8)
|
||||||
OPCODE(CALL, 4, -0) //< Will calculated at compile time.
|
OPCODE(CALL, 4, -0) //< Will calculated at compile time.
|
||||||
|
|
||||||
// A function pointer will be on top of the stack and it'll be called by OP_CALL...
|
|
||||||
// and doesn't need to specify opcode for extern or not.
|
|
||||||
//
|
|
||||||
// Call a function from an imported script.
|
|
||||||
// params: 2 bytes script ID and 2 bytes index. _N -> +2 bytes for argc.
|
|
||||||
//OPCODE(CALL_EXT_0, 4, 0)
|
|
||||||
//OPCODE(CALL_EXT_1, 4, -1)
|
|
||||||
//OPCODE(CALL_EXT_2, 4, -2)
|
|
||||||
//OPCODE(CALL_EXT_3, 4, -3)
|
|
||||||
//OPCODE(CALL_EXT_4, 4, -4)
|
|
||||||
//OPCODE(CALL_EXT_5, 4, -5)
|
|
||||||
//OPCODE(CALL_EXT_6, 4, -6)
|
|
||||||
//OPCODE(CALL_EXT_7, 4, -7)
|
|
||||||
//OPCODE(CALL_EXT_8, 4, -8)
|
|
||||||
//OPCODE(CALL_EXT_N, 6, -0) //< Will calculated at compile time.
|
|
||||||
|
|
||||||
// The address to jump to. It'll set the ip to the address it should jump to
|
// The address to jump to. It'll set the ip to the address it should jump to
|
||||||
// and the address is absolute not an offset from ip's current value.
|
// and the address is absolute not an offset from ip's current value.
|
||||||
// param: 2 bytes jump address.
|
// param: 2 bytes jump address.
|
||||||
|
29
src/var.c
29
src/var.c
@ -58,6 +58,14 @@ String* newString(MSVM* vm, const char* text, uint32_t length) {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Range* newRange(MSVM* vm, double from, double to) {
|
||||||
|
Range* range = ALLOCATE(vm, Range);
|
||||||
|
varInitObject(&range->_super, vm, OBJ_RANGE);
|
||||||
|
range->from = from;
|
||||||
|
range->to = to;
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
Script* newScript(MSVM* vm) {
|
Script* newScript(MSVM* vm) {
|
||||||
Script* script = ALLOCATE(vm, Script);
|
Script* script = ALLOCATE(vm, Script);
|
||||||
varInitObject(&script->_super, vm, OBJ_SCRIPT);
|
varInitObject(&script->_super, vm, OBJ_SCRIPT);
|
||||||
@ -142,13 +150,20 @@ String* toString(MSVM* vm, Var v) {
|
|||||||
return newString(vm, ((String*)obj)->data, ((String*)obj)->length);
|
return newString(vm, ((String*)obj)->data, ((String*)obj)->length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OBJ_ARRAY: TODO;
|
case OBJ_ARRAY: return newString(vm, "[Array]", 7); // TODO;
|
||||||
case OBJ_MAP: TODO;
|
case OBJ_MAP: return newString(vm, "[Map]", 5); // TODO;
|
||||||
case OBJ_RANGE: TODO;
|
case OBJ_RANGE: return newString(vm, "[Range]", 7); // TODO;
|
||||||
case OBJ_SCRIPT: TODO;
|
case OBJ_SCRIPT: return newString(vm, "[Script]", 8); // TODO;
|
||||||
case OBJ_FUNC: TODO;
|
case OBJ_FUNC: {
|
||||||
case OBJ_INSTANCE: TODO;
|
const char* name = ((Function*)obj)->name;
|
||||||
case OBJ_USER: TODO;
|
int length = (int)strlen(name); // TODO: Assert length.
|
||||||
|
char buff[TO_STRING_BUFF_SIZE];
|
||||||
|
memcpy(buff, "[func:", 6);
|
||||||
|
memcpy(buff + 6, name, length);
|
||||||
|
buff[6 + length] = ']';
|
||||||
|
return newString(vm, buff, 6 + length + 1);
|
||||||
|
}
|
||||||
|
case OBJ_USER: return newString(vm, "[UserObj]", 9); // TODO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,6 @@ typedef enum /* ObjectType */ {
|
|||||||
|
|
||||||
OBJ_SCRIPT,
|
OBJ_SCRIPT,
|
||||||
OBJ_FUNC,
|
OBJ_FUNC,
|
||||||
OBJ_INSTANCE,
|
|
||||||
|
|
||||||
OBJ_USER,
|
OBJ_USER,
|
||||||
} ObjectType;
|
} ObjectType;
|
||||||
@ -281,6 +280,9 @@ double varToDouble(Var value);
|
|||||||
// Allocate new String object and return String*.
|
// Allocate new String object and return String*.
|
||||||
String* newString(MSVM* vm, const char* text, uint32_t length);
|
String* newString(MSVM* vm, const char* text, uint32_t length);
|
||||||
|
|
||||||
|
// Allocate new Range object and return Range*.
|
||||||
|
Range* newRange(MSVM* vm, double from, double to);
|
||||||
|
|
||||||
// Allocate new Script object and return Script*.
|
// Allocate new Script object and return Script*.
|
||||||
Script* newScript(MSVM* vm);
|
Script* newScript(MSVM* vm);
|
||||||
|
|
||||||
|
67
src/vm.c
67
src/vm.c
@ -61,8 +61,7 @@ void vmPopTempRef(MSVM* self) {
|
|||||||
void _printStackTop(MSVM* vm) {
|
void _printStackTop(MSVM* vm) {
|
||||||
if (vm->sp != vm->stack) {
|
if (vm->sp != vm->stack) {
|
||||||
Var v = *(vm->sp - 1);
|
Var v = *(vm->sp - 1);
|
||||||
double n = AS_NUM(v);
|
printf("%s\n", toString(vm, v)->data);
|
||||||
printf("%f\n", n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +93,6 @@ static inline void pushCallFrame(MSVM* vm, Function* fn) {
|
|||||||
frame->ip = fn->fn->opcodes.data;
|
frame->ip = fn->fn->opcodes.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void msSetRuntimeError(MSVM* vm, const char* format, ...) {
|
void msSetRuntimeError(MSVM* vm, const char* format, ...) {
|
||||||
vm->error = newString(vm, "TODO:", 5);
|
vm->error = newString(vm, "TODO:", 5);
|
||||||
TODO;
|
TODO;
|
||||||
@ -168,7 +166,7 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
#error "OPCODE" should not be deifined here.
|
#error "OPCODE" should not be deifined here.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG_INSTRUCTION()
|
#define DEBUG_INSTRUCTION() //_printStackTop(vm)
|
||||||
|
|
||||||
#define SWITCH(code) \
|
#define SWITCH(code) \
|
||||||
L_vm_main_loop: \
|
L_vm_main_loop: \
|
||||||
@ -231,7 +229,6 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
PUSH(rbp[index]);
|
PUSH(rbp[index]);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_LOCAL_N):
|
OPCODE(PUSH_LOCAL_N):
|
||||||
{
|
{
|
||||||
int index = READ_SHORT();
|
int index = READ_SHORT();
|
||||||
@ -248,8 +245,17 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
OPCODE(STORE_LOCAL_6):
|
OPCODE(STORE_LOCAL_6):
|
||||||
OPCODE(STORE_LOCAL_7):
|
OPCODE(STORE_LOCAL_7):
|
||||||
OPCODE(STORE_LOCAL_8):
|
OPCODE(STORE_LOCAL_8):
|
||||||
|
{
|
||||||
|
int index = (int)(instruction - OP_STORE_LOCAL_0);
|
||||||
|
rbp[index] = POP();
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
OPCODE(STORE_LOCAL_N):
|
OPCODE(STORE_LOCAL_N):
|
||||||
TODO;
|
{
|
||||||
|
int index = READ_SHORT();
|
||||||
|
rbp[index] = POP();
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_GLOBAL):
|
OPCODE(PUSH_GLOBAL):
|
||||||
{
|
{
|
||||||
@ -267,10 +273,6 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_GLOBAL_EXT):
|
|
||||||
OPCODE(STORE_GLOBAL_EXT):
|
|
||||||
TODO;
|
|
||||||
|
|
||||||
OPCODE(PUSH_FN):
|
OPCODE(PUSH_FN):
|
||||||
{
|
{
|
||||||
int index = READ_SHORT();
|
int index = READ_SHORT();
|
||||||
@ -280,9 +282,6 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(PUSH_FN_EXT) :
|
|
||||||
TODO;
|
|
||||||
|
|
||||||
OPCODE(PUSH_BUILTIN_FN):
|
OPCODE(PUSH_BUILTIN_FN):
|
||||||
{
|
{
|
||||||
Function* fn = getBuiltinFunction(READ_SHORT());
|
Function* fn = getBuiltinFunction(READ_SHORT());
|
||||||
@ -298,7 +297,6 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
{
|
{
|
||||||
int argc = READ_SHORT();
|
int argc = READ_SHORT();
|
||||||
Var* callable = vm->sp - argc - 1;
|
Var* callable = vm->sp - argc - 1;
|
||||||
vm->rbp = callable; //< Next call frame starts here.
|
|
||||||
|
|
||||||
if (IS_OBJ(*callable) && AS_OBJ(*callable)->type == OBJ_FUNC) {
|
if (IS_OBJ(*callable) && AS_OBJ(*callable)->type == OBJ_FUNC) {
|
||||||
|
|
||||||
@ -311,8 +309,13 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
// initialized with VAR_NULL as return value.
|
// initialized with VAR_NULL as return value.
|
||||||
*callable = VAR_NULL;
|
*callable = VAR_NULL;
|
||||||
|
|
||||||
|
// Next call frame starts here. (including return value).
|
||||||
|
vm->rbp = callable;
|
||||||
|
|
||||||
if (fn->is_native) {
|
if (fn->is_native) {
|
||||||
fn->native(vm);
|
fn->native(vm);
|
||||||
|
// Pop function arguments except for the return value.
|
||||||
|
vm->sp = vm->rbp + 1;
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -330,7 +333,30 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
OPCODE(JUMP):
|
OPCODE(JUMP):
|
||||||
OPCODE(JUMP_NOT):
|
OPCODE(JUMP_NOT):
|
||||||
OPCODE(JUMP_IF_NOT):
|
OPCODE(JUMP_IF_NOT):
|
||||||
|
TODO;
|
||||||
|
|
||||||
OPCODE(RETURN):
|
OPCODE(RETURN):
|
||||||
|
{
|
||||||
|
Var ret = POP();
|
||||||
|
vm->frame_count--;
|
||||||
|
|
||||||
|
// If no more call frames. We're done.
|
||||||
|
if (vm->frame_count == 0) {
|
||||||
|
vm->sp = vm->stack;
|
||||||
|
PUSH(ret);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the return value.
|
||||||
|
*(frame->rbp - 1) = ret;
|
||||||
|
|
||||||
|
// Pop the locals and update stack pointer.
|
||||||
|
vm->sp = frame->rbp;
|
||||||
|
|
||||||
|
LOAD_FRAME();
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(GET_ATTRIB):
|
OPCODE(GET_ATTRIB):
|
||||||
OPCODE(SET_ATTRIB):
|
OPCODE(SET_ATTRIB):
|
||||||
OPCODE(GET_SUBSCRIPT):
|
OPCODE(GET_SUBSCRIPT):
|
||||||
@ -370,9 +396,22 @@ MSInterpretResult vmRunScript(MSVM* vm, Script* _script) {
|
|||||||
OPCODE(LTEQ):
|
OPCODE(LTEQ):
|
||||||
OPCODE(GT):
|
OPCODE(GT):
|
||||||
OPCODE(GTEQ):
|
OPCODE(GTEQ):
|
||||||
|
TODO;
|
||||||
|
|
||||||
OPCODE(RANGE):
|
OPCODE(RANGE):
|
||||||
|
{
|
||||||
|
Var to = POP();
|
||||||
|
Var from = POP();
|
||||||
|
if (!IS_NUM(from) || !IS_NUM(to)) {
|
||||||
|
RUNTIME_ERROR("Range arguments must be number.");
|
||||||
|
}
|
||||||
|
PUSH(VAR_OBJ(newRange(vm, AS_NUM(from), AS_NUM(to))));
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
OPCODE(IN):
|
OPCODE(IN):
|
||||||
OPCODE(END):
|
OPCODE(END):
|
||||||
|
TODO;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -12,13 +12,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
// FIXME:
|
|
||||||
//#include "../src/common.h"
|
|
||||||
//#include "../src/var.h"
|
|
||||||
//#include "../src/vm.h"
|
|
||||||
//#include "../src/types/gen/string_buffer.h"
|
|
||||||
//#include "../src/types/gen/byte_buffer.h"
|
|
||||||
|
|
||||||
static const char* opnames[] = {
|
static const char* opnames[] = {
|
||||||
#define OPCODE(name, params, stack) #name,
|
#define OPCODE(name, params, stack) #name,
|
||||||
#include "../src/opcodes.h"
|
#include "../src/opcodes.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user