Compare commits

..

3 Commits

Author SHA1 Message Date
e77c7028b9 ... 2026-02-08 01:22:24 +01:00
26d365cf4f ... 2026-02-08 00:53:55 +01:00
f2ea00b34d ... 2026-02-08 00:21:38 +01:00
4 changed files with 118 additions and 146 deletions

View File

@@ -1,5 +1,4 @@
using System.Globalization;
using System.Text;
using System.Text;
namespace Compiler;
@@ -15,6 +14,12 @@ public sealed class Generator(List<NodeDefinition> nodes)
private string Emit()
{
writer.WriteLine("""
#include <float.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
struct string {
const char *data;
int length;
@@ -24,16 +29,16 @@ public sealed class Generator(List<NodeDefinition> nodes)
foreach (var node in nodes.OfType<NodeDefinitionFunc>())
{
var parameters = node.Parameters.Select(x => $"{CType(x.Type)} {x.Name.Ident}");
writer.WriteLine($"{CType(node.ReturnType)} {node.Name.Ident}({string.Join(", ", parameters)});");
var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident));
writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)});");
}
writer.WriteLine();
foreach (var node in nodes.OfType<NodeDefinitionFunc>())
{
var parameters = node.Parameters.Select(x => $"{CType(x.Type)} {x.Name.Ident}");
writer.WriteLine($"{CType(node.ReturnType)} {node.Name.Ident}({string.Join(", ", parameters)})");
var parameters = node.Parameters.Select(x => CType(x.Type, x.Name.Ident));
writer.WriteLine($"{CType(node.ReturnType, node.Name.Ident)}({string.Join(", ", parameters)})");
writer.WriteLine("{");
using (writer.Indent())
{
@@ -57,6 +62,11 @@ public sealed class Generator(List<NodeDefinition> nodes)
case NodeStatementFuncCall statement:
EmitStatementFuncCall(statement);
break;
case NodeStatementReturn statement:
EmitStatementReturn(statement);
break;
default:
throw new ArgumentOutOfRangeException(nameof(node), node, null);
}
}
@@ -79,138 +89,98 @@ public sealed class Generator(List<NodeDefinition> nodes)
writer.WriteLine($"{name}({string.Join(", ", parameterValues)});");
}
private void EmitStatementReturn(NodeStatementReturn statement)
{
var value = EmitExpression(statement.Value);
writer.WriteLine($"return {value};");
}
private string EmitExpression(NodeExpression node)
{
return node switch
{
NodeExpressionBoolLiteral expression => EmitExpressionBoolLiteral(expression),
NodeExpressionFloatLiteral expression => EmitExpressionFloatLiteral(expression),
NodeExpressionIntLiteral expression => EmitExpressionIntLiteral(expression),
NodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
NodeExpressionIdent expression => EmitExpressionIdent(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} }}",
NodeExpressionIdent expression => expression.Value.Ident,
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
};
}
private string EmitExpressionBoolLiteral(NodeExpressionBoolLiteral expression)
{
return expression.Value.Value ? "1" : "0";
}
private string EmitExpressionFloatLiteral(NodeExpressionFloatLiteral expression)
{
return expression.Value.Value.ToString(CultureInfo.InvariantCulture);
}
private string EmitExpressionIntLiteral(NodeExpressionIntLiteral expression)
{
return expression.Value.Value.ToString();
}
private string EmitExpressionStringLiteral(NodeExpressionStringLiteral expression)
{
return $"(struct string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}";
}
private string EmitExpressionIdent(NodeExpressionIdent expression)
{
return expression.Value.Ident;
}
private static string CType(NodeType node)
private static string CType(NodeType node, string? varName = null)
{
return node switch
{
NodeTypeCustom type => $"struct {type.Name.Ident}",
NodeTypeFloat type => type.Width switch
{
32 => "float",
64 => "double",
},
NodeTypePointer type => $"{CType(type.To)}*",
NodeTypeSInt type => type.Width switch
{
8 => "byte",
16 => "short",
32 => "int",
64 => "long",
},
NodeTypeUInt type => type.Width switch
{
8 => "unsigned byte",
16 => "unsigned short",
32 => "unsigned int",
64 => "unsigned long",
},
NodeTypeString => "struct string",
NubTypeVoid => "void",
_ => throw new ArgumentOutOfRangeException(nameof(node))
NodeTypeVoid => "void" + (varName != null ? $" {varName}" : ""),
NodeTypeBool => "bool" + (varName != null ? $" {varName}" : ""),
NodeTypeCustom type => $"struct {type}" + (varName != null ? $" {varName}" : ""),
NodeTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NodeTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NodeTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"),
NodeTypeString => "struct string" + (varName != null ? $" {varName}" : ""),
NodeTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})",
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
};
}
}
internal class IndentedTextWriter
{
private readonly StringBuilder _builder = new();
private int _indentLevel;
private readonly StringBuilder builder = new();
private int indentLevel;
public IDisposable Indent()
{
_indentLevel++;
indentLevel++;
return new IndentScope(this);
}
public void WriteLine(string text)
{
WriteIndent();
_builder.AppendLine(text);
builder.AppendLine(text);
}
public void Write(string text)
{
WriteIndent();
_builder.Append(text);
builder.Append(text);
}
public void WriteLine()
{
_builder.AppendLine();
builder.AppendLine();
}
public override string ToString()
{
return _builder.ToString();
return builder.ToString();
}
private void WriteIndent()
{
if (_builder.Length > 0)
if (builder.Length > 0)
{
var lastChar = _builder[^1];
var lastChar = builder[^1];
if (lastChar != '\n' && lastChar != '\r')
return;
}
for (var i = 0; i < _indentLevel; i++)
for (var i = 0; i < indentLevel; i++)
{
_builder.Append(" ");
builder.Append(" ");
}
}
private class IndentScope : IDisposable
private class IndentScope(IndentedTextWriter writer) : IDisposable
{
private readonly IndentedTextWriter _writer;
private bool _disposed;
public IndentScope(IndentedTextWriter writer)
{
_writer = writer;
}
private bool disposed;
public void Dispose()
{
if (_disposed) return;
_writer._indentLevel--;
_disposed = true;
if (disposed) return;
writer.indentLevel--;
disposed = true;
}
}
}

View File

@@ -64,6 +64,12 @@ public sealed class Parser(List<Token> tokens)
return new NodeStatementBlock(TokensFrom(startIndex), statements);
}
if (TryExpectKeyword(Keyword.Return))
{
var value = ParseExpression();
return new NodeStatementReturn(TokensFrom(startIndex), value);
}
var expression = ParseExpression();
var parameters = new List<NodeExpression>();
@@ -83,11 +89,6 @@ public sealed class Parser(List<Token> tokens)
return new NodeExpressionIntLiteral(TokensFrom(startIndex), intLiteral);
}
if (TryExpectFloatLiteral(out var floatLiteral))
{
return new NodeExpressionFloatLiteral(TokensFrom(startIndex), floatLiteral);
}
if (TryExpectStringLiteral(out var stringLiteral))
{
return new NodeExpressionStringLiteral(TokensFrom(startIndex), stringLiteral);
@@ -116,14 +117,32 @@ public sealed class Parser(List<Token> tokens)
return new NodeTypePointer(TokensFrom(startIndex), to);
}
if (TryExpectKeyword(Keyword.Func))
{
var parameters = new List<NodeType>();
ExpectSymbol(Symbol.OpenParen);
while (!TryExpectSymbol(Symbol.CloseParen))
{
parameters.Add(ParseType());
}
ExpectSymbol(Symbol.Colon);
var returnType = ParseType();
return new NodeTypeFunc(TokensFrom(startIndex), parameters, returnType);
}
if (TryExpectIdent(out var ident))
{
switch (ident.Ident)
{
case "void":
return new NubTypeVoid(TokensFrom(startIndex));
return new NodeTypeVoid(TokensFrom(startIndex));
case "string":
return new NodeTypeString(TokensFrom(startIndex));
case "bool":
return new NodeTypeBool(TokensFrom(startIndex));
case "i8":
return new NodeTypeSInt(TokensFrom(startIndex), 8);
case "i16":
@@ -140,10 +159,6 @@ public sealed class Parser(List<Token> tokens)
return new NodeTypeUInt(TokensFrom(startIndex), 32);
case "u64":
return new NodeTypeUInt(TokensFrom(startIndex), 64);
case "f32":
return new NodeTypeFloat(TokensFrom(startIndex), 32);
case "f64":
return new NodeTypeFloat(TokensFrom(startIndex), 64);
default:
return new NodeTypeCustom(TokensFrom(startIndex), ident);
}
@@ -227,19 +242,6 @@ public sealed class Parser(List<Token> tokens)
return false;
}
private bool TryExpectFloatLiteral([NotNullWhen(true)] out TokenFloatLiteral? floatLiteral)
{
if (Peek() is TokenFloatLiteral token)
{
Consume();
floatLiteral = token;
return true;
}
floatLiteral = null;
return false;
}
private bool TryExpectStringLiteral([NotNullWhen(true)] out TokenStringLiteral? stringLiteral)
{
if (Peek() is TokenStringLiteral token)
@@ -290,18 +292,17 @@ public abstract class Node(List<Token> tokens)
public abstract class NodeDefinition(List<Token> tokens) : Node(tokens);
public sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType)
: NodeDefinition(tokens)
public sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens)
{
public TokenIdent Name = name;
public List<Param> Parameters = parameters;
public NodeStatement Body = body;
public NodeType ReturnType = returnType;
public readonly TokenIdent Name = name;
public readonly List<Param> Parameters = parameters;
public readonly NodeStatement Body = body;
public readonly NodeType ReturnType = returnType;
public sealed class Param(List<Token> tokens, TokenIdent name, NodeType type) : Node(tokens)
{
public TokenIdent Name = name;
public NodeType Type = type;
public readonly TokenIdent Name = name;
public readonly NodeType Type = type;
}
}
@@ -309,69 +310,72 @@ public abstract class NodeStatement(List<Token> tokens) : Node(tokens);
public sealed class NodeStatementBlock(List<Token> tokens, List<NodeStatement> statements) : NodeStatement(tokens)
{
public List<NodeStatement> Statements = statements;
public readonly List<NodeStatement> Statements = statements;
}
public sealed class NodeStatementFuncCall(List<Token> tokens, NodeExpression func, List<NodeExpression> parameters) : NodeStatement(tokens)
{
public NodeExpression Func = func;
public List<NodeExpression> Parameters = parameters;
public readonly NodeExpression Func = func;
public readonly List<NodeExpression> Parameters = parameters;
}
internal class NodeStatementReturn(List<Token> tokens, NodeExpression value) : NodeStatement(tokens)
{
public readonly NodeExpression Value = value;
}
public abstract class NodeExpression(List<Token> tokens) : Node(tokens);
public sealed class NodeExpressionIntLiteral(List<Token> tokens, TokenIntLiteral value) : NodeExpression(tokens)
{
public TokenIntLiteral Value = value;
}
public sealed class NodeExpressionFloatLiteral(List<Token> tokens, TokenFloatLiteral value) : NodeExpression(tokens)
{
public TokenFloatLiteral Value = value;
public readonly TokenIntLiteral Value = value;
}
public sealed class NodeExpressionStringLiteral(List<Token> tokens, TokenStringLiteral value) : NodeExpression(tokens)
{
public TokenStringLiteral Value = value;
public readonly TokenStringLiteral Value = value;
}
public sealed class NodeExpressionBoolLiteral(List<Token> tokens, TokenBoolLiteral value) : NodeExpression(tokens)
{
public TokenBoolLiteral Value = value;
public readonly TokenBoolLiteral Value = value;
}
public sealed class NodeExpressionIdent(List<Token> tokens, TokenIdent value) : NodeExpression(tokens)
{
public TokenIdent Value = value;
public readonly TokenIdent Value = value;
}
public abstract class NodeType(List<Token> tokens) : Node(tokens);
public sealed class NubTypeVoid(List<Token> tokens) : NodeType(tokens);
public sealed class NodeTypeVoid(List<Token> tokens) : NodeType(tokens);
public sealed class NodeTypeUInt(List<Token> tokens, int width) : NodeType(tokens)
{
public int Width = width;
public readonly int Width = width;
}
public sealed class NodeTypeSInt(List<Token> tokens, int width) : NodeType(tokens)
{
public int Width = width;
public readonly int Width = width;
}
public sealed class NodeTypeFloat(List<Token> tokens, int width) : NodeType(tokens)
{
public int Width = width;
}
public sealed class NodeTypeBool(List<Token> tokens) : NodeType(tokens);
public sealed class NodeTypeString(List<Token> tokens) : NodeType(tokens);
public sealed class NodeTypeCustom(List<Token> tokens, TokenIdent name) : NodeType(tokens)
{
public TokenIdent Name = name;
public readonly TokenIdent Name = name;
}
public sealed class NodeTypePointer(List<Token> tokens, NodeType to) : NodeType(tokens)
{
public NodeType To = to;
public readonly NodeType To = to;
}
public sealed class NodeTypeFunc(List<Token> tokens, List<NodeType> parameters, NodeType returnType) : NodeType(tokens)
{
public readonly List<NodeType> Parameters = parameters;
public readonly NodeType ReturnType = returnType;
}

View File

@@ -1,8 +1,9 @@
using Compiler;
const string contents = """
func main(): void {
func main(): i32 {
do_something("test")
return 69
}
func do_something(text: string): void {

View File

@@ -279,6 +279,7 @@ public sealed class Tokenizer(string contents)
"func" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Func),
"let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let),
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If),
"return" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Return),
"true" => new TokenBoolLiteral(line, startColumn, column - startColumn, true),
"false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false),
_ => new TokenIdent(line, startColumn, column - startColumn, value)
@@ -342,7 +343,7 @@ public abstract class Token(int line, int column, int length)
public sealed class TokenIdent(int line, int column, int length, string ident) : Token(line, column, length)
{
public string Ident = ident;
public readonly string Ident = ident;
}
public sealed class TokenIntLiteral(int line, int column, int length, BigInteger value) : Token(line, column, length)
@@ -350,19 +351,14 @@ public sealed class TokenIntLiteral(int line, int column, int length, BigInteger
public BigInteger Value = value;
}
public sealed class TokenFloatLiteral(int line, int column, int length, decimal value) : Token(line, column, length)
{
public decimal Value = value;
}
public sealed class TokenStringLiteral(int line, int column, int length, string value) : Token(line, column, length)
{
public string Value = value;
public readonly string Value = value;
}
public sealed class TokenBoolLiteral(int line, int column, int length, bool value) : Token(line, column, length)
{
public bool Value = value;
public readonly bool Value = value;
}
public enum Symbol
@@ -394,7 +390,7 @@ public enum Symbol
public sealed class TokenSymbol(int line, int column, int length, Symbol symbol) : Token(line, column, length)
{
public Symbol Symbol = symbol;
public readonly Symbol Symbol = symbol;
}
public enum Keyword
@@ -402,9 +398,10 @@ public enum Keyword
Func,
Let,
If,
Return,
}
public sealed class TokenKeyword(int line, int column, int length, Keyword keyword) : Token(line, column, length)
{
public Keyword Keyword = keyword;
public readonly Keyword Keyword = keyword;
}