Global Variables 21

This commit is contained in:
nazrin 2025-06-07 08:05:31 +00:00
parent a7b7348f61
commit 4f2211eb72
9 changed files with 178 additions and 36 deletions

View file

@ -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);
}