This commit is contained in:
2026-02-08 17:55:15 +01:00
parent 423ec4c798
commit 4761cd1f83
4 changed files with 245 additions and 9 deletions

View File

@@ -120,10 +120,65 @@ public sealed class Parser(List<Token> tokens)
throw new Exception("Not a valid followup for expression statement");
}
private NodeExpression ParseExpression()
private NodeExpression ParseExpression(int minPrecedence = -1)
{
var startIndex = index;
var left = ParseExpressionLeaf();
while (TryPeekBinaryOperator(out var op) && GetPrecedence(op) >= minPrecedence)
{
Consume();
var right = ParseExpression(GetPrecedence(op) + 1);
left = new NodeExpressionBinary(TokensFrom(startIndex), left, op, right);
}
return left;
}
private static int GetPrecedence(NodeExpressionBinary.Op operation)
{
return operation switch
{
NodeExpressionBinary.Op.Multiply => 10,
NodeExpressionBinary.Op.Divide => 10,
NodeExpressionBinary.Op.Modulo => 10,
NodeExpressionBinary.Op.Add => 9,
NodeExpressionBinary.Op.Subtract => 9,
NodeExpressionBinary.Op.LeftShift => 8,
NodeExpressionBinary.Op.RightShift => 8,
NodeExpressionBinary.Op.GreaterThan => 7,
NodeExpressionBinary.Op.GreaterThanOrEqual => 7,
NodeExpressionBinary.Op.LessThan => 7,
NodeExpressionBinary.Op.LessThanOrEqual => 7,
NodeExpressionBinary.Op.Equal => 7,
NodeExpressionBinary.Op.NotEqual => 7,
// NodeExpressionBinary.Op.BitwiseAnd => 6,
// NodeExpressionBinary.Op.BitwiseXor => 5,
// NodeExpressionBinary.Op.BitwiseOr => 4,
NodeExpressionBinary.Op.LogicalAnd => 3,
NodeExpressionBinary.Op.LogicalOr => 2,
_ => throw new ArgumentOutOfRangeException(nameof(operation), operation, null)
};
}
private NodeExpression ParseExpressionLeaf()
{
var startIndex = index;
if (TryExpectSymbol(Symbol.OpenParen))
{
var value = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return value;
}
if (TryExpectIntLiteral(out var intLiteral))
{
return new NodeExpressionIntLiteral(TokensFrom(startIndex), intLiteral);
@@ -144,7 +199,7 @@ public sealed class Parser(List<Token> tokens)
return new NodeExpressionIdent(TokensFrom(startIndex), ident);
}
throw new Exception("Not a valid expression");
throw new Exception("Not a valid expression leaf");
}
private NodeType ParseType()
@@ -323,6 +378,67 @@ public sealed class Parser(List<Token> tokens)
return tokens[index + offset];
}
private bool TryPeekBinaryOperator(out NodeExpressionBinary.Op op)
{
if (Peek() is not TokenSymbol token)
{
op = default;
return false;
}
switch (token.Symbol)
{
case Symbol.Plus:
op = NodeExpressionBinary.Op.Add;
return true;
case Symbol.Minus:
op = NodeExpressionBinary.Op.Subtract;
return true;
case Symbol.Star:
op = NodeExpressionBinary.Op.Multiply;
return true;
case Symbol.ForwardSlash:
op = NodeExpressionBinary.Op.Divide;
return true;
case Symbol.Percent:
op = NodeExpressionBinary.Op.Modulo;
return true;
case Symbol.BangEqual:
op = NodeExpressionBinary.Op.NotEqual;
return true;
case Symbol.EqualEqual:
op = NodeExpressionBinary.Op.Equal;
return true;
case Symbol.LessThan:
op = NodeExpressionBinary.Op.LessThan;
return true;
case Symbol.LessThanEqual:
op = NodeExpressionBinary.Op.LessThanOrEqual;
return true;
case Symbol.GreaterThan:
op = NodeExpressionBinary.Op.GreaterThan;
return true;
case Symbol.GreaterThanEqual:
op = NodeExpressionBinary.Op.GreaterThanOrEqual;
return true;
case Symbol.LessThanLessThan:
op = NodeExpressionBinary.Op.LeftShift;
return true;
case Symbol.GreaterThanGreaterThan:
op = NodeExpressionBinary.Op.RightShift;
return true;
case Symbol.AmpersandAmpersand:
op = NodeExpressionBinary.Op.LogicalAnd;
return true;
case Symbol.PipePipe:
op = NodeExpressionBinary.Op.LogicalOr;
return true;
default:
op = default;
return false;
}
}
}
public abstract class Node(List<Token> tokens)
@@ -359,32 +475,32 @@ public sealed class NodeStatementFuncCall(List<Token> tokens, NodeExpression tar
public readonly List<NodeExpression> Parameters = parameters;
}
internal class NodeStatementReturn(List<Token> tokens, NodeExpression value) : NodeStatement(tokens)
public class NodeStatementReturn(List<Token> tokens, NodeExpression value) : NodeStatement(tokens)
{
public readonly NodeExpression Value = value;
}
internal class NodeStatementVariableDeclaration(List<Token> tokens, TokenIdent name, NodeType type, NodeExpression value) : NodeStatement(tokens)
public class NodeStatementVariableDeclaration(List<Token> tokens, TokenIdent name, NodeType type, NodeExpression value) : NodeStatement(tokens)
{
public readonly TokenIdent Name = name;
public readonly NodeType Type = type;
public readonly NodeExpression Value = value;
}
internal class NodeStatementAssignment(List<Token> tokens, NodeExpression target, NodeExpression value) : NodeStatement(tokens)
public class NodeStatementAssignment(List<Token> tokens, NodeExpression target, NodeExpression value) : NodeStatement(tokens)
{
public readonly NodeExpression Target = target;
public readonly NodeExpression Value = value;
}
internal class NodeStatementIf(List<Token> tokens, NodeExpression condition, NodeStatement thenBlock, NodeStatement? elseBlock) : NodeStatement(tokens)
public class NodeStatementIf(List<Token> tokens, NodeExpression condition, NodeStatement thenBlock, NodeStatement? elseBlock) : NodeStatement(tokens)
{
public readonly NodeExpression Condition = condition;
public readonly NodeStatement ThenBlock = thenBlock;
public readonly NodeStatement? ElseBlock = elseBlock;
}
internal class NodeStatementWhile(List<Token> tokens, NodeExpression condition, NodeStatement block) : NodeStatement(tokens)
public class NodeStatementWhile(List<Token> tokens, NodeExpression condition, NodeStatement block) : NodeStatement(tokens)
{
public readonly NodeExpression Condition = condition;
public readonly NodeStatement Block = block;
@@ -412,6 +528,40 @@ public sealed class NodeExpressionIdent(List<Token> tokens, TokenIdent value) :
public readonly TokenIdent Value = value;
}
public class NodeExpressionBinary(List<Token> tokens, NodeExpression left, NodeExpressionBinary.Op operation, NodeExpression right) : NodeExpression(tokens)
{
public NodeExpression Left { get; } = left;
public readonly Op Operation = operation;
public NodeExpression Right { get; } = right;
public enum Op
{
Add,
Subtract,
Multiply,
Divide,
Modulo,
Equal,
NotEqual,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual,
LeftShift,
RightShift,
// BitwiseAnd,
// BitwiseXor,
// BitwiseOr,
LogicalAnd,
LogicalOr,
}
}
public abstract class NodeType(List<Token> tokens) : Node(tokens);
public sealed class NodeTypeVoid(List<Token> tokens) : NodeType(tokens);