/// <summary> /// Compiles a single expression (e.g. part of an expression list) /// </summary> private IFunction CompileExpression(IFunction?previous, Match exprAst, CompilationStack stack, CompilationContext context) { switch (exprAst.Name) { case ElementAST.NumberExpression: return(new Constant((float)exprAst.Value)); case ElementAST.VariableExpression: context.Push(MakeCallSite(exprAst)); var variable = CompileFunction(exprAst.Text, stack, context); context.Pop(); return(variable); case ElementAST.SubExpression: return(previous.Call(exprAst[ElementAST.SubExpressionName].Text, context, MakeCallSite(exprAst))); case ElementAST.CallExpression: // This is called a *lot*, so try to make it high performance: var args = exprAst[ElementAST.CallArguments].Matches; var argList = new IFunction[args.Count]; for (var i = 0; i < argList.Length; i++) { argList[i] = CompileExpressionList(args[i], stack, context); } return(previous.Call(argList, context, MakeCallSite(exprAst))); default: return(context.LogError($"Unknown expression {exprAst}")); } }
public override IFunction CallInternal(IFunction[] arguments, string output, CompilationContext context) { if (IsNamespace && arguments.Length == 0) { return(CompileIntermediate(arguments, output, context)); } else if (IsNamespace && !IsClass) { return(context.LogError($"This is a Namespace, so it has no constructor")); } if (IsClass && arguments.Length == Inputs.Length && Outputs.All(p => p.Name != output) && NamespaceMembers.Contains(output)) { var memberFunction = CompileIntermediate(Array.Empty <IFunction>(), output, context); if (memberFunction.Inputs.Length > 0 && memberFunction.Inputs[0].Name == "this") { var classInstance = this.Call(arguments, context); return(classInstance.AsMethod(memberFunction, MakeCallSite(Ast), context)); } } context.Push(MakeCallSite(Ast)); if (this.CheckArguments(arguments, output, context) != null) { context.Pop(); return(Error.Instance); } context.Pop(); if (IsClass) { return(arguments[Array.FindIndex(Outputs, p => p.Name == output)]); } var outputPort = Outputs.First(p => p.Name == output); var outValue = CompileIntermediate(arguments, output, context); var success = outputPort.Type.SatisfiedBy(outValue, context); return(success switch { false => context.LogError("ELE0008", $"Output `{outputPort}` was not satisfied by its value `{outValue}` (See previous errors)"), null => Error.Instance, _ => outValue });
public static IFunction Call(this IFunction function, IFunction[] arguments, string output, CompilationContext info, CallSite?callSite = null) { if (function == null) { throw new ArgumentNullException(nameof(function)); } if (callSite.HasValue) { info.Push(callSite.Value); } var retval = function.CallInternal(arguments, output, info); if (callSite.HasValue) { info.Pop(); } return(retval); }