Global Variables 21
This commit is contained in:
parent
a7b7348f61
commit
4f2211eb72
9 changed files with 178 additions and 36 deletions
|
|
@ -8,6 +8,8 @@ import clox.compiler;
|
|||
import clox.chunk;
|
||||
import clox.parserules;
|
||||
import clox.util;
|
||||
import clox.object;
|
||||
import clox.value;
|
||||
|
||||
struct Parser{
|
||||
Compiler* compiler;
|
||||
|
|
@ -33,10 +35,72 @@ struct Parser{
|
|||
}
|
||||
errorAtCurrent(message);
|
||||
}
|
||||
bool check(Token.Type type) => current.type == type;
|
||||
bool match(Token.Type type){
|
||||
if(!check(type))
|
||||
return false;
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
|
||||
void expression(){
|
||||
parsePrecedence(Precedence.Assignment);
|
||||
}
|
||||
void expressionStatement(){
|
||||
expression();
|
||||
consume(Token.Type.Semicolon, "Expect ';' after expression.");
|
||||
compiler.emitter.emit(OpCode.Pop);
|
||||
}
|
||||
void varDeclaration(){
|
||||
ubyte global = parseVariable("Expect variable name.");
|
||||
if(match(Token.Type.Equal))
|
||||
expression();
|
||||
else
|
||||
compiler.emitter.emit(OpCode.Nil);
|
||||
consume(Token.Type.Semicolon, "Expect ';' after variable declaration.");
|
||||
defineVariable(global);
|
||||
}
|
||||
void declaration(){
|
||||
if(match(Token.Type.Var))
|
||||
varDeclaration();
|
||||
else
|
||||
statement();
|
||||
if(compiler.parser.panicMode)
|
||||
synchronize();
|
||||
}
|
||||
void statement(){
|
||||
if(match(Token.Type.Print))
|
||||
printStatement();
|
||||
else
|
||||
expressionStatement();
|
||||
}
|
||||
void printStatement(){
|
||||
expression();
|
||||
consume(Token.Type.Semicolon, "Expect ';' after value.");
|
||||
compiler.emitter.emit(OpCode.Print);
|
||||
}
|
||||
|
||||
void defineVariable(ubyte global){
|
||||
compiler.emitter.emit(OpCode.DefineGlobal, global);
|
||||
}
|
||||
ubyte parseVariable(const char* errorMessage){
|
||||
consume(Token.Type.Identifier, errorMessage);
|
||||
return identifierConstant(&previous);
|
||||
}
|
||||
ubyte identifierConstant(Token* name){
|
||||
Value nameVal = Value.from(Obj.String.copy(name.lexeme));
|
||||
return cast(ubyte)compiler.emitter.makeConstant(nameVal);
|
||||
}
|
||||
void namedVariable(Token name, bool canAssign){
|
||||
ubyte arg = compiler.parser.identifierConstant(&name);
|
||||
if(canAssign && match(Token.Type.Equal)){
|
||||
expression();
|
||||
compiler.emitter.emit(OpCode.SetGlobal, arg);
|
||||
} else {
|
||||
compiler.emitter.emit(OpCode.GetGlobal, arg);
|
||||
}
|
||||
}
|
||||
|
||||
void parsePrecedence(Precedence precedence){
|
||||
advance();
|
||||
ParseFn prefixRule = ParseRule.get(previous.type).prefix;
|
||||
|
|
@ -44,14 +108,37 @@ struct Parser{
|
|||
error("Expect expression.");
|
||||
return;
|
||||
}
|
||||
prefixRule(compiler);
|
||||
bool canAssign = precedence <= Precedence.Assignment;
|
||||
prefixRule(compiler, canAssign);
|
||||
while(precedence <= ParseRule.get(current.type).precedence){
|
||||
advance();
|
||||
ParseFn infixRule = ParseRule.get(previous.type).infix;
|
||||
infixRule(compiler);
|
||||
}
|
||||
if(canAssign && match(Token.Type.Equal))
|
||||
error("Invalid assignment target.");
|
||||
}
|
||||
|
||||
void synchronize(){
|
||||
panicMode = false;
|
||||
while(current.type != Token.Type.EOF){
|
||||
if(previous.type == Token.Type.Semicolon)
|
||||
return;
|
||||
switch(current.type){
|
||||
case Token.Type.Class:
|
||||
case Token.Type.Fun:
|
||||
case Token.Type.Var:
|
||||
case Token.Type.For:
|
||||
case Token.Type.If:
|
||||
case Token.Type.While:
|
||||
case Token.Type.Print:
|
||||
case Token.Type.Return:
|
||||
return;
|
||||
default: break;
|
||||
}
|
||||
advance();
|
||||
}
|
||||
}
|
||||
void errorAtCurrent(in char* message){
|
||||
errorAt(current, message);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue