public IExpressionNode Visit(ArrowAnonymFunctionSyntaxNode arrowAnonymFunNode) { if (arrowAnonymFunNode.Definition == null) { throw ErrorFactory.AnonymousFunDefinitionIsMissing(arrowAnonymFunNode); } if (arrowAnonymFunNode.Body == null) { throw ErrorFactory.AnonymousFunBodyIsMissing(arrowAnonymFunNode); } //Anonym fun arguments list var argumentLexNodes = arrowAnonymFunNode.ArgumentsDefinition; //Prepare local variable scope //Capture all outerscope variables var localVariables = new VariableDictionary(_variables.GetAllSources()); var arguments = new VariableSource[argumentLexNodes.Length]; var argIndex = 0; foreach (var arg in argumentLexNodes) { //Convert argument node var varNode = FunArgumentExpressionNode.CreateWith(arg); var source = VariableSource.CreateWithStrictTypeLabel(varNode.Name, varNode.Type, arg.Interval, isOutput: false); //collect argument arguments[argIndex] = source; argIndex++; //add argument to local scope if (!localVariables.TryAdd(source)) { //Check for duplicated arg-names //If outer-scope contains the conflict variable name if (_variables.GetSourceOrNull(varNode.Name) != null) { throw ErrorFactory.AnonymousFunctionArgumentConflictsWithOuterScope(varNode.Name, arrowAnonymFunNode.Interval); } else //else it is duplicated arg name { throw ErrorFactory.AnonymousFunctionArgumentDuplicates(varNode, arrowAnonymFunNode.Definition); } } } 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)); }
private static FunRuntime Build( SyntaxTree syntaxTree, IFunctionDictionary functionsDictionary, IConstantList constants, AprioriTypesMap aprioriTypesMap) { #region build user functions //get topology sort of the functions call //result is the order of functions that need to be compiled //functions that not references other functions have to be compiled firstly //Then those functions will be compiled //that refer to already compiled functions var functionSolveOrder = syntaxTree.FindFunctionSolvingOrderOrThrow(); List <IFunctionSignature> userFunctions; IFunctionDictionary functionDictionary; if (functionSolveOrder.Length == 0) { functionDictionary = functionsDictionary; userFunctions = EmptyUserFunctionsList; } else { userFunctions = new List <IFunctionSignature>(); var scopeFunctionDictionary = new ScopeFunctionDictionary(functionsDictionary); functionDictionary = scopeFunctionDictionary; //build user functions foreach (var functionSyntaxNode in functionSolveOrder) { //todo list capacity var userFun = BuildFunctionAndPutItToDictionary( functionSyntaxNode: functionSyntaxNode, constants: constants, functionsDictionary: scopeFunctionDictionary); userFunctions.Add(userFun); } } #endregion var bodyTypeSolving = SolveBodyTypes(syntaxTree, constants, functionDictionary, aprioriTypesMap); #region build body var variables = new VariableDictionary(); var equations = new List <Equation>(); foreach (var treeNode in syntaxTree.Nodes) { if (treeNode is EquationSyntaxNode node) { var equation = BuildEquationAndPutItToVariables(node, functionDictionary, variables, bodyTypeSolving); equations.Add(equation); if (Helper.DoesItLooksLikeSuperAnonymousVariable(equation.Id)) { throw FunParseException.ErrorStubToDo("variable cannot starts with 'it'"); } if (TraceLog.IsEnabled) { TraceLog.WriteLine($"\r\nEQUATION: {equation.Id}:{equation.Expression.Type} = ... \r\n"); } } else if (treeNode is VarDefinitionSyntaxNode varDef) { if (Helper.DoesItLooksLikeSuperAnonymousVariable(varDef.Id)) { throw FunParseException.ErrorStubToDo("variable cannot starts with 'it'"); } var variableSource = VariableSource.CreateWithStrictTypeLabel( varDef.Id, varDef.FunnyType, varDef.Interval, isOutput: false, varDef.Attributes); if (!variables.TryAdd(variableSource)) { var allUsages = variables.GetUsages(variableSource.Name); throw ErrorFactory.VariableIsDeclaredAfterUsing(allUsages); } if (TraceLog.IsEnabled) { TraceLog.WriteLine($"\r\nVARIABLE: {variableSource.Name}:{variableSource.Type} = ... \r\n"); } } else if (treeNode is UserFunctionDefinitionSyntaxNode) { continue;//user function was built above } else { throw new InvalidOperationException($"Type {treeNode} is not supported as tree root"); } } #endregion foreach (var userFunction in userFunctions) { if (userFunction is GenericUserFunction generic && generic.BuiltCount == 0) { // Generic function is declared but concrete was not built. // We have to build it at least once to search all possible errors GenericUserFunction.CreateSomeConcrete(generic); } } return(new FunRuntime(equations, variables, userFunctions)); }
private static Equation BuildEquationAndPutItToVariables( EquationSyntaxNode equation, IFunctionDictionary functionsDictionary, VariableDictionary variables, TypeInferenceResults typeInferenceResults) { var expression = ExpressionBuilderVisitor.BuildExpression( node: equation.Expression, functions: functionsDictionary, outputType: equation.OutputType, variables: variables, typeInferenceResults: typeInferenceResults, typesConverter: TicTypesConverter.Concrete); VariableSource outputVariableSource; if (equation.OutputTypeSpecified) { outputVariableSource = VariableSource.CreateWithStrictTypeLabel( name: equation.Id, type: equation.OutputType, typeSpecificationIntervalOrNull: equation.TypeSpecificationOrNull.Interval, attributes: equation.Attributes, isOutput: true); } else { outputVariableSource = VariableSource.CreateWithoutStrictTypeLabel( name: equation.Id, type: equation.OutputType, isOutput: true, equation.Attributes); } var itVariable = variables.GetSuperAnonymousVariableOrNull(); if (itVariable != null) { throw FunParseException.ErrorStubToDo("Variable cannot starts with it"); } if (!variables.TryAdd(outputVariableSource)) { //some equation referenced the source before var usages = variables.GetUsages(equation.Id); if (usages.Source.IsOutput) { throw ErrorFactory.OutputNameWithDifferentCase(equation.Id, equation.Expression.Interval); } else { throw ErrorFactory.CannotUseOutputValueBeforeItIsDeclared(usages); } } //ReplaceInputType if (outputVariableSource.Type != expression.Type) { throw new ImpossibleException("fitless"); } return(new Equation(equation.Id, expression, outputVariableSource)); }