Import and export are working

This commit is contained in:
2022-09-05 06:39:05 +01:00
parent dceb83e618
commit 7fb9ebbce0
10 changed files with 266 additions and 12 deletions

View File

@@ -30,9 +30,9 @@ DONE: Address circular references
DONE: are compounds shallow or deep copies? Deep copies DONE: are compounds shallow or deep copies? Deep copies
DONE: third output stream, for lexer/parser/compiler/interpreter errors DONE: third output stream, for lexer/parser/compiler/interpreter errors
DONE: Assertion-based test scripts DONE: Assertion-based test scripts
DONE: Import/export keywords
TODO: Import/export keywords
TODO: slice and dot notation around the builtin _index function TODO: slice and dot notation around the builtin _index function
TODO: ternary operator TODO: ternary operator
TODO: Nullish types? TODO: Nullish types?

View File

@@ -0,0 +1,37 @@
//test basic import/export
{
var variable: int = 42;
export variable as field;
}
{
import field as value;
assert value == 42, "import/export failed";
}
//test functions using import/export
{
fn f() {
import field;
assert field == 42, "import in function failed";
}
}
//test importing/exporting of functions
{
fn func() {
return 69;
}
export func;
}
{
import func;
assert func() == 69, "import/export of functions failed";
}
//TODO: test that variables retain their types with the typeOf keyword
print "All good";

View File

@@ -716,6 +716,26 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd
compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte compiler->bytecode[compiler->count++] = (unsigned char)OP_VAR_ASSIGN; //1 byte
} }
break; break;
case NODE_IMPORT: {
//push the identifier, and the alias
writeLiteralToCompiler(compiler, node->import.identifier);
writeLiteralToCompiler(compiler, node->import.alias);
//push the import opcode
compiler->bytecode[compiler->count++] = (unsigned char)OP_IMPORT; //1 byte
}
break;
case NODE_EXPORT: {
//push the identifier, and the alias
writeLiteralToCompiler(compiler, node->import.identifier);
writeLiteralToCompiler(compiler, node->import.alias);
//push the import opcode
compiler->bytecode[compiler->count++] = (unsigned char)OP_EXPORT; //1 byte
}
break;
} }
} }

View File

