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

View File

@@ -64,6 +64,12 @@ public sealed class Parser(List<Token> tokens)
return new NodeStatementBlock(TokensFrom(startIndex), statements); return new NodeStatementBlock(TokensFrom(startIndex), statements);
} }
if (TryExpectKeyword(Keyword.Return))
{
var value = ParseExpression();
return new NodeStatementReturn(TokensFrom(startIndex), value);
}
var expression = ParseExpression(); var expression = ParseExpression();
var parameters = new List<NodeExpression>(); var parameters = new List<NodeExpression>();
@@ -83,11 +89,6 @@ public sealed class Parser(List<Token> tokens)
return new NodeExpressionIntLiteral(TokensFrom(startIndex), intLiteral); return new NodeExpressionIntLiteral(TokensFrom(startIndex), intLiteral);
} }
if (TryExpectFloatLiteral(out var floatLiteral))
{
return new NodeExpressionFloatLiteral(TokensFrom(startIndex), floatLiteral);
}
if (TryExpectStringLiteral(out var stringLiteral)) if (TryExpectStringLiteral(out var stringLiteral))
{ {
return new NodeExpressionStringLiteral(TokensFrom(startIndex), stringLiteral); return new NodeExpressionStringLiteral(TokensFrom(startIndex), stringLiteral);
@@ -116,14 +117,32 @@ public sealed class Parser(List<Token> tokens)
return new NodeTypePointer(TokensFrom(startIndex), to); 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)) if (TryExpectIdent(out var ident))
{ {
switch (ident.Ident) switch (ident.Ident)
{ {
case "void": case "void":
return new NubTypeVoid(TokensFrom(startIndex)); return new NodeTypeVoid(TokensFrom(startIndex));
case "string": case "string":
return new NodeTypeString(TokensFrom(startIndex)); return new NodeTypeString(TokensFrom(startIndex));
case "bool":
return new NodeTypeBool(TokensFrom(startIndex));
case "i8": case "i8":
return new NodeTypeSInt(TokensFrom(startIndex), 8); return new NodeTypeSInt(TokensFrom(startIndex), 8);
case "i16": case "i16":
@@ -140,10 +159,6 @@ public sealed class Parser(List<Token> tokens)
return new NodeTypeUInt(TokensFrom(startIndex), 32); return new NodeTypeUInt(TokensFrom(startIndex), 32);
case "u64": case "u64":
return new NodeTypeUInt(TokensFrom(startIndex), 64); return new NodeTypeUInt(TokensFrom(startIndex), 64);
case "f32":
return new NodeTypeFloat(TokensFrom(startIndex), 32);
case "f64":
return new NodeTypeFloat(TokensFrom(startIndex), 64);
default: default:
return new NodeTypeCustom(TokensFrom(startIndex), ident); return new NodeTypeCustom(TokensFrom(startIndex), ident);
} }
@@ -227,19 +242,6 @@ public sealed class Parser(List<Token> tokens)
return false; 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) private bool TryExpectStringLiteral([NotNullWhen(true)] out TokenStringLiteral? stringLiteral)
{ {
if (Peek() is TokenStringLiteral token) 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 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) public sealed class NodeDefinitionFunc(List<Token> tokens, TokenIdent name, List<NodeDefinitionFunc.Param> parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens)
: NodeDefinition(tokens)
{ {
public TokenIdent Name = name; public readonly TokenIdent Name = name;
public List<Param> Parameters = parameters; public readonly List<Param> Parameters = parameters;
public NodeStatement Body = body; public readonly NodeStatement Body = body;
public NodeType ReturnType = returnType; public readonly NodeType ReturnType = returnType;
public sealed class Param(List<Token> tokens, TokenIdent name, NodeType type) : Node(tokens) public sealed class Param(List<Token> tokens, TokenIdent name, NodeType type) : Node(tokens)
{ {
public TokenIdent Name = name; public readonly TokenIdent Name = name;
public NodeType Type = type; 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 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 sealed class NodeStatementFuncCall(List<Token> tokens, NodeExpression func, List<NodeExpression> parameters) : NodeStatement(tokens)
{ {
public NodeExpression Func = func; public readonly NodeExpression Func = func;
public List<NodeExpression> Parameters = parameters; 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 abstract class NodeExpression(List<Token> tokens) : Node(tokens);
public sealed class NodeExpressionIntLiteral(List<Token> tokens, TokenIntLiteral value) : NodeExpression(tokens) public sealed class NodeExpressionIntLiteral(List<Token> tokens, TokenIntLiteral value) : NodeExpression(tokens)
{ {
public TokenIntLiteral Value = value; public readonly TokenIntLiteral Value = value;
}
public sealed class NodeExpressionFloatLiteral(List<Token> tokens, TokenFloatLiteral value) : NodeExpression(tokens)
{
public TokenFloatLiteral Value = value;
} }
public sealed class NodeExpressionStringLiteral(List<Token> tokens, TokenStringLiteral value) : NodeExpression(tokens) 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 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 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 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 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 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 sealed class NodeTypeBool(List<Token> tokens) : NodeType(tokens);
{
public int Width = width;
}
public sealed class NodeTypeString(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 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 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; using Compiler;
const string contents = """ const string contents = """
func main(): void { func main(): i32 {
do_something("test") do_something("test")
return 69
} }
func do_something(text: string): void { 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), "func" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Func),
"let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let), "let" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.Let),
"if" => new TokenKeyword(line, startColumn, column - startColumn, Keyword.If), "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), "true" => new TokenBoolLiteral(line, startColumn, column - startColumn, true),
"false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false), "false" => new TokenBoolLiteral(line, startColumn, column - startColumn, false),
_ => new TokenIdent(line, startColumn, column - startColumn, value) _ => 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 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) 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 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 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 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 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 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 public enum Keyword
@@ -402,9 +398,10 @@ public enum Keyword
Func, Func,
Let, Let,
If, If,
Return,
} }
public sealed class TokenKeyword(int line, int column, int length, Keyword keyword) : Token(line, column, length) 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;
} }