mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
changed dot operator to access global functions
This commit is contained in:
@@ -34,17 +34,17 @@ DONE: Import/export keywords
|
||||
DONE: A way to check the type of a variable (typeOf keyword)
|
||||
DONE: slice and dot notation around the builtin _index and _dot functions
|
||||
DONE: maximum recursion/function depth
|
||||
DONE: better sugar for _push, _pop, _length
|
||||
|
||||
|
||||
TODO: nested compound assignment
|
||||
TODO: better sugar for _push, _pop, _length
|
||||
TODO: ternary operator?
|
||||
TODO: Nullish types?
|
||||
TODO: hooks on the external libraries, triggered on import
|
||||
TODO: standard library
|
||||
TODO: external script runner library
|
||||
TODO: document how it all works - book?
|
||||
TODO: better API
|
||||
TODO: better API?
|
||||
TODO: packaging for release?
|
||||
|
||||
NOPE: a = b = c = 1;
|
||||
|
||||
20
docs/spec.md
20
docs/spec.md
@@ -433,15 +433,14 @@ var dict: [string const, int const] const = [
|
||||
];
|
||||
```
|
||||
|
||||
Dictionaries can be indexed using traditional bracket notation, or the dot operator when the keys are strings. Existing elements can be accessed or overwritten, or new ones inserted if they don't already exist this way by using the standard library functions.
|
||||
Dictionaries can be indexed using traditional bracket notation. Existing elements can be accessed or overwritten, or new ones inserted if they don't already exist this way by using the standard library functions.
|
||||
|
||||
```
|
||||
dict["foo"] = "bar";
|
||||
print dict["foo"];
|
||||
print dict.foo; //syntactic sugar, only works if the key is not a built-in function
|
||||
```
|
||||
|
||||
## Indexing, Slice and Dot Notation
|
||||
## Slice Notation
|
||||
|
||||
Strings, arrays and dictionaries can be indexed in several ways, via the globally available functions (see below). Elements can be accessed using traditional bracket notation:
|
||||
|
||||
@@ -485,11 +484,22 @@ print str[::-2]; //drwolH
|
||||
|
||||
0 cannot be used as the third argument.
|
||||
|
||||
### Globally available functions
|
||||
### Globally Available Functions
|
||||
|
||||
The slice and dot notations (the latter of which only works on dictionaries) are simply syntactic sugar for the globally available functions.
|
||||
The dot notation can be used to acces the globally available functions, like so:
|
||||
|
||||
```
|
||||
obj.function(); //passes in obj as the first argument
|
||||
```
|
||||
|
||||
A list of globally available functions is:
|
||||
|
||||
```
|
||||
//usable with arrays, dictionaries and strings - probably a good idea not to use this one, just use index notation
|
||||
fn _index(self, first, second, third, assign, op) {
|
||||
//native code
|
||||
}
|
||||
|
||||
//usable with arrays and dictionaries
|
||||
fn _set(self, key, value) {
|
||||
//native code
|
||||
|
||||
@@ -62,6 +62,16 @@ fn extra(one, two, ...rest) {
|
||||
extra("one", "two", "three", "four", "five", "six", "seven");
|
||||
|
||||
|
||||
//test underscore functions
|
||||
fn _example(self, a, b, c) {
|
||||
assert a == "a", "underscore failed (a)";
|
||||
assert b == "b", "underscore failed (b)";
|
||||
assert c == "c", "underscore failed (c)";
|
||||
return self;
|
||||
}
|
||||
|
||||
assert "hello world".example("a", "b", "c") == "hello world", "underscore call failed";
|
||||
|
||||
|
||||
|
||||
print "All good";
|
||||
|
||||
@@ -8,16 +8,6 @@
|
||||
}
|
||||
|
||||
|
||||
//test dot insertion
|
||||
{
|
||||
var d = [:];
|
||||
|
||||
d.foo = "bar";
|
||||
|
||||
assert d == ["foo":"bar"], "dot insertion failed";
|
||||
}
|
||||
|
||||
|
||||
//test index arithmetic
|
||||
{
|
||||
var d = ["one":1, "two":2, "three":3];
|
||||
@@ -28,28 +18,6 @@
|
||||
}
|
||||
|
||||
|
||||
//test dot arithmetic
|
||||
{
|
||||
var d = ["one":1, "two":2, "three":3];
|
||||
|
||||
d.three *= 3;
|
||||
|
||||
assert d == ["one":1, "two":2, "three":9], "index arithmetic failed";
|
||||
}
|
||||
|
||||
|
||||
//test dot calls
|
||||
{
|
||||
fn f() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
var d = ["foo":f];
|
||||
|
||||
assert d.foo() == 42, "dot calls failed";
|
||||
}
|
||||
|
||||
|
||||
//test indexing with variables
|
||||
{
|
||||
var d = ["one":1, "two":2, "three":3];
|
||||
|
||||
@@ -309,7 +309,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break
|
||||
//special case for when indexing and assigning
|
||||
if (override != OP_EOF && node->binary.opcode >= OP_VAR_ASSIGN && node->binary.opcode <= OP_VAR_MODULO_ASSIGN) {
|
||||
writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override + 2; //1 byte WARNING: enum arithmetic
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override + 1; //1 byte WARNING: enum arithmetic
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)node->binary.opcode; //1 byte
|
||||
return OP_EOF;
|
||||
}
|
||||
@@ -319,7 +319,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
|
||||
//return from the index-binary
|
||||
//return this if...
|
||||
Opcode ret = writeCompilerWithJumps(compiler, node->binary.right, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
|
||||
//loopy logic - if opcode == index or dot
|
||||
@@ -504,7 +504,7 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break
|
||||
}
|
||||
|
||||
//push the argument COUNT to the top of the stack
|
||||
Literal argumentsCountLiteral = TO_INTEGER_LITERAL(node->fnCall.arguments->fnCollection.count);
|
||||
Literal argumentsCountLiteral = TO_INTEGER_LITERAL(node->fnCall.argumentCount); //argumentCount is set elsewhere to support dot operator
|
||||
int argumentsCountIndex = findLiteralIndex(&compiler->literalCache, argumentsCountLiteral);
|
||||
if (argumentsCountIndex < 0) {
|
||||
argumentsCountIndex = pushLiteralArray(&compiler->literalCache, argumentsCountLiteral);
|
||||
@@ -859,20 +859,8 @@ static Opcode writeCompilerWithJumps(Compiler* compiler, Node* node, void* break
|
||||
break;
|
||||
|
||||
case NODE_DOT: {
|
||||
//pass to the child nodes, then embed the opcode
|
||||
if (!node->index.first) {
|
||||
writeLiteralToCompiler(compiler, TO_NULL_LITERAL);
|
||||
}
|
||||
else {
|
||||
Opcode override = writeCompilerWithJumps(compiler, node->index.first, breakAddressesPtr, continueAddressesPtr, jumpOffsets);
|
||||
if (override != OP_EOF) {//compensate for indexing & dot notation being screwy
|
||||
compiler->bytecode[compiler->count++] = (unsigned char)override; //1 byte
|
||||
}
|
||||
}
|
||||
|
||||
// compiler->bytecode[compiler->count++] = (unsigned char)OP_DOT; //1 byte
|
||||
|
||||
return OP_DOT_ASSIGN;
|
||||
fprintf(stderr, ERROR "[internal] NODE_DOT encountered in writeCompilerWithJumps()\n" RESET);
|
||||
compiler->bytecode[compiler->count++] = OP_EOF; //1 byte
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -990,7 +990,7 @@ static bool execFalseJump(Interpreter* interpreter) {
|
||||
static void execInterpreter(Interpreter*);
|
||||
static void readInterpreterSections(Interpreter* interpreter);
|
||||
|
||||
static bool execFnCall(Interpreter* interpreter) {
|
||||
static bool execFnCall(Interpreter* interpreter, bool looseFirstArgument) {
|
||||
//BUGFIX: depth check - don't drown!
|
||||
if (interpreter->depth >= 1000) {
|
||||
interpreter->errorOutput("Depth check failed\n");
|
||||
@@ -1004,7 +1004,14 @@ static bool execFnCall(Interpreter* interpreter) {
|
||||
Literal stackSize = popLiteralArray(&interpreter->stack);
|
||||
|
||||
//unpack the stack of arguments
|
||||
for (int i = 0; i < AS_INTEGER(stackSize); i++) {
|
||||
for (int i = 0; i < AS_INTEGER(stackSize) - 1; i++) {
|
||||
Literal lit = popLiteralArray(&interpreter->stack);
|
||||
pushLiteralArray(&arguments, lit); //NOTE: also reverses the order
|
||||
freeLiteral(lit);
|
||||
}
|
||||
|
||||
//collect one more argument
|
||||
if (!looseFirstArgument && AS_INTEGER(stackSize) > 0) {
|
||||
Literal lit = popLiteralArray(&interpreter->stack);
|
||||
pushLiteralArray(&arguments, lit); //NOTE: also reverses the order
|
||||
freeLiteral(lit);
|
||||
@@ -1012,6 +1019,23 @@ static bool execFnCall(Interpreter* interpreter) {
|
||||
|
||||
Literal identifier = popLiteralArray(&interpreter->stack);
|
||||
|
||||
//collect one more argument
|
||||
if (looseFirstArgument) {
|
||||
Literal lit = popLiteralArray(&interpreter->stack);
|
||||
pushLiteralArray(&arguments, lit); //NOTE: also reverses the order
|
||||
freeLiteral(lit);
|
||||
}
|
||||
|
||||
//let's screw with the fn name, too
|
||||
if (looseFirstArgument) {
|
||||
int length = strlen(AS_IDENTIFIER(identifier)) + 1;
|
||||
char buffer[MAX_STRING_LENGTH];
|
||||
snprintf(buffer, MAX_STRING_LENGTH, "_%s", AS_IDENTIFIER(identifier)); //prepend an underscore
|
||||
|
||||
freeLiteral(identifier);
|
||||
identifier = TO_IDENTIFIER_LITERAL(copyString(buffer, length), length);
|
||||
}
|
||||
|
||||
Literal func = identifier;
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &func)) {
|
||||
@@ -1453,81 +1477,6 @@ static bool execIndex(Interpreter* interpreter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execDot(Interpreter* interpreter) {
|
||||
//assume -> compound, first are all on the stack
|
||||
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
Literal tmp = first;
|
||||
first = TO_STRING_LITERAL(copyString(AS_IDENTIFIER(tmp), strlen(AS_IDENTIFIER(tmp))) , strlen(AS_IDENTIFIER(tmp)) );
|
||||
freeLiteral(tmp);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in dot notation\n");
|
||||
printLiteralCustom(compound, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal idn = compound;
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_DICTIONARY(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in dot notation\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_dot";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _dot function\n");
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, TO_NULL_LITERAL); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//clean up
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
freeLiteralArray(&arguments);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execIndexAssign(Interpreter* interpreter) {
|
||||
//assume -> compound, first, second, third, assign are all on the stack
|
||||
|
||||
@@ -1699,161 +1648,6 @@ static bool execIndexAssign(Interpreter* interpreter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool execDotAssign(Interpreter* interpreter) {
|
||||
//assume -> compound, first, assign are all on the stack
|
||||
|
||||
Literal assign = popLiteralArray(&interpreter->stack);
|
||||
Literal first = popLiteralArray(&interpreter->stack);
|
||||
Literal compound = popLiteralArray(&interpreter->stack);
|
||||
|
||||
Literal tmp = first;
|
||||
first = TO_STRING_LITERAL(copyString(AS_IDENTIFIER(tmp), strlen(AS_IDENTIFIER(tmp))) , strlen(AS_IDENTIFIER(tmp)) );
|
||||
freeLiteral(tmp);
|
||||
|
||||
if (!IS_IDENTIFIER(compound)) {
|
||||
interpreter->errorOutput("Unknown literal found in dot assigning notation\n");
|
||||
printLiteralCustom(compound, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal idn = compound;
|
||||
|
||||
if (!parseIdentifierToValue(interpreter, &compound)) {
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IS_DICTIONARY(compound)) {
|
||||
interpreter->errorOutput("Unknown compound found in dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check const-ness of "first" within "compound"
|
||||
Literal type = getScopeType(interpreter->scope, idn);
|
||||
if (AS_TYPE(type).typeOf == LITERAL_DICTIONARY && AS_TYPE(((Literal*)(AS_TYPE(type).subtypes))[1]).constant) {
|
||||
interpreter->errorOutput("couldn't assign to constant within compound within dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
//get the index function
|
||||
Literal func = TO_NULL_LITERAL;
|
||||
char* keyStr = "_dot";
|
||||
Literal key = TO_IDENTIFIER_LITERAL(copyString(keyStr, strlen(keyStr)), strlen(keyStr));
|
||||
|
||||
if (!getScopeVariable(interpreter->scope, key, &func) || !IS_FUNCTION_NATIVE(func)) {
|
||||
interpreter->errorOutput("couldn't get the _dot function\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
freeLiteral(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
//build the opcode
|
||||
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
|
||||
char* opStr = "";
|
||||
switch(opcode) {
|
||||
case OP_VAR_ASSIGN:
|
||||
opStr = "=";
|
||||
break;
|
||||
case OP_VAR_ADDITION_ASSIGN:
|
||||
opStr = "+=";
|
||||
break;
|
||||
case OP_VAR_SUBTRACTION_ASSIGN:
|
||||
opStr = "-=";
|
||||
break;
|
||||
case OP_VAR_MULTIPLICATION_ASSIGN:
|
||||
opStr = "*=";
|
||||
break;
|
||||
case OP_VAR_DIVISION_ASSIGN:
|
||||
opStr = "/=";
|
||||
break;
|
||||
case OP_VAR_MODULO_ASSIGN:
|
||||
opStr = "%=";
|
||||
break;
|
||||
|
||||
default:
|
||||
interpreter->errorOutput("bad opcode in dot assigning notation\n");
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
freeLiteral(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
Literal op = TO_STRING_LITERAL(copyString(opStr, strlen(opStr)), strlen(opStr));
|
||||
|
||||
//build the argument list
|
||||
LiteralArray arguments;
|
||||
initLiteralArray(&arguments);
|
||||
|
||||
pushLiteralArray(&arguments, compound);
|
||||
pushLiteralArray(&arguments, first);
|
||||
pushLiteralArray(&arguments, assign); //it expects an assignment command
|
||||
pushLiteralArray(&arguments, op); //it expects an assignment "opcode"
|
||||
|
||||
//call the function
|
||||
NativeFn fn = (NativeFn)AS_FUNCTION(func).bytecode;
|
||||
fn(interpreter, &arguments);
|
||||
|
||||
//save the result (assume top of the interpreter stack is the new compound value)
|
||||
Literal result = popLiteralArray(&interpreter->stack);
|
||||
if (!setScopeVariable(interpreter->scope, idn, result, true)) {
|
||||
interpreter->errorOutput("Incorrect type assigned to compound member: ");
|
||||
printLiteralCustom(result, interpreter->errorOutput);
|
||||
interpreter->errorOutput("\n");
|
||||
|
||||
//clean up
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteral(key);
|
||||
freeLiteral(type);
|
||||
freeLiteral(result);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(op);
|
||||
return false;
|
||||
}
|
||||
|
||||
//clean up
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(idn);
|
||||
freeLiteral(func);
|
||||
freeLiteralArray(&arguments);
|
||||
freeLiteral(key);
|
||||
freeLiteral(type);
|
||||
freeLiteral(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//the heart of toy
|
||||
static void execInterpreter(Interpreter* interpreter) {
|
||||
//set the starting point for the interpreter
|
||||
@@ -2038,11 +1832,18 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
break;
|
||||
|
||||
case OP_FN_CALL:
|
||||
if (!execFnCall(interpreter)) {
|
||||
if (!execFnCall(interpreter, false)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DOT:
|
||||
if (!execFnCall(interpreter, true)) { //compensate for the out-of-order arguments
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case OP_FN_RETURN:
|
||||
if (!execFnReturn(interpreter)) {
|
||||
return;
|
||||
@@ -2067,24 +1868,12 @@ static void execInterpreter(Interpreter* interpreter) {
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DOT:
|
||||
if (!execDot(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_INDEX_ASSIGN:
|
||||
if (!execIndexAssign(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_DOT_ASSIGN:
|
||||
if (!execDotAssign(interpreter)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_POP_STACK:
|
||||
while (interpreter->stack.count > 0) {
|
||||
freeLiteral(popLiteralArray(&interpreter->stack));
|
||||
@@ -2450,7 +2239,6 @@ void resetInterpreter(Interpreter* interpreter) {
|
||||
|
||||
//globally available functions
|
||||
injectNativeFn(interpreter, "_index", _index);
|
||||
injectNativeFn(interpreter, "_dot", _dot);
|
||||
injectNativeFn(interpreter, "_set", _set);
|
||||
injectNativeFn(interpreter, "_get", _get);
|
||||
injectNativeFn(interpreter, "_push", _push);
|
||||
|
||||
@@ -913,70 +913,6 @@ int _index(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _dot(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//_dot(compound, first, assignValue, opcode)
|
||||
Literal op = popLiteralArray(arguments);
|
||||
Literal assign = popLiteralArray(arguments);
|
||||
Literal first = popLiteralArray(arguments);
|
||||
Literal compound = popLiteralArray(arguments);
|
||||
|
||||
Literal value = getLiteralDictionary(AS_DICTIONARY(compound), first);
|
||||
|
||||
//dictionary
|
||||
if (IS_NULL(op)) {
|
||||
pushLiteralArray(&interpreter->stack, value);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "=")) {
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, assign);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "+=")) {
|
||||
Literal lit = addition(interpreter, value, assign);
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||
freeLiteral(lit);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "-=")) {
|
||||
Literal lit = subtraction(interpreter, value, assign);
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||
freeLiteral(lit);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "*=")) {
|
||||
Literal lit = multiplication(interpreter, value, assign);
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||
freeLiteral(lit);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "/=")) {
|
||||
Literal lit = division(interpreter, value, assign);
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||
freeLiteral(lit);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
else if (!strcmp( AS_STRING(op), "%=")) {
|
||||
Literal lit = modulo(interpreter, value, assign);
|
||||
setLiteralDictionary(AS_DICTIONARY(compound), first, lit);
|
||||
freeLiteral(lit);
|
||||
pushLiteralArray(&interpreter->stack, compound);
|
||||
}
|
||||
|
||||
//cleanup
|
||||
freeLiteral(op);
|
||||
freeLiteral(assign);
|
||||
freeLiteral(first);
|
||||
freeLiteral(compound);
|
||||
freeLiteral(value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _set(Interpreter* interpreter, LiteralArray* arguments) {
|
||||
//if wrong number of arguments, fail
|
||||
if (arguments->count != 3) {
|
||||
|
||||
@@ -207,11 +207,12 @@ void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
void emitFnCall(Node** nodeHandle, Node* arguments) {
|
||||
void emitFnCall(Node** nodeHandle, Node* arguments, int argumentCount) {
|
||||
Node* tmp = ALLOCATE(Node, 1);
|
||||
|
||||
tmp->type = NODE_FN_CALL;
|
||||
tmp->fnCall.arguments = arguments;
|
||||
tmp->fnCall.argumentCount = argumentCount;
|
||||
|
||||
*nodeHandle = tmp;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ typedef struct NodeFnCollection {
|
||||
typedef struct NodeFnCall {
|
||||
NodeType type;
|
||||
Node* arguments;
|
||||
int argumentCount;
|
||||
} NodeFnCall;
|
||||
|
||||
typedef struct NodePath {
|
||||
@@ -162,7 +163,7 @@ void emitNodeCompound(Node** nodeHandle, LiteralType literalType);
|
||||
void setNodePair(Node* node, Node* left, Node* right);
|
||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
||||
void emitNodeFnDecl(Node** nodeHandle, Literal identifier, Node* arguments, Node* returns, Node* block);
|
||||
void emitFnCall(Node** nodeHandle, Node* arguments);
|
||||
void emitFnCall(Node** nodeHandle, Node* arguments, int argumentCount);
|
||||
void emitNodeFnCollection(Node** nodeHandle);
|
||||
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
||||
void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||
|
||||
@@ -50,10 +50,8 @@ typedef enum Opcode {
|
||||
|
||||
//for indexing
|
||||
OP_INDEX,
|
||||
OP_DOT,
|
||||
|
||||
OP_INDEX_ASSIGN,
|
||||
OP_DOT_ASSIGN,
|
||||
OP_DOT,
|
||||
|
||||
//comparison of values
|
||||
OP_COMPARE_EQUAL,
|
||||
|
||||
@@ -677,7 +677,7 @@ static Opcode decrementInfix(Parser* parser, Node** nodeHandle) {
|
||||
}
|
||||
|
||||
static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
||||
advance(parser);
|
||||
advance(parser); //skip the left paren
|
||||
|
||||
//binary() is an infix rule - so only get the RHS of the operator
|
||||
switch(parser->previous.type) {
|
||||
@@ -708,7 +708,7 @@ static Opcode fnCall(Parser* parser, Node** nodeHandle) {
|
||||
}
|
||||
|
||||
//emit the call
|
||||
emitFnCall(nodeHandle, arguments);
|
||||
emitFnCall(nodeHandle, arguments, arguments->fnCollection.count);
|
||||
|
||||
return OP_FN_CALL;
|
||||
}
|
||||
@@ -786,14 +786,17 @@ static Opcode indexAccess(Parser* parser, Node** nodeHandle) {
|
||||
|
||||
static Opcode dot(Parser* parser, Node** nodeHandle) {
|
||||
advance(parser); //for the dot
|
||||
advance(parser); //for the identifier
|
||||
|
||||
Node* first = NULL;
|
||||
Node* node = NULL;
|
||||
|
||||
identifier(parser, &first); //specific case
|
||||
emitNodeDot(nodeHandle, first);
|
||||
parsePrecedence(parser, &node, PREC_CALL);
|
||||
|
||||
return OP_DOT;
|
||||
//hijack the function call, and hack in an extra parameter
|
||||
node->binary.right->fnCall.argumentCount++;
|
||||
node->binary.opcode = OP_DOT;
|
||||
|
||||
(*nodeHandle) = node;
|
||||
return OP_DOT; //signal that the function name and arguments are in the wrong order
|
||||
}
|
||||
|
||||
ParseRule parseRules[] = { //must match the token types
|
||||
|
||||
Reference in New Issue
Block a user