Expression statements and assignemnts are working

This commit is contained in:
2022-08-14 19:57:15 +01:00
parent e9ab6f3f96
commit 4aa6f75ea7
7 changed files with 112 additions and 50 deletions

View File

@@ -52,18 +52,20 @@ print [:];
//test nested compounds
print [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
//not ready yet
//var declarations
var x = 31;
var y : int = 42;
var arr : [int] = [1, 2, 3, 42];
var dict : [string, int] = ["hello": 1, "world":2];
//print x;
//print x + y;
//print arr;
//print dict;
//printing expressions
print x;
print x + y;
print arr;
print dict;
//test asserts at the end of the file
assert x, "This won't be seen";
assert true, "This won't be seen";
assert false, "This is a failed assert, and will end execution";

View File

@@ -110,13 +110,27 @@ static void consumeShort(unsigned short bytes, unsigned char* tb, int* count) {
*count += 2;
}
static Literal parseIdentifierToValue(Interpreter* interpreter, Literal literal) {
//this converts identifiers to values
if (IS_IDENTIFIER(literal)) {
if (!getScopeVariable(interpreter->scope, literal, &literal)) {
printf("Undeclared variable \"");;
printLiteral(literal);
printf("\"\n");
return TO_NULL_LITERAL;
}
}
return literal;
}
//each available statement
static bool execAssert(Interpreter* interpreter) {
Literal rhs = popLiteralArray(&interpreter->stack);
Literal lhs = popLiteralArray(&interpreter->stack);
Literal lhs = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
if (!IS_STRING(rhs)) {
printf("[internal] The interpreter's assert keyword needs a string as the second argument, received: ");
printf("The assert keyword needs a string as the second argument, received: ");
printLiteral(rhs);
printf("\n");
return false;
@@ -132,7 +146,7 @@ static bool execAssert(Interpreter* interpreter) {
static bool execPrint(Interpreter* interpreter) {
//print what is on top of the stack, then pop it
Literal lit = popLiteralArray(&interpreter->stack);
Literal lit = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
printLiteralCustom(lit, interpreter->printOutput);
@@ -152,7 +166,7 @@ static bool execPushLiteral(Interpreter* interpreter, bool lng) {
index = (int)readByte(interpreter->bytecode, &interpreter->count);
}
//push from cache to stack
//push from cache to stack (DO NOT account for identifiers - will do that later)
pushLiteralArray(&interpreter->stack, interpreter->literalCache.literals[index]);
return true;
@@ -160,7 +174,7 @@ static bool execPushLiteral(Interpreter* interpreter, bool lng) {
static bool execNegate(Interpreter* interpreter) {
//negate the top literal on the stack
Literal lit = popLiteralArray(&interpreter->stack);
Literal lit = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
if (IS_INTEGER(lit)) {
lit = TO_INTEGER_LITERAL(-AS_INTEGER(lit));
@@ -180,8 +194,8 @@ static bool execNegate(Interpreter* interpreter) {
}
static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
Literal rhs = popLiteralArray(&interpreter->stack);
Literal lhs = popLiteralArray(&interpreter->stack);
Literal rhs = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
Literal lhs = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
//type coersion
if (IS_FLOAT(lhs) && IS_INTEGER(rhs)) {
@@ -264,7 +278,11 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) {
}
//wrong types
printf("Bad arithmetic argument\n");
printf("Bad arithmetic argument ");
printLiteral(lhs);
printf(" and ");
printLiteral(rhs);
printf("\n");
return false;
}
@@ -286,19 +304,35 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
Literal type = interpreter->literalCache.literals[typeIndex];
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
printf("Can't redefine the variable \"");;
printf("Can't redefine the variable \"");;
printLiteral(identifier);
printf("\"\n");
return false;
}
if (!setScopeVariable(interpreter->scope, identifier, popLiteralArray(&interpreter->stack) )) {
if (!setScopeVariable(interpreter->scope, identifier, parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack)) )) {
return false;
}
return true;
}
static bool execVarAssign(Interpreter* interpreter) {
Literal rhs = parseIdentifierToValue(interpreter, popLiteralArray(&interpreter->stack));
Literal lhs = popLiteralArray(&interpreter->stack);
if (!IS_IDENTIFIER(lhs)) {
printf("Can't assign to a non-variable \"");;
printLiteral(lhs);
printf("\"\n");
return false;
}
setScopeVariable(interpreter->scope, lhs, rhs);
return true;
}
//the heart of toy
static void execInterpreter(Interpreter* interpreter) {
unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count);
@@ -365,6 +399,12 @@ static void execInterpreter(Interpreter* interpreter) {
}
break;
case OP_VAR_ASSIGN:
if (!execVarAssign(interpreter)) {
return;
}
break;
default:
printf("Unknown opcode found %d, terminating\n", opcode);
printLiteralArray(&interpreter->stack, "\n");

View File

@@ -14,7 +14,7 @@ typedef struct Interpreter {
unsigned char* bytecode;
int length;
int count;
LiteralArray literalCache; //read-only - built from the bytecode
LiteralArray literalCache; //read-only - built from the bytecode, refreshed each time new bytecode is provided
//operation
Scope* scope;

View File

@@ -28,9 +28,10 @@ typedef enum Opcode {
OP_TYPE_DECL, //declare a type to be used (as a literal)
OP_TYPE_DECL_LONG, //declare a type to be used (as a long literal)
OP_VAR_DECL,
OP_VAR_DECL_LONG,
// OP_VAR_ASSIGN, //stack: literal name, literal value
OP_VAR_DECL, //declare a variable to be used (as a literal)
OP_VAR_DECL_LONG, //declare a variable to be used (as a long literal)
OP_VAR_ASSIGN, //assign to a literal
//meta
OP_SECTION_END,

View File

@@ -300,6 +300,11 @@ static Opcode binary(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
return OP_MODULO;
}
case TOKEN_ASSIGN: {
parsePrecedence(parser, nodeHandle, PREC_ASSIGNMENT);
return OP_VAR_ASSIGN;
}
default:
error(parser, parser->previous, "Unexpected token passed to binary precedence rule");
return OP_EOF;
@@ -384,6 +389,17 @@ static Opcode atomic(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
}
}
static Opcode identifier(Parser* parser, Node** nodeHandle, bool canBeAssigned) {
//make a copy of the string
Token identifierToken = parser->previous;
char* cpy = copyString(identifierToken.lexeme, identifierToken.length);
Literal identifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
emitNodeLiteral(nodeHandle, identifier);
return OP_EOF;
}
ParseRule parseRules[] = { //must match the token types
//types
{atomic, NULL, PREC_PRIMARY},// TOKEN_NULL,
@@ -419,7 +435,7 @@ ParseRule parseRules[] = { //must match the token types
{NULL, NULL, PREC_NONE},// TOKEN_WHILE,
//literal values
{NULL, NULL, PREC_NONE},// TOKEN_IDENTIFIER,
{identifier, NULL, PREC_PRIMARY},// TOKEN_IDENTIFIER,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_TRUE,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_FALSE,
{atomic, NULL, PREC_PRIMARY},// TOKEN_LITERAL_INTEGER,
@@ -439,6 +455,7 @@ ParseRule parseRules[] = { //must match the token types
{NULL, NULL, PREC_NONE},// TOKEN_MODULO_ASSIGN,
{NULL, NULL, PREC_NONE},// TOKEN_PLUS_PLUS,
{NULL, NULL, PREC_NONE},// TOKEN_MINUS_MINUS,
{NULL, binary, PREC_ASSIGNMENT},// TOKEN_ASSIGN,
//logical operators
{grouping, NULL, PREC_CALL},// TOKEN_PAREN_LEFT,
@@ -458,7 +475,6 @@ ParseRule parseRules[] = { //must match the token types
{NULL, NULL, PREC_NONE},// TOKEN_OR,
//other operators
{NULL, NULL, PREC_NONE},// TOKEN_ASSIGN,
{NULL, NULL, PREC_NONE},// TOKEN_COLON,
{NULL, NULL, PREC_NONE},// TOKEN_SEMICOLON,
{NULL, NULL, PREC_CALL},// TOKEN_COMMA,
@@ -650,26 +666,26 @@ static void expression(Parser* parser, Node** nodeHandle) {
}
//statements
static void blockStmt(Parser* parser, Node* node) {
static void blockStmt(Parser* parser, Node** nodeHandle) {
//init
node->type = NODE_BLOCK;
node->block.nodes = NULL;
node->block.capacity = 0;
node->block.count = 0;
(*nodeHandle)->type = NODE_BLOCK;
(*nodeHandle)->block.nodes = NULL;
(*nodeHandle)->block.capacity = 0;
(*nodeHandle)->block.count = 0;
//sub-scope, compile it and push it up in a node
while (!match(parser, TOKEN_BRACE_RIGHT)) {
if (node->block.capacity < node->block.count + 1) {
int oldCapacity = node->block.capacity;
if ((*nodeHandle)->block.capacity < (*nodeHandle)->block.count + 1) {
int oldCapacity = (*nodeHandle)->block.capacity;
node->block.capacity = GROW_CAPACITY(oldCapacity);
node->block.nodes = GROW_ARRAY(Node, node->block.nodes, oldCapacity, node->block.capacity);
(*nodeHandle)->block.capacity = GROW_CAPACITY(oldCapacity);
(*nodeHandle)->block.nodes = GROW_ARRAY(Node, (*nodeHandle)->block.nodes, oldCapacity, (*nodeHandle)->block.capacity);
}
//use the next node in sequence
node->block.nodes[node->block.count].type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
(*nodeHandle)->block.nodes[(*nodeHandle)->block.count].type = NODE_ERROR; //BUGFIX: so freeing won't break the damn thing
Node* ptr = &(node->block.nodes[node->block.count++]);
Node* ptr = &((*nodeHandle)->block.nodes[(*nodeHandle)->block.count++]);
//process the grammar rule for this line
declaration(parser, &ptr);
@@ -681,53 +697,54 @@ static void blockStmt(Parser* parser, Node* node) {
}
}
static void printStmt(Parser* parser, Node* node) {
static void printStmt(Parser* parser, Node** nodeHandle) {
//set the node info
node->type = NODE_UNARY;
node->unary.opcode = OP_PRINT;
expression(parser, &(node->unary.child));
(*nodeHandle)->type = NODE_UNARY;
(*nodeHandle)->unary.opcode = OP_PRINT;
expression(parser, &((*nodeHandle)->unary.child));
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of print statement");
}
static void assertStmt(Parser* parser, Node* node) {
static void assertStmt(Parser* parser, Node** nodeHandle) {
//set the node info
node->type = NODE_BINARY;
node->unary.opcode = OP_ASSERT;
(*nodeHandle)->type = NODE_BINARY;
(*nodeHandle)->unary.opcode = OP_ASSERT;
parsePrecedence(parser, &(node->binary.left), PREC_PRIMARY);
parsePrecedence(parser, &((*nodeHandle)->binary.left), PREC_PRIMARY);
consume(parser, TOKEN_COMMA, "Expected ',' in assert statement");
parsePrecedence(parser, &(node->binary.right), PREC_PRIMARY);
parsePrecedence(parser, &((*nodeHandle)->binary.right), PREC_PRIMARY);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of assert statement");
}
//precedence functions
static void expressionStmt(Parser* parser, Node* node) {
error(parser, parser->previous, "Expression statements not yet implemented");
static void expressionStmt(Parser* parser, Node** nodeHandle) {
expression(parser, nodeHandle);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at the end of expression statement");
}
static void statement(Parser* parser, Node* node) {
static void statement(Parser* parser, Node** nodeHandle) {
//block
if (match(parser, TOKEN_BRACE_LEFT)) {
blockStmt(parser, node);
blockStmt(parser, nodeHandle);
return;
}
//print
if (match(parser, TOKEN_PRINT)) {
printStmt(parser, node);
printStmt(parser, nodeHandle);
return;
}
//assert
if (match(parser, TOKEN_ASSERT)) {
assertStmt(parser, node);
assertStmt(parser, nodeHandle);
return;
}
//default
expressionStmt(parser, node);
expressionStmt(parser, nodeHandle);
}
//declarations and definitions
@@ -840,7 +857,7 @@ static void declaration(Parser* parser, Node** nodeHandle) { //assume nodeHandle
varDecl(parser, nodeHandle);
}
else {
statement(parser, *nodeHandle);
statement(parser, nodeHandle);
}
}

View File

@@ -78,6 +78,7 @@ unsigned char* compileString(char* source, size_t* size) {
while(node != NULL) {
//pack up and leave
if (node->type == NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
freeNode(node);
freeCompiler(&compiler);
freeParser(&parser);
@@ -163,6 +164,7 @@ void repl() {
while(node != NULL) {
//pack up and restart
if (node->type == NODE_ERROR) {
printf(ERROR "error node detected\n" RESET);
error = true;
freeNode(node);
break;

View File

@@ -55,6 +55,7 @@ typedef enum TokenType {
TOKEN_MODULO_ASSIGN,
TOKEN_PLUS_PLUS,
TOKEN_MINUS_MINUS,
TOKEN_ASSIGN,
//logical operators
TOKEN_PAREN_LEFT,
@@ -74,7 +75,6 @@ typedef enum TokenType {
TOKEN_OR,
//other operators
TOKEN_ASSIGN,
TOKEN_COLON,
TOKEN_SEMICOLON,
TOKEN_COMMA,