mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Implemented scopes
This commit is contained in:
22
scripts/testificate.toy
Normal file
22
scripts/testificate.toy
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
//normal scope stuff
|
||||||
|
var answer = 42;
|
||||||
|
print answer;
|
||||||
|
|
||||||
|
{
|
||||||
|
var answer = 7;
|
||||||
|
print answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
print answer;
|
||||||
|
|
||||||
|
//I wonder if...
|
||||||
|
var question = 42;
|
||||||
|
print question;
|
||||||
|
|
||||||
|
{
|
||||||
|
var question = question;
|
||||||
|
print question;
|
||||||
|
}
|
||||||
|
|
||||||
|
print question;
|
||||||
@@ -4,6 +4,7 @@ void Toy_private_initAstBlock(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
|||||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||||
|
|
||||||
tmp->type = TOY_AST_BLOCK;
|
tmp->type = TOY_AST_BLOCK;
|
||||||
|
tmp->block.innerScope = false;
|
||||||
tmp->block.child = NULL;
|
tmp->block.child = NULL;
|
||||||
tmp->block.next = NULL;
|
tmp->block.next = NULL;
|
||||||
tmp->block.tail = NULL;
|
tmp->block.tail = NULL;
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ typedef union Toy_Ast Toy_Ast;
|
|||||||
|
|
||||||
typedef struct Toy_AstBlock {
|
typedef struct Toy_AstBlock {
|
||||||
Toy_AstType type;
|
Toy_AstType type;
|
||||||
|
bool innerScope;
|
||||||
Toy_Ast* child; //begin encoding the line
|
Toy_Ast* child; //begin encoding the line
|
||||||
Toy_Ast* next; //'next' is either an AstBlock or null
|
Toy_Ast* next; //'next' is either an AstBlock or null
|
||||||
Toy_Ast* tail; //'tail' - either points to the tail of the current list, or null; only used by the head of a list as an optimisation
|
Toy_Ast* tail; //'tail' - either points to the tail of the current list, or null; only used by the head of a list as an optimisation
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ typedef enum Toy_OpcodeType {
|
|||||||
//control instructions
|
//control instructions
|
||||||
TOY_OPCODE_RETURN,
|
TOY_OPCODE_RETURN,
|
||||||
|
|
||||||
|
TOY_OPCODE_SCOPE_PUSH,
|
||||||
|
TOY_OPCODE_SCOPE_POP,
|
||||||
|
|
||||||
//various action instructions
|
//various action instructions
|
||||||
TOY_OPCODE_PRINT,
|
TOY_OPCODE_PRINT,
|
||||||
TOY_OPCODE_CONCAT,
|
TOY_OPCODE_CONCAT,
|
||||||
|
|||||||
@@ -565,6 +565,9 @@ static void makeExpr(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
|
|||||||
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT);
|
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//forward declarations
|
||||||
|
static void makeBlockStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
|
||||||
|
|
||||||
static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
makeExpr(bucketHandle, parser, rootHandle);
|
makeExpr(bucketHandle, parser, rootHandle);
|
||||||
Toy_private_emitAstPrint(bucketHandle, rootHandle);
|
Toy_private_emitAstPrint(bucketHandle, rootHandle);
|
||||||
@@ -608,7 +611,14 @@ static void makeVariableDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* p
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||||
//block
|
//inner scope
|
||||||
|
if (match(parser, TOY_TOKEN_OPERATOR_BRACE_LEFT)) {
|
||||||
|
makeBlockStmt(bucketHandle, parser, rootHandle);
|
||||||
|
consume(parser, TOY_TOKEN_OPERATOR_BRACE_RIGHT, "Expected '}' at the end of block scope");
|
||||||
|
(*rootHandle)->block.innerScope = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
//if-then-else
|
//if-then-else
|
||||||
//while-then
|
//while-then
|
||||||
@@ -619,7 +629,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
|
|||||||
//import
|
//import
|
||||||
|
|
||||||
//check for empty lines
|
//check for empty lines
|
||||||
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
else if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
||||||
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -658,7 +668,7 @@ static void makeBlockStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
|||||||
Toy_private_initAstBlock(bucketHandle, rootHandle);
|
Toy_private_initAstBlock(bucketHandle, rootHandle);
|
||||||
|
|
||||||
//read a series of statements into the block
|
//read a series of statements into the block
|
||||||
while (!match(parser, TOY_TOKEN_EOF)) {
|
while (parser->current.type != TOY_TOKEN_OPERATOR_BRACE_RIGHT && !match(parser, TOY_TOKEN_EOF)) {
|
||||||
//process the grammar rules
|
//process the grammar rules
|
||||||
Toy_Ast* stmt = NULL;
|
Toy_Ast* stmt = NULL;
|
||||||
makeDeclarationStmt(bucketHandle, parser, &stmt);
|
makeDeclarationStmt(bucketHandle, parser, &stmt);
|
||||||
@@ -695,6 +705,11 @@ Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
|||||||
|
|
||||||
makeBlockStmt(bucketHandle, parser, &rootHandle);
|
makeBlockStmt(bucketHandle, parser, &rootHandle);
|
||||||
|
|
||||||
|
//don't emit this error if we're already panicking
|
||||||
|
if (parser->panic != true && parser->previous.type != TOY_TOKEN_EOF) {
|
||||||
|
printError(parser, parser->previous, "Expected 'EOF' and the end of the parser scan (possibly an extra '}' was found)");
|
||||||
|
}
|
||||||
|
|
||||||
return rootHandle;
|
return rootHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -410,8 +410,22 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
//determine how to write each instruction based on the Ast
|
//determine how to write each instruction based on the Ast
|
||||||
switch(ast->type) {
|
switch(ast->type) {
|
||||||
case TOY_AST_BLOCK:
|
case TOY_AST_BLOCK:
|
||||||
|
if (ast->block.innerScope) {
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_SCOPE_PUSH);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
writeRoutineCode(rt, ast->block.child);
|
writeRoutineCode(rt, ast->block.child);
|
||||||
writeRoutineCode(rt, ast->block.next);
|
writeRoutineCode(rt, ast->block.next);
|
||||||
|
|
||||||
|
if (ast->block.innerScope) {
|
||||||
|
EMIT_BYTE(rt, code, TOY_OPCODE_SCOPE_POP);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
EMIT_BYTE(rt, code, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_VALUE:
|
case TOY_AST_VALUE:
|
||||||
|
|||||||
@@ -482,6 +482,14 @@ static void process(Toy_VM* vm) {
|
|||||||
//temp terminator
|
//temp terminator
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
case TOY_OPCODE_SCOPE_PUSH:
|
||||||
|
vm->scope = Toy_pushScope(&vm->scopeBucket, vm->scope);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_SCOPE_POP:
|
||||||
|
vm->scope = Toy_popScope(vm->scope);
|
||||||
|
break;
|
||||||
|
|
||||||
//various action instructions
|
//various action instructions
|
||||||
case TOY_OPCODE_PRINT:
|
case TOY_OPCODE_PRINT:
|
||||||
processPrint(vm);
|
processPrint(vm);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ int test_sizeof_ast_32bit() {
|
|||||||
|
|
||||||
//run for each type
|
//run for each type
|
||||||
TEST_SIZEOF(Toy_AstType, 4);
|
TEST_SIZEOF(Toy_AstType, 4);
|
||||||
TEST_SIZEOF(Toy_AstBlock, 16);
|
TEST_SIZEOF(Toy_AstBlock, 20);
|
||||||
TEST_SIZEOF(Toy_AstValue, 12);
|
TEST_SIZEOF(Toy_AstValue, 12);
|
||||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||||
@@ -61,7 +61,7 @@ int test_sizeof_ast_32bit() {
|
|||||||
TEST_SIZEOF(Toy_AstPass, 4);
|
TEST_SIZEOF(Toy_AstPass, 4);
|
||||||
TEST_SIZEOF(Toy_AstError, 4);
|
TEST_SIZEOF(Toy_AstError, 4);
|
||||||
TEST_SIZEOF(Toy_AstEnd, 4);
|
TEST_SIZEOF(Toy_AstEnd, 4);
|
||||||
TEST_SIZEOF(Toy_Ast, 16);
|
TEST_SIZEOF(Toy_Ast, 20);
|
||||||
|
|
||||||
#undef TEST_SIZEOF
|
#undef TEST_SIZEOF
|
||||||
|
|
||||||
|
|||||||
19
tests/integrations/test_scopes.toy
Normal file
19
tests/integrations/test_scopes.toy
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//shadowing
|
||||||
|
var answer = 42;
|
||||||
|
print answer; //42
|
||||||
|
{
|
||||||
|
var answer = 7;
|
||||||
|
print answer; //7
|
||||||
|
}
|
||||||
|
print answer; //42
|
||||||
|
|
||||||
|
//rebinding
|
||||||
|
var question = 42;
|
||||||
|
print question; //42
|
||||||
|
{
|
||||||
|
var question = question;
|
||||||
|
print question; //42
|
||||||
|
}
|
||||||
|
print question; //42
|
||||||
|
|
||||||
|
//TODO: scope test case
|
||||||
@@ -7,15 +7,13 @@ var empty;
|
|||||||
//assign a previously existing variable
|
//assign a previously existing variable
|
||||||
answer = 6 * 9;
|
answer = 6 * 9;
|
||||||
|
|
||||||
|
//access a variable
|
||||||
answer = answer + 1;
|
answer = answer + 1;
|
||||||
|
|
||||||
|
//compound assignments
|
||||||
answer += 5;
|
answer += 5;
|
||||||
|
|
||||||
answer -= 5;
|
answer -= 5;
|
||||||
|
|
||||||
answer *= 9;
|
answer *= 9;
|
||||||
|
|
||||||
answer /= 2;
|
answer /= 2;
|
||||||
|
|
||||||
answer %= 10;
|
answer %= 10;
|
||||||
|
|
||||||
Reference in New Issue
Block a user