...
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
_sourceFiles = sourceFiles;
|
||||
_builder = new StringBuilder();
|
||||
_variables = new Dictionary<string, Variable>();
|
||||
_strings = [];
|
||||
_breakLabels = [];
|
||||
_continueLabels = [];
|
||||
_variableIndex = 0;
|
||||
_codeIsReachable = true;
|
||||
|
||||
public string Generate()
|
||||
{
|
||||
foreach (var structDefinition in _definitions.OfType<StructDefinitionNode>())
|
||||
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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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), 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());
|
||||
}
|
||||
}
|
||||
|
||||
expr = new StructInitializerNode(GetTokensForNode(startIndex), type, initializers);
|
||||
break;
|
||||
}
|
||||
case Symbol.Ampersand:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -29,7 +39,7 @@ 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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user