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; }
public UserDefinedUnaryOperator(string name, AstFuncExpr func) { this.Name = name; this.SubExprType = func.Parameters[0].Type; this.ResultType = func.ReturnType; this.Declaration = func; }
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)); }
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); }
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); }
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); }
private void AddFunction(AstFuncExpr func) { mAllFunctions.Add(func); mUnresolvedFunctions.Enqueue(func); }
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; }
public GenericFunctionType(AstFuncExpr decl) : base(0, 1, false) { Declaration = decl; }
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; }
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; }
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}"); } }