diff --git a/compiler/Compiler/Generator.cs b/compiler/Compiler/Generator.cs index 2bc648c..6fe4cf3 100644 --- a/compiler/Compiler/Generator.cs +++ b/compiler/Compiler/Generator.cs @@ -23,16 +23,16 @@ public sealed class Generator(List nodes) foreach (var node in nodes.OfType()) { - 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()) { - 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()) { @@ -56,6 +56,9 @@ public sealed class Generator(List nodes) case NodeStatementFuncCall statement: EmitStatementFuncCall(statement); break; + case NodeStatementReturn statement: + EmitStatementReturn(statement); + break; } } @@ -78,6 +81,12 @@ public sealed class Generator(List 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 @@ -109,36 +118,63 @@ public sealed class Generator(List nodes) return expression.Value.Ident; } - private static string CType(NodeType node) + private static string CType(NodeType type, string? variableName = null) { - return node switch + return type 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" + (variableName != null ? $" {variableName}" : ""), + NodeTypeBool => "bool" + (variableName != null ? $" {variableName}" : ""), + NodeTypeSInt intType => CTypeSInt(intType, variableName), + NodeTypeUInt intType => CTypeUInt(intType, variableName), + NodeTypePointer ptr => CType(ptr.To) + "*" + (variableName != null ? $" {variableName}" : ""), + NodeTypeString => "struct string" + (variableName != null ? $" {variableName}" : ""), + NodeTypeFunc fn => CTypeFunc(fn, variableName), }; } + + private static string CTypeSInt(NodeTypeSInt intType, string? varName) + { + var cType = intType.Width switch + { + 8 => "char", + 16 => "short", + 32 => "int", + 64 => "long long", + }; + + return cType + (varName != null ? $" {varName}" : ""); + } + + private static string CTypeUInt(NodeTypeUInt intType, string? varName) + { + var cType = intType.Width switch + { + 8 => "unsigned char", + 16 => "unsigned short", + 32 => "unsigned int", + 64 => "unsigned long long", + }; + + return cType + (varName != null ? $" {varName}" : ""); + } + + private static string CTypeFunc(NodeTypeFunc fn, string? varName) + { + var returnType = CType(fn.ReturnType); + var parameters = string.Join(", ", fn.Parameters.Select(p => CType(p))); + + if (string.IsNullOrEmpty(parameters)) + { + parameters = "void"; + } + + if (varName != null) + { + return $"{returnType} (*{varName})({parameters})"; + } + + return $"{returnType} (*)({parameters})"; + } } internal class IndentedTextWriter diff --git a/compiler/Compiler/Parser.cs b/compiler/Compiler/Parser.cs index 6a974f4..197d9d3 100644 --- a/compiler/Compiler/Parser.cs +++ b/compiler/Compiler/Parser.cs @@ -64,6 +64,12 @@ public sealed class Parser(List 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(); @@ -111,14 +117,32 @@ public sealed class Parser(List tokens) return new NodeTypePointer(TokensFrom(startIndex), to); } + if (TryExpectKeyword(Keyword.Func)) + { + var parameters = new List(); + + 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": @@ -135,10 +159,6 @@ public sealed class Parser(List 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); } @@ -272,8 +292,7 @@ public abstract class Node(List tokens) public abstract class NodeDefinition(List tokens) : Node(tokens); -public sealed class NodeDefinitionFunc(List tokens, TokenIdent name, List parameters, NodeStatement body, NodeType returnType) - : NodeDefinition(tokens) +public sealed class NodeDefinitionFunc(List tokens, TokenIdent name, List parameters, NodeStatement body, NodeType returnType) : NodeDefinition(tokens) { public readonly TokenIdent Name = name; public readonly List Parameters = parameters; @@ -300,6 +319,11 @@ public sealed class NodeStatementFuncCall(List tokens, NodeExpression fun public readonly List Parameters = parameters; } +internal class NodeStatementReturn(List tokens, NodeExpression value) : NodeStatement(tokens) +{ + public readonly NodeExpression Value = value; +} + public abstract class NodeExpression(List tokens) : Node(tokens); public sealed class NodeExpressionIntLiteral(List tokens, TokenIntLiteral value) : NodeExpression(tokens) @@ -324,7 +348,7 @@ public sealed class NodeExpressionIdent(List tokens, TokenIdent value) : public abstract class NodeType(List tokens) : Node(tokens); -public sealed class NubTypeVoid(List tokens) : NodeType(tokens); +public sealed class NodeTypeVoid(List tokens) : NodeType(tokens); public sealed class NodeTypeUInt(List tokens, int width) : NodeType(tokens) { @@ -336,10 +360,7 @@ public sealed class NodeTypeSInt(List tokens, int width) : NodeType(token public readonly int Width = width; } -public sealed class NodeTypeFloat(List tokens, int width) : NodeType(tokens) -{ - public readonly int Width = width; -} +public sealed class NodeTypeBool(List tokens) : NodeType(tokens); public sealed class NodeTypeString(List tokens) : NodeType(tokens); @@ -351,4 +372,10 @@ public sealed class NodeTypeCustom(List tokens, TokenIdent name) : NodeTy public sealed class NodeTypePointer(List tokens, NodeType to) : NodeType(tokens) { public readonly NodeType To = to; +} + +public sealed class NodeTypeFunc(List tokens, List parameters, NodeType returnType) : NodeType(tokens) +{ + public readonly List Parameters = parameters; + public readonly NodeType ReturnType = returnType; } \ No newline at end of file diff --git a/compiler/Compiler/Program.cs b/compiler/Compiler/Program.cs index c89edc7..8c9cd6f 100644 --- a/compiler/Compiler/Program.cs +++ b/compiler/Compiler/Program.cs @@ -1,11 +1,12 @@ using Compiler; const string contents = """ - func main(): void { + func main(): i32 { do_something("test") + return 69 } - func do_something(text: string): void { + func do_something(text: string): func(i32 u32): void { } """; diff --git a/compiler/Compiler/Tokenizer.cs b/compiler/Compiler/Tokenizer.cs index 4e1b8d3..629cfeb 100644 --- a/compiler/Compiler/Tokenizer.cs +++ b/compiler/Compiler/Tokenizer.cs @@ -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) @@ -397,6 +398,7 @@ public enum Keyword Func, Let, If, + Return, } public sealed class TokenKeyword(int line, int column, int length, Keyword keyword) : Token(line, column, length)