This commit is contained in:
nub31
2025-05-26 20:10:22 +02:00
parent 37b4ce3989
commit f63cee1011
5 changed files with 127 additions and 26 deletions

View File

@@ -5,10 +5,10 @@ namespace main
global func main(args: []string) { global func main(args: []string) {
i = 0 i = 0
printf("%d\n", args.count) c::printf("%d\n", args.count)
while i < args.count { while i < args.count {
printf("%s\n", args[i]) c::printf("%s\n", args[i])
i = i + 1 i = i + 1
} }

View File

@@ -596,7 +596,19 @@ public class Parser
{ {
if (TryExpectIdentifier(out var name)) if (TryExpectIdentifier(out var name))
{ {
return NubType.Parse(name); if (NubPrimitiveType.TryParse(name, out var primitiveTypeKind))
{
return new NubPrimitiveType(primitiveTypeKind.Value);
}
else
{
var @namespace = _namespace;
if (TryExpectSymbol(Symbol.DoubleColon))
{
@namespace = ExpectIdentifier().Value;
}
return new NubStructType(@namespace, name);
}
} }
if (TryExpectSymbol(Symbol.Caret)) if (TryExpectSymbol(Symbol.Caret))

View File

@@ -10,27 +10,26 @@ public class TypeChecker
private List<Diagnostic> _diagnostics = []; private List<Diagnostic> _diagnostics = [];
private NubType? _currentFunctionReturnType; private NubType? _currentFunctionReturnType;
private bool _hasReturnStatement; private bool _hasReturnStatement;
private List<DefinitionNode> _definitions = [];
public DiagnosticsResult<List<DefinitionNode>> TypeCheck(List<SourceFile> sourceFiles) public DiagnosticsResult<List<DefinitionNode>> TypeCheck(List<SourceFile> sourceFiles)
{ {
_variables = new Dictionary<string, NubType>(); _variables = new Dictionary<string, NubType>();
_diagnostics = []; _diagnostics = [];
_definitions = sourceFiles.SelectMany(x => x.Definitions).ToList();
_currentFunctionReturnType = null; _currentFunctionReturnType = null;
_hasReturnStatement = false; _hasReturnStatement = false;
_sourceFiles = sourceFiles;
foreach (var structDef in _definitions.OfType<StructDefinitionNode>()) foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
{ {
TypeCheckStructDef(structDef); TypeCheckStructDef(structDef);
} }
foreach (var funcDef in _definitions.OfType<LocalFuncDefinitionNode>()) foreach (var funcDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<LocalFuncDefinitionNode>())
{ {
TypeCheckFuncDef(funcDef); TypeCheckFuncDef(funcDef);
} }
return new DiagnosticsResult<List<DefinitionNode>>(_diagnostics, _definitions); return new DiagnosticsResult<List<DefinitionNode>>(_diagnostics, _sourceFiles.SelectMany(f => f.Definitions).ToList());
} }
private void TypeCheckStructDef(StructDefinitionNode structDef) private void TypeCheckStructDef(StructDefinitionNode structDef)
@@ -169,8 +168,16 @@ public class TypeChecker
private NubType? TypeCheckFuncCall(FuncCall funcCall, Node node) private NubType? TypeCheckFuncCall(FuncCall funcCall, Node node)
{ {
var localFuncDef = _definitions.OfType<LocalFuncDefinitionNode>().FirstOrDefault(f => f.Name == funcCall.Name); List<NubType> parameterTypes = [];
var externFuncDef = _definitions.OfType<ExternFuncDefinitionNode>().FirstOrDefault(f => f.Name == funcCall.Name); foreach (var funcCallParameter in funcCall.Parameters)
{
var parameterType = TypeCheckExpression(funcCallParameter);
if (parameterType == null) return null;
parameterTypes.Add(parameterType);
}
var localFuncDef = LookupLocalFuncDefinition(funcCall.Namespace, funcCall.Name, parameterTypes);
var externFuncDef = LookupExternFuncDefinition(funcCall.Namespace, funcCall.Name, parameterTypes);
List<FuncParameter> parameters; List<FuncParameter> parameters;
Optional<NubType> returnType; Optional<NubType> returnType;
@@ -198,8 +205,7 @@ public class TypeChecker
for (var i = 0; i < funcCall.Parameters.Count; i++) for (var i = 0; i < funcCall.Parameters.Count; i++)
{ {
var argType = TypeCheckExpression(funcCall.Parameters[i]); var argType = funcCall.Parameters[i].Type;
if (argType == null) continue;
NubType paramType; NubType paramType;
if (i < parameters.Count) if (i < parameters.Count)
@@ -420,7 +426,7 @@ public class TypeChecker
return null; return null;
} }
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == structInit.StructType.Name); var definition = LookupStructDefinition(customType.Namespace, customType.Name);
if (definition == null) if (definition == null)
{ {
ReportError($"Struct type '{customType.Name}' is not defined", structInit); ReportError($"Struct type '{customType.Name}' is not defined", structInit);
@@ -519,7 +525,7 @@ public class TypeChecker
} }
case NubStructType structType: case NubStructType structType:
{ {
var definition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(s => s.Name == structType.Name); var definition = LookupStructDefinition(structType.Namespace, structType.Name);
if (definition == null) if (definition == null)
{ {
ReportError($"Struct type '{structType.Name}' is not defined", memberAccess); ReportError($"Struct type '{structType.Name}' is not defined", memberAccess);
@@ -599,4 +605,90 @@ public class TypeChecker
return false; return false;
} }
} }
private TDefinition? LookupDefinition<TDefinition>(string @namespace, Func<TDefinition, bool> predicate) where TDefinition : DefinitionNode
{
return _sourceFiles
.Where(f => f.Namespace == @namespace)
.SelectMany(f => f.Definitions)
.OfType<TDefinition>()
.FirstOrDefault(predicate);
}
private ExternFuncDefinitionNode? LookupExternFuncDefinition(string @namespace, string name, List<NubType> parameters)
{
return LookupDefinition<ExternFuncDefinitionNode>(@namespace, SignatureMatches);
bool SignatureMatches(ExternFuncDefinitionNode 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;
}
}
private LocalFuncDefinitionNode? LookupLocalFuncDefinition(string @namespace, string name, List<NubType> parameters)
{
return LookupDefinition<LocalFuncDefinitionNode>(@namespace, SignatureMatches);
bool SignatureMatches(LocalFuncDefinitionNode 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;
}
}
private StructDefinitionNode? LookupStructDefinition(string @namespace, string name)
{
return LookupDefinition<StructDefinitionNode>(@namespace, d => d.Name == name);
}
} }

View File

@@ -11,22 +11,15 @@ public abstract class NubType
public string Name { get; } public string Name { get; }
public static NubType Parse(string s)
{
if (NubPrimitiveType.TryParse(s, out var kind))
{
return new NubPrimitiveType(kind.Value);
}
return new NubStructType(s);
}
public override bool Equals(object? obj) => obj is NubType item && Name.Equals(item.Name); public override bool Equals(object? obj) => obj is NubType item && Name.Equals(item.Name);
public override int GetHashCode() => HashCode.Combine(Name); public override int GetHashCode() => HashCode.Combine(Name);
public override string ToString() => Name; public override string ToString() => Name;
} }
public class NubStructType(string name) : NubType(name); public class NubStructType(string name, string @namespace) : NubType(name)
{
public string Namespace { get; } = @namespace;
}
public class NubPointerType(NubType baseType) : NubType("^" + baseType) public class NubPointerType(NubType baseType) : NubType("^" + baseType)
{ {

View File

@@ -30,6 +30,7 @@ internal static class Program
private static int Compile(string srcDir) private static int Compile(string srcDir)
{ {
var error = false;
var lexer = new Lexer(); var lexer = new Lexer();
var parser = new Parser(); var parser = new Parser();
var typeChecker = new TypeChecker(); var typeChecker = new TypeChecker();
@@ -41,9 +42,11 @@ internal static class Program
var tokenizeResult = lexer.Tokenize(new SourceText(file, content)); var tokenizeResult = lexer.Tokenize(new SourceText(file, content));
tokenizeResult.PrintAllDiagnostics(); tokenizeResult.PrintAllDiagnostics();
error = error || tokenizeResult.HasErrors;
var parseResult = parser.ParseModule(tokenizeResult.Value); var parseResult = parser.ParseModule(tokenizeResult.Value);
parseResult.PrintAllDiagnostics(); parseResult.PrintAllDiagnostics();
error = error || parseResult.HasErrors;
if (parseResult.Value != null) if (parseResult.Value != null)
{ {
@@ -53,12 +56,13 @@ internal static class Program
var typeCheckResult = typeChecker.TypeCheck(files); var typeCheckResult = typeChecker.TypeCheck(files);
typeCheckResult.PrintAllDiagnostics(); typeCheckResult.PrintAllDiagnostics();
error = error || typeCheckResult.HasErrors;
var generator = new Generator(typeCheckResult.Value); var generator = new Generator(typeCheckResult.Value);
var result = generator.Generate(); var result = generator.Generate();
Console.Out.Write(result); Console.Out.Write(result);
return 0; return error ? 1 : 0;
} }
} }