void CompileFunction(FunctionDeclaration funcdecl) { // Check if a symbol with the name of the function is already defined Symbol sym = null; // Check if only local functions should be generated if (Table.TopScope.IsFunction) { // Declare the function DeclareFunctionPrototype(funcdecl); } if (!Table.FindSymbol(funcdecl.Name, out sym)) { throw LoreException.Create(funcdecl.Location).Describe($"Undefined function: '{funcdecl.Name}'."); } // Check if the symbol is a prototype if (!sym.IsPrototype) { throw new LoreException(funcdecl.Location).Describe($"Function without prototype: '{funcdecl.Name}'."); } // Get the function prototype LLVMValueRef functionRef = sym.Value; // Enter a new scope for the function Table.PushScope(Scope.CreateFunction(functionRef)); // Check if the function returns multiple values var returnType = LLVM.VoidType(); var tupleReturnTypes = new LLVMTypeRef [0]; if (funcdecl.ReturnsTuple) { var count = funcdecl.TupleReturnTypes.Count; tupleReturnTypes = new LLVMTypeRef [count]; for (var i = 0; i < count; i++) { var current = funcdecl.TupleReturnTypes [i]; tupleReturnTypes [i] = Helper.GetBuiltinTypeFromString(current.Name); } returnType = LLVM.StructType(tupleReturnTypes, true); } // Create the return type else if (funcdecl.HasReturnType) { returnType = Helper.GetBuiltinTypeFromString(funcdecl.ReturnType.Name); } // Add function parameters for (var i = 0; i < funcdecl.Parameters.Count; i++) { var argname = funcdecl.Parameters [i].Name.Name; // Get the i-th function parameter var param = LLVM.GetParam(functionRef, (uint)i); // Set the correct name LLVM.SetValueName(param, argname); // Add the named parameter to the scope Table.AddSymbol(Symbol.Create(argname, param, Location)); } // Create the entry block for the function var block = LLVM.AppendBasicBlock(functionRef, "entry"); LLVM.PositionBuilderAtEnd(Builder, block); // Visit the function body funcdecl.VisitChildren(this); // Return void and clear the stack if the // function return type is void if (Helper.CompareType(returnType, LLVM.VoidType())) { // Build return statement LLVM.BuildRetVoid(Builder); } else if (Stack.Count == 0) { // The function has a return type, // but nothing was returned! if (funcdecl.HasReturnType) { throw LoreException.Create(Location) .Describe($"Function '{funcdecl.Name}' has return type '{funcdecl.ReturnType.Name}' but does not return anything!") .Resolve($"Return a value of type '{funcdecl.ReturnType.Name}' or change the return type to 'void'."); } // There are no elements on the stack // Just return void LLVM.BuildRetVoid(Builder); } else if (funcdecl.ReturnsTuple && Stack.Count >= funcdecl.TupleReturnTypes.Count) { // Prepare element array var elems = new LLVMValueRef [funcdecl.TupleReturnTypes.Count]; // Fill the element array for (var i = 0; i < elems.Length; i++) { // Pop the element from the stack var current = Stack.Pop().Value; // Check if the current element is a defined symbol if (Table.FindSymbolByRef(current, out sym)) { // Check if the current element is a pointer if (sym.IsPointer) { // Load the element current = LLVM.BuildLoad(Builder, current, "tmpload"); } } // Cast the element to the right type current = Helper.BuildCast(Builder, current, tupleReturnTypes [i]); // Add the element to the array elems [elems.Length - i - 1] = current; } // Build the return statement LLVM.BuildAggregateRet(Builder, elems); // What the hellt } else if (funcdecl.HasReturnType && Stack.Count > 0) { // There are elements on the stack // Take the top element from the stack var elem = Stack.Pop().Value; // Check if the return element is a defined symbol if (Table.FindSymbolByRef(elem, out sym)) { // Check if the return element is a pointer if (sym.IsPointer) { // Load the element elem = LLVM.BuildLoad(Builder, elem, "tmpload"); } } Helper.BuildOptimalReturn(Builder, elem, returnType); } else { throw LoreException.Create(Location) .Describe($"Unable to construct a return value for function '{funcdecl.Name}'.") .Describe($"This is a compiler bug."); } // Validate the function if (LLVM.VerifyFunction(functionRef, LLVMVerifierFailureAction.LLVMPrintMessageAction).Value != 0) { throw LoreException.Create(funcdecl.Location).Describe($"Function failed to compile: '{funcdecl.Name}'"); } // Exit the scope of the function Table.PopScope(); if (Table.TopScope.IsFunction) { var func = Table.TopScope.Function; LLVM.PositionBuilderAtEnd(Builder, func.GetEntryBasicBlock()); } // Add the function symbol Table.AddSymbol(Symbol.Create(funcdecl.Name, functionRef, funcdecl.Location)); Stack.Clear(); }
internal void DeclareFunctionPrototype(FunctionDeclaration funcdecl) { // Prepare argument type array var argumentCount = funcdecl.Parameters.Count; var arguments = new LLVMTypeRef [Math.Max(argumentCount, 0)]; // Check if the function is already defined Symbol sym; if ((Table.TopScope.IsFunction && Table.TopScope.FindSymbol(funcdecl.Name, out sym)) || (!Table.TopScope.IsFunction && Table.FindSymbol(funcdecl.Name, out sym))) { var e = LoreException.Create(funcdecl.Location).Describe($"Redefinition of function '{funcdecl.Name}'!"); e.Describe($"Previous declaration was at {sym.Location}."); e.Resolve($"Rename the function to avoid a collision."); throw e; } // Add function parameter types to array for (var i = 0; i < funcdecl.Parameters.Count; i++) { arguments [i] = Helper.GetBuiltinTypeFromString(funcdecl.Parameters [i].Type.Name); } // Check if the function returns multiple values var returnType = LLVM.VoidType(); var tupleReturnTypes = new LLVMTypeRef [0]; if (funcdecl.ReturnsTuple) { var count = funcdecl.TupleReturnTypes.Count; tupleReturnTypes = new LLVMTypeRef [count]; for (var i = 0; i < count; i++) { var current = funcdecl.TupleReturnTypes [i]; tupleReturnTypes [i] = Helper.GetBuiltinTypeFromString(current.Name); } returnType = LLVM.StructType(tupleReturnTypes, true); } // Create the return type else if (funcdecl.HasReturnType) { returnType = Helper.GetBuiltinTypeFromString(funcdecl.ReturnType.Name); } // Create the function type var functionType = LLVM.FunctionType( ReturnType: returnType, ParamTypes: arguments, IsVarArg: LLVMFalse ); // Create the actual function var functionRef = LLVM.AddFunction(LLVMModule, funcdecl.Name, functionType); LLVM.SetLinkage(functionRef, LLVMLinkage.LLVMExternalLinkage); // Add the function prototype as a symbol Table.AddSymbol(Symbol.CreatePrototype(funcdecl.Name, functionRef, funcdecl.Location)); }
public override void Accept(FunctionDeclaration func) { base.Accept(func); Compiler.DeclareFunctionPrototype(func); }
/* * fn name (parameters...) -> type [captures...] { * code... * } */ FunctionDeclaration ParseFunction() { var function = FunctionDeclaration.Create(unit.Location); unit.Expect(LoreToken.Keyword, "fn"); // Read the name of the function var name = unit.Expect(LoreToken.Identifier); function.SetName(name.Value); // Read the parameter list if (unit.Match(LoreToken.OpenParen)) { function.SetParameters(ParseDeclarationArgumentList()); } // Read the return type if (unit.Accept(LoreToken.Operator, "->")) { var names = new List <NameExpression> (); while (unit.Match(LoreToken.Identifier)) { names.Add(ParseName()); if (!unit.Accept(LoreToken.Comma)) { break; } } if (names.Count == 1) { function.SetReturnType(names [0]); } else { function.SetReturnTuple(names); } } // Create the function body CodeBlock body = CodeBlock.Create(unit.Location); // Parse captures if (unit.Accept(LoreToken.OpenBracket)) { while (!unit.Match(LoreToken.CloseBracket)) { var lex = unit.Read(); var capture = Capture.Create(unit, lex); body.AddCapture(capture); } unit.Expect(LoreToken.CloseBracket); } // Parse body if (unit.Match(LoreToken.OpenBrace)) { body = ParseBlock(); } else if (unit.Accept(LoreToken.Operator, "=>")) { body.AddChild(ParseExpression()); } // Return the function function.SetBody(body); return(function); }
public virtual void Accept(FunctionDeclaration func) => Update(func);
public override void Accept(FunctionDeclaration func) { base.Accept(func); CompileFunction(func); }