...
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user