public Construct VisitPrototype(Prototype node) { // Retrieve argument count within node. uint argumentCount = (uint)node.Arguments.Length; // Create the argument buffer array. LlvmType[] arguments = new LlvmType[Math.Max(argumentCount, 1)]; // Attempt to retrieve an existing function value. LlvmFunction?function = this.module.GetFunction(node.Identifier); // Function may be already defined. if (function != null) { // Function already has a body, disallow re-definition. if (function.HasBlocks) { throw new Exception($"Cannot re-define function: {node.Identifier}"); } // If the function takes a different number of arguments, reject. else if (function.ArgumentCount != argumentCount) { throw new Exception("redefinition of function with different # args"); } } else { // TODO: Wrong type. for (int i = 0; i < argumentCount; ++i) { arguments[i] = LLVM.DoubleType().Wrap(); } // TODO: Support for infinite arguments and hard-coded return type. // Create the function type. LlvmType type = LlvmFactory.Function(LlvmFactory.Void(), arguments, false); // Create the function within the module. function = this.module.CreateFunction(node.Identifier, type); // Set the function's linkage. function.SetLinkage(LLVMLinkage.LLVMExternalLinkage); } // Process arguments. for (int i = 0; i < argumentCount; ++i) { // Retrieve the argument name. string argumentName = node.Arguments[i].Item2.Value; // Retrieve the argument at the current index iterator. LlvmValue argument = function.GetArgumentAt((uint)i); // Name the argument. argument.SetName(argumentName); // TODO: Watch out for already existing ones. // Stored the named argument in the named values cache. this.namedValues.Add(argumentName, argument); } // Push the function onto the stack. this.valueStack.Push(function); // Return the node. return(node); }
public Construct VisitRoutine(Routine node) { // Ensure body was provided or created. if (node.Body == null) { throw new Exception("Unexpected function body to be null"); } // Ensure prototype is set. else if (node.Prototype == null) { throw new Exception("Unexpected function prototype to be null"); } // Ensures the function does not already exist. else if (this.module.ContainsFunction(node.Prototype.Identifier)) { throw new Exception($"A function with the identifier '{node.Prototype.Identifier}' already exists"); } // Clear named values. this.namedValues.Clear(); // Create an argument buffer list. List <LlvmType> arguments = new List <LlvmType>(); // Process the prototype's arguments. foreach ((Kind kind, Reference reference) in node.Prototype.Arguments) { // Visit the argument's type. this.Visit(kind); // Pop the resulting type off the stack. LlvmType argumentType = this.typeStack.Pop(); // Append the argument's type to the argument list. arguments.Add(argumentType); } // Visit the return type node. this.Visit(node.Prototype.ReturnKind); // Pop off the return type off the stack. LlvmType returnType = this.typeStack.Pop(); // Emit the function type. LlvmType type = LlvmFactory.Function(returnType, arguments.ToArray(), node.Prototype.HasInfiniteArguments); // Create the function. LlvmFunction function = this.module.CreateFunction(node.Prototype.Identifier, type); // Register as the temporary, local function. this.function = function; // Create the argument index counter. uint argumentIndexCounter = 0; // Name arguments. foreach ((Kind kind, Reference reference) in node.Prototype.Arguments) { // Retrieve the argument. LlvmValue argument = function.GetArgumentAt(argumentIndexCounter); // Name the argument. argument.SetName(reference.Value); // Increment the index counter for next iteration. argumentIndexCounter++; } // Visit the body. this.VisitSection(node.Body); // Pop the body off the stack. this.blockStack.Pop(); // TODO // Ensure that body returns a value if applicable. // else if (!node.Prototype.ReturnKind.IsVoid && !node.Body.HasReturnValue) // { // throw new Exception("Functions that do not return void must return a value"); // } // Verify the function. function.Verify(); // Append the function onto the stack. this.valueStack.Push(function); // Return the node. return(node); }