mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
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.
This commit is contained in:
@@ -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";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -145,9 +162,12 @@ int hashLiteral(Literal 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef enum {
|
||||
// LITERAL_ARRAY,
|
||||
// LITERAL_DICTIONARY,
|
||||
// LITERAL_FUNCTION,
|
||||
LITERAL_IDENTIFIER,
|
||||
} LiteralType;
|
||||
|
||||
typedef struct {
|
||||
@@ -23,13 +24,19 @@ 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;
|
||||
|
||||
@@ -41,24 +48,46 @@ typedef struct {
|
||||
#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_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_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);
|
||||
@@ -66,10 +95,13 @@ void freeLiteral(Literal literal);
|
||||
#define IS_TRUTHY(x) _isTruthy(x)
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "memory.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void freeNode(Node* node) {
|
||||
//don't free a NULL node
|
||||
@@ -31,6 +32,12 @@ void freeNode(Node* node) {
|
||||
case NODE_GROUPING:
|
||||
freeNode(node->grouping.child);
|
||||
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;
|
||||
@@ -106,5 +124,15 @@ void printNode(Node* node) {
|
||||
printNode(node->grouping.child);
|
||||
printf(")");
|
||||
break;
|
||||
|
||||
case NODE_BLOCK:
|
||||
printf("{\n");
|
||||
|
||||
for (int i = 0; i < node->block.count; i++) {
|
||||
printNode(&(node->block.nodes[i]));
|
||||
}
|
||||
|
||||
printf("}\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
86
source/scope.c
Normal file
86
source/scope.c
Normal file
@@ -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;
|
||||
}
|
||||
21
source/scope.h
Normal file
21
source/scope.h
Normal file
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user