public static Tok MoveIfOrThrow(this TokFlow flow, TokType tokType) { var cur = flow.Current; if (cur == null) { var prev = flow.Previous; if (prev == null) { throw FunParseException.ErrorStubToDo($"\"{tokType}\" is missing at end of stream"); } else { throw FunParseException.ErrorStubToDo($"\"{tokType}\" is missing at end of stream"); } } if (!cur.Is(tokType)) { throw FunParseException.ErrorStubToDo( $"\"{tokType}\" is missing but was \"{cur}\""); } flow.MoveNext(); return(cur); }
public static FunnyType ReadType(this TokFlow flow) { var cur = flow.Current; var readType = ToFunnyType(cur); flow.MoveNext(); var lastPosition = cur.Finish; while (flow.IsCurrent(TokType.ArrOBr)) { if (flow.Current.Start != lastPosition) { throw FunParseException.ErrorStubToDo("unexpected space before []"); } flow.MoveNext(); lastPosition = flow.Current.Finish; if (!flow.MoveIf(TokType.ArrCBr)) { throw ErrorFactory.ArrTypeCbrMissed(new Interval(cur.Start, flow.Current.Start)); } readType = FunnyType.ArrayOf(readType); } return(readType); }
public override IConcreteFunction CreateConcrete(FunnyType[] concreteTypes) { var from = concreteTypes[1]; var to = concreteTypes[0]; if (to == FunnyType.Anything || from == to) { return(new ConcreteConverter(o => o, from, to)); } if (to == FunnyType.Text) { return(new ConcreteConverter(o => o.ToString(), from, to)); } var safeConverter = VarTypeConverter.GetConverterOrNull(from, to); if (safeConverter != null) { return(new ConcreteConverter(safeConverter, from, to)); } if (to.ArrayTypeSpecification?.FunnyType == FunnyType.UInt8) { var serializer = CreateSerializerOrNull(from); if (serializer != null) { return(new ConcreteConverter(serializer, from, to)); } } else if (to.ArrayTypeSpecification?.FunnyType == FunnyType.Bool) { var serializer = CreateBinarizerOrNull(from); if (serializer != null) { return(new ConcreteConverter(serializer, from, to)); } } if (from.ArrayTypeSpecification?.FunnyType == FunnyType.UInt8) { var deserializer = CreateDeserializerOrNull(to); if (deserializer != null) { return(new ConcreteConverter(deserializer, from, to)); } } else if (from.IsText) { var parser = CreateParserOrNull(to); if (parser != null) { return(new ConcreteConverter(parser, from, to)); } } throw FunParseException.ErrorStubToDo($"Impossible explicit convertation {from}->{to}"); }
public IExpressionNode Visit(StructFieldAccessSyntaxNode node) { var structNode = ReadNode(node.Source); //Funtic allows default values for not specified types // so call: // y = {}.missingField // is allowed, but it semantically incorrect if (!structNode.Type.StructTypeSpecification.ContainsKey(node.FieldName)) { throw FunParseException.ErrorStubToDo($"Access to non exist field {node.FieldName}"); } return(new StructFieldAccessExpressionNode(node.FieldName, structNode, node.Interval)); }
public StructInitSyntaxNode(List <EquationSyntaxNode> equations, Interval interval) { var fields = new List <FieldDefenition>(equations.Count); foreach (var equation in equations) { if (equation.TypeSpecificationOrNull != null) { throw FunParseException.ErrorStubToDo("Field type specification is not supported yet"); } fields.Add(new FieldDefenition(equation.Id, equation.Expression)); } Fields = fields; Interval = interval; }
public IExpressionNode Visit(StructInitSyntaxNode node) { var types = new Dictionary <string, FunnyType>(node.Fields.Count); var names = new string[node.Fields.Count]; var nodes = new IExpressionNode[node.Fields.Count]; for (int i = 0; i < node.Fields.Count; i++) { var field = node.Fields[i]; nodes[i] = ReadNode(field.Node); names[i] = field.Name; types.Add(field.Name, field.Node.OutputType); } foreach (var field in node.OutputType.StructTypeSpecification) { if (!types.ContainsKey(field.Key)) { throw FunParseException.ErrorStubToDo($"Field {field.Key} is missed in struct"); } } return(new StructInitExpressionNode(names, nodes, node.Interval, FunnyType.StructOf(types))); }
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 IFunctionSignature BuildFunctionAndPutItToDictionary( UserFunctionDefinitionSyntaxNode functionSyntaxNode, IConstantList constants, ScopeFunctionDictionary functionsDictionary) { #if DEBUG TraceLog.WriteLine($"\r\n====BUILD {functionSyntaxNode.Id}(..) ===="); #endif ////introduce function variable var graphBuider = new GraphBuilder(); var resultsBuilder = new TypeInferenceResultsBuilder(); ITicResults types; try { if (!TicSetupVisitor.SetupTicForUserFunction( userFunctionNode: functionSyntaxNode, ticGraph: graphBuider, functions: functionsDictionary, constants: constants, results: resultsBuilder)) { throw FunParseException.ErrorStubToDo($"Function '{functionSyntaxNode.Id}' is not solved"); } // solve the types types = graphBuider.Solve(); } catch (TicException e) { throw ErrorFactory.TranslateTicError(e, functionSyntaxNode); } resultsBuilder.SetResults(types); var typeInferenceResuls = resultsBuilder.Build(); if (!types.HasGenerics) { #region concreteFunction //set types to nodes functionSyntaxNode.ComeOver( enterVisitor: new ApplyTiResultEnterVisitor( solving: typeInferenceResuls, tiToLangTypeConverter: TicTypesConverter.Concrete), exitVisitor: new ApplyTiResultsExitVisitor()); var funType = TicTypesConverter.Concrete.Convert( typeInferenceResuls.GetVariableType(functionSyntaxNode.Id + "'" + functionSyntaxNode.Args.Count)); var returnType = funType.FunTypeSpecification.Output; var argTypes = funType.FunTypeSpecification.Inputs; if (TraceLog.IsEnabled) { TraceLog.WriteLine($"\r\n=====> Generic {functionSyntaxNode.Id} {funType}"); } //make function prototype var prototype = new ConcreteUserFunctionPrototype(functionSyntaxNode.Id, returnType, argTypes); //add prototype to dictionary for future use functionsDictionary.Add(prototype); var function = functionSyntaxNode.BuildConcrete( argTypes: argTypes, returnType: returnType, functionsDictionary: functionsDictionary, results: typeInferenceResuls, converter: TicTypesConverter.Concrete); prototype.SetActual(function, functionSyntaxNode.Interval); return(function); #endregion } else { var function = GenericUserFunction.Create(typeInferenceResuls, functionSyntaxNode, functionsDictionary); functionsDictionary.Add(function); if (TraceLog.IsEnabled) { TraceLog.WriteLine($"\r\n=====> Concrete {functionSyntaxNode.Id} {function}"); } return(function); } }
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)); }