This commit is contained in:
nub31
2025-05-26 20:39:41 +02:00
parent dcf62e3e05
commit 3279eb7df5
8 changed files with 145 additions and 107 deletions

View File

@@ -1,5 +1,6 @@
namespace c
extern func printf(fmt: string, ...args: any)
extern func printf(fmt: string, ...args: any)
extern func getchar(): i32
extern func puts(str: string)

View File

@@ -6,31 +6,35 @@ namespace Nub.Lang.Backend;
public class Generator
{
private readonly List<DefinitionNode> _definitions;
private readonly StringBuilder _builder = new();
private readonly Dictionary<string, Variable> _variables = new();
private readonly List<string> _strings = [];
private readonly Stack<string> _breakLabels = new();
private readonly Stack<string> _continueLabels = new();
private List<SourceFile> _sourceFiles = [];
private StringBuilder _builder = new();
private Dictionary<string, Variable> _variables = [];
private List<string> _strings = [];
private Stack<string> _breakLabels = [];
private Stack<string> _continueLabels = [];
private int _variableIndex;
private bool _codeIsReachable = true;
public Generator(List<DefinitionNode> definitions)
public string Generate(List<SourceFile> sourceFiles)
{
_definitions = definitions;
}
public string Generate()
{
foreach (var structDefinition in _definitions.OfType<StructDefinitionNode>())
_sourceFiles = sourceFiles;
_builder = new StringBuilder();
_variables = new Dictionary<string, Variable>();
_strings = [];
_breakLabels = [];
_continueLabels = [];
_variableIndex = 0;
_codeIsReachable = true;
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
{
GenerateStructDefinition(structDefinition);
GenerateStructDefinition(structDef);
_builder.AppendLine();
}
foreach (var funcDefinition in _definitions.OfType<LocalFuncDefinitionNode>())
foreach (var funcDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<LocalFuncDefinitionNode>())
{
GenerateFuncDefinition(funcDefinition);
GenerateFuncDefinition(funcDef);
_builder.AppendLine();
}
@@ -213,12 +217,12 @@ public class Generator
throw new ArgumentOutOfRangeException();
}
}
case NubStructType nubCustomType:
case NubStructType nubStructType:
{
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == nubCustomType.Name);
var definition = LookupStructDefinition(nubStructType.Namespace, nubStructType.Name);
if (definition == null)
{
throw new Exception($"Cannot determine size of non-existent type {nubCustomType}");
throw new Exception($"Cannot determine size of non-existent type {nubStructType}");
}
return definition.Fields.Sum(f => QbeTypeSize(f.Type));
@@ -362,12 +366,8 @@ public class Generator
private string GenerateFuncCall(FuncCall funcCall)
{
var parameterDefinitions = _definitions
.OfType<IFuncSignature>()
.FirstOrDefault(d => d.Name == funcCall.Name)
?.Parameters;
if (parameterDefinitions == null)
var funcDefinition = LookupFuncSignature(funcCall.Namespace, funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
if (funcDefinition == null)
{
throw new Exception($"Unknown function {funcCall}");
}
@@ -376,19 +376,19 @@ public class Generator
for (var i = 0; i < funcCall.Parameters.Count; i++)
{
if (i < parameterDefinitions.Count && parameterDefinitions[i].Variadic)
if (i < funcDefinition.Parameters.Count && funcDefinition.Parameters[i].Variadic)
{
parameterStrings.Add("...");
}
NubType expectedType;
if (i < parameterDefinitions.Count)
if (i < funcDefinition.Parameters.Count)
{
expectedType = parameterDefinitions[i].Type;
expectedType = funcDefinition.Parameters[i].Type;
}
else if (parameterDefinitions[^1].Variadic)
else if (funcDefinition.Parameters[^1].Variadic)
{
expectedType = parameterDefinitions[^1].Type;
expectedType = funcDefinition.Parameters[^1].Type;
}
else
{
@@ -1295,7 +1295,7 @@ public class Generator
private string GenerateStructInitializer(StructInitializerNode structInitializer)
{
var structDefinition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == structInitializer.StructType.Name);
var structDefinition = LookupStructDefinition(structInitializer.StructType.Namespace, structInitializer.StructType.Name);
if (structDefinition == null)
{
throw new Exception($"Struct {structInitializer.StructType.Name} is not defined");
@@ -1399,10 +1399,7 @@ public class Generator
}
case NubStructType structType:
{
var structDefinition = _definitions
.OfType<StructDefinitionNode>()
.FirstOrDefault(s => s.Name == structType.Name);
var structDefinition = LookupStructDefinition(structType.Namespace, structType.Namespace);
if (structDefinition == null)
{
throw new Exception($"Struct {structType.Name} is not defined");
@@ -1449,6 +1446,24 @@ public class Generator
return $"v{++_variableIndex}";
}
private IFuncSignature? LookupFuncSignature(string @namespace, string name, List<NubType> parameters)
{
return _sourceFiles
.Where(f => f.Namespace == @namespace)
.SelectMany(f => f.Definitions)
.OfType<IFuncSignature>()
.FirstOrDefault(f => f.SignatureMatches(name, parameters));
}
private StructDefinitionNode? LookupStructDefinition(string @namespace, string name)
{
return _sourceFiles
.Where(f => f.Namespace == @namespace)
.SelectMany(f => f.Definitions)
.OfType<StructDefinitionNode>()
.FirstOrDefault(d => d.Name == name);
}
private class Variable
{
public required string Pointer { get; init; }

View File

@@ -8,10 +8,41 @@ public interface IFuncSignature
public List<FuncParameter> Parameters { get; }
public Optional<NubType> ReturnType { get; }
public bool SignatureMatches(string name, List<NubType> parameters)
{
if (Name != name) return false;
if (Parameters.Count == 0 && parameters.Count == 0) return true;
if (Parameters.Count > parameters.Count) return false;
for (var i = 0; i < parameters.Count; i++)
{
if (i > Parameters.Count)
{
if (Parameters[^1].Variadic)
{
if (!NubType.IsCompatibleWith(parameters[i], Parameters[^1].Type))
{
return false;
}
}
else
{
return false;
}
}
else if (!NubType.IsCompatibleWith(parameters[i], Parameters[i].Type))
{
return false;
}
}
return true;
}
public string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
}
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool global) : DefinitionNode(tokens, documentation)
public class LocalFuncDefinitionNode(IReadOnlyList<Token> tokens, Optional<string> documentation, string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType, bool global) : DefinitionNode(tokens, documentation), IFuncSignature
{
public string Name { get; } = name;
public List<FuncParameter> Parameters { get; } = parameters;

View File

@@ -484,17 +484,36 @@ public class Parser
case Symbol.New:
{
var type = ParseType();
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
switch (type)
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
}
case NubStructType structType:
{
Dictionary<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.Assign);
var value = ParseExpression();
initializers.Add(name, value);
}
expr = new StructInitializerNode(GetTokensForNode(startIndex), type, initializers);
expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers);
break;
}
case NubArrayType arrayType:
{
throw new NotImplementedException();
}
default:
{
throw new ParseException(Diagnostic
.Error($"Cannot use new keyword on type {type}")
.At(symbolToken)
.Build());
}
}
break;
}
case Symbol.Ampersand:

