WIP: dev #1

Draft
nub31 wants to merge 103 commits from dev into master
4 changed files with 245 additions and 9 deletions
Showing only changes of commit 4761cd1f83 - Show all commits

View File

@@ -159,6 +159,7 @@ public sealed class Generator(List<NodeDefinition> nodes)
{
EmitStatement(statement.Block);
}
writer.WriteLine("}");
}
@@ -166,6 +167,7 @@ public sealed class Generator(List<NodeDefinition> nodes)
{
return node switch
{
NodeExpressionBinary expression => EmitExpressionBinary(expression),
NodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false",
NodeExpressionIntLiteral expression => expression.Value.Value.ToString(),
NodeExpressionStringLiteral expression => $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}",
@@ -174,6 +176,32 @@ public sealed class Generator(List<NodeDefinition> nodes)
};
}
private string EmitExpressionBinary(NodeExpressionBinary expression)
{
var left = EmitExpression(expression.Left);
var right = EmitExpression(expression.Right);
return expression.Operation switch
{
NodeExpressionBinary.Op.Add => $"({left} + {right})",
NodeExpressionBinary.Op.Subtract => $"({left} - {right})",
NodeExpressionBinary.Op.Multiply => $"({left} * {right})",
NodeExpressionBinary.Op.Divide => $"({left} / {right})",
NodeExpressionBinary.Op.Modulo => $"({left} % {right})",
NodeExpressionBinary.Op.Equal => $"({left} == {right})",
NodeExpressionBinary.Op.NotEqual => $"({left} != {right})",
NodeExpressionBinary.Op.LessThan => $"({left} < {right})",
NodeExpressionBinary.Op.LessThanOrEqual => $"({left} <= {right})",
NodeExpressionBinary.Op.GreaterThan => $"({left} > {right})",
NodeExpressionBinary.Op.GreaterThanOrEqual => $"({left} >= {right})",
NodeExpressionBinary.Op.LeftShift => $"({left} << {right})",
NodeExpressionBinary.Op.RightShift => $"({left} >> {right})",
NodeExpressionBinary.Op.LogicalAnd => $"({left} && {right})",
NodeExpressionBinary.Op.LogicalOr => $"({left} || {right})",
_ => throw new ArgumentOutOfRangeException()
};
}
private static string CType(NodeType node, string? varName = null)
{
return node switch

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

View File

@@ -11,8 +11,13 @@ const string contents = """
x = 3
}
while false {
x = 6
let i: i32 = 0
x = 1 + 2 * 34
while i < 10 {
i = i + 1
x = i
}
do_something("test")

View File

@@ -197,6 +197,12 @@ public sealed class Tokenizer(string contents)
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.Equal);
}
case '<' when Peek(1) is '<':
{
Consume();
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.LessThanLessThan);
}
case '<' when Peek(1) is '=':
{
Consume();
@@ -208,6 +214,12 @@ public sealed class Tokenizer(string contents)
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.LessThan);
}
case '>' when Peek(1) is '>':
{
Consume();
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.GreaterThanGreaterThan);
}
case '>' when Peek(1) is '=':
{
Consume();
@@ -263,6 +275,39 @@ public sealed class Tokenizer(string contents)
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.ForwardSlash);
}
case '%' when Peek(1) is '=':
{
Consume();
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.PercentEqual);
}
case '%':
{
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.Percent);
}
case '&' when Peek(1) is '&':
{
Consume();
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.AmpersandAmpersand);
}
case '&':
{
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.Ampersand);
}
case '|' when Peek(1) is '|':
{
Consume();
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.PipePipe);
}
case '|':
{
Consume();
return new TokenSymbol(line, startColumn, column - startColumn, Symbol.Pipe);
}
default:
{
if (char.IsLetter(c) || c == '_')
@@ -377,8 +422,10 @@ public enum Symbol
EqualEqual,
BangEqual,
LessThan,
LessThanLessThan,
LessThanEqual,
GreaterThan,
GreaterThanGreaterThan,
GreaterThanEqual,
Plus,
PlusEqual,
@@ -388,6 +435,12 @@ public enum Symbol
StarEqual,
ForwardSlash,
ForwardSlashEqual,
Percent,
PercentEqual,
Ampersand,
AmpersandAmpersand,
Pipe,
PipePipe,
}
public sealed class TokenSymbol(int line, int column, int length, Symbol symbol) : Token(line, column, length)