Statements and State 8

This commit is contained in:
nazrin 2025-06-01 19:53:00 +00:00
parent f4338ba51f
commit e749367886
7 changed files with 250 additions and 69 deletions

View file

@ -7,21 +7,21 @@ import jlox.tokentype;
import jlox.util;
import jlox.expr;
import jlox.main;
import jlox.stmt;
class Parser{
private Token[] tokens;
private int current = 0;
mixin defaultCtor;
Expr parse(){
try {
return expression();
} catch (ParseError error) {
return null;
}
Stmt[] parse(){
Stmt[] statements;
while(!isAtEnd)
statements ~= declaration();
return statements;
}
private bool isAtEnd() => peek().type == EOF;
private bool isAtEnd() => peek().type == TokenType.EOF;
private Token peek() => tokens[current];
private Token previous() => tokens[current-1];
private bool check(TokenType type){
@ -30,7 +30,7 @@ class Parser{
return peek().type == type;
}
private Token advance(){
if(!isAtEnd())
if(!isAtEnd)
current++;
return previous();
}
@ -59,7 +59,7 @@ class Parser{
}
private void synchronize(){
advance();
with(TokenType) while(!isAtEnd()){
with(TokenType) while(!isAtEnd){
if(previous().type == SEMICOLON)
return;
switch(peek().type){
@ -73,15 +73,49 @@ class Parser{
case RETURN:
return;
default:
assert(0);
/* assert(0); */
}
advance();
}
}
private Stmt printStatement(){
Expr value = expression();
consume(TokenType.SEMICOLON, "Expect ';' after value.");
return new Stmt.Print(value);
}
private Stmt expressionStatement(){
Expr expr = expression();
consume(TokenType.SEMICOLON, "Expect ';' after expression.");
return new Stmt.Expression(expr);
}
private Stmt statement(){
if(match(TokenType.LEFT_BRACE))
return new Stmt.Block(block());
if(match(TokenType.PRINT))
return printStatement();
return expressionStatement();
}
private Stmt[] block(){
Stmt[] statements;
while(!check(TokenType.RIGHT_BRACE) && !isAtEnd)
statements ~= declaration();
consume(TokenType.RIGHT_BRACE, "Expect '}' after block.");
return statements;
}
private Expr expression(){
return equality();
return assignment();
}
private Expr assignment(){
Expr expr = equality();
if(match(TokenType.EQUAL)){
Token equals = previous();
Expr value = assignment();
if(auto v = cast(Expr.Variable)expr)
return new Expr.Assign(v.name, value);
error(equals, "Invalid assignment target.");
}
return expr;
}
private Expr equality(){
Expr expr = comparison();
@ -128,12 +162,14 @@ class Parser{
return primary();
}
private Expr primary(){
if(match(TokenType.IDENTIFIER))
return new Expr.Variable(previous());
if(match(TokenType.FALSE))
return new Expr.Literal(false);
return new Expr.Literal(TValue.bln(false));
if(match(TokenType.TRUE))
return new Expr.Literal(true);
return new Expr.Literal(TValue.bln(true));
if(match(TokenType.NIL))
return new Expr.Literal(null);
return new Expr.Literal(TValue.nil(0));
if(match(TokenType.NUMBER, TokenType.STRING))
return new Expr.Literal(previous().literal);
if(match(TokenType.LEFT_PAREN)){
@ -142,7 +178,23 @@ class Parser{
return new Expr.Grouping(expr);
}
throw error(peek(), "Expect expression.");
assert(0);
}
private Stmt varDeclaration(){
Token name = consume(TokenType.IDENTIFIER, "Expect variable name.");
Expr initializer = null;
if(match(TokenType.EQUAL))
initializer = expression();
consume(TokenType.SEMICOLON, "Expect ';' after variable declaration.");
return new Stmt.Var(name, initializer);
}
private Stmt declaration(){
try {
if(match(TokenType.VAR))
return varDeclaration();
return statement();
} catch(ParseError error){
synchronize();
return null;
}
}
}