Example #1
0
 public UserDefinedNaryOperator(string name, AstFuncExpr func)
 {
     this.Name        = name;
     this.ArgTypes    = func.Parameters.Select(p => p.Type).ToArray();
     this.ResultType  = func.ReturnType;
     this.Declaration = func;
 }
 public AstFunctionRef(AstFuncExpr func, AstExpression original, ILocation Location = null) : base(Location)
 {
     Declaration   = func;
     Type          = func.Type;
     this.Original = original;
     Value         = func;
 }
Example #3
0
 public UserDefinedUnaryOperator(string name, AstFuncExpr func)
 {
     this.Name        = name;
     this.SubExprType = func.Parameters[0].Type;
     this.ResultType  = func.ReturnType;
     this.Declaration = func;
 }
Example #4
0
        public override NodeFinderResult VisitFuncExpr(AstFuncExpr function, int index = 0)
        {
            if (GetRelativeLocation(function.Body.Location, index) == RelativeLocation.Same)
            {
                return(function.Body.Accept(this, index));
            }

            return(new NodeFinderResult(function.Scope, expr: function));
        }
Example #5
0
        public override string VisitFuncExpr(AstFuncExpr expr, int data = default(int))
        {
            var pars = string.Join(", ", expr.Parameters.Select(p => p.Accept(this)));
            var head = $"({pars})";

            if (expr.ReturnTypeExpr != null)
            {
                head += $" -> {expr.ReturnTypeExpr.Accept(this)}";
            }

            return(head);
        }
Example #6
0
        public string VisitFunctionSignature(AstFuncExpr function)
        {
            var pars = string.Join(", ", function.Parameters.Select(p => p.Accept(this)));
            var head = $"({pars})";

            if (function.ReturnTypeExpr != null)
            {
                head += $" -> {function.ReturnTypeExpr.Accept(this)}";
            }

            return(head);
        }
