From 55aa6eb273486f6d50b97a016f707c1d9853cb29 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 12 Aug 2022 17:27:57 +0100 Subject: [PATCH] The value is displaying correctly, but not the type --- scripts/small.toy | 2 +- source/compiler.c | 67 ++++++++++++++++++++++++++++++++------- source/interpreter.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ source/opcodes.h | 3 +- source/parser.c | 21 +++++-------- source/repl_main.c | 13 ++++++++ source/scope.c | 5 ++- source/scope.h | 2 +- 8 files changed, 157 insertions(+), 30 deletions(-) diff --git a/scripts/small.toy b/scripts/small.toy index 6976b64..920f5d1 100644 --- a/scripts/small.toy +++ b/scripts/small.toy @@ -1 +1 @@ -var a : [string const, int] = 42; \ No newline at end of file +var name : [string const, int] = ["foo" : 42]; \ No newline at end of file diff --git a/source/compiler.c b/source/compiler.c index c8a0e91..e83b3ce 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -88,7 +88,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, Node* node) { } //push the store to the cache, with instructions about how pack it - index = pushLiteralArray(&compiler->literalCache, TO_DICTIONARY_LITERAL(store)); + index = pushLiteralArray(&compiler->literalCache, TO_DICTIONARY_LITERAL(store)); //pushed as an array, so below can recognize it } else if (node->compound.literalType == LITERAL_ARRAY) { //ensure each literal value is in the cache, individually @@ -128,7 +128,7 @@ static int writeNodeCompoundToCache(Compiler* compiler, Node* node) { return index; } -static int writeLiteralTypeToCache(Compiler* compiler, Literal literal) { +static int writeLiteralTypeToCache(LiteralArray* parent, Literal literal) { int index = -1; //for now, stored as an array @@ -136,9 +136,9 @@ static int writeLiteralTypeToCache(Compiler* compiler, Literal literal) { initLiteralArray(store); //save the mask to the store - int maskIndex = findLiteralIndex(store, TO_INTEGER_LITERAL(AS_TYPE(literal).mask)); + int maskIndex = findLiteralIndex(parent, TO_INTEGER_LITERAL(AS_TYPE(literal).mask)); if (maskIndex < 0) { - maskIndex = pushLiteralArray(store, TO_INTEGER_LITERAL(AS_TYPE(literal).mask)); + maskIndex = pushLiteralArray(parent, TO_INTEGER_LITERAL(AS_TYPE(literal).mask)); } pushLiteralArray(store, TO_INTEGER_LITERAL(maskIndex)); @@ -146,13 +146,13 @@ static int writeLiteralTypeToCache(Compiler* compiler, Literal literal) { //if it's a compound type, recurse if (AS_TYPE(literal).mask & (MASK_ARRAY|MASK_DICTIONARY)) { for (int i = 0; i < AS_TYPE(literal).count; i++) { - int subIndex = writeLiteralTypeToCache(compiler, ((Literal*)(AS_TYPE(literal).subtypes))[i]); + int subIndex = writeLiteralTypeToCache(parent, ((Literal*)(AS_TYPE(literal).subtypes))[i]); pushLiteralArray(store, TO_INTEGER_LITERAL(subIndex)); } } - //push the store to the compiler - index = pushLiteralArray(&compiler->literalCache, TO_ARRAY_LITERAL(store)); + //push the store to the parent + index = pushLiteralArray(parent, TO_ARRAY_LITERAL(store)); return index; } @@ -250,8 +250,8 @@ void writeCompiler(Compiler* compiler, Node* node) { fprintf(stderr, "[Internal] NODE_PAIR encountered in writeCompiler()"); break; - case NODE_VAR_TYPES: { - int index = writeLiteralTypeToCache(compiler, node->varTypes.typeLiteral); + case NODE_VAR_TYPES: { //TODO: the "type" keyword + int index = writeLiteralTypeToCache(&compiler->literalCache, node->varTypes.typeLiteral); //embed the info into the bytecode if (index >= 256) { @@ -269,9 +269,39 @@ void writeCompiler(Compiler* compiler, Node* node) { } break; - // case NODE_VAR_DECL: - // //TODO: OP_VAR_DECL + OP_VAR_ASSIGN - // break; + case NODE_VAR_DECL: { + //first, embed the expression (leaves it on the stack) + writeCompiler(compiler, node->varDecl.expression); + + //write each piece of the declaration to the bytecode + int identifierIndex = findLiteralIndex(&compiler->literalCache, node->varDecl.identifier); + if (identifierIndex < 0) { + identifierIndex = pushLiteralArray(&compiler->literalCache, node->varDecl.identifier); + } + + int typeIndex = writeLiteralTypeToCache(&compiler->literalCache, node->varDecl.typeLiteral); + + //embed the info into the bytecode + if (identifierIndex >= 256 || typeIndex >= 256) { + //push a "long" declaration + compiler->bytecode[compiler->count++] = OP_VAR_DECL_LONG; //1 byte + + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)identifierIndex; //2 bytes + compiler->count += sizeof(unsigned short); + + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)typeIndex; //2 bytes + compiler->count += sizeof(unsigned short); + } + else { + //push a declaration + compiler->bytecode[compiler->count++] = OP_VAR_DECL; //1 byte + compiler->bytecode[compiler->count++] = (unsigned char)identifierIndex; //1 byte + compiler->bytecode[compiler->count++] = (unsigned char)typeIndex; //1 byte + } + } + break; + + //TODO: OP_VAR_ASSIGN } } @@ -428,6 +458,19 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) { } break; + case LITERAL_IDENTIFIER: { + emitByte(&collation, &capacity, &count, LITERAL_IDENTIFIER); + + Literal identifier = compiler->literalCache.literals[i]; + + for (int c = 0; c < STRLEN_I(identifier); c++) { + emitByte(&collation, &capacity, &count, AS_IDENTIFIER(identifier)[c]); + } + + emitByte(&collation, &capacity, &count, '\0'); //terminate the string + } + break; + case LITERAL_TYPE: { emitByte(&collation, &capacity, &count, LITERAL_TYPE); diff --git a/source/interpreter.c b/source/interpreter.c index ef47ef7..a53f5bf 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -250,6 +250,34 @@ static bool execArithmetic(Interpreter* interpreter, Opcode opcode) { return false; } +static bool execVarDecl(Interpreter* interpreter, bool lng) { + //read the index in the cache + int identifierIndex = 0; + int typeIndex = 0; + + if (lng) { + identifierIndex = (int)readShort(interpreter->bytecode, &interpreter->count); + typeIndex = (int)readShort(interpreter->bytecode, &interpreter->count); + } + else { + identifierIndex = (int)readByte(interpreter->bytecode, &interpreter->count); + typeIndex = (int)readByte(interpreter->bytecode, &interpreter->count); + } + + Literal identifier = interpreter->literalCache.literals[identifierIndex]; + Literal type = interpreter->literalCache.literals[typeIndex]; + + if (!declareScopeVariable(interpreter->scope, identifier, type)) { + return false; + } + + if (!setScopeVariable(interpreter->scope, identifier, popLiteralArray(&interpreter->stack) )) { + return false; + } + + return true; +} + //the heart of toy static void execInterpreter(Interpreter* interpreter) { unsigned char opcode = readByte(interpreter->bytecode, &interpreter->count); @@ -307,6 +335,15 @@ static void execInterpreter(Interpreter* interpreter) { interpreter->scope = popScope(interpreter->scope); break; + //TODO: type declarations + + case OP_VAR_DECL: + case OP_VAR_DECL_LONG: + if (!execVarDecl(interpreter, opcode == OP_LITERAL_LONG)) { + return; + } + break; + default: printf("Unknown opcode found %d, terminating\n", opcode); printLiteralArray(&interpreter->stack, "\n"); @@ -449,6 +486,43 @@ void runInterpreter(Interpreter* interpreter) { pushLiteralArray(&interpreter->literalCache, TO_DICTIONARY_LITERAL(dictionary)); } break; + + //TODO: functions + + case LITERAL_IDENTIFIER: { + char* str = readString(interpreter->bytecode, &interpreter->count); + + Literal identifier = TO_IDENTIFIER_LITERAL(str); + + pushLiteralArray(&interpreter->literalCache, identifier); + + if (command.verbose) { + printf("(identifier %s)\n", AS_IDENTIFIER(identifier)); + } + } + break; + + case LITERAL_TYPE: { + Literal typeLiteral; + + // read the mask + unsigned char mask = readByte(interpreter->bytecode, &interpreter->count); + + typeLiteral = TO_TYPE_LITERAL(mask); + + AS_TYPE(typeLiteral).count = readShort(interpreter->bytecode, &interpreter->count); + + //if it's got subtypes, grab them from the existing cache + if (AS_TYPE(typeLiteral).count > 0) { + AS_TYPE(typeLiteral).subtypes = ALLOCATE(Literal, AS_TYPE(typeLiteral).count); + for (int i = 0; i < AS_TYPE(typeLiteral).count; i++) { + //read each index + int index = readShort(interpreter->bytecode, &interpreter->count); + ((Literal*)(AS_TYPE(typeLiteral).subtypes))[i] = interpreter->literalCache.literals[index]; + } + } + } + break; } } diff --git a/source/opcodes.h b/source/opcodes.h index f6f7697..41f7a92 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -28,7 +28,8 @@ 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, //stack: literal name, literal type (referenced by array index) + OP_VAR_DECL, + OP_VAR_DECL_LONG, // OP_VAR_ASSIGN, //stack: literal name, literal value //meta diff --git a/source/parser.c b/source/parser.c index a2b6070..df79dee 100644 --- a/source/parser.c +++ b/source/parser.c @@ -801,25 +801,18 @@ static Literal readTypeToLiteral(Parser* parser) { return literal; } -static void readVarType(Parser* parser, Node** nodeHandle) { - //TODO: custom types with the "type" keyword - - //get the type literal - Literal type = readTypeToLiteral(parser); - - //generate the node - emitNodeVarTypes(nodeHandle, type); -} - static void varDecl(Parser* parser, Node** nodeHandle) { //read the identifier consume(parser, TOKEN_IDENTIFIER, "Expected identifier after var keyword"); Token identifierToken = parser->previous; + Literal identifier = TO_IDENTIFIER_LITERAL(identifierToken.lexeme); + identifier.as.identifier.length = identifierToken.length; //BUGFIX + //read the type, if present - Node* typeNode = NULL; + Literal typeLiteral; if (match(parser, TOKEN_COLON)) { - readVarType(parser, &typeNode); + typeLiteral = readTypeToLiteral(parser); } //variable definition is an expression @@ -830,8 +823,8 @@ static void varDecl(Parser* parser, Node** nodeHandle) { //TODO: static type checking? - //finally - // emitNodeVarDecl(nodeHandle, TO_IDENTIFIER_LITERAL(identifierToken.lexeme), typeNode, expressionNode); + //declare it + emitNodeVarDecl(nodeHandle, identifier, typeLiteral, expressionNode); consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of var declaration"); } diff --git a/source/repl_main.c b/source/repl_main.c index 1e0562a..253ce06 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -105,6 +105,19 @@ void runBinary(unsigned char* tb, size_t size) { Interpreter interpreter; initInterpreter(&interpreter, tb, size); runInterpreter(&interpreter); + + //DEBUG + Literal lit; + + printf("DEBUG> "); + if (getScopeVariable(interpreter.scope, TO_IDENTIFIER_LITERAL("name"), &lit)) { + printLiteral(lit); + } + else { + printf("Failed"); + } + printf("\n"); + freeInterpreter(&interpreter); } diff --git a/source/scope.c b/source/scope.c index 008c0c8..1520ed1 100644 --- a/source/scope.c +++ b/source/scope.c @@ -44,7 +44,10 @@ Scope* popScope(Scope* scope) { } //returns false if error -bool declareScopeVariable(Scope* scope, Literal key) { +bool declareScopeVariable(Scope* scope, Literal key, Literal type) { + //store the type, for later checking on assignment + //TODO + //don't redefine a variable within this scope if (existsLiteralDictionary(&scope->variables, key)) { return false; diff --git a/source/scope.h b/source/scope.h index 7ee7d3c..906f105 100644 --- a/source/scope.h +++ b/source/scope.h @@ -12,7 +12,7 @@ Scope* pushScope(Scope* scope); Scope* popScope(Scope* scope); //returns false if error -bool declareScopeVariable(Scope* scope, Literal key); +bool declareScopeVariable(Scope* scope, Literal key, Literal type); //return false if undefined bool setScopeVariable(Scope* scope, Literal key, Literal value);