Ejemplo n.º 1
0
        public Construct VisitExtern(Extern node)
        {
            // Ensure prototype is set.
            if (node.Prototype == null)
            {
                throw new Exception("Unexpected external definition's prototype to be null");
            }

            // Create the argument buffer list.
            List <LlvmType> arguments = new List <LlvmType>();

            // TODO: What about reference? Arguments must be named for extern?
            foreach ((Kind kind, Reference reference) in node.Prototype.Arguments)
            {
                // Visit the kind.
                this.VisitKind(kind);

                // Pop the type off the stack.
                LlvmType argumentType = this.typeStack.Pop();

                // Append onto the arguments list.
                arguments.Add(argumentType);
            }

            // Visit the prototype's return kind.
            this.Visit(node.Prototype.ReturnKind);

            // Pop 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);

            // Emit the external definition to context and capture the LLVM value reference.
            LlvmValue @extern = this.module.CreateFunction(node.Prototype.Identifier, type);

            // Determine if should be registered on the symbol table.
            if (!this.module.ContainsFunction(node.Prototype.Identifier))
            {
                // Register the external definition as a function in the symbol table.
                this.module.RegisterFunction((LlvmFunction)@extern);
            }
            // Otherwise, throw an error.
            else
            {
                throw new Exception($"Warning: Extern definition '{node.Prototype.Identifier}' being re-defined");
            }

            // Push the resulting value onto the stack.
            this.valueStack.Push(@extern);

            // Return the node.
            return(node);
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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);
        }