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));
        }
Exemple #2
0
        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));
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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));
        }