View File

@@ -2,8 +2,8 @@
namespace Nub.Lang.Frontend.Parsing;
public class StructInitializerNode(IReadOnlyList<Token> tokens, NubType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode(tokens)
public class StructInitializerNode(IReadOnlyList<Token> tokens, NubStructType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode(tokens)
{
public NubType StructType { get; } = structType;
public NubStructType StructType { get; } = structType;
public Dictionary<string, ExpressionNode> Initializers { get; } = initializers;
}

View File

@@ -11,7 +11,7 @@ public class TypeChecker
private NubType? _currentFunctionReturnType;
private bool _hasReturnStatement;
public DiagnosticsResult<List<DefinitionNode>> TypeCheck(List<SourceFile> sourceFiles)
public DiagnosticsResult TypeCheck(List<SourceFile> sourceFiles)
{
_variables = new Dictionary<string, NubType>();
_diagnostics = [];
@@ -19,6 +19,16 @@ public class TypeChecker
_hasReturnStatement = false;
_sourceFiles = sourceFiles;
var externFunctionNames = _sourceFiles
.SelectMany(f => f.Definitions)
.OfType<ExternFuncDefinitionNode>()
.ToArray();
foreach (var funcName in externFunctionNames.Where(x => externFunctionNames.Count(y => x.Name == y.Name) > 1))
{
ReportError($"Extern function '{funcName}' has been declared more than once", funcName);
}
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
{
TypeCheckStructDef(structDef);
@@ -28,8 +38,8 @@ public class TypeChecker
{
TypeCheckFuncDef(funcDef);
}
return new DiagnosticsResult<List<DefinitionNode>>(_diagnostics, _sourceFiles.SelectMany(f => f.Definitions).ToList());
return new DiagnosticsResult(_diagnostics);
}
private void TypeCheckStructDef(StructDefinitionNode structDef)
@@ -120,14 +130,14 @@ public class TypeChecker
{
if (varAssign.ExplicitType.HasValue)
{
if (!AreTypesCompatible(existingVariable, varAssign.ExplicitType.Value))
if (!NubType.IsCompatibleWith(existingVariable, varAssign.ExplicitType.Value))
{
ReportError($"Explicit type '{varAssign.ExplicitType.Value}' on variable '{varAssign.Name}' is not compatible with declared type '{existingVariable}'", varAssign);
return;
}
}
if (!AreTypesCompatible(valueType, existingVariable))
if (!NubType.IsCompatibleWith(valueType, existingVariable))
{
ReportError($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{existingVariable}'", varAssign);
}
@@ -137,7 +147,7 @@ public class TypeChecker
if (varAssign.ExplicitType.HasValue)
{
var explicitType = varAssign.ExplicitType.Value;
if (!AreTypesCompatible(valueType, explicitType))
if (!NubType.IsCompatibleWith(valueType, explicitType))
{
ReportError($"Cannot assign expression of type '{valueType}' to variable '{varAssign.Name}' of type '{explicitType}'", varAssign);
return;
@@ -208,7 +218,7 @@ public class TypeChecker
continue;
}
if (!AreTypesCompatible(argType, paramType))
if (!NubType.IsCompatibleWith(argType, paramType))
{
ReportError($"Parameter {i + 1} of function '{funcCall.Name}' expects type '{paramType}', but got '{argType}'", funcCall.Parameters[i]);
}
@@ -260,7 +270,7 @@ public class TypeChecker
return;
}
if (!AreTypesCompatible(returnType, _currentFunctionReturnType))
if (!NubType.IsCompatibleWith(returnType, _currentFunctionReturnType))
{
ReportError($"Return value of type '{returnType}' is not compatible with function return type '{_currentFunctionReturnType}'", returnNode.Value.Value);
}
@@ -405,17 +415,10 @@ public class TypeChecker
{
var initialized = new HashSet<string>();
var structType = structInit.StructType;
if (structType is not NubStructType customType)
{
ReportError($"Type '{structType}' is not a struct type", structInit);
return null;
}
var definition = LookupStructDefinition(customType.Namespace, customType.Name);
var definition = LookupStructDefinition(structInit.StructType.Namespace, structInit.StructType.Name);
if (definition == null)
{
ReportError($"Struct type '{customType.Name}' is not defined", structInit);
ReportError($"Struct type '{structInit.StructType.Name}' is not defined", structInit);
return null;
}
@@ -424,12 +427,12 @@ public class TypeChecker
var definitionField = definition.Fields.FirstOrDefault(f => f.Name == initializer.Key);
if (definitionField == null)
{
ReportError($"Field '{initializer.Key}' does not exist in struct '{customType.Name}'", initializer.Value);
ReportError($"Field '{initializer.Key}' does not exist in struct '{structInit.StructType.Name}'", initializer.Value);
continue;
}
var initializerType = TypeCheckExpression(initializer.Value);
if (initializerType != null && !AreTypesCompatible(initializerType, definitionField.Type))
if (initializerType != null && !NubType.IsCompatibleWith(initializerType, definitionField.Type))
{
ReportError($"Cannot initialize field '{initializer.Key}' of type '{definitionField.Type}' with expression of type '{initializerType}'", initializer.Value);
}
@@ -446,11 +449,11 @@ public class TypeChecker
{
if (!initialized.Contains(field.Name))
{
ReportError($"Struct field '{field.Name}' is not initialized on type '{customType.Name}'", structInit);
ReportError($"Struct field '{field.Name}' is not initialized on type '{structInit.StructType.Name}'", structInit);
}
}
return structType;
return structInit.StructType;
}
private NubType? TypeCheckUnaryExpression(UnaryExpressionNode unaryExpression)
@@ -539,11 +542,6 @@ public class TypeChecker
_diagnostics.Add(diagnostic);
}
private static bool AreTypesCompatible(NubType sourceType, NubType targetType)
{
return targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType);
}
private static bool IsNumeric(NubType type)
{
if (type is not NubPrimitiveType primitiveType)
@@ -598,38 +596,7 @@ public class TypeChecker
.Where(f => f.Namespace == @namespace)
.SelectMany(f => f.Definitions)
.OfType<IFuncSignature>()
.FirstOrDefault(SignatureMatches);
bool SignatureMatches(IFuncSignature node)
{
if (node.Name != name) return false;
if (node.Parameters.Count == 0 && parameters.Count == 0) return true;
if (node.Parameters.Count > parameters.Count) return false;
for (var i = 0; i < parameters.Count; i++)
{
if (i > node.Parameters.Count)
{
if (node.Parameters[^1].Variadic)
{
if (!AreTypesCompatible(parameters[i], node.Parameters[^1].Type))
{
return false;
}
}
else
{
return false;
}
}
else if (!AreTypesCompatible(parameters[i], node.Parameters[i].Type))
{
return false;
}
}
return true;
}
.FirstOrDefault(f => f.SignatureMatches(name, parameters));
}
private StructDefinitionNode? LookupStructDefinition(string @namespace, string name)

View File

@@ -11,6 +11,11 @@ public abstract class NubType
public string Name { get; }
public static bool IsCompatibleWith(NubType sourceType, NubType targetType)
{
return targetType.Equals(NubPrimitiveType.Any) || sourceType.Equals(targetType);
}
public override bool Equals(object? obj) => obj is NubType item && Name.Equals(item.Name);
public override int GetHashCode() => HashCode.Combine(Name);
public override string ToString() => Name;

View File

@@ -58,8 +58,8 @@ internal static class Program
typeCheckResult.PrintAllDiagnostics();
error = error || typeCheckResult.HasErrors;
var generator = new Generator(typeCheckResult.Value);
var result = generator.Generate();
var generator = new Generator();
var result = generator.Generate(files);
Console.Out.Write(result);