From 6d5549fc8e0102d66cc3a93b6341b15971bf508a Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Mon, 8 Aug 2022 15:02:12 +0100 Subject: [PATCH] Added scopes using '{}' symbols, read more I've also added a new literal type called 'identifier'. This will be used for variable names, and has a type mask embedded in it. --- scripts/example.toy | 11 ++++- source/compiler.c | 16 ++++++- source/interpreter.c | 11 +++++ source/interpreter.h | 2 + source/literal.c | 32 +++++++++++--- source/literal.h | 84 +++++++++++++++++++++++++----------- source/literal_dictionary.c | 5 +++ source/literal_dictionary.h | 2 + source/node.c | 48 ++++++++++++++++----- source/node.h | 10 +++++ source/opcodes.h | 2 + source/parser.c | 54 ++++++++++++++++++++--- source/repl_main.c | 19 +------- source/scope.c | 86 +++++++++++++++++++++++++++++++++++++ source/scope.h | 21 +++++++++ 15 files changed, 335 insertions(+), 68 deletions(-) create mode 100644 source/scope.c create mode 100644 source/scope.h diff --git a/scripts/example.toy b/scripts/example.toy index 511acb8..6e7ba23 100644 --- a/scripts/example.toy +++ b/scripts/example.toy @@ -14,7 +14,16 @@ print -69; print -4.20; print 2 + (3 * 3); -assert true, "This won't be seen"; +//test scopes +{ + print "This statement is within a scope."; + { + print "This is a deeper scope."; + } +} +print "Back to the outer scope."; +//test asserts +assert true, "This won't be seen"; assert false, "This is an error"; diff --git a/source/compiler.c b/source/compiler.c index ffbee55..e102ab8 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -33,7 +33,7 @@ void writeCompiler(Compiler* compiler, Node* node) { switch(node->type) { //TODO: more types, like variables, etc. case NODE_ERROR: { - printf("[internal] NODE_ERROR encountered in writeCompiler()"); + fprintf(stderr, "[Internal] NODE_ERROR encountered in writeCompiler()"); compiler->bytecode[compiler->count++] = OP_EOF; //1 byte } break; @@ -80,6 +80,16 @@ void writeCompiler(Compiler* compiler, Node* node) { compiler->bytecode[compiler->count++] = (unsigned char)OP_GROUPING_END; //1 byte break; + case NODE_BLOCK: + compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_BEGIN; //1 byte + + for (int i = 0; i < node->block.count; i++) { + writeCompiler(compiler, &(node->block.nodes[i])); + } + + compiler->bytecode[compiler->count++] = (unsigned char)OP_SCOPE_END; //1 byte + break; + //TODO: conditional } } @@ -202,6 +212,10 @@ unsigned char* collateCompiler(Compiler* compiler, int* size) { emitByte(&collation, &capacity, &count, '\0'); //terminate the string } break; + + default: + fprintf(stderr, "[Internal] Unknown literal type encountered within literal cache\n"); + return NULL; } } diff --git a/source/interpreter.c b/source/interpreter.c index b557e47..37fb6ad 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -19,6 +19,7 @@ static void stderrWrapper(const char* output) { void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int length) { initLiteralArray(&interpreter->literalCache); + interpreter->scope = pushScope(NULL); interpreter->bytecode = bytecode; interpreter->length = length; interpreter->count = 0; @@ -31,6 +32,7 @@ void initInterpreter(Interpreter* interpreter, unsigned char* bytecode, int leng void freeInterpreter(Interpreter* interpreter) { freeLiteralArray(&interpreter->literalCache); + interpreter->scope = popScope(interpreter->scope); FREE_ARRAY(char, interpreter->bytecode, interpreter->length); freeLiteralArray(&interpreter->stack); } @@ -283,6 +285,15 @@ static void execInterpreter(Interpreter* interpreter) { case OP_GROUPING_END: return; + //scope + case OP_SCOPE_BEGIN: + interpreter->scope = pushScope(interpreter->scope); + break; + + case OP_SCOPE_END: + interpreter->scope = popScope(interpreter->scope); + break; + default: printf("Unknown opcode found %d, terminating\n", opcode); printLiteralArray(&interpreter->stack, "\n"); diff --git a/source/interpreter.h b/source/interpreter.h index 4e887c7..b4b6bf5 100644 --- a/source/interpreter.h +++ b/source/interpreter.h @@ -4,12 +4,14 @@ #include "literal_array.h" #include "literal_dictionary.h" +#include "scope.h" typedef void (*PrintFn)(const char*); //the interpreter acts depending on the bytecode instructions typedef struct Interpreter { LiteralArray literalCache; //generally doesn't change after initialization + Scope* scope; unsigned char* bytecode; int length; int count; diff --git a/source/literal.c b/source/literal.c index d19a511..17c5a3c 100644 --- a/source/literal.c +++ b/source/literal.c @@ -43,9 +43,16 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) { } break; + case LITERAL_IDENTIFIER: { + char buffer[256]; + snprintf(buffer, 256, "%.*s", STRLEN_I(literal), AS_IDENTIFIER(literal)); + printFn(buffer); + } + break; + default: //should never bee seen - fprintf(stderr, "[Internal] Unrecognized literal type: %d", literal.type); + fprintf(stderr, "[Internal] Unrecognized literal type in print: %d\n", literal.type); } } @@ -60,8 +67,12 @@ bool _isTruthy(Literal x) { return (IS_NULL(x) || (IS_BOOLEAN(x) && AS_BOOLEAN(x)) || (IS_INTEGER(x) && AS_INTEGER(x) != 0) || (IS_FLOAT(x) && AS_FLOAT(x) != 0)); } -Literal _toStringLiteral(char* cstr) { - return ((Literal){LITERAL_STRING, { .string.ptr = (char*)cstr, .string.length = strlen((char*)cstr) }}); +Literal _toStringLiteral(char* str) { + return ((Literal){LITERAL_STRING, {.string.ptr = (char*)str, .string.length = strlen((char*)str)}}); +} + +Literal _toIdentifierLiteral(char* str, unsigned char types) { + return ((Literal){LITERAL_IDENTIFIER,{.identifier.ptr = (char*)str,.identifier.length = strlen((char*)str),.identifier.types = types}}); } char* copyString(char* original, int length) { @@ -102,9 +113,15 @@ bool literalsAreEqual(Literal lhs, Literal rhs) { } return !strncmp(AS_STRING(lhs), AS_STRING(rhs), STRLEN(lhs)); + case LITERAL_IDENTIFIER: + if (STRLEN_I(lhs) != STRLEN_I(rhs)) { + return false; + } + return !strncmp(AS_IDENTIFIER(lhs), AS_IDENTIFIER(rhs), STRLEN_I(lhs)); + default: //should never bee seen - fprintf(stderr, "[Internal] Unrecognized literal type: %d", lhs.type); + fprintf(stderr, "[Internal] Unrecognized literal type: %d\n", lhs.type); return false; } } @@ -140,14 +157,17 @@ int hashLiteral(Literal lit) { return hash((unsigned int)AS_INTEGER(lit)); case LITERAL_FLOAT: - return hash( *(unsigned int*)(&AS_FLOAT(lit)) ); + return hash(*(unsigned int*)(&AS_FLOAT(lit))); case LITERAL_STRING: return hashString(AS_STRING(lit), STRLEN(lit)); + case LITERAL_IDENTIFIER: + return hashString(AS_IDENTIFIER(lit), STRLEN_I(lit)); + default: //should never bee seen - fprintf(stderr, "[Internal] Unrecognized literal type in hash: %d", lit.type); + fprintf(stderr, "[Internal] Unrecognized literal type in hash: %d\n", lit.type); return 0; } } diff --git a/source/literal.h b/source/literal.h index 15ae44a..e5b13ee 100644 --- a/source/literal.h +++ b/source/literal.h @@ -13,6 +13,7 @@ typedef enum { // LITERAL_ARRAY, // LITERAL_DICTIONARY, // LITERAL_FUNCTION, + LITERAL_IDENTIFIER, } LiteralType; typedef struct { @@ -23,53 +24,84 @@ typedef struct { float number; struct { char* ptr; - int length; //could possibly cut it down further by removing this + int length; } string; // //experimental // void* array; // void* dictionary; // void* function; + + struct { //for variable names + char* ptr; + int length; + unsigned char types; + } identifier; } as; } Literal; -#define IS_NULL(value) ((value).type == LITERAL_NULL) -#define IS_BOOLEAN(value) ((value).type == LITERAL_BOOLEAN) -#define IS_INTEGER(value) ((value).type == LITERAL_INTEGER) -#define IS_FLOAT(value) ((value).type == LITERAL_FLOAT) -#define IS_STRING(value) ((value).type == LITERAL_STRING) -#define IS_ARRAY(value) ((value).type == LITERAL_ARRAY) -#define IS_DICTIONARY(value) ((value).type == LITERAL_DICTIONARY) -#define IS_FUNCTION(value) ((value).type == LITERAL_FUNCTION) +#define IS_NULL(value) ((value).type == LITERAL_NULL) +#define IS_BOOLEAN(value) ((value).type == LITERAL_BOOLEAN) +#define IS_INTEGER(value) ((value).type == LITERAL_INTEGER) +#define IS_FLOAT(value) ((value).type == LITERAL_FLOAT) +#define IS_STRING(value) ((value).type == LITERAL_STRING) +#define IS_ARRAY(value) ((value).type == LITERAL_ARRAY) +#define IS_DICTIONARY(value) ((value).type == LITERAL_DICTIONARY) +#define IS_FUNCTION(value) ((value).type == LITERAL_FUNCTION) +#define IS_IDENTIFIER(value) ((value).type == LITERAL_IDENTIFIER) -#define AS_BOOLEAN(value) ((value).as.boolean) -#define AS_INTEGER(value) ((value).as.integer) -#define AS_FLOAT(value) ((value).as.number) -#define AS_STRING(value) ((value).as.string.ptr) -// #define AS_ARRAY_PTR(value) -// #define AS_DICTIONARY_PTR(value) -// #define AS_FUNCTION_PTR(value) ((Function*)((value).as.function)) +#define AS_BOOLEAN(value) ((value).as.boolean) +#define AS_INTEGER(value) ((value).as.integer) +#define AS_FLOAT(value) ((value).as.number) +#define AS_STRING(value) ((value).as.string.ptr) +// #define AS_ARRAY(value) +// #define AS_DICTIONARY(value) +// #define AS_FUNCTION(value) +#define AS_IDENTIFIER(value) ((value).as.identifier.ptr) -#define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }}) -#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }}) -#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }}) -#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }}) -#define TO_STRING_LITERAL(value) _toStringLiteral(value) -// #define TO_ARRAY_PTR -// #define TO_DICTIONARY_PTR -// #define TO_FUNCTION_PTR(value) ((Literal){LITERAL_FUNCTION, { .function = (Function*)value }}) +#define TO_NULL_LITERAL ((Literal){LITERAL_NULL, { .integer = 0 }}) +#define TO_BOOLEAN_LITERAL(value) ((Literal){LITERAL_BOOLEAN, { .boolean = value }}) +#define TO_INTEGER_LITERAL(value) ((Literal){LITERAL_INTEGER, { .integer = value }}) +#define TO_FLOAT_LITERAL(value) ((Literal){LITERAL_FLOAT, { .number = value }}) +#define TO_STRING_LITERAL(value) _toStringLiteral(value) +// #define TO_ARRAY_LITERAL +// #define TO_DICTIONARY_LITERAL +// #define TO_FUNCTION_LITERAL +#define TO_IDENTIFIER_LITERAL(value, types) _toIdentifierLiteral(value, types) +#define MASK(x) (1 >> (x)) +#define TYPE_CONST 0 +#define TYPE_BOOLEAN 1 +#define TYPE_INTEGER 2 +#define TYPE_FLOAT 3 +#define TYPE_STRING 4 +#define TYPE_ARRAY 5 +#define TYPE_DICTIONARY 6 +#define TYPE_FUNCTION 7 +#define MASK_CONST (MASK(TYPE_CONST)) +#define MASK_BOOLEAN (MASK(TYPE_BOOLEAN)) +#define MASK_INTEGER (MASK(TYPE_INTEGER)) +#define MASK_FLOAT (MASK(TYPE_FLOAT)) +#define MASK_STRING (MASK(TYPE_STRING)) +#define MASK_ARRAY (MASK(TYPE_ARRAY)) +#define MASK_DICTIONARY (MASK(TYPE_DICTIONARY)) +#define MASK_FUNCTION (MASK(TYPE_FUNCTION)) + +//utils void printLiteral(Literal literal); void printLiteralCustom(Literal literal, void (printFn)(const char*)); void freeLiteral(Literal literal); #define IS_TRUTHY(x) _isTruthy(x) -#define STRLEN(lit) ((lit).as.string.length) +#define STRLEN(lit) ((lit).as.string.length) +#define STRLEN_I(lit) ((lit).as.identifier.length) +#define TYPES(lit) ((lit).as.identifier.types) //BUGFIX: macros are not functions bool _isTruthy(Literal x); -Literal _toStringLiteral(char* cstr); +Literal _toStringLiteral(char* str); +Literal _toIdentifierLiteral(char* str, unsigned char types); //utils char* copyString(char* original, int length); diff --git a/source/literal_dictionary.c b/source/literal_dictionary.c index ef9873a..7c524d6 100644 --- a/source/literal_dictionary.c +++ b/source/literal_dictionary.c @@ -199,3 +199,8 @@ void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key) { } } +bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key) { + //null & not tombstoned + _entry* entry = getEntryArray(dictionary->entries, dictionary->capacity, key, hashLiteral(key), false); + return !(IS_NULL(entry->key) && IS_NULL(entry->value)); +} \ No newline at end of file diff --git a/source/literal_dictionary.h b/source/literal_dictionary.h index 629ff64..0523be9 100644 --- a/source/literal_dictionary.h +++ b/source/literal_dictionary.h @@ -23,3 +23,5 @@ void freeLiteralDictionary(LiteralDictionary* dictionary); void setLiteralDictionary(LiteralDictionary* dictionary, Literal key, Literal value); Literal getLiteralDictionary(LiteralDictionary* dictionary, Literal key); void removeLiteralDictionary(LiteralDictionary* dictionary, Literal key); + +bool existsLiteralDictionary(LiteralDictionary* dictionary, Literal key); diff --git a/source/node.c b/source/node.c index 260ac9d..0b14703 100644 --- a/source/node.c +++ b/source/node.c @@ -3,6 +3,7 @@ #include "memory.h" #include +#include void freeNode(Node* node) { //don't free a NULL node @@ -13,24 +14,30 @@ void freeNode(Node* node) { switch(node->type) { case NODE_ERROR: //NO-OP - break; + break; case NODE_LITERAL: freeLiteral(node->atomic.literal); - break; + break; case NODE_UNARY: freeNode(node->unary.child); - break; + break; case NODE_BINARY: freeNode(node->binary.left); freeNode(node->binary.right); - break; + break; case NODE_GROUPING: freeNode(node->grouping.child); - break; + break; + + case NODE_BLOCK: + for (int i = 0; i < node->block.count; i++) { + freeNode(node->block.nodes + i); + } + break; } FREE(Node, node); @@ -73,6 +80,17 @@ void emitNodeGrouping(Node** nodeHandle) { *nodeHandle = tmp; } +void emitNodeBlock(Node** nodeHandle) { + Node* tmp = ALLOCATE(Node, 1); + + tmp->type = NODE_BLOCK; + tmp->block.nodes = NULL; + tmp->block.capacity = 0; + tmp->block.count = 0; + + *nodeHandle = tmp; +} + void printNode(Node* node) { if (node == NULL) { return; @@ -81,17 +99,17 @@ void printNode(Node* node) { switch(node->type) { case NODE_ERROR: printf("error"); - break; + break; case NODE_LITERAL: printf("literal:"); printLiteral(node->atomic.literal); - break; + break; case NODE_UNARY: printf("unary:"); printNode(node->unary.child); - break; + break; case NODE_BINARY: printf("binary-left:"); @@ -99,12 +117,22 @@ void printNode(Node* node) { printf(";binary-right:"); printNode(node->binary.right); printf(";"); - break; + break; case NODE_GROUPING: printf("("); printNode(node->grouping.child); printf(")"); - break; + break; + + case NODE_BLOCK: + printf("{\n"); + + for (int i = 0; i < node->block.count; i++) { + printNode(&(node->block.nodes[i])); + } + + printf("}\n"); + break; } } \ No newline at end of file diff --git a/source/node.h b/source/node.h index 9d24f48..fb3b7a7 100644 --- a/source/node.h +++ b/source/node.h @@ -12,6 +12,7 @@ typedef enum NodeType { NODE_UNARY, //one child NODE_BINARY, //two children, left and right NODE_GROUPING, //one child + NODE_BLOCK, //contains bytecode // NODE_CONDITIONAL, //three children: conditional, then path, else path } NodeType; @@ -38,12 +39,20 @@ typedef struct NodeGrouping { Node* child; } NodeGrouping; +typedef struct NodeBlock { + NodeType type; + Node* nodes; + int capacity; + int count; +} NodeBlock; + union _node { NodeType type; NodeLiteral atomic; NodeUnary unary; NodeBinary binary; NodeGrouping grouping; + NodeBlock block; }; void freeNode(Node* node); @@ -51,6 +60,7 @@ void emitNodeLiteral(Node** nodeHandle, Literal literal); void emitNodeUnary(Node** nodeHandle, Opcode opcode); void emitNodeBinary(Node** nodeHandle, Node* rhs, Opcode opcode); void emitNodeGrouping(Node** nodeHandle); +void emitNodeBlock(Node** nodeHandle); void printNode(Node* node); diff --git a/source/opcodes.h b/source/opcodes.h index b9fa2d6..599fb0b 100644 --- a/source/opcodes.h +++ b/source/opcodes.h @@ -20,6 +20,8 @@ typedef enum Opcode { OP_MODULO, OP_GROUPING_BEGIN, OP_GROUPING_END, + OP_SCOPE_BEGIN, + OP_SCOPE_END, //meta OP_SECTION_END, diff --git a/source/parser.c b/source/parser.c index f518f62..935e185 100644 --- a/source/parser.c +++ b/source/parser.c @@ -111,6 +111,7 @@ typedef struct { ParseRule parseRules[]; //forward declarations +static void declaration(Parser* parser, Node** nodeHandle); static void parsePrecedence(Parser* parser, Node** nodeHandle, PrecedenceRule rule); //the expression rules @@ -523,6 +524,37 @@ static void expression(Parser* parser, Node** nodeHandle) { } //statements +static void blockStmt(Parser* parser, Node* node) { + //init + node->type = NODE_BLOCK; + node->block.nodes = NULL; + node->block.capacity = 0; + node->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; + + node->block.capacity = GROW_CAPACITY(oldCapacity); + node->block.nodes = GROW_ARRAY(Node, node->block.nodes, oldCapacity, node->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 + + Node* ptr = &(node->block.nodes[node->block.count++]); + + //process the grammar rule for this line + declaration(parser, &ptr); + + // Ground floor: perfumery / Stationery and leather goods / Wigs and haberdashery / Kitchenware and food / Going up! + if (parser->panic) { + return; + } + } +} + static void printStmt(Parser* parser, Node* node) { //set the node info node->type = NODE_UNARY; @@ -550,6 +582,12 @@ static void expressionStmt(Parser* parser, Node* node) { } static void statement(Parser* parser, Node* node) { + //block + if (match(parser, TOKEN_BRACE_LEFT)) { + blockStmt(parser, node); + return; + } + //print if (match(parser, TOKEN_PRINT)) { printStmt(parser, node); @@ -567,14 +605,9 @@ static void statement(Parser* parser, Node* node) { } static void declaration(Parser* parser, Node** nodeHandle) { - statement(parser, *nodeHandle); + //TODO: variable declarations - if (parser->panic) { - synchronize(parser); - //return an error node for this iteration - *nodeHandle = ALLOCATE(Node, 1); - (*nodeHandle)->type = NODE_ERROR; - } + statement(parser, *nodeHandle); } //exposed functions @@ -610,5 +643,12 @@ Node* scanParser(Parser* parser) { //process the grammar rule for this line declaration(parser, &node); + if (parser->panic) { + synchronize(parser); + //return an error node for this iteration + node = ALLOCATE(Node, 1); + node->type = NODE_ERROR; + } + return node; } diff --git a/source/repl_main.c b/source/repl_main.c index 97f7036..5510305 100644 --- a/source/repl_main.c +++ b/source/repl_main.c @@ -194,23 +194,8 @@ void debug() { initLiteralDictionary(&dictionary); - for (int i = 0; i < 100; i++) { - setLiteralDictionary(&dictionary, TO_INTEGER_LITERAL(i), TO_INTEGER_LITERAL(i * 2)); - } - - for (int i = 0; i < 100; i++) { - printf("%d: ", i); - printLiteral( getLiteralDictionary(&dictionary, TO_INTEGER_LITERAL(i)) ); - printf("\n"); - } - - printf("-------------"); - - for (int i = 0; i < dictionary.capacity; i++) { - printf("%d: ", i); - printLiteral(dictionary.entries[i].key); - printf("\n"); - } + setLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER), TO_INTEGER_LITERAL(2)); + printLiteral( getLiteralDictionary(&dictionary, TO_IDENTIFIER_LITERAL("variable", MASK_INTEGER)) ); freeLiteralDictionary(&dictionary); } diff --git a/source/scope.c b/source/scope.c new file mode 100644 index 0000000..008c0c8 --- /dev/null +++ b/source/scope.c @@ -0,0 +1,86 @@ +#include "scope.h" + +#include "memory.h" + +//run up the ancestor chain, freeing anything with 0 references left +static void freeAncestorChain(Scope* scope) { + scope->references--; + + //free scope chain + if (scope->ancestor != NULL) { + freeAncestorChain(scope->ancestor); + } + + if (scope->references > 0) { + return; + } + + freeLiteralDictionary(&scope->variables); + + FREE(Scope, scope); +} + +//exposed functions +Scope* pushScope(Scope* ancestor) { + Scope* scope = ALLOCATE(Scope, 1); + scope->ancestor = ancestor; + initLiteralDictionary(&scope->variables); + + //tick up all scope reference counts + scope->references = 0; + for (Scope* ptr = scope; ptr; ptr = ptr->ancestor) { + ptr->references++; + } + + return scope; +} + +Scope* popScope(Scope* scope) { + Scope* ret = scope->ancestor; + + freeAncestorChain(scope); + + return ret; +} + +//returns false if error +bool declareScopeVariable(Scope* scope, Literal key) { + //don't redefine a variable within this scope + if (existsLiteralDictionary(&scope->variables, key)) { + return false; + } + + setLiteralDictionary(&scope->variables, key, TO_NULL_LITERAL); + return true; +} + +//return false if undefined +bool setScopeVariable(Scope* scope, Literal key, Literal value) { + //dead end + if (scope == NULL) { + return false; + } + + //if it's not in this scope, keep searching up the chain + if (!existsLiteralDictionary(&scope->variables, key)) { + return setScopeVariable(scope->ancestor, key, value); + } + + setLiteralDictionary(&scope->variables, key, value); + return true; +} + +bool getScopeVariable(Scope* scope, Literal key, Literal* valueHandle) { + //dead end + if (scope == NULL) { + return false; + } + + //if it's not in this scope, keep searching up the chain + if (!existsLiteralDictionary(&scope->variables, key)) { + return getScopeVariable(scope->ancestor, key, valueHandle); + } + + *valueHandle = getLiteralDictionary(&scope->variables, key); + return true; +} diff --git a/source/scope.h b/source/scope.h new file mode 100644 index 0000000..3e21fb7 --- /dev/null +++ b/source/scope.h @@ -0,0 +1,21 @@ +#pragma once + +#include "common.h" +#include "literal_dictionary.h" + +typedef struct Scope { + LiteralDictionary variables; + struct Scope* ancestor; + int references; //how many scopes point here +} Scope; + +Scope* pushScope(Scope* scope); +Scope* popScope(Scope* scope); + +//returns false if error +bool declareScopeVariable(Scope* scope, Literal key); + +//return false if undefined +bool setScopeVariable(Scope* scope, Literal key, Literal value); +bool getScopeVariable(Scope* scope, Literal key, Literal* value); +