mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Increment and decrement operators work
This commit is contained in:
@@ -11,9 +11,9 @@ DONE: for-then
|
|||||||
DONE: break and continue statements
|
DONE: break and continue statements
|
||||||
DONE: truthiness rethink
|
DONE: truthiness rethink
|
||||||
DONE: string concat with the + operator
|
DONE: string concat with the + operator
|
||||||
|
DONE: increment & decrement operators
|
||||||
|
|
||||||
TODO: increment & decrement operators
|
TODO: a = b = c = 1; ?
|
||||||
TODO: a = b = c = 1;
|
|
||||||
TODO: are compounds shallow or deep copies?
|
TODO: are compounds shallow or deep copies?
|
||||||
TODO: functions, and all of their features
|
TODO: functions, and all of their features
|
||||||
TODO: Assertion-based test scripts
|
TODO: Assertion-based test scripts
|
||||||
|
|||||||
@@ -147,6 +147,30 @@ static int writeLiteralTypeToCache(LiteralArray* literalCache, Literal literal)
|
|||||||
return pushLiteralArray(literalCache, lit);
|
return pushLiteralArray(literalCache, lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int writeLiteralToCompiler(Compiler* compiler, Literal literal) {
|
||||||
|
//get the index
|
||||||
|
int index = findLiteralIndex(&compiler->literalCache, literal);
|
||||||
|
if (index < 0) {
|
||||||
|
index = pushLiteralArray(&compiler->literalCache, literal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//push the literal to the bytecode
|
||||||
|
if (index >= 256) {
|
||||||
|
//push a "long" index
|
||||||
|
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
|
||||||
|
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes
|
||||||
|
|
||||||
|
compiler->count += sizeof(unsigned short);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//push the index
|
||||||
|
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr) {
|
static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAddressesPtr, void* continueAddressesPtr) {
|
||||||
//grow if the bytecode space is too small
|
//grow if the bytecode space is too small
|
||||||
if (compiler->capacity < compiler->count + 1) {
|
if (compiler->capacity < compiler->count + 1) {
|
||||||
@@ -166,25 +190,7 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NODE_LITERAL: {
|
case NODE_LITERAL: {
|
||||||
//ensure the literal is in the cache
|
writeLiteralToCompiler(compiler, node->atomic.literal);
|
||||||
int index = findLiteralIndex(&compiler->literalCache, node->atomic.literal);
|
|
||||||
if (index < 0) {
|
|
||||||
index = pushLiteralArray(&compiler->literalCache, node->atomic.literal);
|
|
||||||
}
|
|
||||||
|
|
||||||
//push the node opcode to the bytecode
|
|
||||||
if (index >= 256) {
|
|
||||||
//push a "long" index
|
|
||||||
compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte
|
|
||||||
*((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)index; //2 bytes
|
|
||||||
|
|
||||||
compiler->count += sizeof(unsigned short);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//push the index
|
|
||||||
compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte
|
|
||||||
compiler->bytecode[compiler->count++] = (unsigned char)index; //1 byte
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -461,6 +467,48 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
|
|||||||
compiler->count += sizeof(unsigned short); //2 bytes
|
compiler->count += sizeof(unsigned short); //2 bytes
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_INCREMENT_PREFIX: {
|
||||||
|
//push the literal to the stack (twice)
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
|
||||||
|
//push the increment / decrement
|
||||||
|
Literal increment = TO_INTEGER_LITERAL(node->increment.increment);
|
||||||
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
|
//push the add opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_ADDITION; //1 byte
|
||||||
|
|
||||||
|
//push the assign
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
|
|
||||||
|
//leave the result on the stack
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NODE_INCREMENT_POSTFIX: {
|
||||||
|
//push the identifier's VALUE to the stack
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_LITERAL_RAW; //1 byte
|
||||||
|
|
||||||
|
//push the identifier (twice)
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
writeLiteralToCompiler(compiler, node->increment.identifier);
|
||||||
|
|
||||||
|
//push the increment / decrement
|
||||||
|
Literal increment = TO_INTEGER_LITERAL(node->increment.increment);
|
||||||
|
writeLiteralToCompiler(compiler, increment);
|
||||||
|
|
||||||
|
//push the add opcode
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_ADDITION; //1 byte
|
||||||
|
|
||||||
|
//push the assign
|
||||||
|
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,18 @@ static bool execPushLiteral(Interpreter* interpreter, bool lng) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rawLiteral(Interpreter* interpreter) {
|
||||||
|
Literal lit = popLiteralArray(&interpreter->stack);
|
||||||
|
|
||||||
|
if (!parseIdentifierToValue(interpreter, &lit)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pushLiteralArray(&interpreter->stack, lit);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool execNegate(Interpreter* interpreter) {
|
static bool execNegate(Interpreter* interpreter) {
|
||||||
//negate the top literal on the stack (numbers only)
|
//negate the top literal on the stack (numbers only)
|
||||||
Literal lit = popLiteralArray(&interpreter->stack);
|
Literal lit = popLiteralArray(&interpreter->stack);
|
||||||
@@ -657,6 +669,12 @@ static void execInterpreter(Interpreter* interpreter) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_LITERAL_RAW:
|
||||||
|
if (!rawLiteral(interpreter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OP_NEGATE:
|
case OP_NEGATE:
|
||||||
if (!execNegate(interpreter)) {
|
if (!execNegate(interpreter)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ void freeNode(Node* node) {
|
|||||||
freeNode(node->path.thenPath);
|
freeNode(node->path.thenPath);
|
||||||
freeNode(node->path.elsePath);
|
freeNode(node->path.elsePath);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NODE_INCREMENT_PREFIX:
|
||||||
|
case NODE_INCREMENT_POSTFIX:
|
||||||
|
freeLiteral(node->increment.identifier);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +184,26 @@ void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postC
|
|||||||
*nodeHandle = tmp;
|
*nodeHandle = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emiteNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_INCREMENT_PREFIX;
|
||||||
|
tmp->increment.identifier = identifier;
|
||||||
|
tmp->increment.increment = increment;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emiteNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment) {
|
||||||
|
Node* tmp = ALLOCATE(Node, 1);
|
||||||
|
|
||||||
|
tmp->type = NODE_INCREMENT_POSTFIX;
|
||||||
|
tmp->increment.identifier = identifier;
|
||||||
|
tmp->increment.increment = increment;
|
||||||
|
|
||||||
|
*nodeHandle = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
void printNode(Node* node) {
|
void printNode(Node* node) {
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -271,6 +296,11 @@ void printNode(Node* node) {
|
|||||||
printf(")");
|
printf(")");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// case NODE_INCREMENT_PREFIX:
|
||||||
|
// case NODE_INCREMENT_POSTFIX:
|
||||||
|
// //TODO
|
||||||
|
// break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("[internal] unkown node type in printNode: %d\n", node->type);
|
printf("[internal] unkown node type in printNode: %d\n", node->type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ typedef enum NodeType {
|
|||||||
NODE_PATH_FOR, //for control flow
|
NODE_PATH_FOR, //for control flow
|
||||||
NODE_PATH_BREAK,
|
NODE_PATH_BREAK,
|
||||||
NODE_PATH_CONTINUE,
|
NODE_PATH_CONTINUE,
|
||||||
|
NODE_INCREMENT_PREFIX,
|
||||||
|
NODE_INCREMENT_POSTFIX,
|
||||||
} NodeType;
|
} NodeType;
|
||||||
|
|
||||||
typedef struct NodeLiteral {
|
typedef struct NodeLiteral {
|
||||||
@@ -90,6 +92,12 @@ typedef struct NodePath {
|
|||||||
Node* elsePath;
|
Node* elsePath;
|
||||||
} NodePath;
|
} NodePath;
|
||||||
|
|
||||||
|
typedef struct NodeIncrement {
|
||||||
|
NodeType type;
|
||||||
|
Literal identifier;
|
||||||
|
int increment;
|
||||||
|
} NodeIncrement;
|
||||||
|
|
||||||
union _node {
|
union _node {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
NodeLiteral atomic;
|
NodeLiteral atomic;
|
||||||
@@ -102,6 +110,7 @@ union _node {
|
|||||||
NodeVarTypes varTypes;
|
NodeVarTypes varTypes;
|
||||||
NodeVarDecl varDecl;
|
NodeVarDecl varDecl;
|
||||||
NodePath path;
|
NodePath path;
|
||||||
|
NodeIncrement increment;
|
||||||
};
|
};
|
||||||
|
|
||||||
void freeNode(Node* node);
|
void freeNode(Node* node);
|
||||||
@@ -115,5 +124,7 @@ void emitNodePair(Node** nodeHandle, Node* left, Node* right);
|
|||||||
void emitNodeVarTypes(Node** nodeHandle, Literal literal);
|
void emitNodeVarTypes(Node** nodeHandle, Literal literal);
|
||||||
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
void emitNodeVarDecl(Node** nodeHandle, Literal identifier, Literal type, Node* expression);
|
||||||
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
void emitNodePath(Node** nodeHandle, NodeType type, Node* preClause, Node* postClause, Node* condition, Node* thenPath, Node* elsePath);
|
||||||
|
void emiteNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
|
void emiteNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment);
|
||||||
|
|
||||||
void printNode(Node* node);
|
void printNode(Node* node);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ typedef enum Opcode {
|
|||||||
//data
|
//data
|
||||||
OP_LITERAL,
|
OP_LITERAL,
|
||||||
OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
OP_LITERAL_LONG, //for more than 256 literals in a chunk
|
||||||
|
OP_LITERAL_RAW, //forcibly get the raw value of the literal
|
||||||
|
|
||||||
//arithmetic operators
|
//arithmetic operators
|
||||||
OP_NEGATE,
|
OP_NEGATE,
|
||||||
|
|||||||
@@ -541,6 +541,50 @@ static Opcode castingInfix(Parser* parser, Node** nodeHandle) {
|
|||||||
return OP_TYPE_CAST;
|
return OP_TYPE_CAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Opcode incrementPrefix(Parser* parser, Node** nodeHandle) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
Node* node = NULL;
|
||||||
|
identifier(parser, &node);
|
||||||
|
|
||||||
|
emiteNodePrefixIncrement(nodeHandle, node->atomic.literal, 1);
|
||||||
|
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Opcode incrementInfix(Parser* parser, Node** nodeHandle) {
|
||||||
|
Node* node = NULL;
|
||||||
|
identifier(parser, &node);
|
||||||
|
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
emiteNodePostfixIncrement(nodeHandle, node->atomic.literal, 1);
|
||||||
|
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Opcode decrementPrefix(Parser* parser, Node** nodeHandle) {
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
Node* node = NULL;
|
||||||
|
identifier(parser, &node);
|
||||||
|
|
||||||
|
emiteNodePrefixIncrement(nodeHandle, node->atomic.literal, -1);
|
||||||
|
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Opcode decrementInfix(Parser* parser, Node** nodeHandle) {
|
||||||
|
Node* node = NULL;
|
||||||
|
identifier(parser, &node);
|
||||||
|
|
||||||
|
advance(parser);
|
||||||
|
|
||||||
|
emiteNodePostfixIncrement(nodeHandle, node->atomic.literal, -1);
|
||||||
|
|
||||||
|
return OP_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
ParseRule parseRules[] = { //must match the token types
|
ParseRule parseRules[] = { //must match the token types
|
||||||
//types
|
//types
|
||||||
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
|
||||||
@@ -594,8 +638,8 @@ ParseRule parseRules[] = { //must match the token types
|
|||||||
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_MULTIPLY_ASSIGN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_DIVIDE_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_DIVIDE_ASSIGN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MODULO_ASSIGN,
|
{NULL, NULL, PREC_NONE},// TOKEN_MODULO_ASSIGN,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_PLUS_PLUS,
|
{incrementPrefix, incrementInfix, PREC_CALL},// TOKEN_PLUS_PLUS,
|
||||||
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS,
|
{decrementPrefix, decrementInfix, PREC_CALL},// TOKEN_MINUS_MINUS,
|
||||||
{NULL, binary, PREC_ASSIGNMENT},// TOKEN_ASSIGN,
|
{NULL, binary, PREC_ASSIGNMENT},// TOKEN_ASSIGN,
|
||||||
|
|
||||||
//logical operators
|
//logical operators
|
||||||
@@ -841,6 +885,13 @@ static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule ru
|
|||||||
|
|
||||||
Node* rhsNode = NULL;
|
Node* rhsNode = NULL;
|
||||||
const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser
|
const Opcode opcode = infixRule(parser, &rhsNode); //NOTE: infix rule must advance the parser
|
||||||
|
|
||||||
|
if (opcode == OP_EOF) {
|
||||||
|
freeNode(*nodeHandle);
|
||||||
|
*nodeHandle = rhsNode;
|
||||||
|
return; //we're done here
|
||||||
|
}
|
||||||
|
|
||||||
emitNodeBinary(nodeHandle, rhsNode, opcode);
|
emitNodeBinary(nodeHandle, rhsNode, opcode);
|
||||||
|
|
||||||
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
|
if (!calcStaticBinaryArithmetic(parser, nodeHandle)) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ assert whileCounter == 10, "while-loop failed";
|
|||||||
|
|
||||||
//test for loop
|
//test for loop
|
||||||
var forCache = 0;
|
var forCache = 0;
|
||||||
for (var i = 0; i < 20; i = i + 1) {
|
for (var i = 0; i < 20; i++) {
|
||||||
forCache = i;
|
forCache = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ while (continueWhileCache < 10) {
|
|||||||
|
|
||||||
|
|
||||||
//test break - for
|
//test break - for
|
||||||
for (var i = 0; i < 10; i = i + 1) {
|
for (var i = 0; i < 10; i++) {
|
||||||
if (i >= 7) {
|
if (i >= 7) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ for (var i = 0; i < 10; i = i + 1) {
|
|||||||
|
|
||||||
|
|
||||||
//test break - continue
|
//test break - continue
|
||||||
for (var i = 0; i < 10; i = i + 1) {
|
for (var i = 0; i < 10; i++) {
|
||||||
if (i >= 7) {
|
if (i >= 7) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user