Amogulator/Suslang/Parser.cs
2023-03-14 12:53:56 +01:00

156 lines
4.7 KiB
C#

namespace Amogulator.Suslang;
public class Parser {
private string text;
private Lexer lexer;
private Token currentToken;
public Parser(string text, Lexer lexer) {
this.text = text;
this.lexer = lexer;
this.currentToken = this.lexer.next();
}
public Expr parseExpr() {
return parsePrec11();
}
public Expr parsePrec11() {
var left = parsePrec12();
if (!done() && current().type == TokenType.Plus) {
step();
var right = parsePrec11();
return new BinaryExpr() {
type = BinaryType.Add,
left = left,
right = right,
};
} else if (!done() && current().type == TokenType.Minus) {
step();
var right = parsePrec11();
return new BinaryExpr() {
type = BinaryType.Subtract,
left = left,
right = right,
};
} else {
return left;
}
}
public Expr parsePrec12() {
var left = parsePrec13();
if (!done() && current().type == TokenType.Asterisk) {
step();
var right = parsePrec12();
return new BinaryExpr() {
type = BinaryType.Multiply,
left = left,
right = right,
};
} else if (!done() && current().type == TokenType.Slash) {
step();
var right = parsePrec12();
return new BinaryExpr() {
type = BinaryType.Divide,
left = left,
right = right,
};
} else if (!done() && current().type == TokenType.Percent) {
step();
var right = parsePrec12();
return new BinaryExpr() {
type = BinaryType.Modulo,
left = left,
right = right,
};
} else {
return left;
}
}
public Expr parsePrec13() {
return parsePrec18();
}
public Expr parsePrec18() {
if (!done() && current().type == TokenType.LParen) {
step();
var expr = parseExpr();
if (done() || current().type != TokenType.RParen) {
var pos = position();
step();
return new ErrorExpr() {
position = pos,
message = "expected ')'"
};
}
step();
return expr;
} else {
return parseOperand();
}
}
public Expr parseOperand() {
var start = position();
if (done()) {
step();
return new ErrorExpr() {
position = start,
message = "expected value, got Eof",
};
} else if (current().type == TokenType.Int) {
var intToken = current();
step();
if (!done() && current().type == TokenType.Decimal) {
var decimalToken = current();
step();
return new FloatExpr() {
value = double.Parse(this.text.Substring(start.index, intToken.length + decimalToken.length).Replace(".", ",")),
};
} else {
return new IntExpr() {
value = int.Parse(this.text.Substring(start.index, intToken.length)),
};
}
} else if (current().type == TokenType.Decimal) {
var decimalToken = current();
step();
return new FloatExpr() {
value = double.Parse("0" + this.text.Substring(start.index, decimalToken.length).Replace(".", ",")),
};
} else if (current().type == TokenType.String) {
var stringToken = current();
step();
return new StringExpr() {
value = this.text.Substring(start.index, stringToken.length),
};
} else if (current().type == TokenType.False) {
step();
return new BoolExpr() {
value = false,
};
} else if (current().type == TokenType.True) {
step();
return new BoolExpr() {
value = true,
};
} else {
step();
return new ErrorExpr() {
position = start,
message = "expected value",
};
}
}
private Position position() => current().position;
private Token current() => this.currentToken;
private bool done() => this.currentToken.type == TokenType.Eof;
private void step() {
this.currentToken = this.lexer.next();
}
}