Example #7
0
 private static void CheckForSelfParam(AstFuncExpr func)
 {
     if (func.Parameters.Count > 0)
     {
         var param = func.Parameters[0];
         if (param.TypeExpr is AstIdExpr i && i.Name == "Self")
         {
             func.SelfType = SelfParamType.Value;
         }
         else if (param.TypeExpr is AstReferenceTypeExpr p2 && p2.Target is AstIdExpr i3 && i3.Name == "Self")
         {
             func.SelfType = SelfParamType.Reference;
         }
     }
        public override string VisitFuncExpr(AstFuncExpr function, int data = 0)
        {
            var pars = string.Join(", ", function.Parameters.Select(p => p.Accept(this)));
            var head = $"{function.Name}({pars})";

            if (function.ReturnTypeExpr != null)
            {
                head += $" -> {function.ReturnTypeExpr.Accept(this)}";
            }

            // @todo
            if (function.Directives.Count > 0)
            {
                head += " " + string.Join(" ", function.Directives.Select(d => VisitDirective(d)));
            }

            return(head);
        }
Example #9
0
 private void AddFunction(AstFuncExpr func)
 {
     mAllFunctions.Add(func);
     mUnresolvedFunctions.Enqueue(func);
 }
Example #10
0
 public virtual ReturnType VisitFuncExpr(AstFuncExpr expr, DataType data = default) => default;
 public AstUfcFuncExpr(AstExpression self, AstFuncExpr func, ILocation Location) : base(Location)
 {
     this.SelfArg      = self;
     this.FunctionDecl = func;
 }
Example #12
0
 public GenericFunctionType(AstFuncExpr decl)
     : base(0, 1, false)
 {
     Declaration = decl;
 }
Example #13
0
        private void GenerateFunctionHeader(AstFuncExpr function, bool forceEmitCode)
        {
            // Don't emit global functions that aren't even used
            if (!forceEmitCode && dontEmitUnusedDeclarations && !function.IsUsed)
            {
                return;
            }

            if (function.IsMacroFunction)
            {
                return;
            }

            var name = "";

            if (function.ImplBlock != null)
            {
                name += function.ImplBlock.TargetType + ".";
                if (function.ImplBlock.Trait != null)
                {
                    name += function.ImplBlock.Trait + ".";
                }
            }

            name += function.Name;

            if (function.PolymorphicTypes != null && function.PolymorphicTypes.Count > 0)
            {
                name += "." + string.Join(".", function.PolymorphicTypes.Select(p => $"{p.Key}.{p.Value}"));
            }
            if (function.ConstParameters != null && function.ConstParameters.Count > 0)
            {
                name += "." + string.Join(".", function.ConstParameters.Select(p => $"{p.Key}.{p.Value.type}.{p.Value.value}"));
            }

            if (function.Body != null)
            {
                name += ".che";
            }

            var linkname = function.GetDirective("linkname");

            LLVMValueRef lfunc = new LLVMValueRef();

            if (linkname != null)
            {
                name = linkname.Arguments[0].Value as string;

                lfunc = module.GetNamedFunction(name);
            }

            LLVMTypeRef ltype = FuncTypeToLLVMType(function.FunctionType);

            if (lfunc.Pointer.ToInt64() == 0)
            {
                lfunc = module.AddFunction(name, ltype);
            }

            // :temporary
            if (function.Body != null)
            {
                lfunc.SetLinkage(LLVMLinkage.LLVMInternalLinkage);
            }

            if (function.HasDirective("extern"))
            {
                lfunc.SetLinkage(LLVMLinkage.LLVMExternalLinkage);
            }

            // TODO

            if (function.HasDirective("noinline"))
            {
                lfunc.AddFunctionAttribute(context, LLVMAttributeKind.NoInline);
            }
            lfunc.AddFunctionAttribute(context, LLVMAttributeKind.NoUnwind);

            var ccDir = function.GetDirective("stdcall");

            if (ccDir != null)
            {
                LLVM.SetFunctionCallConv(lfunc, (int)LLVMCallConv.LLVMX86StdcallCallConv);
            }

            valueMap[function] = lfunc;
        }
Example #14
0
        private void GenerateFunctionImplementation(AstFuncExpr function, bool forceEmitCode)
        {
            // Don't emit global functions that aren't even used
            if (!forceEmitCode && dontEmitUnusedDeclarations && !function.IsUsed)
            {
                return;
            }

            if (function.Body == null || function.IsMacroFunction)
            {
                return;
            }

            currentFunction = function;

            keepTrackOfStackTrace = !function.HasDirective("nostacktrace") && enableStackTrace;

            var lfunc = valueMap[function];

            currentLLVMFunction = lfunc;

            // generate body
            {
                var builder = new IRBuilder();
                this.builder = builder;

                var bbParams = lfunc.AppendBasicBlock("locals");
                //var bbTemps = lfunc.AppendBasicBlock("temps");
                var bbBody = lfunc.AppendBasicBlock("body");

                // allocate space for parameters and return values on stack
                builder.PositionBuilderAtEnd(bbParams);

                PushStackTrace(function);

                for (int i = 0; i < function.Parameters.Count; i++)
                {
                    var param = function.Parameters[i];
                    var p     = lfunc.GetParam((uint)i);
                    var ptype = LLVM.TypeOf(p);
                    p = builder.CreateAlloca(ptype, $"p_{param.Name?.Name}");
                    valueMap[param] = p;
                }

                // @todo: do we still need this?
                //foreach (var c in function.ConstScope.Symbols)
                //{
                //    if (c.Value is ConstSymbol s && !s.Type.IsComptimeOnly)
                //    {
                //        var val = CheezValueToLLVMValue(s.Type, s.Value);
                //        var cnst = builder.CreateAlloca(CheezTypeToLLVMType(s.Type), $"c_");
                //        builder.CreateStore(val, cnst);
                //        valueMap[s] = cnst;
                //    }
                //}

                if (function.ReturnTypeExpr != null)
                {
                    var ptype = CheezTypeToLLVMType(function.ReturnTypeExpr.Type);
                    var p     = builder.CreateAlloca(ptype, $"ret_{function.ReturnTypeExpr.Name?.Name}");
                    valueMap[function.ReturnTypeExpr] = p;
                }

                // store params and rets in local variables
                for (int i = 0; i < function.Parameters.Count; i++)
                {
                    var param = function.Parameters[i];
                    var p     = lfunc.GetParam((uint)i);
                    builder.CreateStore(p, valueMap[param]);
                }

                // temp values
                //builder.PositionBuilderAtEnd(bbTemps);
                builder.CreateBr(bbBody);

                // body
                builder.PositionBuilderAtEnd(bbBody);
                GenerateExpression(function.Body, false);

                // ret if void
                if (function.ReturnTypeExpr == null && !function.Body.GetFlag(ExprFlags.Returns))
                {
                    PopStackTrace();
                    builder.CreateRetVoid();
                }
                builder.Dispose();
            }

            // remove empty basic blocks
            var bb = lfunc.GetFirstBasicBlock();

            while (bb.Pointer.ToInt64() != 0)
            {
                var first = bb.GetFirstInstruction();

                if (bb.GetBasicBlockTerminator().Pointer.ToInt64() == 0)
                {
                    var b = new IRBuilder();
                    b.PositionBuilderAtEnd(bb);
                    b.CreateUnreachable();
                    b.Dispose();
                }

                bb = bb.GetNextBasicBlock();
            }

            // TODO
            //if (lfunc.VerifyFunction(LLVMVerifierFailureAction.LLVMPrintMessageAction))
            //{
            //    Console.Error.WriteLine($"in function {lfunc}");
            //}

            currentFunction = null;
        }
Example #15
0
        private void AnalyseFunction(AstFuncExpr func)
        {
            if (func.IsAnalysed)
            {
                return;
            }
            func.IsAnalysed = true;

            Log($"Analysing function {func.Name}", $"impl = {func.ImplBlock?.Accept(new SignatureAstPrinter())}", $"poly = {func.IsGeneric}");
            PushLogScope();

            var prevCurrentFunction = currentFunction;

            currentFunction = func;
            try
            {
                if (func.SelfType != SelfParamType.None)
                {
                    var p = func.Parameters[0];
                    if (p.Name == null)
                    {
                        p.Name = new AstIdExpr("self", false, p.Location);
                    }

                    if (func.ImplBlock.TargetType is StructType @struct)
                    {
                        ComputeStructMembers(@struct.Declaration);
                        foreach (var m in @struct.Declaration.Members)
                        {
                            AstExpression expr = new AstDotExpr(new AstSymbolExpr(p), new AstIdExpr(m.Name, false, p.Location), p.Location);
                            expr.AttachTo(func, func.SubScope);
                            expr = InferType(expr, m.Type);

                            // define use if no parameter has the same name
                            if (!func.Parameters.Any(pa => pa.Name?.Name == m.Name))
                            {
                                var(ok, other) = func.SubScope.DefineUse(m.Name, expr, false, out var use);

                                if (!ok)
                                {
                                    ReportError(p, $"A symbol with name '{m.Name}' already exists", ("Other here:", other));
                                }
                            }
                        }
                    }
                }

                if (func.IsGeneric)
                {
                    return;
                }

                if (func.TryGetDirective("linkname", out var ln))
                {
                    if (ln.Arguments.Count != 1)
                    {
                        ReportError(ln, $"#linkname requires exactly one argument!");
                    }
                    else
                    {
                        var arg = ln.Arguments[0];
                        arg.SetFlag(ExprFlags.ValueRequired, true);
                        arg = ln.Arguments[0] = InferType(arg, null);
                        if (!(arg.Value is string))
                        {
                            ReportError(arg, $"Argument to #linkname must be a constant string!");
                        }
                    }
                }

                // define parameters
                foreach (var p in func.Parameters)
                {
                    p.ContainingFunction = func;
                    if (p.Name != null)
                    {
                        var(ok, other) = func.SubScope.DefineSymbol(p);
                        if (!ok)
                        {
                            ReportError(p, $"Duplicate parameter '{p.Name}'", ("Other parameter here:", other));
                        }
                    }

                    if (p.DefaultValue != null)
                    {
                        p.DefaultValue.Scope = func.Scope;
                        p.DefaultValue       = InferTypeHelper(p.DefaultValue, p.Type, new TypeInferenceContext {
                            TypeOfExprContext = p.Type
                        });
                        ConvertLiteralTypeToDefaultType(p.DefaultValue, p.Type);
                        p.DefaultValue = CheckType(p.DefaultValue, p.Type);
                        if (p.DefaultValue.Type != p.Type && !p.DefaultValue.Type.IsErrorType)
                        {
                            ReportError(p.DefaultValue,
                                        $"The type of the default value ({p.DefaultValue.Type}) does not match the type of the parameter ({p.Type})");
                        }
                    }
                }

                if (func.ReturnTypeExpr != null)
                {
                    func.ReturnTypeExpr.Mutable = true;
                }

                if (func.ReturnTypeExpr?.Name != null)
                {
                    func.ReturnTypeExpr.ContainingFunction = func;
                    func.ReturnTypeExpr.IsReturnParam      = true;
                    var(ok, other) = func.SubScope.DefineSymbol(func.ReturnTypeExpr);
                    if (!ok)
                    {
                        ReportError(func.ReturnTypeExpr, $"A symbol with name '{func.ReturnTypeExpr.Name.Name}' already exists in current scope", ("Other symbol here:", other));
                    }
                }
                else if (func.ReturnTypeExpr != null)
                {
                    func.SubScope.DefineSymbol(func.ReturnTypeExpr, ".ret");
                }
                if (func.ReturnTypeExpr?.TypeExpr is AstTupleExpr t)
                {
                    int index = 0;
                    foreach (var m in t.Types)
                    {
                        if (m.Name == null)
                        {
                            continue;
                        }
                        m.Mutable = true;
                        AstExpression access = new AstArrayAccessExpr(new AstSymbolExpr(func.ReturnTypeExpr), new AstNumberExpr(index, Location: func.ReturnTypeExpr.Location), func.ReturnTypeExpr.Location);
                        access         = InferType(access, null);
                        var(ok, other) = func.SubScope.DefineUse(m.Name.Name, access, false, out var use);
                        if (!ok)
                        {
                            ReportError(m, $"A symbol with name '{m.Name.Name}' already exists in current scope", ("Other symbol here:", other));
                        }
                        m.Symbol = use;
                        ++index;
                    }
                }

                if (func.FunctionType.IsErrorType || func.FunctionType.IsPolyType)
                {
                    return;
                }

                if (func.Body != null && !func.IsMacroFunction)
                {
                    var errs = PushSilentErrorHandler();
                    func.Body.AttachTo(func, func.SubScope);
                    InferType(func.Body, null);

                    if (func.ReturnTypeExpr != null && !func.Body.GetFlag(ExprFlags.Returns))
                    {
                        // TODO: check that all return values are set
                        var ret = new AstReturnStmt(null, new Location(func.Body.End));
                        ret.Scope = func.Body.SubScope;
                        ret       = AnalyseReturnStatement(ret);
                        func.Body.Statements.Add(ret);
                        func.Body.SetFlag(ExprFlags.Returns, true);
                    }

                    PopErrorHandler();

                    if (errs.HasErrors)
                    {
                        if (func.IsPolyInstance && func.InstantiatedAt != null)
                        {
                            ReportError($"Errors in polymorphic function '{func.Name}':");
                            errs.ForwardErrors(CurrentErrorHandler);

                            void ReportSources(AstFuncExpr func, string indent = "")
                            {
                                if (func.InstantiatedAt == null)
                                {
                                    return;
                                }
                                foreach (var loc in func.InstantiatedAt)
                                {
                                    ReportError(loc, indent + $"Failed to instantiate function '{func.Name}'");
                                }
                                foreach (var loc in func.InstantiatedBy)
                                {
                                    ReportError(loc, indent + $"Failed to instantiate function '{func.Name}'");
                                    ReportSources(loc, indent + "  ");
                                }
                            }

                            ReportError($"Caused from invocations here:");
                            ReportSources(func);
                        }
                        else
                        {
                            errs.ForwardErrors(CurrentErrorHandler);
                        }
                    }
                    else
                    {
                        PassVariableLifetimes(func);
                    }
                }
            }
            finally
            {
                currentFunction = prevCurrentFunction;
                PopLogScope();
                Log($"Finished function {func.Name}");
            }
        }