WIP: dev #1

Draft
nub31 wants to merge 103 commits from dev into master
6 changed files with 185 additions and 41 deletions
Showing only changes of commit 84627dde45 - Show all commits

View File

@@ -23,6 +23,8 @@ public class Generator
private IndentedTextWriter writer = new(); private IndentedTextWriter writer = new();
private HashSet<NubType> referencedTypes = new(); private HashSet<NubType> referencedTypes = new();
private readonly HashSet<NubType> emittedTypes = new(); private readonly HashSet<NubType> emittedTypes = new();
private readonly Stack<Scope> scopes = new();
private int tmpNameIndex = 0;
private string Emit() private string Emit()
{ {
@@ -57,7 +59,9 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
EmitStatement(function.Body); EmitStatement(function.Body);
PopScope();
} }
writer.WriteLine("}"); writer.WriteLine("}");
writer.WriteLine(); writer.WriteLine();
@@ -67,25 +71,11 @@ public class Generator
writer = new IndentedTextWriter(); writer = new IndentedTextWriter();
writer.WriteLine("""
#include <float.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
""");
while (referencedTypes.Count != 0)
{
var type = referencedTypes.ElementAt(0);
EmitTypeDefinitionIfNotEmitted(type);
referencedTypes.Remove(type);
}
foreach (var module in moduleGraph.GetModules()) foreach (var module in moduleGraph.GetModules())
{ {
foreach (var (name, info) in module.GetIdentifiers()) foreach (var (name, info) in module.GetIdentifiers())
{
if (info.Source == Module.DefinitionSource.Internal || info.Exported)
{ {
if (info.Source == Module.DefinitionSource.Imported || info.Extern) if (info.Source == Module.DefinitionSource.Imported || info.Extern)
writer.Write("extern "); writer.Write("extern ");
@@ -98,10 +88,32 @@ public class Generator
writer.WriteLine($"{CType(info.Type, info.MangledName)};"); writer.WriteLine($"{CType(info.Type, info.MangledName)};");
} }
} }
}
var declarations = writer.ToString();
writer = new IndentedTextWriter();
writer.WriteLine("""
#include <float.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
""");
while (referencedTypes.Count != 0)
{
var type = referencedTypes.ElementAt(0);
EmitTypeDefinitionIfNotEmitted(type);
referencedTypes.Remove(type);
}
var header = writer.ToString(); var header = writer.ToString();
return $"{header}\n{implementations}"; return $"{header}\n{declarations}\n{implementations}";
} }
private void EmitTypeDefinitionIfNotEmitted(NubType type) private void EmitTypeDefinitionIfNotEmitted(NubType type)
@@ -121,6 +133,7 @@ public class Generator
{ {
writer.WriteLine("char *data;"); writer.WriteLine("char *data;");
writer.WriteLine("size_t length;"); writer.WriteLine("size_t length;");
writer.WriteLine("uint32_t ref;");
} }
writer.WriteLine("};"); writer.WriteLine("};");
writer.WriteLine(); writer.WriteLine();
@@ -211,6 +224,9 @@ public class Generator
private void EmitStatement(TypedNodeStatement node) private void EmitStatement(TypedNodeStatement node)
{ {
if (scopes.Peek().Unreachable)
return;
switch (node) switch (node)
{ {
case TypedNodeStatementBlock statement: case TypedNodeStatementBlock statement:
@@ -247,8 +263,10 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
foreach (var statement in node.Statements) foreach (var statement in node.Statements)
EmitStatement(statement); EmitStatement(statement);
PopScope();
} }
writer.WriteLine("}"); writer.WriteLine("}");
} }
@@ -261,21 +279,38 @@ public class Generator
} }
private void EmitStatementReturn(TypedNodeStatementReturn statement) private void EmitStatementReturn(TypedNodeStatementReturn statement)
{
if (statement.Value != null)
{ {
var value = EmitExpression(statement.Value); var value = EmitExpression(statement.Value);
writer.WriteLine($"return {value};"); var variableName = TmpName();
writer.WriteLine($"{CType(statement.Value.Type, variableName)} = {value};");
EmitCleanupAllScopes();
writer.WriteLine($"return {variableName};");
}
else
{
EmitCleanupAllScopes();
writer.WriteLine($"return;");
}
scopes.Peek().Unreachable = true;
} }
private void EmitStatementVariableDeclaration(TypedNodeStatementVariableDeclaration statement) private void EmitStatementVariableDeclaration(TypedNodeStatementVariableDeclaration statement)
{ {
var value = EmitExpression(statement.Value); var value = EmitExpression(statement.Value);
EmitCopyConstructor(value, statement.Value.Type);
writer.WriteLine($"{CType(statement.Type, statement.Name.Ident)} = {value};"); writer.WriteLine($"{CType(statement.Type, statement.Name.Ident)} = {value};");
scopes.Peek().Locals.Add((statement.Name.Ident, statement.Type));
} }
private void EmitStatementAssignment(TypedNodeStatementAssignment statement) private void EmitStatementAssignment(TypedNodeStatementAssignment statement)
{ {
var target = EmitExpression(statement.Target); var target = EmitExpression(statement.Target);
EmitCopyDestructor(target, statement.Target.Type);
var value = EmitExpression(statement.Value); var value = EmitExpression(statement.Value);
EmitCopyConstructor(value, statement.Value.Type);
writer.WriteLine($"{target} = {value};"); writer.WriteLine($"{target} = {value};");
} }
@@ -286,7 +321,9 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
EmitStatement(statement.ThenBlock); EmitStatement(statement.ThenBlock);
PopScope();
} }
writer.WriteLine("}"); writer.WriteLine("}");
@@ -301,7 +338,9 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
EmitStatement(statement.ElseBlock); EmitStatement(statement.ElseBlock);
PopScope();
} }
writer.WriteLine("}"); writer.WriteLine("}");
} }
@@ -314,7 +353,9 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
EmitStatement(statement.Body); EmitStatement(statement.Body);
PopScope();
} }
writer.WriteLine("}"); writer.WriteLine("}");
} }
@@ -342,8 +383,10 @@ public class Generator
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) using (writer.Indent())
{ {
PushScope();
writer.WriteLine($"{CType(variantInfo.Type, @case.VariableName.Ident)} = {target}.{@case.Variant.Ident};"); writer.WriteLine($"{CType(variantInfo.Type, @case.VariableName.Ident)} = {target}.{@case.Variant.Ident};");
EmitStatement(@case.Body); EmitStatement(@case.Body);
PopScope();
writer.WriteLine("break;"); writer.WriteLine("break;");
} }
writer.WriteLine("}"); writer.WriteLine("}");
@@ -360,7 +403,7 @@ public class Generator
TypedNodeExpressionUnary expression => EmitExpressionUnary(expression), TypedNodeExpressionUnary expression => EmitExpressionUnary(expression),
TypedNodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false", TypedNodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false",
TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(), TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(),
TypedNodeExpressionStringLiteral expression => $"({CType(expression.Type)}){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}", TypedNodeExpressionStringLiteral expression => EmitExpressionStringLiteral(expression),
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression), TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression), TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression), TypedNodeExpressionStructMemberAccess expression => EmitExpressionMemberAccess(expression),
@@ -411,6 +454,21 @@ public class Generator
}; };
} }
private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression)
{
var name = TmpName();
scopes.Peek().Locals.Add((name, expression.Type));
var variable = CType(expression.Type, name);
writer.WriteLine($"{variable} = malloc(sizeof(struct {NameMangler.Mangle("core", "string", expression.Type)}));");
writer.WriteLine($"{name}->data = \"{expression.Value.Value}\";");
writer.WriteLine($"{name}->length = {expression.Value.Value.Length};");
writer.WriteLine($"{name}->ref = 1;");
return name;
}
private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression) private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression)
{ {
var initializerValues = new Dictionary<string, string>(); var initializerValues = new Dictionary<string, string>();
@@ -450,13 +508,13 @@ public class Generator
private string EmitExpressionStringLength(TypedNodeExpressionStringLength expression) private string EmitExpressionStringLength(TypedNodeExpressionStringLength expression)
{ {
var target = EmitExpression(expression.Target); var target = EmitExpression(expression.Target);
return $"{target}.length"; return $"{target}->length";
} }
private string EmitExpressionStringPointer(TypedNodeExpressionStringPointer expression) private string EmitExpressionStringPointer(TypedNodeExpressionStringPointer expression)
{ {
var target = EmitExpression(expression.Target); var target = EmitExpression(expression.Target);
return $"{target}.data"; return $"{target}->data";
} }
private string EmitNodeExpressionGlobalIdent(TypedNodeExpressionGlobalIdent expression) private string EmitNodeExpressionGlobalIdent(TypedNodeExpressionGlobalIdent expression)
@@ -489,7 +547,7 @@ public class Generator
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"), NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"),
NubTypeString type => $"struct {NameMangler.Mangle("core", "string", type)}" + (varName != null ? $" {varName}" : ""), NubTypeString type => $"struct {NameMangler.Mangle("core", "string", type)}" + (varName != null ? $" *{varName}" : "*"),
NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})", NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})",
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null) _ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
}; };
@@ -499,6 +557,78 @@ public class Generator
{ {
return $"struct {NameMangler.Mangle("anonymous", "struct", type)}{(varName != null ? $" {varName}" : "")}"; return $"struct {NameMangler.Mangle("anonymous", "struct", type)}{(varName != null ? $" {varName}" : "")}";
} }
private string TmpName()
{
return $"_tmp{tmpNameIndex++}";
}
private void EmitCleanupAllScopes()
{
foreach (var scope in scopes.Reverse())
{
for (int i = scope.Locals.Count - 1; i >= 0; i--)
{
var (name, type) = scope.Locals[i];
EmitCopyDestructor(name, type);
}
}
}
private void EmitCleanupCurrentScope(Scope scope)
{
for (int i = scope.Locals.Count - 1; i >= 0; i--)
{
var (name, type) = scope.Locals[i];
EmitCopyDestructor(name, type);
}
}
private void EmitCopyConstructor(string value, NubType type)
{
switch (type)
{
case NubTypeString:
writer.WriteLine($"{value}->ref += 1;");
break;
}
}
private void EmitCopyDestructor(string value, NubType type)
{
switch (type)
{
case NubTypeString:
writer.WriteLine($"{value}->ref -= 1;");
writer.WriteLine($"if ({value}->ref == 0)");
writer.WriteLine("{");
using (writer.Indent())
{
writer.WriteLine("puts(\"free\");");
writer.WriteLine($"free({value});");
}
writer.WriteLine("}");
break;
}
}
private void PushScope()
{
scopes.Push(new Scope());
}
private void PopScope()
{
var scope = scopes.Pop();
if (!scope.Unreachable)
EmitCleanupCurrentScope(scope);
}
private class Scope
{
public List<(string Name, NubType Type)> Locals { get; } = [];
public bool Unreachable { get; set; }
}
} }
internal class IndentedTextWriter internal class IndentedTextWriter

