mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Fixed logical AND and OR operators, read more
The definition of '&&': Return the first falsy value, or the last value, skipping the evaluation of other operands. The definition of '||': Return the first truthy value, or the last value, skipping the evaluation of other operands. Toy now follows these definitions. Fixed #154
This commit is contained in:
@@ -0,0 +1,64 @@
|
|||||||
|
//logical short-circuits and chained assignments
|
||||||
|
|
||||||
|
//logical AND
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a + 1 && b + 2;
|
||||||
|
|
||||||
|
assert a == 1, "short circuit 1.1";
|
||||||
|
assert b == 2, "short circuit 1.2";
|
||||||
|
assert c == 4, "short circuit 1.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = (a + 1) && b + 2;
|
||||||
|
|
||||||
|
assert a == 4, "short circuit 2.1";
|
||||||
|
assert b == 2, "short circuit 2.2";
|
||||||
|
assert c == 4, "short circuit 2.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = a + 1 && b + 2;
|
||||||
|
|
||||||
|
assert a == 4, "short circuit 3.1";
|
||||||
|
assert b == 2, "short circuit 3.2";
|
||||||
|
assert c == 4, "short circuit 3.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//logical OR
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a + 1 || b + 2;
|
||||||
|
|
||||||
|
assert a == 1, "short circuit 4.1";
|
||||||
|
assert b == 2, "short circuit 4.2";
|
||||||
|
assert c == 2, "short circuit 4.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = (a + 1) || b + 2;
|
||||||
|
|
||||||
|
assert a == 2, "short circuit 5.1";
|
||||||
|
assert b == 2, "short circuit 5.2";
|
||||||
|
assert c == 2, "short circuit 5.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = a + 1 || b + 2;
|
||||||
|
|
||||||
|
assert a == 2, "short circuit 6.1";
|
||||||
|
assert b == 2, "short circuit 6.2";
|
||||||
|
assert c == 2, "short circuit 6.3";
|
||||||
|
}
|
||||||
|
|||||||
@@ -64,6 +64,17 @@ void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, T
|
|||||||
(*astHandle) = tmp;
|
(*astHandle) = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Toy_private_emitAstBinaryShortCircuit(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||||
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
|
tmp->type = TOY_AST_BINARY_SHORT_CIRCUIT;
|
||||||
|
tmp->binary.flag = flag;
|
||||||
|
tmp->binary.left = *astHandle; //left-recursive
|
||||||
|
tmp->binary.right = right;
|
||||||
|
|
||||||
|
(*astHandle) = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag, Toy_Ast* right) {
|
||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ typedef enum Toy_AstType {
|
|||||||
TOY_AST_VALUE,
|
TOY_AST_VALUE,
|
||||||
TOY_AST_UNARY,
|
TOY_AST_UNARY,
|
||||||
TOY_AST_BINARY,
|
TOY_AST_BINARY,
|
||||||
|
TOY_AST_BINARY_SHORT_CIRCUIT,
|
||||||
TOY_AST_COMPARE,
|
TOY_AST_COMPARE,
|
||||||
TOY_AST_GROUP,
|
TOY_AST_GROUP,
|
||||||
TOY_AST_COMPOUND,
|
TOY_AST_COMPOUND,
|
||||||
@@ -106,6 +107,13 @@ typedef struct Toy_AstBinary {
|
|||||||
Toy_Ast* right;
|
Toy_Ast* right;
|
||||||
} Toy_AstBinary;
|
} Toy_AstBinary;
|
||||||
|
|
||||||
|
typedef struct Toy_AstBinaryShortCircuit {
|
||||||
|
Toy_AstType type;
|
||||||
|
Toy_AstFlag flag;
|
||||||
|
Toy_Ast* left;
|
||||||
|
Toy_Ast* right;
|
||||||
|
} Toy_AstBinaryShortCircuit;
|
||||||
|
|
||||||
typedef struct Toy_AstCompare {
|
typedef struct Toy_AstCompare {
|
||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
Toy_AstFlag flag;
|
Toy_AstFlag flag;
|
||||||
@@ -193,29 +201,30 @@ typedef struct Toy_AstEnd {
|
|||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
} Toy_AstEnd;
|
} Toy_AstEnd;
|
||||||
|
|
||||||
union Toy_Ast { //32 | 64 BITNESS
|
union Toy_Ast { //32 | 64 BITNESS
|
||||||
Toy_AstType type; //4 | 4
|
Toy_AstType type; //4 | 4
|
||||||
Toy_AstBlock block; //16 | 32
|
Toy_AstBlock block; //16 | 32
|
||||||
Toy_AstValue value; //12 | 24
|
Toy_AstValue value; //12 | 24
|
||||||
Toy_AstUnary unary; //12 | 16
|
Toy_AstUnary unary; //12 | 16
|
||||||
Toy_AstBinary binary; //16 | 24
|
Toy_AstBinary binary; //16 | 24
|
||||||
Toy_AstCompare compare; //16 | 24
|
Toy_AstBinaryShortCircuit binaryShortCircuit; //16 | 24
|
||||||
Toy_AstGroup group; //8 | 16
|
Toy_AstCompare compare; //16 | 24
|
||||||
Toy_AstCompound compound; //12 | 16
|
Toy_AstGroup group; //8 | 16
|
||||||
Toy_AstAggregate aggregate; //16 | 24
|
Toy_AstCompound compound; //12 | 16
|
||||||
Toy_AstAssert assert; //16 | 24
|
Toy_AstAggregate aggregate; //16 | 24
|
||||||
Toy_AstIfThenElse ifThenElse; //16 | 32
|
Toy_AstAssert assert; //16 | 24
|
||||||
Toy_AstWhileThen whileThen; //16 | 24
|
Toy_AstIfThenElse ifThenElse; //16 | 32
|
||||||
Toy_AstBreak breakPoint; //4 | 4
|
Toy_AstWhileThen whileThen; //16 | 24
|
||||||
Toy_AstContinue continuePoint; //4 | 4
|
Toy_AstBreak breakPoint; //4 | 4
|
||||||
Toy_AstPrint print; //8 | 16
|
Toy_AstContinue continuePoint; //4 | 4
|
||||||
Toy_AstVarDeclare varDeclare; //16 | 24
|
Toy_AstPrint print; //8 | 16
|
||||||
Toy_AstVarAssign varAssign; //16 | 24
|
Toy_AstVarDeclare varDeclare; //16 | 24
|
||||||
Toy_AstVarAccess varAccess; //8 | 16
|
Toy_AstVarAssign varAssign; //16 | 24
|
||||||
Toy_AstPass pass; //4 | 4
|
Toy_AstVarAccess varAccess; //8 | 16
|
||||||
Toy_AstError error; //4 | 4
|
Toy_AstPass pass; //4 | 4
|
||||||
Toy_AstEnd end; //4 | 4
|
Toy_AstError error; //4 | 4
|
||||||
}; //16 | 32
|
Toy_AstEnd end; //4 | 4
|
||||||
|
}; //16 | 32
|
||||||
|
|
||||||
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_Ast* child);
|
void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_Ast* child);
|
||||||
@@ -223,6 +232,7 @@ void Toy_private_appendAstBlock(Toy_Bucket** bucketHandle, Toy_Ast* block, Toy_A
|
|||||||
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value);
|
void Toy_private_emitAstValue(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Value value);
|
||||||
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag);
|
void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_AstFlag flag);
|
||||||
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
|
void Toy_private_emitAstBinaryShortCircuit(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
void Toy_private_emitAstCompare(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
|
||||||
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||||
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag);
|
void Toy_private_emitAstCompound(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef enum Toy_OpcodeType {
|
|||||||
TOY_OPCODE_ASSIGN_COMPOUND, //assign to a compound's internals
|
TOY_OPCODE_ASSIGN_COMPOUND, //assign to a compound's internals
|
||||||
TOY_OPCODE_ACCESS,
|
TOY_OPCODE_ACCESS,
|
||||||
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
|
||||||
|
TOY_OPCODE_ELIMINATE, //remove the top of the stack
|
||||||
|
|
||||||
//arithmetic instructions
|
//arithmetic instructions
|
||||||
TOY_OPCODE_ADD,
|
TOY_OPCODE_ADD,
|
||||||
|
|||||||
@@ -708,7 +708,13 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
|
|||||||
Toy_private_emitAstAggregate(bucketHandle, rootHandle, flag, ptr);
|
Toy_private_emitAstAggregate(bucketHandle, rootHandle, flag, ptr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
//BUGFIX: '&&' and '||' are special cases, with short-circuit logic
|
||||||
|
if (flag == TOY_AST_FLAG_AND || flag == TOY_AST_FLAG_OR) {
|
||||||
|
Toy_private_emitAstBinaryShortCircuit(bucketHandle, rootHandle, flag, ptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Toy_private_emitAstBinary(bucketHandle, rootHandle, flag, ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -192,13 +192,6 @@ static unsigned int writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast)
|
|||||||
EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
EMIT_BYTE(rt, code,TOY_OPCODE_MODULO);
|
||||||
}
|
}
|
||||||
|
|
||||||
//nowhere to really put these for now
|
|
||||||
else if (ast.flag == TOY_AST_FLAG_AND) {
|
|
||||||
EMIT_BYTE(rt, code,TOY_OPCODE_AND);
|
|
||||||
}
|
|
||||||
else if (ast.flag == TOY_AST_FLAG_OR) {
|
|
||||||
EMIT_BYTE(rt, code,TOY_OPCODE_OR);
|
|
||||||
}
|
|
||||||
else if (ast.flag == TOY_AST_FLAG_CONCAT) {
|
else if (ast.flag == TOY_AST_FLAG_CONCAT) {
|
||||||
EMIT_BYTE(rt, code, TOY_OPCODE_CONCAT);
|
EMIT_BYTE(rt, code, TOY_OPCODE_CONCAT);
|
||||||
}
|
}
|
||||||
@@ -215,6 +208,55 @@ static unsigned int writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast)
|
|||||||
return 1; //leaves only 1 value on the stack
|
return 1; //leaves only 1 value on the stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int writeInstructionBinaryShortCircuit(Toy_Routine** rt, Toy_AstBinaryShortCircuit ast) {
|
||||||
|
//lhs
|
||||||
|
writeRoutineCode(rt, ast.left);
|
||||||
|
|
||||||
|
//duplicate the top (so the lhs can be 'returned' by this expression, if needed)
|
||||||
|
EMIT_BYTE(rt, code,TOY_OPCODE_DUPLICATE);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
|
||||||
|
// && return the first falsy operand, or the last operand
|
||||||
|
if (ast.flag == TOY_AST_FLAG_AND) {
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_JUMP);
|
||||||
|
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
||||||
|
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_IF_FALSE);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// || return the first truthy operand, or the last operand
|
||||||
|
else if (ast.flag == TOY_AST_FLAG_OR) {
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_JUMP);
|
||||||
|
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_RELATIVE);
|
||||||
|
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_IF_TRUE);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary short circuit flag found\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//parameter address
|
||||||
|
unsigned int endAddr = SKIP_INT(rt, code); //parameter to be written later
|
||||||
|
|
||||||
|
//if the lhs value isn't needed, pop it
|
||||||
|
EMIT_BYTE(rt, code,TOY_OPCODE_ELIMINATE);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
|
||||||
|
//rhs
|
||||||
|
writeRoutineCode(rt, ast.right);
|
||||||
|
|
||||||
|
//set the parameter
|
||||||
|
OVERWRITE_INT(rt, code, endAddr, CURRENT_ADDRESS(rt, code) - (endAddr + 4));
|
||||||
|
|
||||||
|
return 1; //leaves only 1 value on the stack
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) {
|
static unsigned int writeInstructionCompare(Toy_Routine** rt, Toy_AstCompare ast) {
|
||||||
//left, then right, then the compare's operation
|
//left, then right, then the compare's operation
|
||||||
writeRoutineCode(rt, ast.left);
|
writeRoutineCode(rt, ast.left);
|
||||||
@@ -683,6 +725,10 @@ static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
result += writeInstructionBinary(rt, ast->binary);
|
result += writeInstructionBinary(rt, ast->binary);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_AST_BINARY_SHORT_CIRCUIT:
|
||||||
|
result += writeInstructionBinaryShortCircuit(rt, ast->binaryShortCircuit);
|
||||||
|
break;
|
||||||
|
|
||||||
case TOY_AST_COMPARE:
|
case TOY_AST_COMPARE:
|
||||||
result += writeInstructionCompare(rt, ast->compare);
|
result += writeInstructionCompare(rt, ast->compare);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -29,6 +29,26 @@ void Toy_freeStack(Toy_Stack* stack) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Toy_resetStack(Toy_Stack** stackHandle) {
|
||||||
|
if ((*stackHandle) == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if some values will be removed, free them first
|
||||||
|
for (unsigned int i = 0; i < (*stackHandle)->count; i++) {
|
||||||
|
Toy_freeValue((*stackHandle)->data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//reset to the stack's default state
|
||||||
|
if ((*stackHandle)->capacity > TOY_STACK_INITIAL_CAPACITY) {
|
||||||
|
(*stackHandle) = realloc((*stackHandle), TOY_STACK_INITIAL_CAPACITY * sizeof(Toy_Value) + sizeof(Toy_Stack));
|
||||||
|
|
||||||
|
(*stackHandle)->capacity = TOY_STACK_INITIAL_CAPACITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*stackHandle)->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value) {
|
void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value) {
|
||||||
//don't go overboard
|
//don't go overboard
|
||||||
if ((*stackHandle)->count >= TOY_STACK_OVERFLOW_THRESHOLD) {
|
if ((*stackHandle)->count >= TOY_STACK_OVERFLOW_THRESHOLD) {
|
||||||
@@ -58,7 +78,7 @@ void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value) {
|
|||||||
|
|
||||||
Toy_Value Toy_peekStack(Toy_Stack** stackHandle) {
|
Toy_Value Toy_peekStack(Toy_Stack** stackHandle) {
|
||||||
if ((*stackHandle)->count == 0) {
|
if ((*stackHandle)->count == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow when peeking\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +87,7 @@ Toy_Value Toy_peekStack(Toy_Stack** stackHandle) {
|
|||||||
|
|
||||||
Toy_Value Toy_popStack(Toy_Stack** stackHandle) {
|
Toy_Value Toy_popStack(Toy_Stack** stackHandle) {
|
||||||
if ((*stackHandle)->count == 0) {
|
if ((*stackHandle)->count == 0) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow when popping\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ typedef struct Toy_Stack { //32 | 64 BITNESS
|
|||||||
|
|
||||||
TOY_API Toy_Stack* Toy_allocateStack(void);
|
TOY_API Toy_Stack* Toy_allocateStack(void);
|
||||||
TOY_API void Toy_freeStack(Toy_Stack* stack);
|
TOY_API void Toy_freeStack(Toy_Stack* stack);
|
||||||
|
TOY_API void Toy_resetStack(Toy_Stack** stackHandle);
|
||||||
|
|
||||||
TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value);
|
TOY_API void Toy_pushStack(Toy_Stack** stackHandle, Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle);
|
TOY_API Toy_Value Toy_peekStack(Toy_Stack** stackHandle);
|
||||||
|
|||||||
@@ -229,7 +229,10 @@ static void processAssign(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//assign it
|
//assign it
|
||||||
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value); //scope now owns value, doesn't need to be freed
|
Toy_assignScope(vm->scope, TOY_VALUE_AS_STRING(name), value); //scope now owns the value, doesn't need to be freed
|
||||||
|
|
||||||
|
//in case of chaining, leave a copy on the stack
|
||||||
|
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(name);
|
Toy_freeValue(name);
|
||||||
@@ -276,6 +279,9 @@ static void processAssignCompound(Toy_VM* vm) {
|
|||||||
//set the value
|
//set the value
|
||||||
array->data[index] = Toy_copyValue(Toy_unwrapValue(value));
|
array->data[index] = Toy_copyValue(Toy_unwrapValue(value));
|
||||||
|
|
||||||
|
//in case of chaining, leave a copy on the stack
|
||||||
|
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(value);
|
Toy_freeValue(value);
|
||||||
}
|
}
|
||||||
@@ -286,6 +292,9 @@ static void processAssignCompound(Toy_VM* vm) {
|
|||||||
//set the value
|
//set the value
|
||||||
Toy_insertTable(&table, Toy_copyValue(Toy_unwrapValue(key)), Toy_copyValue(Toy_unwrapValue(value)));
|
Toy_insertTable(&table, Toy_copyValue(Toy_unwrapValue(key)), Toy_copyValue(Toy_unwrapValue(value)));
|
||||||
|
|
||||||
|
//in case of chaining, leave a copy on the stack
|
||||||
|
Toy_pushStack(&vm->stack, Toy_copyValue(value));
|
||||||
|
|
||||||
//cleanup
|
//cleanup
|
||||||
Toy_freeValue(value);
|
Toy_freeValue(value);
|
||||||
}
|
}
|
||||||
@@ -343,6 +352,12 @@ static void processDuplicate(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void processEliminate(Toy_VM* vm) {
|
||||||
|
//discard the stack top
|
||||||
|
Toy_Value value = Toy_popStack(&vm->stack);
|
||||||
|
Toy_freeValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||||
Toy_Value right = Toy_popStack(&vm->stack);
|
Toy_Value right = Toy_popStack(&vm->stack);
|
||||||
Toy_Value left = Toy_popStack(&vm->stack);
|
Toy_Value left = Toy_popStack(&vm->stack);
|
||||||
@@ -564,7 +579,7 @@ static void processAssert(Toy_VM* vm) {
|
|||||||
|
|
||||||
//determine the args
|
//determine the args
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, "assertion failed"));
|
message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, "assertion failed")); //TODO: needs a better default message
|
||||||
value = Toy_popStack(&vm->stack);
|
value = Toy_popStack(&vm->stack);
|
||||||
}
|
}
|
||||||
else if (count == 2) {
|
else if (count == 2) {
|
||||||
@@ -827,6 +842,10 @@ static void process(Toy_VM* vm) {
|
|||||||
processDuplicate(vm);
|
processDuplicate(vm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_ELIMINATE:
|
||||||
|
processEliminate(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
//arithmetic instructions
|
//arithmetic instructions
|
||||||
case TOY_OPCODE_ADD:
|
case TOY_OPCODE_ADD:
|
||||||
case TOY_OPCODE_SUBTRACT:
|
case TOY_OPCODE_SUBTRACT:
|
||||||
@@ -999,8 +1018,6 @@ void Toy_freeVM(Toy_VM* vm) {
|
|||||||
Toy_popScope(vm->scope);
|
Toy_popScope(vm->scope);
|
||||||
Toy_freeBucket(&vm->stringBucket);
|
Toy_freeBucket(&vm->stringBucket);
|
||||||
Toy_freeBucket(&vm->scopeBucket);
|
Toy_freeBucket(&vm->scopeBucket);
|
||||||
|
|
||||||
Toy_resetVM(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_resetVM(Toy_VM* vm) {
|
void Toy_resetVM(Toy_VM* vm) {
|
||||||
@@ -1020,5 +1037,7 @@ void Toy_resetVM(Toy_VM* vm) {
|
|||||||
|
|
||||||
vm->programCounter = 0;
|
vm->programCounter = 0;
|
||||||
|
|
||||||
//NOTE: stack, scope and memory are not altered during resets
|
Toy_resetStack(&vm->stack);
|
||||||
|
|
||||||
|
//NOTE: scope and memory are not altered during resets
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ int test_sizeof_ast_64bit(void) {
|
|||||||
TEST_SIZEOF(Toy_AstValue, 24);
|
TEST_SIZEOF(Toy_AstValue, 24);
|
||||||
TEST_SIZEOF(Toy_AstUnary, 16);
|
TEST_SIZEOF(Toy_AstUnary, 16);
|
||||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||||
|
TEST_SIZEOF(Toy_AstBinaryShortCircuit, 24);
|
||||||
TEST_SIZEOF(Toy_AstCompare, 24);
|
TEST_SIZEOF(Toy_AstCompare, 24);
|
||||||
TEST_SIZEOF(Toy_AstGroup, 16);
|
TEST_SIZEOF(Toy_AstGroup, 16);
|
||||||
TEST_SIZEOF(Toy_AstCompound, 16);
|
TEST_SIZEOF(Toy_AstCompound, 16);
|
||||||
@@ -60,6 +61,7 @@ int test_sizeof_ast_32bit(void) {
|
|||||||
TEST_SIZEOF(Toy_AstValue, 12);
|
TEST_SIZEOF(Toy_AstValue, 12);
|
||||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||||
|
TEST_SIZEOF(Toy_AstBinaryShortCircuit, 16);
|
||||||
TEST_SIZEOF(Toy_AstCompare, 16);
|
TEST_SIZEOF(Toy_AstCompare, 16);
|
||||||
TEST_SIZEOF(Toy_AstGroup, 8);
|
TEST_SIZEOF(Toy_AstGroup, 8);
|
||||||
TEST_SIZEOF(Toy_AstCompound, 12);
|
TEST_SIZEOF(Toy_AstCompound, 12);
|
||||||
|
|||||||
@@ -49,8 +49,67 @@ print false || false; //false
|
|||||||
print !true; //false
|
print !true; //false
|
||||||
print !false; //true
|
print !false; //true
|
||||||
|
|
||||||
//precedence
|
//logical AND short-circuits and chained assignments
|
||||||
print true && false || true; //URGENT: a grouping warning is needed for this, see issue #154
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a + 1 && b + 2;
|
||||||
|
|
||||||
|
assert a == 1, "short circuit 1.1";
|
||||||
|
assert b == 2, "short circuit 1.2";
|
||||||
|
assert c == 4, "short circuit 1.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = (a + 1) && b + 2;
|
||||||
|
|
||||||
|
assert a == 4, "short circuit 2.1";
|
||||||
|
assert b == 2, "short circuit 2.2";
|
||||||
|
assert c == 4, "short circuit 2.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = a + 1 && b + 2;
|
||||||
|
|
||||||
|
assert a == 4, "short circuit 3.1";
|
||||||
|
assert b == 2, "short circuit 3.2";
|
||||||
|
assert c == 4, "short circuit 3.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
//logical OR short-circuits and chained assignments
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a + 1 || b + 2;
|
||||||
|
|
||||||
|
assert a == 1, "short circuit 4.1";
|
||||||
|
assert b == 2, "short circuit 4.2";
|
||||||
|
assert c == 2, "short circuit 4.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = (a + 1) || b + 2;
|
||||||
|
|
||||||
|
assert a == 2, "short circuit 5.1";
|
||||||
|
assert b == 2, "short circuit 5.2";
|
||||||
|
assert c == 2, "short circuit 5.3";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
var c = a = a + 1 || b + 2;
|
||||||
|
|
||||||
|
assert a == 2, "short circuit 6.1";
|
||||||
|
assert b == 2, "short circuit 6.2";
|
||||||
|
assert c == 2, "short circuit 6.3";
|
||||||
|
}
|
||||||
|
|
||||||
//types
|
//types
|
||||||
var a: int;
|
var a: int;
|
||||||
|
|||||||
Reference in New Issue
Block a user