mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +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));
|
||||
|
||||
tmp->type = TOY_AST_BLOCK;
|
||||
tmp->block.innerScope = false;
|
||||
tmp->block.child = NULL;
|
||||
tmp->block.next = NULL;
|
||||
tmp->block.tail = NULL;
|
||||
|
||||
@@ -69,6 +69,7 @@ typedef union Toy_Ast Toy_Ast;
|
||||
|
||||
typedef struct Toy_AstBlock {
|
||||
Toy_AstType type;
|
||||
bool innerScope;
|
||||
Toy_Ast* child; //begin encoding the line
|
||||
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
|
||||
|
||||
@@ -33,6 +33,9 @@ typedef enum Toy_OpcodeType {
|
||||
//control instructions
|
||||
TOY_OPCODE_RETURN,
|
||||
|
||||
TOY_OPCODE_SCOPE_PUSH,
|
||||
TOY_OPCODE_SCOPE_POP,
|
||||
|
||||
//various action instructions
|
||||
TOY_OPCODE_PRINT,
|
||||
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);
|
||||
}
|
||||
|
||||
//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) {
|
||||
makeExpr(bucketHandle, parser, 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) {
|
||||
//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
|
||||
//if-then-else
|
||||
//while-then
|
||||
@@ -619,7 +629,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
|
||||
//import
|
||||
|
||||
//check for empty lines
|
||||
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
||||
else if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
|
||||
Toy_private_emitAstPass(bucketHandle, rootHandle);
|
||||
return;
|
||||
}
|
||||
@@ -658,7 +668,7 @@ static void makeBlockStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
||||
Toy_private_initAstBlock(bucketHandle, rootHandle);
|
||||
|
||||
//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
|
||||
Toy_Ast* stmt = NULL;
|
||||
makeDeclarationStmt(bucketHandle, parser, &stmt);
|
||||
@@ -695,6 +705,11 @@ Toy_Ast* Toy_scanParser(Toy_Bucket** bucketHandle, Toy_Parser* parser) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -410,8 +410,22 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
||||
//determine how to write each instruction based on the Ast
|
||||
switch(ast->type) {
|
||||
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.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;
|
||||
|
||||
case TOY_AST_VALUE:
|
||||
|
||||
@@ -482,6 +482,14 @@ static void process(Toy_VM* vm) {
|
||||
//temp terminator
|
||||
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
|
||||
case TOY_OPCODE_PRINT:
|
||||
processPrint(vm);
|
||||
|
||||
@@ -48,7 +48,7 @@ int test_sizeof_ast_32bit() {
|
||||
|
||||
//run for each type
|
||||
TEST_SIZEOF(Toy_AstType, 4);
|
||||
TEST_SIZEOF(Toy_AstBlock, 16);
|
||||
TEST_SIZEOF(Toy_AstBlock, 20);
|
||||
TEST_SIZEOF(Toy_AstValue, 12);
|
||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||
@@ -61,7 +61,7 @@ int test_sizeof_ast_32bit() {
|
||||
TEST_SIZEOF(Toy_AstPass, 4);
|
||||
TEST_SIZEOF(Toy_AstError, 4);
|
||||
TEST_SIZEOF(Toy_AstEnd, 4);
|
||||
TEST_SIZEOF(Toy_Ast, 16);
|
||||
TEST_SIZEOF(Toy_Ast, 20);
|
||||
|
||||
#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
|
||||
answer = 6 * 9;
|
||||
|
||||
//access a variable
|
||||
answer = answer + 1;
|
||||
|
||||
//compound assignments
|
||||
answer += 5;
|
||||
|
||||
answer -= 5;
|
||||
|
||||
answer *= 9;
|
||||
|
||||
answer /= 2;
|
||||
|
||||
answer %= 10;
|
||||
|
||||
Reference in New Issue
Block a user