private static AltRule createSubstitution(SymbolPosition position, string substSymbolName) { var code = new CodeBody().AddIdentifier("obj"); return(AltRule.CreateInternally(position, new RhsGroup[] { RhsGroup.CreateSequence(position, RepetitionEnum.Once, new RhsSymbol(position, "obj", substSymbolName)) }, new CodeMix(CodeMix.SubstitutionComment).AddBody(code))); }
private static AltRule createAppend(SymbolPosition position, string lhsSymbolName, IEnumerable <string> elementTypeNames, params RhsSymbol[] symbols) { // if it does not exists it means we don't care about adding it IEnumerable <RhsSymbol> named_symbols = symbols.Where(it => it.ObjName != null).ToArray(); string list_obj_name; if (named_symbols.Count() == 1) { list_obj_name = "list"; } else { list_obj_name = "tuple_list"; } // since we are creating this code, the only conflict can come from symbol object names list_obj_name = Grammar.RegisterName(list_obj_name, named_symbols.Select(it => it.ObjName).ToList()); var code = new CodeBody().AddSnippet("{"); if (named_symbols.Count() == 1) { code.AddWithIdentifier(list_obj_name, ".", "Add", "(", named_symbols.Single().ObjName, ");"); } else { foreach (Tuple <RhsSymbol, int> sym_pair in named_symbols.ZipWithIndex()) { code.AddWithIdentifier(list_obj_name, ".", CodeWords.Item(sym_pair.Item2 + 1), ".", "Add", "("); code.AddIdentifier(sym_pair.Item1.ObjName); code.AddSnippet(");"); } } code.AddWithIdentifier("return", " ", list_obj_name, ";}"); return(AltRule.CreateInternally(position, new RhsGroup[] { RhsGroup.CreateSequence(position, RepetitionEnum.Once, new RhsSymbol(position, list_obj_name, lhsSymbolName)), RhsGroup.CreateSequence(position, RepetitionEnum.Once, symbols.Select(it => it.ShallowClone().SetSkip(false)).ToArray()) }, new CodeMix(CodeMix.AppendComment).AddBody(code))); }
private IEnumerable <ProductionInfo> buildAltRule(string lhsSymbol, RecursiveEnum recursive, AltRule alt, string treeNodeName) { // for each group assign a selector which enables/disables given symbols, to make all valid variations // for example // a -> X? [Y Z] // is turned into (\ denotes disabled symbol) // a -> \X Y \Z // a -> \X \Y Z // a -> X Y \Z // a -> X \Y Z IEnumerable <RhsEntitySelector> selectors = alt.RhsGroups.Select(it => new RhsEntitySelector(it)).ToArray(); while (true) { yield return(makeBuilderCall(lhsSymbol, recursive, alt, selectors.Select(it => it.BuildConfiguration()).Flatten().ToArray(), treeNodeName)); if (!selectors.Iterate()) { break; } } }
private ProductionInfo makeBuilderCall(string lhsSymbol, RecursiveEnum recursive, AltRule alt, IEnumerable <SymbolMarked> symbolsMarked, string treeNodeName) { // add production with no code var prod_info = new ProductionInfo(alt.Position, lhsSymbol, recursive, symbolsMarked.Where(it => it.IsEnabled).Select(it => it.Symbol), alt.MarkWith); CodeBody code_body = null; if (alt.Code != null) { code_body = (alt.Code as CodeMix).BuildBody(symbolsMarked.Where(sym => sym.Symbol.ObjName != null) .Select(sym => sym.Symbol.GetCodeArgumentNames().Select(it => Tuple.Create(it, sym.IsEnabled))).Flatten()) .Trim(); string identity_function_on = null; // are we just passing one of the parameters? if (code_body.IsIdentity) { identity_function_on = code_body.IdentityIdentifier; } foreach (string var_name in code_body.GetVariables()) { SymbolMarked sym = symbolsMarked .Where(sm => sm.Symbol.GetCodeArgumentNames().Contains(var_name)) // there could be duplicates so we "prefer" enabled element .OrderBy(it => it.IsEnabled ? 0 : 1) .FirstOrDefault(); if (sym != null) { sym.IsParamUsed = true; } } var anon_args = new Dictionary <SymbolMarked, string>(); foreach (Tuple <SymbolMarked, int> sym_pair in symbolsMarked.ZipWithIndex()) { if (sym_pair.Item1.Symbol.ObjName == null) { anon_args.Add(sym_pair.Item1, code_body.RegisterNewIdentifier("_" + sym_pair.Item2)); } } IEnumerable <SymbolMarked> arg_symbols = symbolsMarked.Where(it => it.IsEnabled || it.IsParamUsed).ToList(); // build external function to run the user code string func_ref = registerLambda(lhsSymbol, arg_symbols.Select(sym => sym.Symbol.GetCodeArgumentTypes(grammar)).Flatten(), grammar.TreeNodeName, arg_symbols.Select(sym => sym.Symbol.GetCodeArgumentNames() .Select(it => Tuple.Create(it, anon_args.GetOrNull(sym)))).Flatten(), code_body); // build a lambda with call to a just built function // note that our lambda can have fewer arguments than the actual fuction // in such case we pass "nulls" for disabled arguments // we add nulls to params in order to keep track which arguments comes from which parameters IEnumerable <FuncParameter> lambda_params = arg_symbols.Where(it => it.IsEnabled) .Select(it => FuncParameter.Create(it.Symbol.ObjName, anon_args.GetOrNull(it), grammar.GetTypeNameOfSymbol(it.Symbol))).ToArray(); // if the code indicates that this is identity function, then just find out which parameter is passed along if (identity_function_on != null) { // we can fail for two reasons here: // (1) ok -- single variable we found in the code body is not a parameter, but global variable // (2) BAD -- we have case of unpacking the data, and that case so far we cannot handle // ad.2) consider such rule as // x -> (a b)+ { b }; // "a" and "b" will be handled as tuple of lists // so in entry function we will get a tuple, and then we will call actuall user action code // some "__function_13__(a,b)" which returns the "b" // so we could compute index for inner parameter (for "b" it is 1) // but we cannot compute index for outer function, because there is no index for "b" at all // there is only one parameter -- tuple -- holding "a" (in Item1) and "b" (in Item2) at the same time // so if anything we would have to introduce some combo index: // outer index --> optional unpacking index --> inner index // too much trouble for now Option <int> index = lambda_params.Select(it => it.Name) .ZipWithIndex().Where(it => it.Item1 == identity_function_on).Select(it => it.Item2).OptSingle(); if (index.HasValue) { prod_info.IdentityOuterFunctionParamIndex = index.Value; } } prod_info.ActionCode = CodeLambda.CreateProxy( lhsSymbol, // lambda arguments lambda_params, treeNodeName, func_ref, arg_symbols.Select(arg => arg.Symbol.CombinedSymbols == null // regular symbols ? new[] { new CodeBody().AddIdentifier(arg.IsEnabled ? (arg.Symbol.ObjName ?? anon_args[arg]) : CodeWords.Null) } // compound symbols, we have to use embedded atomic symbols instead now : arg.Symbol.UnpackTuple(arg.IsEnabled) ) .Flatten()); prod_info.CodeComment = alt.Code.Comment; } return(prod_info); }
private AltRule createSeed(SymbolPosition position, List <Production> productions, bool doubled, // should we double the seed right at the start string lhsSymbolName, IEnumerable <string> elementTypeNames, params RhsSymbol[] symbols) { RhsSymbol[] init_symbols = symbols.Where(it => !it.SkipInitially).ToArray(); var main_code = new CodeBody().AddWithIdentifier(CodeWords.New, " "); main_code.Append(makeTupleListCode(position, elementTypeNames)); main_code.AddSnippet("("); IEnumerable <CodeBody> code_lists = elementTypeNames.Select(it => new CodeBody().AddWithIdentifier(CodeWords.New, " ", CodeWords.List, "<", it, ">{")).ToList(); // purpose: to handle names in doubled seed mode Dictionary <RhsSymbol, string[]> obj_name_substs = new Dictionary <RhsSymbol, string[]>(); { IEnumerable <RhsSymbol> named_symbols = symbols.Where(it => it.ObjName != null); if (named_symbols.Any()) { foreach (Tuple <RhsSymbol, CodeBody> tuple in named_symbols.SyncZip(code_lists)) { RhsSymbol nsymbol = tuple.Item1; CodeBody lcode = tuple.Item2; bool double_sym = doubled && !nsymbol.SkipInitially; string[] name_subst = new string[double_sym ? 2 : 1]; obj_name_substs.Add(nsymbol, name_subst); // if we double the element, we have to come up with new names if (double_sym) { name_subst[0] = AutoNames.Double1 + nsymbol.ObjName + "__"; name_subst[1] = AutoNames.Double2 + nsymbol.ObjName + "__"; } else { name_subst[0] = nsymbol.ObjName; } for (int i = 0; i < (double_sym ? 2 : 1); ++i) { if (i == 1) { lcode.AddSnippet(","); } if (double_sym) { lcode.AddIdentifier(name_subst[i]); } else { lcode.AddIdentifier(nsymbol.ObjName); } } } } } foreach (Tuple <CodeBody, int> code_pair in code_lists.ZipWithIndex()) { code_pair.Item1.AddSnippet("}"); if (code_pair.Item2 > 0) { main_code.AddSnippet(","); } main_code.Append(code_pair.Item1); } main_code.AddSnippet(")"); // in case of doubled seed we have to rename the symbols // otherwise just make shallow copies without renaming // but since we already set proxy name correctly, we can use shared code for both cases var seed_symbols = new LinkedList <RhsSymbol>(); for (int i = 0; i < (doubled ? 2 : 1); ++i) { foreach (RhsSymbol sym in (i == 0 ? init_symbols : symbols)) { if (sym.ObjName == null) { seed_symbols.AddLast(sym.ShallowClone()); } else { int s_idx = (i == 1 && sym.SkipInitially) ? 0 : i; seed_symbols.AddLast(sym.Renamed(obj_name_substs[sym][s_idx])); } } } return(AltRule.CreateInternally(position, // are there any symbols for production seed_symbols.Any() ? new RhsGroup[] { RhsGroup.CreateSequence(position, RepetitionEnum.Once, seed_symbols.Select(it => it.SetSkip(false)).ToArray()) } : new RhsGroup[] { }, new CodeMix(CodeMix.SeedComment).AddBody(main_code))); }