public IExpressionNode Visit(SuperAnonymFunctionSyntaxNode arrowAnonymFunNode) { var outputTypeFunDefinition = arrowAnonymFunNode.OutputType.FunTypeSpecification; if (outputTypeFunDefinition == null) { throw new ImpossibleException("Fun definition expected"); } string[] argNames = null; if (outputTypeFunDefinition.Inputs.Length == 1) { argNames = new[] { "it" } } ; else { argNames = new string[outputTypeFunDefinition.Inputs.Length]; for (int i = 0; i < outputTypeFunDefinition.Inputs.Length; i++) { argNames[i] = $"it{i + 1}"; } } //Prepare local variable scope //Capture all outerscope variables var localVariables = new VariableDictionary(_variables.GetAllSources()); var arguments = new VariableSource[argNames.Length]; for (var i = 0; i < argNames.Length; i++) { var arg = argNames[i]; var type = outputTypeFunDefinition.Inputs[i]; var source = VariableSource.CreateWithoutStrictTypeLabel(arg, type, false); //collect argument arguments[i] = source; //add argument to local scope //if argument with it* name already exist - replace it localVariables.AddOrReplace(source); } var body = arrowAnonymFunNode.Body; return(BuildAnonymousFunction(arrowAnonymFunNode.Interval, body, localVariables, arguments)); }
public static ConcreteUserFunction BuildConcrete( this UserFunctionDefinitionSyntaxNode functionSyntax, FunnyType[] argTypes, FunnyType returnType, IFunctionDictionary functionsDictionary, TypeInferenceResults results, TicTypesConverter converter) { var vars = new VariableDictionary(functionSyntax.Args.Count); for (int i = 0; i < functionSyntax.Args.Count; i++) { var variableSource = RuntimeBuilderHelper.CreateVariableSourceForArgument( argSyntax: functionSyntax.Args[i], actualType: argTypes[i]); if (!vars.TryAdd(variableSource)) { throw ErrorFactory.FunctionArgumentDuplicates(functionSyntax, functionSyntax.Args[i]); } } var bodyExpression = ExpressionBuilderVisitor.BuildExpression( node: functionSyntax.Body, functions: functionsDictionary, outputType: returnType, variables: vars, typeInferenceResults: results, typesConverter: converter); vars.ThrowIfSomeVariablesNotExistsInTheList( functionSyntax.Args.Select(a => a.Id)); var function = ConcreteUserFunction.Create( isRecursive: functionSyntax.IsRecursive, name: functionSyntax.Id, variables: vars.GetAllSources().ToArray(), isReturnTypeStrictlyTyped: functionSyntax.ReturnType != FunnyType.Empty, expression: bodyExpression); return(function); }
private IExpressionNode BuildAnonymousFunction(Interval interval, ISyntaxNode body, VariableDictionary localVariables, VariableSource[] arguments) { var sources = localVariables.GetAllSources().ToArray(); var originVariables = new string[sources.Length]; for (int i = 0; i < originVariables.Length; i++) { originVariables[i] = sources[i].Name; } var expr = BuildExpression(body, _functions, localVariables, _typeInferenceResults, _typesConverter); //New variables are new closured var closured = localVariables.GetAllUsages() .Where(s => !originVariables.Contains(s.Source.Name)) .ToList(); if (closured.Any(c => Helper.DoesItLooksLikeSuperAnonymousVariable(c.Source.Name))) { throw FunParseException.ErrorStubToDo("Unexpected it* variable"); } //Add closured vars to outer-scope dictionary foreach (var newVar in closured) { _variables.TryAdd(newVar); //add full usage info to allow analyze outer errors } var fun = ConcreteUserFunction.Create( isRecursive: false, name: "anonymous", variables: arguments, isReturnTypeStrictlyTyped: false, expression: expr); return(new FunVariableExpressionNode(fun, interval)); }