@@ -81,6 +81,11 @@ void initInterpreter(Interpreter* interpreter) {
initLiteralArray(&interpreter->stack); initLiteralArray(&interpreter->stack);
interpreter->exports = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(interpreter->exports);
interpreter->exportTypes = ALLOCATE(LiteralDictionary, 1);
initLiteralDictionary(interpreter->exportTypes);
setInterpreterPrint(interpreter, printWrapper); setInterpreterPrint(interpreter, printWrapper);
setInterpreterAssert(interpreter, assertWrapper); setInterpreterAssert(interpreter, assertWrapper);
setInterpreterError(interpreter, errorWrapper); setInterpreterError(interpreter, errorWrapper);
@@ -115,6 +120,11 @@ void freeInterpreter(Interpreter* interpreter) {
interpreter->scope = popScope(interpreter->scope); interpreter->scope = popScope(interpreter->scope);
} }
FREE(LiteralDictionary, interpreter->exports);
interpreter->exports = NULL;
FREE(LiteralDictionary, interpreter->exportTypes);
interpreter->exportTypes = NULL;
freeLiteralArray(&interpreter->literalCache); freeLiteralArray(&interpreter->literalCache);
freeLiteralArray(&interpreter->stack); freeLiteralArray(&interpreter->stack);
} }
@@ -509,7 +519,7 @@ static bool execVarDecl(Interpreter* interpreter, bool lng) {
printLiteralCustom(identifier, interpreter->errorOutput); printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n"); interpreter->errorOutput("\"\n");
freeLiteral(identifier); //TODO: test this freeLiteral(identifier);
freeLiteral(type); freeLiteral(type);
freeLiteral(val); freeLiteral(val);
@@ -1071,6 +1081,8 @@ static bool execFnCall(Interpreter* interpreter) {
inner.codeStart = -1; inner.codeStart = -1;
inner.panic = false; inner.panic = false;
initLiteralArray(&inner.stack); initLiteralArray(&inner.stack);
inner.exports = interpreter->exports;
inner.exportTypes = interpreter->exportTypes;
setInterpreterPrint(&inner, interpreter->printOutput); setInterpreterPrint(&inner, interpreter->printOutput);
setInterpreterAssert(&inner, interpreter->assertOutput); setInterpreterAssert(&inner, interpreter->assertOutput);
setInterpreterError(&inner, interpreter->errorOutput); setInterpreterError(&inner, interpreter->errorOutput);
@@ -1097,7 +1109,9 @@ static bool execFnCall(Interpreter* interpreter) {
//free, and skip out //free, and skip out
freeLiteralArray(&arguments); freeLiteralArray(&arguments);
popScope(inner.scope); popScope(inner.scope);
freeInterpreter(&inner);
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
return false; return false;
} }
@@ -1111,7 +1125,9 @@ static bool execFnCall(Interpreter* interpreter) {
//free, and skip out //free, and skip out
freeLiteralArray(&arguments); freeLiteralArray(&arguments);
popScope(inner.scope); popScope(inner.scope);
freeInterpreter(&inner);
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
return false; return false;
} }
@@ -1131,7 +1147,10 @@ static bool execFnCall(Interpreter* interpreter) {
freeLiteral(arg); freeLiteral(arg);
freeLiteralArray(&arguments); freeLiteralArray(&arguments);
popScope(inner.scope); popScope(inner.scope);
freeInterpreter(&inner);
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
return false; return false;
} }
@@ -1162,7 +1181,9 @@ static bool execFnCall(Interpreter* interpreter) {
freeLiteralArray(&rest); freeLiteralArray(&rest);
freeLiteralArray(&arguments); freeLiteralArray(&arguments);
popScope(inner.scope); popScope(inner.scope);
freeInterpreter(&inner);
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
return false; return false;
} }
@@ -1176,7 +1197,9 @@ static bool execFnCall(Interpreter* interpreter) {
freeLiteral(lit); freeLiteral(lit);
freeLiteralArray(&arguments); freeLiteralArray(&arguments);
popScope(inner.scope); popScope(inner.scope);
freeInterpreter(&inner);
freeLiteralArray(&inner.stack);
freeLiteralArray(&inner.literalCache);
return false; return false;
} }
@@ -1227,7 +1250,7 @@ static bool execFnCall(Interpreter* interpreter) {
freeLiteral(ret); freeLiteral(ret);
} }
//free //manual free
//BUGFIX: handle scopes of functions, which refer to the parent scope (leaking memory) //BUGFIX: handle scopes of functions, which refer to the parent scope (leaking memory)
while(inner.scope != AS_FUNCTION(func).scope) { while(inner.scope != AS_FUNCTION(func).scope) {
for (int i = 0; i < inner.scope->variables.capacity; i++) { for (int i = 0; i < inner.scope->variables.capacity; i++) {
@@ -1284,6 +1307,81 @@ static bool execFnReturn(Interpreter* interpreter) {
return false; return false;
} }
static bool execImport(Interpreter* interpreter) {
Literal alias = popLiteralArray(&interpreter->stack);
Literal identifier = popLiteralArray(&interpreter->stack);
Literal lit = getLiteralDictionary(interpreter->exports, identifier);
Literal type = getLiteralDictionary(interpreter->exportTypes, identifier);
//use the alias
if (!IS_NULL(alias)) {
if (!declareScopeVariable(interpreter->scope, alias, type)) {
interpreter->errorOutput("Can't redefine the variable \"");
printLiteralCustom(alias, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return false;
}
setScopeVariable(interpreter->scope, alias, lit, false);
}
//use the original identifier
else {
if (!declareScopeVariable(interpreter->scope, identifier, type)) {
interpreter->errorOutput("Can't redefine the variable \"");
printLiteralCustom(identifier, interpreter->errorOutput);
interpreter->errorOutput("\"\n");
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return false;
}
setScopeVariable(interpreter->scope, identifier, lit, false);
}
//cleanup
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return true;
}
static bool execExport(Interpreter* interpreter) {
Literal alias = popLiteralArray(&interpreter->stack);
Literal identifier = popLiteralArray(&interpreter->stack);
Literal lit = TO_NULL_LITERAL;
getScopeVariable(interpreter->scope, identifier, &lit);
Literal type = getScopeType(interpreter->scope, identifier);
if (!IS_NULL(alias)) {
setLiteralDictionary(interpreter->exports, alias, lit);
setLiteralDictionary(interpreter->exportTypes, alias, type);
}
else {
setLiteralDictionary(interpreter->exports, identifier, lit);
setLiteralDictionary(interpreter->exportTypes, identifier, type);
}
//cleanup
freeLiteral(lit);
freeLiteral(type);
freeLiteral(alias);
freeLiteral(identifier);
return true;
}
//the heart of toy //the heart of toy
static void execInterpreter(Interpreter* interpreter) { static void execInterpreter(Interpreter* interpreter) {
//set the starting point for the interpreter //set the starting point for the interpreter
@@ -1473,6 +1571,18 @@ static void execInterpreter(Interpreter* interpreter) {
} }
break; break;
case OP_IMPORT:
if (!execImport(interpreter)) {
return;
}
break;
case OP_EXPORT:
if (!execExport(interpreter)) {
return;
}
break;
case OP_POP_STACK: case OP_POP_STACK:
while (interpreter->stack.count > 0) { while (interpreter->stack.count > 0) {
freeLiteral(popLiteralArray(&interpreter->stack)); freeLiteral(popLiteralArray(&interpreter->stack));

View File

@@ -21,7 +21,8 @@ typedef struct Interpreter {
LiteralArray stack; LiteralArray stack;
//output //output
// LiteralDictionary exports; //TODO: read-write - interface with Toy from C LiteralDictionary* exports; //read-write - interface with Toy from C - this is a pointer, since it works at a script-level
LiteralDictionary* exportTypes;
PrintFn printOutput; PrintFn printOutput;
PrintFn assertOutput; PrintFn assertOutput;
PrintFn errorOutput; PrintFn errorOutput;

View File

@@ -93,6 +93,12 @@ void freeNodeCustom(Node* node, bool freeSelf) {
case NODE_INCREMENT_POSTFIX: case NODE_INCREMENT_POSTFIX:
freeLiteral(node->increment.identifier); freeLiteral(node->increment.identifier);
break; break;
case NODE_IMPORT:
case NODE_EXPORT:
freeLiteral(node->import.identifier);
freeLiteral(node->import.alias);
break;
} }
if (freeSelf) { if (freeSelf) {
@@ -246,3 +252,13 @@ void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increme
*nodeHandle = tmp; *nodeHandle = tmp;
} }
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias) {
Node* tmp = ALLOCATE(Node, 1);
tmp->type = mode;
tmp->import.identifier = copyLiteral(identifier);
tmp->import.alias = copyLiteral(alias);
*nodeHandle = tmp;
}

View File

@@ -23,11 +23,13 @@ typedef enum NodeType {
NODE_PATH_IF, //for control flow NODE_PATH_IF, //for control flow
NODE_PATH_WHILE, //for control flow NODE_PATH_WHILE, //for control flow
NODE_PATH_FOR, //for control flow NODE_PATH_FOR, //for control flow
NODE_PATH_BREAK, NODE_PATH_BREAK, //for control flow
NODE_PATH_CONTINUE, NODE_PATH_CONTINUE, //for control flow
NODE_PATH_RETURN, NODE_PATH_RETURN,
NODE_INCREMENT_PREFIX, NODE_INCREMENT_PREFIX,
NODE_INCREMENT_POSTFIX, NODE_INCREMENT_POSTFIX,
NODE_IMPORT,
NODE_EXPORT,
} NodeType; } NodeType;
typedef struct NodeLiteral { typedef struct NodeLiteral {
@@ -116,6 +118,12 @@ typedef struct NodeIncrement {
int increment; int increment;
} NodeIncrement; } NodeIncrement;
typedef struct NodeImport {
NodeType type;
Literal identifier;
Literal alias;
} NodeImport;
union _node { union _node {
NodeType type; NodeType type;
NodeLiteral atomic; NodeLiteral atomic;
@@ -131,6 +139,7 @@ union _node {
NodeFnCall fnCall; NodeFnCall fnCall;
NodePath path; NodePath path;
NodeIncrement increment; NodeIncrement increment;
NodeImport import;
}; };
void freeNode(Node* node); void freeNode(Node* node);
@@ -148,3 +157,4 @@ void emitNodeFnCollection(Node** nodeHandle);
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 emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment); void emitNodePrefixIncrement(Node** nodeHandle, Literal identifier, int increment);
void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment); void emitNodePostfixIncrement(Node** nodeHandle, Literal identifier, int increment);
void emitNodeImport(Node** nodeHandle, NodeType mode, Literal identifier, Literal alias);

View File

@@ -44,6 +44,9 @@ typedef enum Opcode {
OP_TYPE_CAST, //temporarily change a type of an atomic value OP_TYPE_CAST, //temporarily change a type of an atomic value
OP_IMPORT,
OP_EXPORT,
//comparion of values //comparion of values
OP_COMPARE_EQUAL, OP_COMPARE_EQUAL,
OP_COMPARE_NOT_EQUAL, OP_COMPARE_NOT_EQUAL,

View File

@@ -1175,6 +1175,50 @@ static void returnStmt(Parser* parser, Node** nodeHandle) {
emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL); emitNodePath(nodeHandle, NODE_PATH_RETURN, NULL, NULL, NULL, returnValues, NULL);
} }
static void importStmt(Parser* parser, Node** nodeHandle) {
//read the identifier
Node* node = NULL;
advance(parser);
identifier(parser, &node);
Literal idn = copyLiteral(node->atomic.literal);
freeNode(node);
Literal alias = TO_NULL_LITERAL;
if (match(parser, TOKEN_AS)) {
advance(parser);
identifier(parser, &node);
alias = copyLiteral(node->atomic.literal);
freeNode(node);
}
emitNodeImport(nodeHandle, NODE_IMPORT, idn, alias);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of import statement");
}
static void exportStmt(Parser* parser, Node** nodeHandle) {
//read the identifier
Node* node = NULL;
advance(parser);
identifier(parser, &node);
Literal idn = copyLiteral(node->atomic.literal);
freeNode(node);
Literal alias = TO_NULL_LITERAL;
if (match(parser, TOKEN_AS)) {
advance(parser);
identifier(parser, &node);
alias = copyLiteral(node->atomic.literal);
freeNode(node);
}
emitNodeImport(nodeHandle, NODE_EXPORT, idn, alias);
consume(parser, TOKEN_SEMICOLON, "Expected ';' at end of export statement");
}
//precedence functions //precedence functions
static void expressionStmt(Parser* parser, Node** nodeHandle) { static void expressionStmt(Parser* parser, Node** nodeHandle) {
//BUGFIX: check for empty statements //BUGFIX: check for empty statements
@@ -1248,6 +1292,18 @@ static void statement(Parser* parser, Node** nodeHandle) {
return; return;
} }
//import
if (match(parser, TOKEN_IMPORT)) {
importStmt(parser, nodeHandle);
return;
}
//export
if (match(parser, TOKEN_EXPORT)) {
exportStmt(parser, nodeHandle);
return;
}
//default //default
expressionStmt(parser, nodeHandle); expressionStmt(parser, nodeHandle);
} }

View File

@@ -162,13 +162,14 @@ int main() {
{ {
//run each file in ../scripts/test/ //run each file in ../scripts/test/
int count = 14; int count = 15;
char* filenames[] = { char* filenames[] = {
"arithmetic.toy", "arithmetic.toy",
"casting.toy", "casting.toy",
"comparisons.toy", "comparisons.toy",
"dot-and-matrix.toy", "dot-and-matrix.toy",
"functions.toy", "functions.toy",
"imports-and-exports.toy",
"jumps.toy", "jumps.toy",
"jumps-in-functions.toy", "jumps-in-functions.toy",
"logicals.toy", "logicals.toy",