...
This commit is contained in:
@@ -2,14 +2,13 @@
|
||||
using NubLang.Ast;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Generation;
|
||||
using NubLang.Modules;
|
||||
using NubLang.Syntax;
|
||||
|
||||
var diagnostics = new List<Diagnostic>();
|
||||
var syntaxTrees = new List<SyntaxTree>();
|
||||
|
||||
var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub");
|
||||
var objectFiles = args.Where(x => Path.GetExtension(x) is ".o" or ".a");
|
||||
var nubFiles = args.Where(x => Path.GetExtension(x) == ".nub").ToArray();
|
||||
var objectFileArgs = args.Where(x => Path.GetExtension(x) is ".o" or ".a").ToArray();
|
||||
|
||||
foreach (var file in nubFiles)
|
||||
{
|
||||
@@ -24,16 +23,15 @@ foreach (var file in nubFiles)
|
||||
syntaxTrees.Add(syntaxTree);
|
||||
}
|
||||
|
||||
var moduleRepository = new ModuleRepository(syntaxTrees);
|
||||
var modules = Module.Collect(syntaxTrees);
|
||||
var compilationUnits = new List<CompilationUnit>();
|
||||
|
||||
var definitions = new List<DefinitionNode>();
|
||||
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
for (var i = 0; i < nubFiles.Length; i++)
|
||||
{
|
||||
var typeChecker = new TypeChecker(syntaxTree, moduleRepository);
|
||||
typeChecker.Check();
|
||||
var typeChecker = new TypeChecker(syntaxTrees[i], modules);
|
||||
var compilationUnit = typeChecker.Check();
|
||||
|
||||
definitions.AddRange(typeChecker.Definitions);
|
||||
compilationUnits.Add(compilationUnit);
|
||||
diagnostics.AddRange(typeChecker.Diagnostics);
|
||||
}
|
||||
|
||||
@@ -47,36 +45,57 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
||||
return 1;
|
||||
}
|
||||
|
||||
var cPaths = new List<string>();
|
||||
|
||||
Directory.CreateDirectory(".build");
|
||||
|
||||
var generator = new Generator(definitions);
|
||||
var c = generator.Emit();
|
||||
var cFilePath = Path.Combine(".build", "out.c");
|
||||
|
||||
File.WriteAllText(cFilePath, c);
|
||||
|
||||
using var compileProcess = Process.Start("gcc", [
|
||||
"-ffreestanding", "-nostartfiles", "-std=c23",
|
||||
"-g", "-lm",
|
||||
"-c", "-o", Path.Combine(".build", "out.o"),
|
||||
cFilePath,
|
||||
]);
|
||||
|
||||
compileProcess.WaitForExit();
|
||||
|
||||
if (compileProcess.ExitCode != 0)
|
||||
for (var i = 0; i < nubFiles.Length; i++)
|
||||
{
|
||||
Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}");
|
||||
return 1;
|
||||
var file = nubFiles[i];
|
||||
var compilationUnit = compilationUnits[i];
|
||||
|
||||
var generator = new Generator(compilationUnit);
|
||||
var directory = Path.GetDirectoryName(file);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(".build", directory));
|
||||
}
|
||||
|
||||
var path = Path.Combine(".build", Path.ChangeExtension(file, "c"));
|
||||
File.WriteAllText(path, generator.Emit());
|
||||
cPaths.Add(path);
|
||||
}
|
||||
|
||||
if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
|
||||
var objectPaths = new List<string>();
|
||||
|
||||
foreach (var cPath in cPaths)
|
||||
{
|
||||
var objectPath = Path.ChangeExtension(cPath, "o");
|
||||
using var compileProcess = Process.Start("gcc", [
|
||||
"-ffreestanding", "-nostartfiles", "-std=c23",
|
||||
"-g", "-lm",
|
||||
"-c", "-o", objectPath,
|
||||
cPath,
|
||||
]);
|
||||
|
||||
compileProcess.WaitForExit();
|
||||
|
||||
if (compileProcess.ExitCode != 0)
|
||||
{
|
||||
Console.Error.WriteLine($"gcc failed with exit code {compileProcess.ExitCode}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
objectPaths.Add(objectPath);
|
||||
}
|
||||
|
||||
if (modules.TryGetValue("main", out var mainModule))
|
||||
{
|
||||
var mainFunction = mainModule
|
||||
.Functions(true)
|
||||
.FirstOrDefault(x => x.ExternSymbol == "main");
|
||||
.FirstOrDefault(x => x.Prototype.ExternSymbol == "main");
|
||||
|
||||
if (mainFunction is { ExternSymbol: not null })
|
||||
if (mainFunction is { Prototype.ExternSymbol: not null })
|
||||
{
|
||||
var runtime = $"""
|
||||
.intel_syntax noprefix
|
||||
@@ -85,7 +104,7 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
|
||||
.globl _start
|
||||
_start:
|
||||
mov rdi, rsp # Pass stack pointer to main (length + cstring pointers)
|
||||
call {mainFunction.ExternSymbol}
|
||||
call {mainFunction.Prototype.ExternSymbol}
|
||||
mov rdi, rax # Move return value into rdi
|
||||
mov rax, 60 # syscall: exit
|
||||
syscall
|
||||
@@ -111,9 +130,9 @@ if (moduleRepository.Modules().TryGetValue("main", out var mainModule))
|
||||
"-ffreestanding", "-nostartfiles", "-std=c23",
|
||||
"-g", "-lm",
|
||||
"-o", Path.Combine(".build", "out"),
|
||||
Path.Combine(".build", "out.o"),
|
||||
..objectPaths,
|
||||
Path.Combine(".build", "runtime.o"),
|
||||
..objectFiles
|
||||
..objectFileArgs
|
||||
]));
|
||||
|
||||
if (linkProcess == null) return 1;
|
||||
|
||||
15
compiler/NubLang/Ast/CompilationUnit.cs
Normal file
15
compiler/NubLang/Ast/CompilationUnit.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace NubLang.Ast;
|
||||
|
||||
public sealed class CompilationUnit
|
||||
{
|
||||
public CompilationUnit(List<FuncNode> functions, List<NubStructType> importedStructTypes, List<FuncPrototypeNode> importedFunctions)
|
||||
{
|
||||
Functions = functions;
|
||||
ImportedStructTypes = importedStructTypes;
|
||||
ImportedFunctions = importedFunctions;
|
||||
}
|
||||
|
||||
public List<FuncNode> Functions { get; }
|
||||
public List<NubStructType> ImportedStructTypes { get; }
|
||||
public List<FuncPrototypeNode> ImportedFunctions { get; }
|
||||
}
|
||||
@@ -10,15 +10,9 @@ public abstract record DefinitionNode(List<Token> Tokens, string Module, string
|
||||
|
||||
public record FuncParameterNode(List<Token> Tokens, string Name, NubType Type) : Node(Tokens);
|
||||
|
||||
public record FuncSignatureNode(List<Token> Tokens, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens);
|
||||
public record FuncPrototypeNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens);
|
||||
|
||||
public record FuncNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, FuncSignatureNode Signature, BlockNode? Body) : DefinitionNode(Tokens, Module, Name);
|
||||
|
||||
public record StructFieldNode(List<Token> Tokens, string Name, NubType Type, ExpressionNode? Value) : Node(Tokens);
|
||||
|
||||
public record StructFuncNode(List<Token> Tokens, string Name, FuncSignatureNode Signature, BlockNode Body) : Node(Tokens);
|
||||
|
||||
public record StructNode(List<Token> Tokens, string Module, string Name, List<StructFieldNode> Fields, List<StructFuncNode> Functions) : DefinitionNode(Tokens, Module, Name);
|
||||
public record FuncNode(List<Token> Tokens, FuncPrototypeNode Prototype, BlockNode? Body) : DefinitionNode(Tokens, Prototype.Module, Prototype.Name);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -32,8 +26,6 @@ public record BlockNode(List<Token> Tokens, List<StatementNode> Statements) : St
|
||||
|
||||
public record StatementFuncCallNode(List<Token> Tokens, FuncCallNode FuncCall) : StatementNode(Tokens);
|
||||
|
||||
public record StatementStructFuncCallNode(List<Token> Tokens, StructFuncCallNode StructFuncCall) : StatementNode(Tokens);
|
||||
|
||||
public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(Tokens);
|
||||
|
||||
public record AssignmentNode(List<Token> Tokens, LValueExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens);
|
||||
@@ -108,8 +100,6 @@ public record UnaryExpressionNode(List<Token> Tokens, NubType Type, UnaryOperato
|
||||
|
||||
public record FuncCallNode(List<Token> Tokens, NubType Type, ExpressionNode Expression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record StructFuncCallNode(List<Token> Tokens, NubType Type, string Module, string StructName, string FuncName, ExpressionNode StructExpression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record LValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : LValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record RValueIdentifierNode(List<Token> Tokens, NubType Type, string Name) : RValueExpressionNode(Tokens, Type);
|
||||
|
||||
@@ -100,7 +100,7 @@ public class NubFuncType(List<NubType> parameters, NubType returnType) : NubType
|
||||
}
|
||||
}
|
||||
|
||||
public class NubStructType(string module, string name, List<NubStructFieldType> fields, List<NubStructFuncType> functions) : NubType
|
||||
public class NubStructType(string module, string name, List<NubStructFieldType> fields) : NubType
|
||||
{
|
||||
public override bool IsValueType => true;
|
||||
public override bool IsScalar => false;
|
||||
@@ -108,9 +108,8 @@ public class NubStructType(string module, string name, List<NubStructFieldType>
|
||||
public string Module { get; } = module;
|
||||
public string Name { get; } = name;
|
||||
public List<NubStructFieldType> Fields { get; set; } = fields;
|
||||
public List<NubStructFuncType> Functions { get; set; } = functions;
|
||||
|
||||
public override string ToString() => $"{Module}.{Name}";
|
||||
public override string ToString() => $"{Module}::{Name}";
|
||||
public override bool Equals(NubType? other) => other is NubStructType structType && Name == structType.Name && Module == structType.Module;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Module, Name);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Modules;
|
||||
using NubLang.Syntax;
|
||||
|
||||
namespace NubLang.Ast;
|
||||
@@ -8,64 +7,69 @@ namespace NubLang.Ast;
|
||||
public sealed class TypeChecker
|
||||
{
|
||||
private readonly SyntaxTree _syntaxTree;
|
||||
private readonly Dictionary<string, Module> _visibleModules;
|
||||
private readonly Dictionary<string, Module> _importedModules;
|
||||
|
||||
private readonly Stack<Scope> _scopes = [];
|
||||
private readonly Stack<NubType> _funcReturnTypes = [];
|
||||
private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new();
|
||||
private readonly HashSet<(string Module, string Name)> _resolvingTypes = [];
|
||||
private readonly HashSet<string> _checkedTemplateStructs = [];
|
||||
|
||||
private Scope CurrentScope => _scopes.Peek();
|
||||
|
||||
public TypeChecker(SyntaxTree syntaxTree, ModuleRepository moduleRepository)
|
||||
public List<Diagnostic> Diagnostics { get; } = [];
|
||||
|
||||
public TypeChecker(SyntaxTree syntaxTree, Dictionary<string, Module> modules)
|
||||
{
|
||||
_syntaxTree = syntaxTree;
|
||||
_visibleModules = moduleRepository
|
||||
.Modules()
|
||||
.Where(x => syntaxTree.Metadata.Imports.Contains(x.Key) || _syntaxTree.Metadata.ModuleName == x.Key)
|
||||
_importedModules = modules
|
||||
.Where(x => syntaxTree.Imports.Contains(x.Key) || _syntaxTree.ModuleName == x.Key)
|
||||
.ToDictionary();
|
||||
}
|
||||
|
||||
public List<DefinitionNode> Definitions { get; } = [];
|
||||
public List<Diagnostic> Diagnostics { get; } = [];
|
||||
|
||||
public void Check()
|
||||
public CompilationUnit Check()
|
||||
{
|
||||
_scopes.Clear();
|
||||
_funcReturnTypes.Clear();
|
||||
_typeCache.Clear();
|
||||
_resolvingTypes.Clear();
|
||||
_checkedTemplateStructs.Clear();
|
||||
|
||||
Diagnostics.Clear();
|
||||
Definitions.Clear();
|
||||
|
||||
using (BeginRootScope(_syntaxTree.Metadata.ModuleName))
|
||||
using (BeginRootScope(_syntaxTree.ModuleName))
|
||||
{
|
||||
foreach (var definition in _syntaxTree.Definitions)
|
||||
var functions = new List<FuncNode>();
|
||||
|
||||
foreach (var funcSyntax in _syntaxTree.Definitions.OfType<FuncSyntax>())
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (definition)
|
||||
{
|
||||
case FuncSyntax funcSyntax:
|
||||
Definitions.Add(CheckFuncDefinition(funcSyntax));
|
||||
break;
|
||||
case StructSyntax structSyntax:
|
||||
Definitions.Add(CheckStructDefinition(structSyntax));
|
||||
break;
|
||||
case StructTemplateSyntax:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
functions.Add(CheckFuncDefinition(funcSyntax));
|
||||
}
|
||||
catch (TypeCheckerException e)
|
||||
{
|
||||
Diagnostics.Add(e.Diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
var importedStructTypes = new List<NubStructType>();
|
||||
var importedFunctions = new List<FuncPrototypeNode>();
|
||||
|
||||
foreach (var (name, module) in _importedModules)
|
||||
{
|
||||
foreach (var structSyntax in module.Structs(false))
|
||||
{
|
||||
var fields = structSyntax.Fields
|
||||
.Select(f => new NubStructFieldType(f.Name, ResolveType(f.Type), f.Value != null))
|
||||
.ToList();
|
||||
|
||||
importedStructTypes.Add(new NubStructType(name, structSyntax.Name, fields));
|
||||
}
|
||||
|
||||
foreach (var funcSyntax in module.Functions(false))
|
||||
{
|
||||
importedFunctions.Add(CheckFuncPrototype(funcSyntax.Prototype));
|
||||
}
|
||||
}
|
||||
|
||||
return new CompilationUnit(functions, importedStructTypes, importedFunctions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +81,7 @@ public sealed class TypeChecker
|
||||
}
|
||||
else
|
||||
{
|
||||
_scopes.Push(new Scope(_syntaxTree.Metadata.ModuleName));
|
||||
_scopes.Push(new Scope(_syntaxTree.ModuleName));
|
||||
}
|
||||
|
||||
return new ScopeDisposer(this);
|
||||
@@ -101,74 +105,25 @@ public sealed class TypeChecker
|
||||
}
|
||||
}
|
||||
|
||||
private StructNode CheckStructDefinition(StructSyntax node)
|
||||
{
|
||||
var fieldTypes = node.Fields
|
||||
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
|
||||
.ToList();
|
||||
|
||||
var fieldFunctions = node.Functions
|
||||
.Select(x =>
|
||||
{
|
||||
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
|
||||
var returnType = ResolveType(x.Signature.ReturnType);
|
||||
return new NubStructFuncType(x.Name, parameters, returnType);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var structType = new NubStructType(CurrentScope.Module, node.Name, fieldTypes, fieldFunctions);
|
||||
|
||||
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
|
||||
|
||||
var fields = node.Fields.Select(CheckStructField).ToList();
|
||||
var functions = node.Functions.Select(CheckStructFunc).ToList();
|
||||
|
||||
return new StructNode(node.Tokens, CurrentScope.Module, node.Name, fields, functions);
|
||||
}
|
||||
|
||||
private StructFuncNode CheckStructFunc(StructFuncSyntax function)
|
||||
{
|
||||
foreach (var parameter in function.Signature.Parameters)
|
||||
{
|
||||
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
|
||||
}
|
||||
|
||||
_funcReturnTypes.Push(ResolveType(function.Signature.ReturnType));
|
||||
var body = CheckBlock(function.Body);
|
||||
_funcReturnTypes.Pop();
|
||||
return new StructFuncNode(function.Tokens, function.Name, CheckFuncSignature(function.Signature), body);
|
||||
}
|
||||
|
||||
private StructFieldNode CheckStructField(StructFieldSyntax field)
|
||||
{
|
||||
ExpressionNode? value = null;
|
||||
if (field.Value != null)
|
||||
{
|
||||
value = CheckExpression(field.Value, ResolveType(field.Type));
|
||||
}
|
||||
|
||||
return new StructFieldNode(field.Tokens, field.Name, ResolveType(field.Type), value);
|
||||
}
|
||||
|
||||
private FuncNode CheckFuncDefinition(FuncSyntax node)
|
||||
{
|
||||
foreach (var parameter in node.Signature.Parameters)
|
||||
foreach (var parameter in node.Prototype.Parameters)
|
||||
{
|
||||
CurrentScope.DeclareVariable(new Variable(parameter.Name, ResolveType(parameter.Type), VariableKind.RValue));
|
||||
}
|
||||
|
||||
var signature = CheckFuncSignature(node.Signature);
|
||||
var prototype = CheckFuncPrototype(node.Prototype);
|
||||
|
||||
BlockNode? body = null;
|
||||
if (node.Body != null)
|
||||
{
|
||||
_funcReturnTypes.Push(signature.ReturnType);
|
||||
_funcReturnTypes.Push(prototype.ReturnType);
|
||||
|
||||
body = CheckBlock(node.Body);
|
||||
|
||||
if (!AlwaysReturns(body))
|
||||
{
|
||||
if (signature.ReturnType is NubVoidType)
|
||||
if (prototype.ReturnType is NubVoidType)
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(node.Tokens.Skip(node.Tokens.Count - 1).ToList(), null));
|
||||
}
|
||||
@@ -184,7 +139,7 @@ public sealed class TypeChecker
|
||||
_funcReturnTypes.Pop();
|
||||
}
|
||||
|
||||
return new FuncNode(node.Tokens, CurrentScope.Module, node.Name, node.ExternSymbol, signature, body);
|
||||
return new FuncNode(node.Tokens, prototype, body);
|
||||
}
|
||||
|
||||
private AssignmentNode CheckAssignment(AssignmentSyntax statement)
|
||||
@@ -231,7 +186,6 @@ public sealed class TypeChecker
|
||||
return expression switch
|
||||
{
|
||||
FuncCallNode funcCall => new StatementFuncCallNode(statement.Tokens, funcCall),
|
||||
StructFuncCallNode structFuncCall => new StatementStructFuncCallNode(statement.Tokens, structFuncCall),
|
||||
_ => throw new TypeCheckerException(Diagnostic.Error("Expressions statements can only be function calls").At(statement).Build())
|
||||
};
|
||||
}
|
||||
@@ -269,7 +223,7 @@ public sealed class TypeChecker
|
||||
return new WhileNode(statement.Tokens, condition, body);
|
||||
}
|
||||
|
||||
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement)
|
||||
private FuncPrototypeNode CheckFuncPrototype(FuncPrototypeSyntax statement)
|
||||
{
|
||||
var parameters = new List<FuncParameterNode>();
|
||||
foreach (var parameter in statement.Parameters)
|
||||
@@ -277,7 +231,7 @@ public sealed class TypeChecker
|
||||
parameters.Add(new FuncParameterNode(parameter.Tokens, parameter.Name, ResolveType(parameter.Type)));
|
||||
}
|
||||
|
||||
return new FuncSignatureNode(statement.Tokens, parameters, ResolveType(statement.ReturnType));
|
||||
return new FuncPrototypeNode(statement.Tokens, CurrentScope.Module, statement.Name, statement.ExternSymbol, parameters, ResolveType(statement.ReturnType));
|
||||
}
|
||||
|
||||
private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null)
|
||||
@@ -290,7 +244,6 @@ public sealed class TypeChecker
|
||||
BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
|
||||
UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
|
||||
DereferenceSyntax expression => CheckDereference(expression),
|
||||
MemberFuncCallSyntax expression => CheckMemberFuncCall(expression),
|
||||
FuncCallSyntax expression => CheckFuncCall(expression),
|
||||
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
|
||||
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression),
|
||||
@@ -608,56 +561,6 @@ public sealed class TypeChecker
|
||||
return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters);
|
||||
}
|
||||
|
||||
private StructFuncCallNode CheckMemberFuncCall(MemberFuncCallSyntax expression)
|
||||
{
|
||||
// todo(nub31): When adding interfaces, also support other types than structs
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target.Type is NubStructType structType)
|
||||
{
|
||||
var function = structType.Functions.FirstOrDefault(x => x.Name == expression.Name);
|
||||
if (function == null)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Function {expression.Name} not found on struct {structType}")
|
||||
.At(expression)
|
||||
.Build());
|
||||
}
|
||||
|
||||
if (expression.Parameters.Count != function.Parameters.Count)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Function {function.Name} expects {function.Parameters.Count} parameters but got {expression.Parameters.Count}")
|
||||
.At(expression.Parameters.LastOrDefault(expression))
|
||||
.Build());
|
||||
}
|
||||
|
||||
var parameters = new List<ExpressionNode>();
|
||||
for (var i = 0; i < expression.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = expression.Parameters[i];
|
||||
var expectedType = function.Parameters[i];
|
||||
|
||||
var parameterExpression = CheckExpression(parameter, expectedType);
|
||||
if (parameterExpression.Type != expectedType)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Parameter {i + 1} does not match the type {expectedType} for function {function}")
|
||||
.At(parameter)
|
||||
.Build());
|
||||
}
|
||||
|
||||
parameters.Add(parameterExpression);
|
||||
}
|
||||
|
||||
return new StructFuncCallNode(expression.Tokens, function.ReturnType, structType.Module, structType.Name, expression.Name, target, parameters);
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"No function {expression.Name} exists on type {target.Type}")
|
||||
.At(expression)
|
||||
.Build());
|
||||
}
|
||||
|
||||
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression)
|
||||
{
|
||||
var scopeIdent = CurrentScope.LookupVariable(expression.Name);
|
||||
@@ -671,14 +574,14 @@ public sealed class TypeChecker
|
||||
};
|
||||
}
|
||||
|
||||
var module = _visibleModules[CurrentScope.Module];
|
||||
var module = _importedModules[CurrentScope.Module];
|
||||
var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name);
|
||||
|
||||
if (function != null)
|
||||
{
|
||||
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType));
|
||||
return new FuncIdentifierNode(expression.Tokens, type, CurrentScope.Module, expression.Name, function.ExternSymbol);
|
||||
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
|
||||
return new FuncIdentifierNode(expression.Tokens, type, CurrentScope.Module, expression.Name, function.Prototype.ExternSymbol);
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build());
|
||||
@@ -686,7 +589,7 @@ public sealed class TypeChecker
|
||||
|
||||
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression)
|
||||
{
|
||||
if (!_visibleModules.TryGetValue(expression.Module, out var module))
|
||||
if (!_importedModules.TryGetValue(expression.Module, out var module))
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Module {expression.Module} not found")
|
||||
@@ -700,9 +603,9 @@ public sealed class TypeChecker
|
||||
var function = module.Functions(includePrivate).FirstOrDefault(x => x.Name == expression.Name);
|
||||
if (function != null)
|
||||
{
|
||||
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var type = new NubFuncType(parameters, ResolveType(function.Signature.ReturnType));
|
||||
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.ExternSymbol);
|
||||
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
|
||||
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.Prototype.ExternSymbol);
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
@@ -824,8 +727,6 @@ public sealed class TypeChecker
|
||||
.Error($"Struct {structType.Name} does not have a field named {initializer.Key}")
|
||||
.At(initializer.Value)
|
||||
.Build());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
initializers.Add(initializer.Key, CheckExpression(initializer.Value, typeField.Type));
|
||||
@@ -849,34 +750,12 @@ public sealed class TypeChecker
|
||||
|
||||
private BlockNode CheckBlock(BlockSyntax node)
|
||||
{
|
||||
var statements = new List<StatementNode>();
|
||||
|
||||
var reachable = true;
|
||||
var warnedUnreachable = false;
|
||||
|
||||
using (BeginScope())
|
||||
{
|
||||
var statements = new List<StatementNode>();
|
||||
foreach (var statement in node.Statements)
|
||||
{
|
||||
var checkedStatement = CheckStatement(statement);
|
||||
|
||||
if (reachable)
|
||||
{
|
||||
if (checkedStatement is TerminalStatementNode)
|
||||
{
|
||||
reachable = false;
|
||||
}
|
||||
|
||||
statements.Add(checkedStatement);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!warnedUnreachable)
|
||||
{
|
||||
Diagnostics.Add(Diagnostic.Warning("Statement is unreachable").At(statement).Build());
|
||||
warnedUnreachable = true;
|
||||
}
|
||||
}
|
||||
statements.Add(CheckStatement(statement));
|
||||
}
|
||||
|
||||
return new BlockNode(node.Tokens, statements);
|
||||
@@ -937,27 +816,11 @@ public sealed class TypeChecker
|
||||
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType)),
|
||||
StringTypeSyntax => new NubStringType(),
|
||||
CustomTypeSyntax c => ResolveCustomType(c),
|
||||
StructTemplateTypeSyntax t => ResolveStructTemplateType(t),
|
||||
SubstitutionTypeSyntax s => ResolveTypeSubstitution(s),
|
||||
VoidTypeSyntax => new NubVoidType(),
|
||||
_ => throw new NotSupportedException($"Unknown type syntax: {type}")
|
||||
};
|
||||
}
|
||||
|
||||
private NubType ResolveTypeSubstitution(SubstitutionTypeSyntax substitution)
|
||||
{
|
||||
var type = CurrentScope.LookupTypeSubstitution(substitution.Name);
|
||||
if (type == null)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Template argument {substitution.Name} does not exist")
|
||||
.At(substitution)
|
||||
.Build());
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private NubType ResolveCustomType(CustomTypeSyntax customType)
|
||||
{
|
||||
var key = (customType.Module, customType.Name);
|
||||
@@ -969,14 +832,14 @@ public sealed class TypeChecker
|
||||
|
||||
if (!_resolvingTypes.Add(key))
|
||||
{
|
||||
var placeholder = new NubStructType(customType.Module, customType.Name, [], []);
|
||||
var placeholder = new NubStructType(customType.Module, customType.Name, []);
|
||||
_typeCache[key] = placeholder;
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!_visibleModules.TryGetValue(customType.Module, out var module))
|
||||
if (!_importedModules.TryGetValue(customType.Module, out var module))
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Module {customType.Module} not found")
|
||||
@@ -990,7 +853,7 @@ public sealed class TypeChecker
|
||||
var structDef = module.Structs(includePrivate).FirstOrDefault(x => x.Name == customType.Name);
|
||||
if (structDef != null)
|
||||
{
|
||||
var result = new NubStructType(customType.Module, structDef.Name, [], []);
|
||||
var result = new NubStructType(customType.Module, structDef.Name, []);
|
||||
_typeCache[key] = result;
|
||||
|
||||
var fields = structDef.Fields
|
||||
@@ -998,19 +861,6 @@ public sealed class TypeChecker
|
||||
.ToList();
|
||||
|
||||
result.Fields.AddRange(fields);
|
||||
|
||||
var functions = structDef.Functions
|
||||
.Select(x =>
|
||||
{
|
||||
var parameters = x.Signature.Parameters
|
||||
.Select(y => ResolveType(y.Type))
|
||||
.ToList();
|
||||
|
||||
return new NubStructFuncType(x.Name, parameters, ResolveType(x.Signature.ReturnType));
|
||||
})
|
||||
.ToList();
|
||||
|
||||
result.Functions.AddRange(functions);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1024,71 +874,6 @@ public sealed class TypeChecker
|
||||
_resolvingTypes.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private NubStructType ResolveStructTemplateType(StructTemplateTypeSyntax structTemplate)
|
||||
{
|
||||
if (!_visibleModules.TryGetValue(structTemplate.Module, out var module))
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Module {structTemplate.Module} not found")
|
||||
.WithHelp($"import \"{structTemplate.Module}\"")
|
||||
.At(structTemplate)
|
||||
.Build());
|
||||
}
|
||||
|
||||
var includePrivate = structTemplate.Module == CurrentScope.Module;
|
||||
|
||||
var templateDef = module
|
||||
.StructTemplates(includePrivate)
|
||||
.FirstOrDefault(x => x.Name == structTemplate.Name);
|
||||
|
||||
if (templateDef == null)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Template type {structTemplate.Name} not found in module {structTemplate.Module}")
|
||||
.At(structTemplate)
|
||||
.Build());
|
||||
}
|
||||
|
||||
var templateParameterTypes = structTemplate.TemplateParameters.Select(ResolveType).ToList();
|
||||
var mangledName = $"{structTemplate.Name}.{NameMangler.Mangle(templateParameterTypes)}";
|
||||
|
||||
using (BeginRootScope(structTemplate.Module))
|
||||
{
|
||||
for (var i = 0; i < templateParameterTypes.Count; i++)
|
||||
{
|
||||
var parameterName = templateDef.TemplateArguments[i];
|
||||
var parameterType = templateParameterTypes[i];
|
||||
CurrentScope.DeclareTypeSubstitution(parameterName, parameterType);
|
||||
}
|
||||
|
||||
var fieldTypes = templateDef.Fields
|
||||
.Select(x => new NubStructFieldType(x.Name, ResolveType(x.Type), x.Value != null))
|
||||
.ToList();
|
||||
|
||||
var fieldFunctions = templateDef.Functions
|
||||
.Select(x =>
|
||||
{
|
||||
var parameters = x.Signature.Parameters.Select(y => ResolveType(y.Type)).ToList();
|
||||
var returnType = ResolveType(x.Signature.ReturnType);
|
||||
return new NubStructFuncType(x.Name, parameters, returnType);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var structType = new NubStructType(structTemplate.Module, mangledName, fieldTypes, fieldFunctions);
|
||||
|
||||
if (!_checkedTemplateStructs.Contains($"{structTemplate.Module}.{mangledName}"))
|
||||
{
|
||||
CurrentScope.DeclareVariable(new Variable("this", structType, VariableKind.RValue));
|
||||
var fields = templateDef.Fields.Select(CheckStructField).ToList();
|
||||
var functions = templateDef.Functions.Select(CheckStructFunc).ToList();
|
||||
Definitions.Add(new StructNode(templateDef.Tokens, structTemplate.Module, mangledName, fields, functions));
|
||||
_checkedTemplateStructs.Add($"{structTemplate.Module}.{mangledName}");
|
||||
}
|
||||
|
||||
return structType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum VariableKind
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Text;
|
||||
using NubLang.Ast;
|
||||
using NubLang.Syntax;
|
||||
|
||||
@@ -6,17 +5,14 @@ namespace NubLang.Generation;
|
||||
|
||||
public class Generator
|
||||
{
|
||||
private readonly List<DefinitionNode> _definitions;
|
||||
private readonly CompilationUnit _compilationUnit;
|
||||
private readonly IndentedTextWriter _writer;
|
||||
private readonly Stack<List<DeferNode>> _deferStack = [];
|
||||
private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = [];
|
||||
private readonly List<NubStructType> _structTypes = [];
|
||||
private int _tmpIndex;
|
||||
private int _funcDefIndex;
|
||||
|
||||
public Generator(List<DefinitionNode> definitions)
|
||||
public Generator(CompilationUnit compilationUnit)
|
||||
{
|
||||
_definitions = definitions;
|
||||
_compilationUnit = compilationUnit;
|
||||
_writer = new IndentedTextWriter();
|
||||
}
|
||||
|
||||
@@ -26,54 +22,6 @@ public class Generator
|
||||
return $"_t{++_tmpIndex}";
|
||||
}
|
||||
|
||||
private string MapType(NubType nubType)
|
||||
{
|
||||
return nubType switch
|
||||
{
|
||||
NubArrayType arrayType => MapType(arrayType.ElementType),
|
||||
NubConstArrayType arrayType => MapType(arrayType.ElementType),
|
||||
NubBoolType => "bool",
|
||||
NubCStringType => "char",
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "f32",
|
||||
64 => "f64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubFuncType funcType => MapFuncType(funcType),
|
||||
NubIntType intType => (intType.Signed, intType.Width) switch
|
||||
{
|
||||
(false, 8) => "u8",
|
||||
(false, 16) => "u16",
|
||||
(false, 32) => "u32",
|
||||
(false, 64) => "u64",
|
||||
(true, 8) => "i8",
|
||||
(true, 16) => "i16",
|
||||
(true, 32) => "i32",
|
||||
(true, 64) => "i64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubPointerType pointerType => MapType(pointerType.BaseType),
|
||||
NubStringType => throw new NotImplementedException(),
|
||||
NubStructType structType => MapStructType(structType),
|
||||
NubVoidType => "void",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(nubType))
|
||||
};
|
||||
}
|
||||
|
||||
private string MapStructType(NubStructType structType)
|
||||
{
|
||||
_structTypes.Add(structType);
|
||||
return StructName(structType.Module, structType.Name);
|
||||
}
|
||||
|
||||
private string MapFuncType(NubFuncType funcType)
|
||||
{
|
||||
var name = $"_func_type_def{++_funcDefIndex}";
|
||||
_funcDefs.Push((name, funcType));
|
||||
return name;
|
||||
}
|
||||
|
||||
private string MapNameWithType(NubType nubType, string name)
|
||||
{
|
||||
var prefix = "";
|
||||
@@ -81,7 +29,7 @@ public class Generator
|
||||
|
||||
switch (nubType)
|
||||
{
|
||||
case NubCStringType or NubPointerType:
|
||||
case NubCStringType or NubPointerType or NubFuncType:
|
||||
prefix = "*";
|
||||
break;
|
||||
case NubArrayType:
|
||||
@@ -92,7 +40,42 @@ public class Generator
|
||||
break;
|
||||
}
|
||||
|
||||
return $"{MapType(nubType)} {prefix}{name}{postfix}";
|
||||
return $"{MapBaseType(nubType)} {prefix}{name}{postfix}";
|
||||
|
||||
string MapBaseType(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NubArrayType arrayType => MapBaseType(arrayType.ElementType),
|
||||
NubConstArrayType arrayType => MapBaseType(arrayType.ElementType),
|
||||
NubBoolType => "bool",
|
||||
NubCStringType => "char",
|
||||
NubFloatType floatType => floatType.Width switch
|
||||
{
|
||||
32 => "f32",
|
||||
64 => "f64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubFuncType funcType => "void",
|
||||
NubIntType intType => (intType.Signed, intType.Width) switch
|
||||
{
|
||||
(false, 8) => "u8",
|
||||
(false, 16) => "u16",
|
||||
(false, 32) => "u32",
|
||||
(false, 64) => "u64",
|
||||
(true, 8) => "i8",
|
||||
(true, 16) => "i16",
|
||||
(true, 32) => "i32",
|
||||
(true, 64) => "i64",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
NubPointerType pointerType => MapBaseType(pointerType.BaseType),
|
||||
NubStringType => throw new NotImplementedException(),
|
||||
NubStructType structType => StructName(structType.Module, structType.Name),
|
||||
NubVoidType => "void",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static string FuncName(string module, string name, string? externSymbol)
|
||||
@@ -105,139 +88,101 @@ public class Generator
|
||||
return $"{module}_{name}";
|
||||
}
|
||||
|
||||
private static string StructFuncName(string module, string name, string function)
|
||||
{
|
||||
return $"{module}_{name}_{function}";
|
||||
}
|
||||
|
||||
public string Emit()
|
||||
{
|
||||
const string header = """
|
||||
typedef __builtin_va_list va_list;
|
||||
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
#define NULL ((void*)0)
|
||||
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long i64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define I8_C(x) x
|
||||
#define U8_C(x) x##U
|
||||
|
||||
#define I16_C(x) x
|
||||
#define U16_C(x) x##U
|
||||
|
||||
#define I32_C(x) x
|
||||
#define U32_C(x) x##U
|
||||
|
||||
#define I64_C(x) x##LL
|
||||
#define U64_C(x) x##ULL
|
||||
""";
|
||||
|
||||
_writer.WriteLine();
|
||||
|
||||
var appendNewLine = false;
|
||||
|
||||
foreach (var funcNode in _definitions.OfType<FuncNode>())
|
||||
// note(nub31): Struct definitions
|
||||
foreach (var structType in _compilationUnit.ImportedStructTypes)
|
||||
{
|
||||
EmitLine(funcNode.Tokens.FirstOrDefault());
|
||||
appendNewLine = true;
|
||||
var parameters = funcNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
|
||||
: "void";
|
||||
_writer.WriteLine("typedef struct");
|
||||
_writer.WriteLine("{");
|
||||
using (_writer.Indent())
|
||||
{
|
||||
foreach (var field in structType.Fields)
|
||||
{
|
||||
_writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};");
|
||||
}
|
||||
}
|
||||
|
||||
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
|
||||
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters});");
|
||||
}
|
||||
|
||||
if (appendNewLine)
|
||||
{
|
||||
_writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};");
|
||||
_writer.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var structNode in _definitions.OfType<StructNode>())
|
||||
// note(nub31): Forward declarations
|
||||
foreach (var prototype in _compilationUnit.ImportedFunctions)
|
||||
{
|
||||
foreach (var structFuncNode in structNode.Functions)
|
||||
{
|
||||
EmitLine(structFuncNode.Tokens.FirstOrDefault());
|
||||
var parameters = structFuncNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
|
||||
: "void";
|
||||
EmitLine(prototype.Tokens.FirstOrDefault());
|
||||
var parameters = prototype.Parameters.Count != 0
|
||||
? string.Join(", ", prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
|
||||
: "void";
|
||||
|
||||
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name);
|
||||
_writer.WriteLine($"{MapNameWithType(structFuncNode.Signature.ReturnType, name)}({parameters})");
|
||||
EmitBlock(structFuncNode.Body);
|
||||
_writer.WriteLine();
|
||||
}
|
||||
var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol);
|
||||
_writer.WriteLine($"{MapNameWithType(prototype.ReturnType, name)}({parameters});");
|
||||
}
|
||||
|
||||
foreach (var funcNode in _definitions.OfType<FuncNode>())
|
||||
_writer.WriteLine();
|
||||
|
||||
// note(nub31): Normal functions
|
||||
foreach (var funcNode in _compilationUnit.Functions)
|
||||
{
|
||||
if (funcNode.Body == null) continue;
|
||||
|
||||
EmitLine(funcNode.Tokens.FirstOrDefault());
|
||||
var parameters = funcNode.Signature.Parameters.Count != 0
|
||||
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
|
||||
var parameters = funcNode.Prototype.Parameters.Count != 0
|
||||
? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
|
||||
: "void";
|
||||
|
||||
if (funcNode.ExternSymbol == null)
|
||||
if (funcNode.Prototype.ExternSymbol == null)
|
||||
{
|
||||
_writer.Write("static ");
|
||||
}
|
||||
|
||||
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
|
||||
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters})");
|
||||
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
|
||||
_writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters})");
|
||||
EmitBlock(funcNode.Body);
|
||||
_writer.WriteLine();
|
||||
}
|
||||
|
||||
List<string> typedefs = [];
|
||||
return $"""
|
||||
typedef __builtin_va_list va_list;
|
||||
|
||||
while (_funcDefs.TryPop(out var funcTypeDef))
|
||||
{
|
||||
var returnType = MapType(funcTypeDef.FuncType.ReturnType);
|
||||
var paramList = string.Join(", ", funcTypeDef.FuncType.Parameters.Select((type, i) => MapNameWithType(type, $"arg{i}")));
|
||||
if (funcTypeDef.FuncType.Parameters.Count == 0)
|
||||
{
|
||||
paramList = "void";
|
||||
}
|
||||
#define va_start(ap, last) __builtin_va_start(ap, last)
|
||||
#define va_arg(ap, type) __builtin_va_arg(ap, type)
|
||||
#define va_end(ap) __builtin_va_end(ap)
|
||||
#define va_copy(dest, src) __builtin_va_copy(dest, src)
|
||||
|
||||
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});");
|
||||
}
|
||||
#define NULL ((void*)0)
|
||||
|
||||
var structDefSb = new StringBuilder();
|
||||
foreach (var structType in _structTypes)
|
||||
{
|
||||
structDefSb.AppendLine("typedef struct");
|
||||
structDefSb.AppendLine("{");
|
||||
foreach (var field in structType.Fields)
|
||||
{
|
||||
structDefSb.AppendLine($" {MapNameWithType(field.Type, field.Name)};");
|
||||
}
|
||||
typedef unsigned long size_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
structDefSb.AppendLine($"}} {StructName(structType.Module, structType.Name)};");
|
||||
structDefSb.AppendLine();
|
||||
}
|
||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||
|
||||
return header + structDefSb + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer;
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long i64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define I8_C(x) x
|
||||
#define U8_C(x) x##U
|
||||
|
||||
#define I16_C(x) x
|
||||
#define U16_C(x) x##U
|
||||
|
||||
#define I32_C(x) x
|
||||
#define U32_C(x) x##U
|
||||
|
||||
#define I64_C(x) x##LL
|
||||
#define U64_C(x) x##ULL
|
||||
|
||||
{_writer}
|
||||
""";
|
||||
}
|
||||
|
||||
private void EmitStatement(StatementNode statementNode)
|
||||
@@ -269,9 +214,6 @@ public class Generator
|
||||
case StatementFuncCallNode statementFuncCallNode:
|
||||
EmitStatementFuncCall(statementFuncCallNode);
|
||||
break;
|
||||
case StatementStructFuncCallNode statementStructFuncCallNode:
|
||||
EmitStatementStructFuncCall(statementStructFuncCallNode);
|
||||
break;
|
||||
case VariableDeclarationNode variableDeclarationNode:
|
||||
EmitVariableDeclaration(variableDeclarationNode);
|
||||
break;
|
||||
@@ -316,7 +258,7 @@ public class Generator
|
||||
private void EmitIf(IfNode ifNode, bool elseIf = false)
|
||||
{
|
||||
var condition = EmitExpression(ifNode.Condition);
|
||||
_writer.WriteLine($"{(elseIf ? "else" : "")} if ({condition})");
|
||||
_writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})");
|
||||
EmitBlock(ifNode.Body);
|
||||
ifNode.Else?.Match
|
||||
(
|
||||
@@ -373,12 +315,6 @@ public class Generator
|
||||
_writer.WriteLine($"{funcCall};");
|
||||
}
|
||||
|
||||
private void EmitStatementStructFuncCall(StatementStructFuncCallNode statementStructFuncCallNode)
|
||||
{
|
||||
var structFuncCall = EmitStructFuncCall(statementStructFuncCallNode.StructFuncCall);
|
||||
_writer.WriteLine($"{structFuncCall};");
|
||||
}
|
||||
|
||||
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
|
||||
{
|
||||
if (variableDeclarationNode.Assignment != null)
|
||||
@@ -423,7 +359,6 @@ public class Generator
|
||||
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
|
||||
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
|
||||
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
|
||||
StructFuncCallNode structFuncCallNode => EmitStructFuncCall(structFuncCallNode),
|
||||
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
|
||||
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
|
||||
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
|
||||
@@ -606,12 +541,7 @@ public class Generator
|
||||
|
||||
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
|
||||
{
|
||||
if (sizeBuiltinNode.TargetType is NubConstArrayType constArrayType)
|
||||
{
|
||||
return $"sizeof({MapType(constArrayType.ElementType)}) * {constArrayType.Size}";
|
||||
}
|
||||
|
||||
return $"sizeof({MapType(sizeBuiltinNode.TargetType)})";
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
|
||||
@@ -625,14 +555,6 @@ public class Generator
|
||||
return $"{structExpr}.{structFieldAccessNode.Field}";
|
||||
}
|
||||
|
||||
private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode)
|
||||
{
|
||||
var thisParameter = EmitExpression(structFuncCallNode.StructExpression);
|
||||
var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName);
|
||||
var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList();
|
||||
return $"{name}({thisParameter}, {string.Join(", ", parameterNames)})";
|
||||
}
|
||||
|
||||
private string EmitStructInitializer(StructInitializerNode structInitializerNode)
|
||||
{
|
||||
var initValues = new List<string>();
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
using NubLang.Syntax;
|
||||
|
||||
namespace NubLang.Modules;
|
||||
|
||||
public class Module
|
||||
{
|
||||
private readonly List<DefinitionSyntax> _definitions = [];
|
||||
|
||||
public void Register(DefinitionSyntax definition)
|
||||
{
|
||||
_definitions.Add(definition);
|
||||
}
|
||||
|
||||
public List<StructSyntax> Structs(bool includePrivate)
|
||||
{
|
||||
return _definitions
|
||||
.OfType<StructSyntax>()
|
||||
.Where(x => x.Exported || includePrivate)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<StructTemplateSyntax> StructTemplates(bool includePrivate)
|
||||
{
|
||||
return _definitions
|
||||
.OfType<StructTemplateSyntax>()
|
||||
.Where(x => x.Exported || includePrivate)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<FuncSyntax> Functions(bool includePrivate)
|
||||
{
|
||||
return _definitions
|
||||
.OfType<FuncSyntax>()
|
||||
.Where(x => x.Exported || includePrivate)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using NubLang.Syntax;
|
||||
|
||||
namespace NubLang.Modules;
|
||||
|
||||
public class ModuleRepository
|
||||
{
|
||||
private readonly Dictionary<string, Module> _modules = new();
|
||||
|
||||
public ModuleRepository(List<SyntaxTree> syntaxTrees)
|
||||
{
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
var module = GetOrCreate(syntaxTree.Metadata.ModuleName);
|
||||
ProcessSyntaxTree(module, syntaxTree);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessSyntaxTree(Module module, SyntaxTree syntaxTree)
|
||||
{
|
||||
foreach (var definition in syntaxTree.Definitions)
|
||||
{
|
||||
module.Register(definition);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, Module> Modules()
|
||||
{
|
||||
return _modules;
|
||||
}
|
||||
|
||||
private Module GetOrCreate(string name)
|
||||
{
|
||||
if (!_modules.TryGetValue(name, out var module))
|
||||
{
|
||||
module = new Module();
|
||||
_modules[name] = module;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
39
compiler/NubLang/Syntax/Module.cs
Normal file
39
compiler/NubLang/Syntax/Module.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace NubLang.Syntax;
|
||||
|
||||
public sealed class Module
|
||||
{
|
||||
public static Dictionary<string, Module> Collect(List<SyntaxTree> syntaxTrees)
|
||||
{
|
||||
var modules = new Dictionary<string, Module>();
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
if (!modules.TryGetValue(syntaxTree.ModuleName, out var module))
|
||||
{
|
||||
module = new Module();
|
||||
modules.Add(syntaxTree.ModuleName, module);
|
||||
}
|
||||
|
||||
module._definitions.AddRange(syntaxTree.Definitions);
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
private readonly List<DefinitionSyntax> _definitions = [];
|
||||
|
||||
public List<StructSyntax> Structs(bool includePrivate)
|
||||
{
|
||||
return _definitions
|
||||
.OfType<StructSyntax>()
|
||||
.Where(x => x.Exported || includePrivate)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<FuncSyntax> Functions(bool includePrivate)
|
||||
{
|
||||
return _definitions
|
||||
.OfType<FuncSyntax>()
|
||||
.Where(x => x.Exported || includePrivate)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ namespace NubLang.Syntax;
|
||||
|
||||
public sealed class Parser
|
||||
{
|
||||
private readonly HashSet<string> _templateArguments = [];
|
||||
private List<Token> _tokens = [];
|
||||
private int _tokenIndex;
|
||||
private string _moduleName = string.Empty;
|
||||
@@ -21,16 +20,7 @@ public sealed class Parser
|
||||
_tokens = tokens;
|
||||
_tokenIndex = 0;
|
||||
_moduleName = string.Empty;
|
||||
_templateArguments.Clear();
|
||||
|
||||
var metadata = ParseMetadata();
|
||||
var definitions = ParseDefinitions();
|
||||
|
||||
return new SyntaxTree(definitions, metadata);
|
||||
}
|
||||
|
||||
private SyntaxTreeMetadata ParseMetadata()
|
||||
{
|
||||
var imports = new List<string>();
|
||||
|
||||
try
|
||||
@@ -57,11 +47,6 @@ public sealed class Parser
|
||||
}
|
||||
}
|
||||
|
||||
return new SyntaxTreeMetadata(_moduleName, imports);
|
||||
}
|
||||
|
||||
private List<DefinitionSyntax> ParseDefinitions()
|
||||
{
|
||||
var definitions = new List<DefinitionSyntax>();
|
||||
|
||||
while (HasToken)
|
||||
@@ -80,7 +65,7 @@ public sealed class Parser
|
||||
}
|
||||
|
||||
var keyword = ExpectSymbol();
|
||||
var definition = keyword.Symbol switch
|
||||
DefinitionSyntax definition = keyword.Symbol switch
|
||||
{
|
||||
Symbol.Func => ParseFunc(startIndex, exported, null),
|
||||
Symbol.Struct => ParseStruct(startIndex, exported),
|
||||
@@ -108,12 +93,22 @@ public sealed class Parser
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
return new SyntaxTree(definitions, _moduleName, imports);
|
||||
}
|
||||
|
||||
private FuncSignatureSyntax ParseFuncSignature()
|
||||
private FuncParameterSyntax ParseFuncParameter()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var type = ParseType();
|
||||
|
||||
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
|
||||
}
|
||||
|
||||
private FuncSyntax ParseFunc(int startIndex, bool exported, string? externSymbol)
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
List<FuncParameterSyntax> parameters = [];
|
||||
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
@@ -131,23 +126,7 @@ public sealed class Parser
|
||||
|
||||
var returnType = TryExpectSymbol(Symbol.Colon) ? ParseType() : new VoidTypeSyntax([]);
|
||||
|
||||
return new FuncSignatureSyntax(GetTokens(startIndex), parameters, returnType);
|
||||
}
|
||||
|
||||
private FuncParameterSyntax ParseFuncParameter()
|
||||
{
|
||||
var startIndex = _tokenIndex;
|
||||
var name = ExpectIdentifier();
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var type = ParseType();
|
||||
|
||||
return new FuncParameterSyntax(GetTokens(startIndex), name.Value, type);
|
||||
}
|
||||
|
||||
private FuncSyntax ParseFunc(int startIndex, bool exported, string? externSymbol)
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
var signature = ParseFuncSignature();
|
||||
var prototype = new FuncPrototypeSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, parameters, returnType);
|
||||
|
||||
BlockSyntax? body = null;
|
||||
var bodyStartIndex = _tokenIndex;
|
||||
@@ -156,64 +135,36 @@ public sealed class Parser
|
||||
body = ParseBlock(bodyStartIndex);
|
||||
}
|
||||
|
||||
return new FuncSyntax(GetTokens(startIndex), name.Value, exported, externSymbol, signature, body);
|
||||
return new FuncSyntax(GetTokens(startIndex), prototype, body);
|
||||
}
|
||||
|
||||
private DefinitionSyntax ParseStruct(int startIndex, bool exported)
|
||||
private StructSyntax ParseStruct(int startIndex, bool exported)
|
||||
{
|
||||
var name = ExpectIdentifier();
|
||||
|
||||
if (TryExpectSymbol(Symbol.LessThan))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.GreaterThan))
|
||||
{
|
||||
_templateArguments.Add(ExpectIdentifier().Value);
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
ExpectSymbol(Symbol.OpenBrace);
|
||||
|
||||
List<StructFieldSyntax> fields = [];
|
||||
List<StructFuncSyntax> funcs = [];
|
||||
|
||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||
{
|
||||
var memberStartIndex = _tokenIndex;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Func))
|
||||
var fieldName = ExpectIdentifier().Value;
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var fieldType = ParseType();
|
||||
|
||||
ExpressionSyntax? fieldValue = null;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Assign))
|
||||
{
|
||||
var funcName = ExpectIdentifier().Value;
|
||||
var funcSignature = ParseFuncSignature();
|
||||
var funcBody = ParseBlock();
|
||||
|
||||
funcs.Add(new StructFuncSyntax(GetTokens(memberStartIndex), funcName, funcSignature, funcBody));
|
||||
fieldValue = ParseExpression();
|
||||
}
|
||||
else
|
||||
{
|
||||
var fieldName = ExpectIdentifier().Value;
|
||||
ExpectSymbol(Symbol.Colon);
|
||||
var fieldType = ParseType();
|
||||
|
||||
ExpressionSyntax? fieldValue = null;
|
||||
|
||||
if (TryExpectSymbol(Symbol.Assign))
|
||||
{
|
||||
fieldValue = ParseExpression();
|
||||
}
|
||||
|
||||
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
|
||||
}
|
||||
fields.Add(new StructFieldSyntax(GetTokens(memberStartIndex), fieldName, fieldType, fieldValue));
|
||||
}
|
||||
|
||||
if (_templateArguments.Count > 0)
|
||||
{
|
||||
var templateArguments = _templateArguments.ToList();
|
||||
_templateArguments.Clear();
|
||||
return new StructTemplateSyntax(GetTokens(startIndex), templateArguments, name.Value, exported, fields, funcs);
|
||||
}
|
||||
|
||||
return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields, funcs);
|
||||
return new StructSyntax(GetTokens(startIndex), name.Value, exported, fields);
|
||||
}
|
||||
|
||||
private StatementSyntax ParseStatement()
|
||||
@@ -543,24 +494,6 @@ public sealed class Parser
|
||||
if (TryExpectSymbol(Symbol.Period))
|
||||
{
|
||||
var member = ExpectIdentifier().Value;
|
||||
if (TryExpectSymbol(Symbol.OpenParen))
|
||||
{
|
||||
var parameters = new List<ExpressionSyntax>();
|
||||
|
||||
while (!TryExpectSymbol(Symbol.CloseParen))
|
||||
{
|
||||
parameters.Add(ParseExpression());
|
||||
if (!TryExpectSymbol(Symbol.Comma))
|
||||
{
|
||||
ExpectSymbol(Symbol.CloseParen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expr = new MemberFuncCallSyntax(GetTokens(startIndex), member, expr, parameters);
|
||||
continue;
|
||||
}
|
||||
|
||||
expr = new MemberAccessSyntax(GetTokens(startIndex), expr, member);
|
||||
continue;
|
||||
}
|
||||
@@ -672,11 +605,6 @@ public sealed class Parser
|
||||
var startIndex = _tokenIndex;
|
||||
if (TryExpectIdentifier(out var name))
|
||||
{
|
||||
if (_templateArguments.Contains(name.Value))
|
||||
{
|
||||
return new SubstitutionTypeSyntax(GetTokens(startIndex), name.Value);
|
||||
}
|
||||
|
||||
if (name.Value[0] == 'u' && int.TryParse(name.Value[1..], out var size))
|
||||
{
|
||||
if (size is not 8 and not 16 and not 32 and not 64)
|
||||
@@ -740,21 +668,6 @@ public sealed class Parser
|
||||
name = customTypeName;
|
||||
}
|
||||
|
||||
var templateParameters = new List<TypeSyntax>();
|
||||
if (TryExpectSymbol(Symbol.LessThan))
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.GreaterThan))
|
||||
{
|
||||
templateParameters.Add(ParseType());
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
if (templateParameters.Count > 0)
|
||||
{
|
||||
return new StructTemplateTypeSyntax(GetTokens(startIndex), templateParameters, module, name.Value);
|
||||
}
|
||||
|
||||
return new CustomTypeSyntax(GetTokens(startIndex), module, name.Value);
|
||||
}
|
||||
}
|
||||
@@ -946,9 +859,7 @@ public sealed class Parser
|
||||
}
|
||||
}
|
||||
|
||||
public record SyntaxTreeMetadata(string ModuleName, List<string> Imports);
|
||||
|
||||
public record SyntaxTree(List<DefinitionSyntax> Definitions, SyntaxTreeMetadata Metadata);
|
||||
public record SyntaxTree(List<DefinitionSyntax> Definitions, string ModuleName, List<string> Imports);
|
||||
|
||||
public class ParseException : Exception
|
||||
{
|
||||
|
||||
@@ -8,17 +8,13 @@ public abstract record DefinitionSyntax(List<Token> Tokens, string Name, bool Ex
|
||||
|
||||
public record FuncParameterSyntax(List<Token> Tokens, string Name, TypeSyntax Type) : SyntaxNode(Tokens);
|
||||
|
||||
public record FuncSignatureSyntax(List<Token> Tokens, List<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens);
|
||||
public record FuncPrototypeSyntax(List<Token> Tokens, string Name, bool Exported, string? ExternSymbol, List<FuncParameterSyntax> Parameters, TypeSyntax ReturnType) : SyntaxNode(Tokens);
|
||||
|
||||
public record FuncSyntax(List<Token> Tokens, string Name, bool Exported, string? ExternSymbol, FuncSignatureSyntax Signature, BlockSyntax? Body) : DefinitionSyntax(Tokens, Name, Exported);
|
||||
public record FuncSyntax(List<Token> Tokens, FuncPrototypeSyntax Prototype, BlockSyntax? Body) : DefinitionSyntax(Tokens, Prototype.Name, Prototype.Exported);
|
||||
|
||||
public record StructFieldSyntax(List<Token> Tokens, string Name, TypeSyntax Type, ExpressionSyntax? Value) : SyntaxNode(Tokens);
|
||||
|
||||
public record StructFuncSyntax(List<Token> Tokens, string Name, FuncSignatureSyntax Signature, BlockSyntax Body) : SyntaxNode(Tokens);
|
||||
|
||||
public record StructSyntax(List<Token> Tokens, string Name, bool Exported, List<StructFieldSyntax> Fields, List<StructFuncSyntax> Functions) : DefinitionSyntax(Tokens, Name, Exported);
|
||||
|
||||
public record StructTemplateSyntax(List<Token> Tokens, List<string> TemplateArguments, string Name, bool Exported, List<StructFieldSyntax> Fields, List<StructFuncSyntax> Functions) : DefinitionSyntax(Tokens, Name, Exported);
|
||||
public record StructSyntax(List<Token> Tokens, string Name, bool Exported, List<StructFieldSyntax> Fields) : DefinitionSyntax(Tokens, Name, Exported);
|
||||
|
||||
public enum UnaryOperatorSyntax
|
||||
{
|
||||
@@ -86,8 +82,6 @@ public record UnaryExpressionSyntax(List<Token> Tokens, UnaryOperatorSyntax Oper
|
||||
|
||||
public record FuncCallSyntax(List<Token> Tokens, ExpressionSyntax Expression, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record MemberFuncCallSyntax(List<Token> Tokens, string Name, ExpressionSyntax Target, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record LocalIdentifierSyntax(List<Token> Tokens, string Name) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record ModuleIdentifierSyntax(List<Token> Tokens, string Module, string Name) : ExpressionSyntax(Tokens);
|
||||
@@ -146,8 +140,4 @@ public record ConstArrayTypeSyntax(List<Token> Tokens, TypeSyntax BaseType, int
|
||||
|
||||
public record CustomTypeSyntax(List<Token> Tokens, string Module, string Name) : TypeSyntax(Tokens);
|
||||
|
||||
public record StructTemplateTypeSyntax(List<Token> Tokens, List<TypeSyntax> TemplateParameters, string Module, string Name) : TypeSyntax(Tokens);
|
||||
|
||||
public record SubstitutionTypeSyntax(List<Token> Tokens, string Name) : TypeSyntax(Tokens);
|
||||
|
||||
#endregion
|
||||
@@ -5,7 +5,10 @@ module "main"
|
||||
extern "main" func main(args: []cstring): i64
|
||||
{
|
||||
raylib::SetConfigFlags(4 | 64)
|
||||
|
||||
raylib::InitWindow(1600, 900, "Hi from nub-lang")
|
||||
defer raylib::CloseWindow()
|
||||
|
||||
raylib::SetTargetFPS(240)
|
||||
|
||||
let width: i32 = 150
|
||||
@@ -20,26 +23,20 @@ extern "main" func main(args: []cstring): i64
|
||||
let bgColor: raylib::Color = { r = 0 g = 0 b = 0 a = 255 }
|
||||
let color: raylib::Color = { r = 255 g = 255 b = 255 a = 255 }
|
||||
|
||||
while !raylib::WindowShouldClose()
|
||||
{
|
||||
if x <= 0
|
||||
{
|
||||
while !raylib::WindowShouldClose() {
|
||||
if x <= 0 {
|
||||
direction.x = 1
|
||||
}
|
||||
else if x + width >= raylib::GetScreenWidth()
|
||||
{
|
||||
} else if x + width >= raylib::GetScreenWidth() {
|
||||
direction.x = -1
|
||||
}
|
||||
else if y <= 0
|
||||
{
|
||||
|
||||
if y <= 0 {
|
||||
direction.y = 1
|
||||
}
|
||||
else if y + height >= raylib::GetScreenHeight()
|
||||
{
|
||||
} else if y + height >= raylib::GetScreenHeight() {
|
||||
direction.y = -1
|
||||
}
|
||||
|
||||
x = x + @floatToInt(i32, direction.x * speed * raylib::GetFrameTime())
|
||||
x = x + @floatToInt(i32, direction.x * speed * raylib::GetFrameTime())
|
||||
y = y + @floatToInt(i32, direction.y * speed * raylib::GetFrameTime())
|
||||
|
||||
raylib::BeginDrawing()
|
||||
|
||||
Reference in New Issue
Block a user