lox-d/src/clox/parserules.d
2025-06-08 05:32:04 +00:00

160 lines
6.6 KiB
D

module clox.parserules;
import clox.chunk;
import clox.compiler;
import clox.parser;
import clox.scanner;
import clox.emitter;
import clox.value;
import clox.object;
alias ParseFn = void function(Compiler* compiler, bool canAssign = false);
private void grouping(Compiler* compiler, bool _){
compiler.parser.expression();
compiler.parser.consume(Token.Type.RightParen, "Expect ')' after expression.");
}
private void unary(Compiler* compiler, bool _){
Token operator = compiler.parser.previous;
compiler.parser.parsePrecedence(Precedence.Unary);
switch(operator.type){
case Token.Type.Minus: compiler.emitter.emit(OpCode.Negate); break;
case Token.Type.Bang: compiler.emitter.emit(OpCode.Not); break;
default: assert(0);
}
}
private void binary(Compiler* compiler, bool _){
Token operator = compiler.parser.previous;
immutable(ParseRule)* rule = ParseRule.get(operator.type);
compiler.parser.parsePrecedence(cast(Precedence)(rule.precedence + 1));
switch(operator.type){
case Token.Type.Plus: compiler.emitter.emit(OpCode.Add); break;
case Token.Type.Minus: compiler.emitter.emit(OpCode.Subtract); break;
case Token.Type.Star: compiler.emitter.emit(OpCode.Multiply); break;
case Token.Type.Slash: compiler.emitter.emit(OpCode.Divide); break;
case Token.Type.BangEqual: compiler.emitter.emit(OpCode.NotEqual); break;
case Token.Type.EqualEqual: compiler.emitter.emit(OpCode.Equal); break;
case Token.Type.Greater: compiler.emitter.emit(OpCode.Greater); break;
case Token.Type.GreaterEqual: compiler.emitter.emit(OpCode.GreaterEqual); break;
case Token.Type.Less: compiler.emitter.emit(OpCode.Less); break;
case Token.Type.LessEqual: compiler.emitter.emit(OpCode.LessEqual); break;
default: assert(0);
}
}
private void number(Compiler* compiler, bool _){
import core.stdc.stdlib : strtod;
Token token = compiler.parser.previous;
double value = strtod(token.lexeme.ptr, null);
compiler.emitter.emitConstant(Value.from(value));
}
private void literal(Compiler* compiler, bool _){
Token token = compiler.parser.previous;
switch(token.type){
case Token.Type.True: compiler.emitter.emit(OpCode.True); break;
case Token.Type.False: compiler.emitter.emit(OpCode.False); break;
case Token.Type.Nil: compiler.emitter.emit(OpCode.Nil); break;
default: assert(0);
}
}
private void strlit(Compiler* compiler, bool _){
Token token = compiler.parser.previous;
const char[] str = token.lexeme[1 .. $-1];
Obj.String* strObj = Obj.String.copy(str);
compiler.emitter.emitConstant(Value.from(strObj));
}
private void variable(Compiler* compiler, bool canAssign){
compiler.parser.namedVariable(compiler.parser.previous, canAssign);
}
private void and(Compiler* compiler, bool _){
int endJump = compiler.parser.emitJump(OpCode.JumpIfFalse);
compiler.emitter.emit(OpCode.Pop);
compiler.parser.parsePrecedence(Precedence.And);
compiler.parser.patchJump(endJump);
}
private void or(Compiler* compiler, bool _){
int elseJump = compiler.parser.emitJump(OpCode.JumpIfFalse);
int endJump = compiler.parser.emitJump(OpCode.Jump);
compiler.parser.patchJump(elseJump);
compiler.emitter.emit(OpCode.Pop);
compiler.parser.parsePrecedence(Precedence.Or);
compiler.parser.patchJump(endJump);
}
struct ParseRule{
ParseFn prefix;
ParseFn infix;
Precedence precedence;
static immutable(ParseRule)* get(Token.Type type){
return &rules[type];
}
}
enum Precedence{
None,
Assignment, // =
Or, // or
And, // and
Equality, // == !=
Comparison, // < > <= >=
Term, // + -
Factor, // * /
Unary, // ! -
Call, // . ()
Primary
}
immutable ParseRule[Token.Type.max+1] rules = [
Token.Type.LeftParen : ParseRule(&grouping, null, Precedence.None),
Token.Type.RightParen : ParseRule(null, null, Precedence.None),
Token.Type.LeftBrace : ParseRule(null, null, Precedence.None),
Token.Type.RightBrace : ParseRule(null, null, Precedence.None),
Token.Type.Comma : ParseRule(null, null, Precedence.None),
Token.Type.Dot : ParseRule(null, null, Precedence.None),
Token.Type.Minus : ParseRule(&unary, &binary, Precedence.Term),
Token.Type.Plus : ParseRule(null, &binary, Precedence.Term),
Token.Type.Semicolon : ParseRule(null, null, Precedence.None),
Token.Type.Slash : ParseRule(null, &binary, Precedence.Factor),
Token.Type.Star : ParseRule(null, &binary, Precedence.Factor),
Token.Type.Bang : ParseRule(&unary, null, Precedence.None),
Token.Type.BangEqual : ParseRule(null, &binary, Precedence.Equality),
Token.Type.Equal : ParseRule(null, null, Precedence.None),
Token.Type.EqualEqual : ParseRule(null, &binary, Precedence.Equality),
Token.Type.Greater : ParseRule(null, &binary, Precedence.Comparison),
Token.Type.GreaterEqual : ParseRule(null, &binary, Precedence.Comparison),
Token.Type.Less : ParseRule(null, &binary, Precedence.Comparison),
Token.Type.LessEqual : ParseRule(null, &binary, Precedence.Comparison),
Token.Type.Identifier : ParseRule(&variable, null, Precedence.None),
Token.Type.String : ParseRule(&strlit, null, Precedence.None),
Token.Type.Number : ParseRule(&number, null, Precedence.None),
Token.Type.And : ParseRule(null, &and, Precedence.And),
Token.Type.Class : ParseRule(null, null, Precedence.None),
Token.Type.Else : ParseRule(null, null, Precedence.None),
Token.Type.False : ParseRule(&literal, null, Precedence.None),
Token.Type.For : ParseRule(null, null, Precedence.None),
Token.Type.Fun : ParseRule(null, null, Precedence.None),
Token.Type.If : ParseRule(null, null, Precedence.None),
Token.Type.Nil : ParseRule(&literal, null, Precedence.None),
Token.Type.Or : ParseRule(null, &or, Precedence.Or),
Token.Type.Print : ParseRule(null, null, Precedence.None),
Token.Type.Return : ParseRule(null, null, Precedence.None),
Token.Type.Super : ParseRule(null, null, Precedence.None),
Token.Type.This : ParseRule(null, null, Precedence.None),
Token.Type.True : ParseRule(&literal, null, Precedence.None),
Token.Type.Var : ParseRule(null, null, Precedence.None),
Token.Type.While : ParseRule(null, null, Precedence.None),
Token.Type.Error : ParseRule(null, null, Precedence.None),
Token.Type.EOF : ParseRule(null, null, Precedence.None),
];