View File

@@ -195,7 +195,17 @@ public class Parser
if (TryExpectKeyword(Keyword.Return)) if (TryExpectKeyword(Keyword.Return))
{ {
var value = ParseExpression(); NodeExpression? value = null;
if (Peek() is TokenIdent token && token.Ident == "void")
{
Next();
}
else
{
value = ParseExpression();
}
return new NodeStatementReturn(TokensFrom(startIndex), value); return new NodeStatementReturn(TokensFrom(startIndex), value);
} }
@@ -792,9 +802,9 @@ public class NodeStatementExpression(List<Token> tokens, NodeExpression expressi
public NodeExpression Expression { get; } = expression; public NodeExpression Expression { get; } = expression;
} }
public class NodeStatementReturn(List<Token> tokens, NodeExpression value) : NodeStatement(tokens) public class NodeStatementReturn(List<Token> tokens, NodeExpression? value) : NodeStatement(tokens)
{ {
public NodeExpression Value { get; } = value; public NodeExpression? Value { get; } = value;
} }
public 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)

View File

@@ -144,6 +144,15 @@ public class TypeChecker
} }
private TypedNodeStatementReturn CheckStatementReturn(NodeStatementReturn statement) private TypedNodeStatementReturn CheckStatementReturn(NodeStatementReturn statement)
{
if (statement.Value == null)
{
if (functionReturnType is not NubTypeVoid)
throw BasicError($"Missing return value. Expected '{functionReturnType}'", statement);
return new TypedNodeStatementReturn(statement.Tokens, null);
}
else
{ {
var value = CheckExpression(statement.Value, functionReturnType); var value = CheckExpression(statement.Value, functionReturnType);
if (!value.Type.IsAssignableTo(functionReturnType)) if (!value.Type.IsAssignableTo(functionReturnType))
@@ -151,6 +160,7 @@ public class TypeChecker
return new TypedNodeStatementReturn(statement.Tokens, value); return new TypedNodeStatementReturn(statement.Tokens, value);
} }
}
private TypedNodeStatementVariableDeclaration CheckStatementVariableDeclaration(NodeStatementVariableDeclaration statement) private TypedNodeStatementVariableDeclaration CheckStatementVariableDeclaration(NodeStatementVariableDeclaration statement)
{ {
@@ -796,9 +806,9 @@ public class TypedNodeStatementFuncCall(List<Token> tokens, TypedNodeExpression
public List<TypedNodeExpression> Parameters { get; } = parameters; public List<TypedNodeExpression> Parameters { get; } = parameters;
} }
public class TypedNodeStatementReturn(List<Token> tokens, TypedNodeExpression value) : TypedNodeStatement(tokens) public class TypedNodeStatementReturn(List<Token> tokens, TypedNodeExpression? value) : TypedNodeStatement(tokens)
{ {
public TypedNodeExpression Value { get; } = value; public TypedNodeExpression? Value { get; } = value;
} }
public class TypedNodeStatementVariableDeclaration(List<Token> tokens, TokenIdent name, NubType type, TypedNodeExpression value) : TypedNodeStatement(tokens) public class TypedNodeStatementVariableDeclaration(List<Token> tokens, TokenIdent name, NubType type, TypedNodeExpression value) : TypedNodeStatement(tokens)

View File

@@ -1,7 +1,7 @@
set -e set -e
pushd core pushd core
dotnet run --project ../../compiler mem.nub print.nub --type=lib dotnet run --project ../../compiler print.nub --type=lib
popd popd
pushd program pushd program

View File

@@ -1,4 +0,0 @@
module core
export extern func malloc(size: u64): ^void
export extern func free(size: ^void)

View File

@@ -1,7 +1,5 @@
module main module main
func main(): i32 func main(): i32 {
{
core::print("Hello, world")
return 0 return 0
} }