public static LNode static_matchCode(LNode node, IMacroContext context) { if (node.AttrNamed(S.Static) == null && !node.HasSpecialName) return null; // handled by normal matchCode macro var args_body = context.GetArgsAndBody(false); VList<LNode> args = args_body.Item1, body = args_body.Item2; if (args.Count != 1) return Reject(context, args[1], "Expected only one expression to match"); var expression = context.PreProcess(AutoStripBraces(args[0])); var cases = GetCases(body, context.Sink); // The `default:` case is represented by an empty list of patterns. if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty)) context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched."); MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>(); foreach (Pair<VList<LNode>, VList<LNode>> pair in cases) { var patterns = pair.Key.IsEmpty ? new VList<LNode>((LNode)null) : pair.Key; foreach (var pattern in patterns) { captures.Clear(); VList<LNode> _; if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _)) { captures[_hash] = expression; // define $# captures.Remove(__); return ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures); } } } return F.Call(S.Splice); // none of the cases matched }
void SetData(IListSource <T> data) { _hSet = new Dictionary <T, T>(data.Count); _mSet = new MMap <T, T>(); _iSet = new Map <T, T>(data.Select(P)); foreach (T item in data) { _hSet.Add(item, item); _mSet.Add(item, item); } }
public CMap GetCombatMap(MapInitInfo info) { var builder = new MapBuilder(); var hexMap = builder.GetMap(info.Rows, info.Cols, ViewParams.OFFSET, ViewParams.MAP_CENTER); var map = new MMap(hexMap); this._map.SetMap(map); this.InitTiles(info); this.InitArmies(info); this.InitChars(info); return(this._map); }
static void AddCapture(MMap <Symbol, LNode> captures, LNode cap, Slice_ <LNode> items) { Debug.Assert(cap.Calls(S.Substitute, 1) && cap.Args.Last.IsId); if (items.Count == 1) { AddCapture(captures, cap.Args.Last.Name, items[0]); } else { AddCapture(captures, cap.Args.Last.Name, F.Call(S.Splice, items)); } }
internal static void AddMacro(MMap <Symbol, VList <MacroInfo> > macros, MacroInfo info) { foreach (string name in info.Names) { var nameS = (Symbol)name; var cases = macros[nameS, VList <MacroInfo> .Empty]; if (!cases.Any(existing => existing.Macro == info.Macro)) { macros[nameS] = cases.Add(info); } } }
public static byte[] encode_node_k(MMap mm, INode node) { var nk = (NodeK)(object)node; var out1 = str_pstr(nk.name); var id1 = fetch(nk.nid, mm.ks); var stream = new MemoryStream(); var bw = new BinaryWriter(stream); bw.Write(out1); bw.Write(encode_i16(id1)); return(stream.ToArray()); }
static LNode TryReplaceHere(LNode node, Pair <LNode, LNode>[] patterns, MMap <Symbol, LNode> temp) { for (int i = 0; i < patterns.Length; i++) { temp.Clear(); LNode r = TryReplaceHere(node, patterns[i].A, patterns[i].B, temp, patterns); if (r != null) { return(r); } } return(null); }
private static bool IsReachable(Vector3 loc) { if (!MMap.GoodVector3(loc)) { return(false); } return(Main.smap.IsWalkable((int)loc.X + 1, (int)loc.Y, (int)loc.Z) || Main.smap.IsWalkable((int)loc.X - 1, (int)loc.Y, (int)loc.Z) || Main.smap.IsWalkable((int)loc.X, (int)loc.Y + 1, (int)loc.Z) || Main.smap.IsWalkable((int)loc.X, (int)loc.Y - 1, (int)loc.Z) || Main.smap.IsWalkable((int)loc.X, (int)loc.Y, (int)loc.Z + 1) || Main.smap.IsWalkable((int)loc.X, (int)loc.Y, (int)loc.Z - 1)); }
static bool AttributesMatch(LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, out LNodeList unmatchedAttrs) { if (pattern.HasPAttrs()) { unmatchedAttrs = LNode.List(); return(ListMatches(candidate.Attrs, pattern.Attrs, ref captures, ref unmatchedAttrs)); } else { unmatchedAttrs = candidate.Attrs; } return(true); }
static void AddCapture(MMap <Symbol, LNode> captures, LNode cap, Slice_ <LNode> items) { LNode capId = GetCaptureIdentifier(cap); if (items.Count == 1) { AddCapture(captures, capId.Name, items[0]); } else { AddCapture(captures, capId.Name, F.Call(S.Splice, items)); } }
/// <summary>Determines whether one Loyc tree "matches" another. This is /// different from a simple equality test in that (1) trivia atributes do /// not have to match, and (2) the pattern can contain placeholders represented /// by calls to $ (the substitution operator) with an identifier as a parameter. /// Placeholders match any subtree, and are saved to the <c>captures</c> map. /// </summary> /// <param name="candidate">A node that you want to compare with a 'pattern'.</param> /// <param name="pattern">A syntax tree that may contain placeholders. A /// placeholder is a call to the $ operator with one parameter, which must /// be either (A) a simple identifier, or (B) the ".." operator with a simple /// identifier as its single parameter. Otherwise, the $ operator is treated /// literally as something that must exist in <c>candidate</c>). The subtree /// in <c>candidate</c> corresponding to the placeholder is saved in /// <c>captures</c>.</param> /// <param name="captures">A table that maps placeholder names from /// <c>pattern</c> to subtrees in <c>candidate</c>. You can set your map to /// null and a map will be created for you if necessary. If you already have /// a map, you should clear it before calling this method.</param> /// <param name="unmatchedAttrs">On return, a list of trivia attributes in /// <c>candidate</c> that were not present in <c>pattern</c>.</param> /// <returns>true if <c>pattern</c> matches <c>candidate</c>, false otherwise.</returns> /// <remarks> /// Attributes in patterns are not yet supported. /// <para/> /// This method supports multi-part captures, which are matched to /// placeholders whose identifier either (A) has a #params attribute or /// (B) has the unary ".." operator applied to it (for example, if /// the placeholder is called p, this is written as <c>$(params p)</c> in /// EC#.) A placeholder that looks like this can match multiple arguments or /// multiple statements in the <c>candidate</c> (or <i>no</i> arguments, or /// no statements), and will become a #splice(...) node in <c>captures</c> /// if it matches multiple items. Multi-part captures are often useful for /// getting lists of statements before and after some required element, /// e.g. <c>{ $(params before); MatchThis($something); $(params after); }</c> /// <para/> /// If the same placeholder appears twice then the two matching items are /// combined into a single output node (calling #splice). /// <para/> /// If matching is unsuccessful, <c>captures</c> and <c>unmatchedAttrs</c> /// may contain irrelevant information gathered during the attempt to match. /// <para/> /// In EC#, the quote(...) macro can be used to create the LNode object for /// a pattern. /// </remarks> public static bool MatchesPattern(this LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, out LNodeList unmatchedAttrs) { // [$capture] (...) if (!AttributesMatch(candidate, pattern, ref captures, out unmatchedAttrs)) { return(false); } // $capture or $(..capture) LNode sub = GetCaptureIdentifier(pattern); if (sub != null) { captures = captures ?? new MMap <Symbol, LNode>(); AddCapture(captures, sub.Name, candidate); unmatchedAttrs = LNodeList.Empty; // The attrs (if any) were captured return(true); } var kind = candidate.Kind; if (kind != pattern.Kind) { return(false); } if (kind == LNodeKind.Id && candidate.Name != pattern.Name) { return(false); } if (kind == LNodeKind.Literal) { return(object.Equals(candidate.Value, pattern.Value)); } else if (kind == LNodeKind.Call) { if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref unmatchedAttrs)) { return(false); } var cArgs = candidate.Args; var pArgs = pattern.Args; return(ListMatches(cArgs, pArgs, ref captures, ref unmatchedAttrs)); } else // kind == Id { return(true); } }
static bool MatchesPatternNested(LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, ref RVList <LNode> trivia) { RVList <LNode> unmatchedAttrs; if (!MatchesPattern(candidate, pattern, ref captures, out unmatchedAttrs)) { return(false); } if (unmatchedAttrs.Any(a => !a.IsTrivia)) { return(false); } trivia.AddRange(unmatchedAttrs); return(true); }
public static LNode staticMatches(LNode node, IMacroContext context) { if (node.ArgCount != 2) return null; LNode candidate = context.PreProcess(AutoStripBraces(node[0])); LNode pattern = AutoStripBraces(node[1]); MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>(); VList<LNode> _; if (LNodeExt.MatchesPattern(candidate, pattern, ref captures, out _)) { SetSyntaxVariables(captures, context); return F.True; } return F.False; }
protected Precedence FindPrecedence(MMap <object, Precedence> table, object symbol, Precedence @default, bool cacheWordOp) { // You can see the official rules in the LesPrecedence documentation. // Rule 1 (for >= <= != ==) is covered by the pre-populated contents // of the table, and the pre-populated table helps interpret rules // 3-4 also. Precedence prec; if (table.TryGetValue(symbol, out prec)) { return(prec); } string sym = (symbol ?? "").ToString(); if (sym == "") { return(@default); // empty operator! } // Note: all one-character operators should have been found in the table char first = sym[0], last = sym[sym.Length - 1]; if (last == '=' && first != '=' && table == this[OperatorShape.Infix].A) { return(table[symbol] = table[S.Assign]); } var twoCharOp = GSymbol.Get(first.ToString() + last); if (table.TryGetValue(twoCharOp, out prec)) { return(table[symbol] = prec); } var oneCharOp = GSymbol.Get(last.ToString()); if (table.TryGetValue(oneCharOp, out prec)) { return(table[symbol] = prec); } // Default precedence is used for word operators if (cacheWordOp) { table[symbol] = @default; } return(@default); }
internal static void AddMacro(MMap <Symbol, List <MacroInfo> > macros, MacroInfo info) { List <MacroInfo> cases; if (!macros.TryGetValue(info.Name, out cases)) { macros[info.Name] = cases = new List <MacroInfo>(); cases.Add(info); } else { if (!cases.Any(existing => existing.Macro == info.Macro)) { cases.Add(info); } } }
static LNode ReplaceCaptures(LNode node, MMap <Symbol, LNode> captures) { if (captures.Count != 0) { // TODO: EXPAND SPLICES! Generally it works anyway though because // the macro processor has built-in support for #splice. return(node.ReplaceRecursive(n => { LNode sub, cap; if (n.Calls(S.Substitute, 1) && (sub = n.Args.Last).IsId && captures.TryGetValue(sub.Name, out cap)) { return cap; } return null; })); } return(node); }
public async void SizedButton_Clicked(object sender, EventArgs e) { //JsonValue value = JsonValue.Parse(@"{ ""name"":""Prince Charming"", ..."); //JsonObject result = value as JsonObject; Location startLocation = await Geolocation.GetLastKnownLocationAsync(); NetworkAccess current = Connectivity.NetworkAccess; if (current == NetworkAccess.Internet) { double shortestDistance = 0; Models.Directions directions = new Models.Directions(); Location neareatPark = new Location(); foreach (Pin pin in MMap.Pins) { Location endLocation = new Location(pin.Position.Latitude, pin.Position.Longitude); Models.Directions tempDirections = await DirectionsMethods.GetDirectionsInfo(startLocation.Latitude, endLocation.Latitude, startLocation.Longitude, endLocation.Longitude); if (tempDirections != null) { double tempDistance = DirectionsMethods.GetDistance(tempDirections); if (shortestDistance == 0 || shortestDistance > tempDistance) { neareatPark = endLocation; shortestDistance = tempDistance; directions = tempDirections; } } } //map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(neareatPark.Latitude, neareatPark.Longitude), // Distance.FromKilometers(.1))); //foreach (Models.Route route in directions.Routes) //{ // foreach (Models.Leg leg in route.legs) // { // map.LoadRoutes(leg.steps); // } //} foreach (Models.Route route in directions.Routes) { MMap.LoadRoutes(route.overview_polyline); } } }
Precedence FindPrecedence(MMap <object, Precedence> table, object symbol, Precedence @default) { // You can see the official rules in the LesPrecedence documentation. // Rule 1 (for >= <= != ==) is covered by the pre-populated contents // of the table, and the pre-populated table helps interpret rules // 3-4 also. Precedence prec; if (table.TryGetValue(symbol, out prec)) { return(prec); } string sym = symbol.ToString(); if (sym == "") { return(prec); // yikes! } char first = sym[0], last = sym[sym.Length - 1]; // All one-character operators should be found in the table if (table == _infixPrecedence && last == '=') { return(table[symbol] = table[S.Assign]); } var twoCharOp = GSymbol.Get(first.ToString() + last); if (table.TryGetValue(twoCharOp, out prec)) { return(table[symbol] = prec); } var oneCharOp = GSymbol.Get(last.ToString()); if (table.TryGetValue(oneCharOp, out prec)) { return(table[symbol] = prec); } // Default precedence is used for word operators return(table[symbol] = @default); }
public static LNode staticMatches(LNode node, IMacroContext context) { if (node.ArgCount != 2) { return(null); } LNode candidate = context.PreProcess(UnwrapBraces(node[0])); LNode pattern = UnwrapBraces(node[1]); MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>(); if (LNodeExt.MatchesPattern(candidate, pattern, ref captures, out LNodeList _)) { SetSyntaxVariables(captures, context); return(F.True); } return(F.False); }
static LNode TryReplaceHere(LNode node, LNode pattern, LNode replacement, MMap <Symbol, LNode> captures, Pair <LNode, LNode>[] allPatterns) { if (LNodeExt.MatchesPattern(node, pattern, ref captures, out LNodeList attrs)) { foreach (var pair in captures) { var input = pair.Value.AsList(S.Splice); int c; var output = Replace(input, allPatterns, out c); if (output != input) { captures[pair.Key] = output.AsLNode(S.Splice); } } return(ReplaceCaptures(replacement, captures).PlusAttrs(attrs)); } return(null); }
ToiletTip tip;//弹窗 // 构造函数 public MainPage() { InitializeComponent(); this.mapPanel.Children.Add(map = new MMap()); mapLocationLayer = new MapLayer(); map.Children.Add(mapLocationLayer); map.Children.Add(mapWalkingLayer = new MapLayer()); mapToiletLayer = new MapLayer(); map.Children.Add(mapToiletLayer); map.Zoom = 11d; map.ToolBar = Visibility.Visible; // 用于本地化 ApplicationBar 的示例代码 //BuildLocalizedApplicationBar(); this.Loaded += MainPage_Loaded; map.MapLoaded += map_MapLoaded; // map.Hold += map_Hold; Canvas.SetTop(btnLoaction, this.LayoutRoot.ActualHeight - 20); }
public static LNode static_matchCode(LNode node, IMacroContext context) { if (node.AttrNamed(S.Static) == null && !node.HasSpecialName) { return(null); // handled by normal matchCode macro } var args_body = context.GetArgsAndBody(false); VList <LNode> args = args_body.Item1, body = args_body.Item2; if (args.Count != 1) { return(Reject(context, args[1], "Expected only one expression to match")); } var expression = context.PreProcess(AutoStripBraces(args[0])); var cases = GetCases(body, context.Sink); // The `default:` case is represented by an empty list of patterns. if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty)) { context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched."); } MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>(); foreach (Pair <VList <LNode>, VList <LNode> > pair in cases) { var patterns = pair.Key.IsEmpty ? new VList <LNode>((LNode)null) : pair.Key; foreach (var pattern in patterns) { captures.Clear(); VList <LNode> _; if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _)) { captures[_hash] = expression; // define $# captures.Remove(__); return(ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures)); } } } return(F.Call(S.Splice)); // none of the cases matched }
/// <summary>Searches a list of expressions/statements for one or more /// patterns, and performs replacements.</summary> /// <param name="stmts">A list of expressions/statements in which to search.</param> /// <param name="patterns">Each pair consists of (A) something to search /// for and (B) a replacement expression. Part A can use the substitution /// operator with an identifier inside (e.g. $Foo) to "capture" any /// subexpression, and part B can use the same substitution (e.g. $Foo) /// to insert the captured subexpression(s) into the output.</param> /// <param name="replacementCount">Number of replacements that occurred.</param> /// <returns>The result of applying the replacements.</returns> /// <remarks><see cref="LNodeExt.MatchesPattern"/> is used for matching.</remarks> public static RVList<LNode> Replace(RVList<LNode> stmts, Pair<LNode, LNode>[] patterns, out int replacementCount) { // This list is used to support simple token replacement in TokenTrees _tokenTreeRepls = InternalList<Triplet<Symbol, LNode, int>>.Empty; foreach (var pair in patterns) // Look for Id => Id or Id => Literal if (pair.A.IsId && (pair.B.IsId || pair.B.IsLiteral)) _tokenTreeRepls.Add(new Triplet<Symbol,LNode,int>(pair.A.Name, pair.B, 0)); // Scan the syntax tree for things to replace... int count = 0; var temp = new MMap<Symbol, LNode>(); var output = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(n => { LNode r = TryReplaceHere(n, patterns, temp); if (r != null) count++; return r; })); replacementCount = count; return output; }
/// <summary>Finds capture variables like <c>$x</c> and replaces them with values /// from <c>captures</c> (e.g. <c>captures[(Symbol)"x"]</c> for <c>$x</c>)</summary> public static LNode ReplaceCaptures(LNode outputSpec, MMap <Symbol, LNode> captures) { if (captures.Count != 0) { // TODO: EXPAND SPLICES! Generally it works anyway though because // the macro processor has built-in support for #splice. return(outputSpec.ReplaceRecursive(n => { LNode id, cap; if ((id = LNodeExt.GetCaptureIdentifier(n)) != null) { if (captures.TryGetValue(id.Name, out cap)) { return cap; } } return null; })); } return(outputSpec); }
public static void Main(params string[] args) { MMap <string, Pair <string, string> > KnownOptions = LeMP.Compiler.KnownOptions; if (args.Length != 0) { Severity minSeverity = Severity.NoteDetail; #if DEBUG minSeverity = Severity.DebugDetail; #endif var filter = new SeverityMessageFilter(ConsoleMessageSink.Value, minSeverity - 1); LeMP.Compiler c = new LeMP.Compiler(filter, typeof(LeMP.Prelude.BuiltinMacros)); var argList = args.ToList(); var options = c.ProcessArguments(argList, false, true); if (!LeMP.Compiler.MaybeShowHelp(options, KnownOptions)) { LeMP.Compiler.WarnAboutUnknownOptions(options, ConsoleMessageSink.Value, KnownOptions.With("nologo", Pair.Create("", ""))); if (c.Files.Count == 0) { ConsoleMessageSink.Value.Warning(null, "No files specified, stopping."); } else { c.MacroProcessor.PreOpenedNamespaces.Add(GSymbol.Get("LeMP.Prelude.Les")); c.MacroProcessor.PreOpenedNamespaces.Add(GSymbol.Get("LeMP.Prelude")); c.MacroProcessor.PreOpenedNamespaces.Add(Loyc.LLPG.Macros.MacroNamespace); c.AddMacros(typeof(LeMP.StandardMacros).Assembly); c.AddMacros(Assembly.GetExecutingAssembly()); c.Run(); } } } else { LeMP.Compiler.ShowHelp(KnownOptions.OrderBy(p => p.Key)); Test_LLLPG(); } }
public static byte[] encode_node_u(MMap mm, INode node) { var stream = new MemoryStream(); var bw = new BinaryWriter(stream); var nu = ((NodeU)node); var len1 = nu.inputs.l.Count; var len2 = nu.outputs.Count; bw.Write(Osc.str_pstr(nu.name)); bw.Write(Osc.encode_i8((int)nu.rate)); bw.Write(Osc.encode_i16(len1)); bw.Write(Osc.encode_i16(len2)); for (var ind = 0; ind < len1; ind = ind + 1) { bw.Write(encode_input(mk_input(mm, nu.inputs.l[ind]))); } for (var ind = 0; ind < len2; ind = ind + 1) { bw.Write(Osc.encode_i8((int)nu.outputs[ind])); } return(stream.ToArray()); }
public void SetMap(MMap m) { this._map = m; }
public MapPage() { try { InitializeComponent(); if (AlreadyLoaded) { MProgressBar.IsVisible = false; } else { // MMap.IsVisible = false; Device.StartTimer(TimeSpan.FromSeconds(.5), () => { if (!(MProgressBar.Progress < 1)) { return(false); } Device.BeginInvokeOnMainThread(() => MProgressBar.ProgressTo(MProgressBar.Progress + 0.005, 500, Easing.Linear)); return(true); }); } #if __ANDROID__ NavigationPage.SetHasNavigationBar(this, false); #endif #if __IOS__ StackLayout NavStack = new StackLayout() { Children = { new Label() { Text = "Cycles" } } }; NavigationPage.SetTitleView(this, NavStack); #endif } catch (Exception ex) { Console.WriteLine(ex.Message); // Crashlytics.Crashlytics.LogException(Java.Lang.Throwable.FromException(ex)); } BindingContext = this; var pin = new CustomPin { Type = PinType.Place, PinType = CustomPin.CustomType.Park, Position = new Position(6.672219, 3.161639), Label = "Cycles Point @Cafe 2", Address = "Cafeteria 2, Goodness Rd, Canaan Land, Ota", MarkerId = "P2" }; var pin2 = new CustomPin { Type = PinType.Place, PinType = CustomPin.CustomType.Park, Position = new Position(6.67369, 3.15922), Label = "Cycles Point @CST", Address = "College of Science and Tech, CU, Canaan Land, Ota", MarkerId = "P3" }; MMap.CustomPins = new List <CustomPin> { pin, pin2 }; MMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(LAGOS_LATITUDE, LAGOS_LONGITUDE), new Distance(15000d))); // MMap.Pins.Add(pin); // MMap.Pins.Add(pin2); MessagingCenter.Subscribe <MapPageRenderer>(this, "Scanner Opened", async(mainActivity) => { var scanPage = new CustomBarcodeScanner(); if (Application.Current.MainPage.Navigation.ModalStack.Count == 0) { await Application.Current.MainPage.Navigation.PushModalAsync(scanPage); } }); MessagingCenter.Subscribe <MainActivity>(this, "Close Scanner", async(sender) => { if (Application.Current.MainPage.Navigation.ModalStack.Count > 0) { await Application.Current.MainPage.Navigation.PopModalAsync(); } }); MessagingCenter.Subscribe <GraphicBarcodeTracker>(this, "Close Scanner", async(sender) => { if (Application.Current.MainPage.Navigation.ModalStack.Count > 0) { await Application.Current.MainPage.Navigation.PopModalAsync(); } }); }
static bool CaptureGroup(ref int c, ref int p, RVList <LNode> cArgs, RVList <LNode> pArgs, ref MMap <Symbol, LNode> captures, ref RVList <LNode> attrs) { Debug.Assert(IsParamsCapture(pArgs[p])); // The goal now is to find a sequence of nodes in cArgs that matches // the sequence pArgs[p+1 .. p+x] where x is the maximum value such // that none of the nodes in the sequence are $(params caps). int saved_p = p, saved_c = c; var savedCaptures = captures.AsImmutable(); var savedAttrs = attrs; int captureSize = 0; for (;; captureSize++) { for (p++, c += captureSize; ; c++, p++) { // If we run out of pArgs, great, we're done; if we run out // of cArgs, the match fails, unless all remaining pArgs are // $(params caps). if (p >= pArgs.Count || IsParamsCapture(pArgs[p])) { goto done_group; } else { if (c >= cArgs.Count) { return(false); } if (!MatchesPatternNested(cArgs[c], pArgs[p], ref captures, ref attrs)) { goto continue_group; } } } continue_group :; p = saved_p; c = saved_c; attrs = savedAttrs; captures = savedCaptures.AsMutable(); } done_group: AddCapture(captures, pArgs[saved_p], cArgs.Slice(saved_c, captureSize)); return(true); }
/// <summary>Finds capture variables like <c>$x</c> and replaces them with values /// from <c>captures</c> (e.g. <c>captures[(Symbol)"x"]</c> for <c>$x</c>)</summary> public static LNode ReplaceCaptures(LNode outputSpec, MMap<Symbol, LNode> captures) { if (captures.Count != 0) { // TODO: EXPAND SPLICES! Generally it works anyway though because // the macro processor has built-in support for #splice. return outputSpec.ReplaceRecursive(n => { LNode id, cap; if ((id = LNodeExt.GetCaptureIdentifier(n)) != null) { if (captures.TryGetValue(id.Name, out cap)) return cap; } return null; }); } return outputSpec; }
public static LNode replaceFn(LNode node, IMacroContext context1) { var retType = node.Args[0, LNode.Missing].Name; if (retType != _replace && retType != _define) return null; LNode replaceKw, macroName, args, body; if (EcsValidators.MethodDefinitionKind(node, out replaceKw, out macroName, out args, out body, allowDelegate: false) != S.Fn || body == null) return null; MacroMode mode, modes = 0; var leftoverAttrs = node.Attrs.SmartWhere(attr => { if (attr.IsId && Loyc.Compatibility.EnumStatic.TryParse(attr.Name.Name, out mode)) { modes |= mode; return false; } return true; }); LNode pattern = F.Call(macroName, args.Args).PlusAttrs(leftoverAttrs); LNode replacement = body.AsList(S.Braces).AsLNode(S.Splice).PlusAttrs(replaceKw.Attrs); replacement.Style &= ~NodeStyle.OneLiner; WarnAboutMissingDollarSigns(args, context1, pattern, replacement); // Note: we could fill out the macro's Syntax and Description with the // pattern and replacement converted to strings, but it's generally a // waste of CPU time as those strings are usually not requested. var lma = new LexicalMacroAttribute( string.Concat(macroName.Name, "(", args.Args.Count.ToString(), " args)"), "", macroName.Name.Name); var macroInfo = new MacroInfo(null, lma, (candidate, context2) => { MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>(); VList<LNode> unmatchedAttrs; if (candidate.MatchesPattern(pattern, ref captures, out unmatchedAttrs)) { return ReplaceCaptures(replacement, captures).PlusAttrsBefore(unmatchedAttrs); } return null; }) { Mode = modes }; context1.RegisterMacro(macroInfo); return F.Splice(); }
static bool MatchThenParams(VList<LNode> cArgs, VList<LNode> pArgs, LNode paramsCap, ref MMap<Symbol, LNode> captures, ref VList<LNode> attrs) { // This helper function of MatchesPattern() is called when pArgs is followed // by a $(params capture). cArgs is the list of candidate.Args that have not // yet been matched; pArgs is the list of pattern.Args that have not yet been // matched, and paramsCap is the $(params capture) node that follows pArgs. captures = captures ?? new MMap<Symbol, LNode>(); int c = 0, p = 0; restart: for (; p < pArgs.Count; p++, c++) { if (IsParamsCapture(pArgs[p])) { if (!CaptureGroup(ref c, ref p, cArgs, pArgs, ref captures, ref attrs)) return false; goto restart; } else { if (c >= cArgs.Count) return false; if (!MatchesPatternNested(cArgs[c], pArgs[p], ref captures, ref attrs)) return false; } } AddCapture(captures, paramsCap, new Slice_<LNode>(cArgs, c)); return true; }
static bool MatchesPatternNested(LNode candidate, LNode pattern, ref MMap<Symbol, LNode> captures, ref VList<LNode> trivia) { VList<LNode> unmatchedAttrs; if (!MatchesPattern(candidate, pattern, ref captures, out unmatchedAttrs)) return false; if (unmatchedAttrs.Any(a => !a.IsTrivia)) return false; trivia.AddRange(unmatchedAttrs); return true; }
static void AddCapture(MMap<Symbol, LNode> captures, LNode cap, Slice_<LNode> items) { LNode capId = GetCaptureIdentifier(cap); if (items.Count == 1) AddCapture(captures, capId.Name, items[0]); else AddCapture(captures, capId.Name, F.Call(S.Splice, items)); }
protected Precedence FindPrecedence(MMap<object,Precedence> table, object symbol, Precedence @default, bool cacheWordOp) { // You can see the official rules in the LesPrecedence documentation. // Rule 1 (for >= <= != ==) is covered by the pre-populated contents // of the table, and the pre-populated table helps interpret rules // 3-4 also. Precedence prec; if (table.TryGetValue(symbol, out prec)) return prec; string sym = (symbol ?? "").ToString(); if (sym == "") return @default; // empty operator! // Note: all one-character operators should have been found in the table char first = sym[0], last = sym[sym.Length - 1]; if (last == '=' && first != '=' && table == this[OperatorShape.Infix].A) return table[symbol] = table[S.Assign]; var twoCharOp = GSymbol.Get(first.ToString() + last); if (table.TryGetValue(twoCharOp, out prec)) return table[symbol] = prec; var oneCharOp = GSymbol.Get(last.ToString()); if (table.TryGetValue(oneCharOp, out prec)) return table[symbol] = prec; // Default precedence is used for word operators if (cacheWordOp) table[symbol] = @default; return @default; }
/// <summary>Determines whether one Loyc tree "matches" another. This is /// different from a simple equality test in that (1) trivia atributes do /// not have to match, and (2) the pattern can contain placeholders represented /// by calls to $ (the substitution operator) with an identifier as a parameter. /// Placeholders match any subtree, and are saved to the <c>captures</c> map. /// </summary> /// <param name="candidate">A node that you want to compare with a 'pattern'.</param> /// <param name="pattern">A syntax tree that may contain placeholders. A /// placeholder is a call to the $ operator with one parameter, which must /// be a simple identifier (otherwise the $ operator is treated literally as /// something that must exist in <c>candidate</c>). The subtree in /// <c>candidate</c> corresponding to the placeholder is saved in <c>captures</c>.</param> /// <param name="captures">A table that maps placeholder names from /// <c>pattern</c> to subtrees in <c>candidate</c>. You can set your map to /// null and a map will be created for you if necessary. If you already have /// a map, you should clear it before calling this method.</param> /// <param name="unmatchedAttrs">On return, a list of trivia attributes in /// <c>candidate</c> that were not present in <c>pattern</c>.</param> /// <returns>true if <c>pattern</c> matches <c>candidate</c>, false otherwise.</returns> /// <remarks> /// Attributes in patterns are not yet supported. /// <para/> /// This method supports multi-part captures, which are matched to /// placeholders whose identifier has a #params attribute (for example, if /// the placeholder is called p, this is written as <c>$(params p)</c> in /// EC#.) A placeholder that looks like this can match multiple arguments or /// multiple statements in the <c>candidate</c> (or <i>no</i> arguments, or /// no statements), and will become a #splice(...) node in <c>captures</c> /// if it matches multiple items. Multi-part captures are often useful for /// getting lists of statements before and after some required element, /// e.g. <c>{ $(params before); MatchThis($something); $(params after); }</c> /// <para/> /// If the same placeholder appears twice then the two matching items are /// combined into a single output node (calling #splice). /// <para/> /// If matching is unsuccessful, <c>captures</c> and <c>unmatchedAttrs</c> /// may contain irrelevant information gathered during the attempt to match. /// <para/> /// In EC#, the quote(...) macro can be used to create the LNode object for /// a pattern. /// </remarks> public static bool MatchesPattern(LNode candidate, LNode pattern, ref MMap<Symbol, LNode> captures, out RVList<LNode> unmatchedAttrs) { // [$capture] (...) if (!AttributesMatch(candidate, pattern, ref captures, out unmatchedAttrs)) return false; // $capture LNode sub; if (pattern.Calls(S.Substitute, 1) && (sub = pattern.Args.Last).IsId) { captures = captures ?? new MMap<Symbol, LNode>(); AddCapture(captures, sub.Name, candidate); unmatchedAttrs = RVList<LNode>.Empty; // The attrs (if any) were captured return true; } var kind = candidate.Kind; if (kind != pattern.Kind) return false; if (candidate.Name != pattern.Name) return false; if (kind == LNodeKind.Literal) return object.Equals(candidate.Value, pattern.Value); else if (kind == LNodeKind.Call) { if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref unmatchedAttrs)) return false; var cArgs = candidate.Args; var pArgs = pattern.Args; if (pArgs.Count != cArgs.Count && !pArgs.Any(IsParamsCapture)) return false; // Scan from the end of the list to the beginning (RVLists is good at this), // matching args one-by-one. Use MatchThenParams() in case of $(params capture). while (!pArgs.IsEmpty) { LNode pArg = pArgs.Pop(); if (IsParamsCapture(pArg)) return MatchThenParams(cArgs, pArgs, pArg, ref captures, ref unmatchedAttrs); if (cArgs.IsEmpty) return false; if (!MatchesPatternNested(cArgs.Pop(), pArg, ref captures, ref unmatchedAttrs)) return false; } return true; } else // kind == Id return true; }
protected Precedence FindPrecedence(MMap<object,Precedence> table, object symbol, Precedence @default, bool cacheWordOp, bool les3InfixOp = false) { // You can see the official rules in the LesPrecedence documentation. // Rule 1 (for >= <= != ==) is covered by the pre-populated contents // of the table, and the pre-populated table helps interpret other // rules too. CheckParam.IsNotNull("symbol", symbol); Precedence prec; if (table.TryGetValue(symbol, out prec)) return prec; string sym = symbol.ToString(); if (sym.Length <= 1 || sym[0] != '\'') return @default; // empty or non-operator // Note: all one-character operators should have been found in the table char first = sym[1], last = sym[sym.Length - 1]; bool isInfix = table == this[OperatorShape.Infix].A; if (les3InfixOp) { // Check for lowercase word prefix int i = 1; while (first >= 'a' && first <= 'z' || first == '_') { if (++i == sym.Length) { if (cacheWordOp) table[symbol] = P.LowerKeyword; return P.LowerKeyword; } first = sym[i]; } if (i + 1 == sym.Length) { // After the word is a one-character op. See if it is in the table var oneCharOp_ = GSymbol.Get("'" + first); if (table.TryGetValue(oneCharOp_, out prec)) return prec; } } if (isInfix && last == '=') { if (first == '=' || first == '!') return table[symbol] = P.Compare; else return table[symbol] = P.Assign; } var twoCharOp = GSymbol.Get("'" + first + last); if (table.TryGetValue(twoCharOp, out prec)) return table[symbol] = prec; var oneCharOp = GSymbol.Get("'" + first); if (table.TryGetValue(oneCharOp, out prec)) return table[symbol] = prec; if (isInfix && char.IsLower(first)) return table[symbol] = P.LowerKeyword; // Default precedence is used for anything else if (cacheWordOp) return table[symbol] = @default; return @default; }
public static bool MatchesPattern(LNode candidate, LNode pattern, out MMap<Symbol, LNode> captures) { RVList<LNode> unmatchedAttrs = RVList<LNode>.Empty; captures = null; return MatchesPattern(candidate, pattern, ref captures, out unmatchedAttrs); }
static void AddCapture(MMap<Symbol, LNode> captures, LNode cap, Slice_<LNode> items) { Debug.Assert(cap.Calls(S.Substitute, 1) && cap.Args.Last.IsId); if (items.Count == 1) AddCapture(captures, cap.Args.Last.Name, items[0]); else AddCapture(captures, cap.Args.Last.Name, F.Call(S.Splice, items)); }
static bool AttributesMatch(LNode candidate, LNode pattern, ref MMap<Symbol, LNode> captures, out RVList<LNode> unmatchedAttrs) { if (pattern.HasPAttrs()) throw new NotImplementedException("TODO: attributes in patterns are not yet supported"); unmatchedAttrs = candidate.Attrs; return true; }
static void AddCapture(MMap<Symbol, LNode> captures, Symbol capName, LNode candidate) { LNode oldCap = captures.TryGetValue(capName, null); captures[capName] = LNode.MergeLists(oldCap, candidate, S.Splice); }
/// <summary>Get a dictionary of commands from the methods in the specified /// object that have a [Command] attribute.</summary> public static MMap<Symbol, ICommand> GetCommandMap(object obj, Type type = null) { var list = GetCommandList(obj, type); var dict = new MMap<Symbol, ICommand>(); foreach (var c in list) dict.Add(c.Name, c); return dict; }
static bool AttributesMatch(LNode candidate, LNode pattern, ref MMap<Symbol, LNode> captures, out VList<LNode> unmatchedAttrs) { if (pattern.HasPAttrs()) { unmatchedAttrs = LNode.List(); return ListMatches(candidate.Attrs, pattern.Attrs, ref captures, ref unmatchedAttrs); } else { unmatchedAttrs = candidate.Attrs; } return true; }
internal static void AddMacro(MMap<Symbol, List<MacroInfo>> macros, MacroInfo info) { List<MacroInfo> cases; if (!macros.TryGetValue(info.Name, out cases)) { macros[info.Name] = cases = new List<MacroInfo>(); cases.Add(info); } else { if (!cases.Any(existing => existing.Macro == info.Macro)) cases.Add(info); } }
static bool CaptureGroup(ref int c, ref int p, VList<LNode> cArgs, VList<LNode> pArgs, ref MMap<Symbol, LNode> captures, ref VList<LNode> attrs) { Debug.Assert(IsParamsCapture(pArgs[p])); // The goal now is to find a sequence of nodes in cArgs that matches // the sequence pArgs[p+1 .. p+x] where x is the maximum value such // that none of the nodes in the sequence are $(params caps). int saved_p = p, saved_c = c; var savedCaptures = captures.AsImmutable(); var savedAttrs = attrs; int captureSize = 0; for (;; captureSize++) { for (p++, c += captureSize; ; c++, p++) { // If we run out of pArgs, great, we're done; if we run out // of cArgs, the match fails, unless all remaining pArgs are // $(params caps). if (p >= pArgs.Count || IsParamsCapture(pArgs[p])) { goto done_group; } else { if (c >= cArgs.Count) return false; if (!MatchesPatternNested(cArgs[c], pArgs[p], ref captures, ref attrs)) goto continue_group; } } continue_group:; p = saved_p; c = saved_c; attrs = savedAttrs; captures = savedCaptures.AsMutable(); } done_group: AddCapture(captures, pArgs[saved_p], cArgs.Slice(saved_c, captureSize)); return true; }
public static LNode TryReplaceHere(LNode node, LNode pattern, LNode replacement, MMap<Symbol, LNode> captures, Pair<LNode, LNode>[] allPatterns) { RVList<LNode> attrs; if (LNodeExt.MatchesPattern(node, pattern, ref captures, out attrs)) { foreach (var pair in captures) { var input = pair.Value.AsList(S.Splice); int c; var output = Replace(input, allPatterns, out c); if (output != input) captures[pair.Key] = output.AsLNode(S.Splice); } return ReplaceCaptures(replacement, captures).PlusAttrs(attrs); } return null; }
/// <summary>Determines whether one Loyc tree "matches" another. This is /// different from a simple equality test in that (1) trivia atributes do /// not have to match, and (2) the pattern can contain placeholders represented /// by calls to $ (the substitution operator) with an identifier as a parameter. /// Placeholders match any subtree, and are saved to the <c>captures</c> map. /// </summary> /// <param name="candidate">A node that you want to compare with a 'pattern'.</param> /// <param name="pattern">A syntax tree that may contain placeholders. A /// placeholder is a call to the $ operator with one parameter, which must /// be a simple identifier (otherwise the $ operator is treated literally as /// something that must exist in <c>candidate</c>). The subtree in /// <c>candidate</c> corresponding to the placeholder is saved in <c>captures</c>.</param> /// <param name="captures">A table that maps placeholder names from /// <c>pattern</c> to subtrees in <c>candidate</c>. You can set your map to /// null and a map will be created for you if necessary. If you already have /// a map, you should clear it before calling this method.</param> /// <param name="unmatchedAttrs">On return, a list of trivia attributes in /// <c>candidate</c> that were not present in <c>pattern</c>.</param> /// <returns>true if <c>pattern</c> matches <c>candidate</c>, false otherwise.</returns> /// <remarks> /// Attributes in patterns are not yet supported. /// <para/> /// This method supports multi-part captures, which are matched to /// placeholders whose identifier has a #params attribute (for example, if /// the placeholder is called p, this is written as <c>$(params p)</c> in /// EC#.) A placeholder that looks like this can match multiple arguments or /// multiple statements in the <c>candidate</c> (or <i>no</i> arguments, or /// no statements), and will become a #splice(...) node in <c>captures</c> /// if it matches multiple items. Multi-part captures are often useful for /// getting lists of statements before and after some required element, /// e.g. <c>{ $(params before); MatchThis($something); $(params after); }</c> /// <para/> /// If the same placeholder appears twice then the two matching items are /// combined into a single output node (calling #splice). /// <para/> /// If matching is unsuccessful, <c>captures</c> and <c>unmatchedAttrs</c> /// may contain irrelevant information gathered during the attempt to match. /// <para/> /// In EC#, the quote(...) macro can be used to create the LNode object for /// a pattern. /// </remarks> public static bool MatchesPattern(LNode candidate, LNode pattern, ref MMap <Symbol, LNode> captures, out RVList <LNode> unmatchedAttrs) { // [$capture] (...) if (!AttributesMatch(candidate, pattern, ref captures, out unmatchedAttrs)) { return(false); } // $capture LNode sub; if (pattern.Calls(S.Substitute, 1) && (sub = pattern.Args.Last).IsId) { captures = captures ?? new MMap <Symbol, LNode>(); AddCapture(captures, sub.Name, candidate); unmatchedAttrs = RVList <LNode> .Empty; // The attrs (if any) were captured return(true); } var kind = candidate.Kind; if (kind != pattern.Kind) { return(false); } if (candidate.Name != pattern.Name) { return(false); } if (kind == LNodeKind.Literal) { return(object.Equals(candidate.Value, pattern.Value)); } else if (kind == LNodeKind.Call) { if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref unmatchedAttrs)) { return(false); } var cArgs = candidate.Args; var pArgs = pattern.Args; if (pArgs.Count != cArgs.Count && !pArgs.Any(IsParamsCapture)) { return(false); } // Scan from the end of the list to the beginning (RVLists is good at this), // matching args one-by-one. Use MatchThenParams() in case of $(params capture). while (!pArgs.IsEmpty) { LNode pArg = pArgs.Pop(); if (IsParamsCapture(pArg)) { return(MatchThenParams(cArgs, pArgs, pArg, ref captures, ref unmatchedAttrs)); } if (cArgs.IsEmpty) { return(false); } if (!MatchesPatternNested(cArgs.Pop(), pArg, ref captures, ref unmatchedAttrs)) { return(false); } } return(true); } else // kind == Id { return(true); } }
static LNode ReplaceCaptures(LNode node, MMap<Symbol, LNode> captures) { if (captures.Count != 0) { // TODO: EXPAND SPLICES! Generally it works anyway though because // the macro processor has built-in support for #splice. return node.ReplaceRecursive(n => { LNode sub, cap; if (n.Calls(S.Substitute, 1) && (sub = n.Args.Last).IsId && captures.TryGetValue(sub.Name, out cap)) return cap; return null; }); } return node; }
static void AddCapture(MMap <Symbol, LNode> captures, Symbol capName, LNode candidate) { LNode oldCap = captures.TryGetValue(capName, null); captures[capName] = LNode.MergeLists(oldCap, candidate, S.Splice); }
static LNode TryReplaceHere(LNode node, Pair<LNode, LNode>[] patterns, MMap<Symbol, LNode> temp) { for (int i = 0; i < patterns.Length; i++) { temp.Clear(); LNode r = TryReplaceHere(node, patterns[i].A, patterns[i].B, temp, patterns); if (r != null) return r; } // Support simple token replacement in TokenTrees TokenTree tt; if (node.IsLiteral && (tt = node.Value as TokenTree) != null) { bool modified = ReplaceInTokenTree(ref tt, _tokenTreeRepls); if (modified) return node.WithValue(tt); } return null; }
static bool MatchThenParams(RVList <LNode> cArgs, RVList <LNode> pArgs, LNode paramsCap, ref MMap <Symbol, LNode> captures, ref RVList <LNode> attrs) { // This helper function of MatchesPattern() is called when pArgs is followed // by a $(params capture). cArgs is the list of candidate.Args that have not // yet been matched; pArgs is the list of pattern.Args that have not yet been // matched, and paramsCap is the $(params capture) node that follows pArgs. captures = captures ?? new MMap <Symbol, LNode>(); int c = 0, p = 0; restart: for (; p < pArgs.Count; p++, c++) { if (IsParamsCapture(pArgs[p])) { if (!CaptureGroup(ref c, ref p, cArgs, pArgs, ref captures, ref attrs)) { return(false); } goto restart; } else { if (c >= cArgs.Count) { return(false); } if (!MatchesPatternNested(cArgs[c], pArgs[p], ref captures, ref attrs)) { return(false); } } } AddCapture(captures, paramsCap, new Slice_ <LNode>(cArgs, c)); return(true); }
/// <summary>Determines whether one Loyc tree "matches" another. This is /// different from a simple equality test in that (1) trivia atributes do /// not have to match, and (2) the pattern can contain placeholders represented /// by calls to $ (the substitution operator) with an identifier as a parameter. /// Placeholders match any subtree, and are saved to the <c>captures</c> map. /// </summary> /// <param name="candidate">A node that you want to compare with a 'pattern'.</param> /// <param name="pattern">A syntax tree that may contain placeholders. A /// placeholder is a call to the $ operator with one parameter, which must /// be either (A) a simple identifier, or (B) the ".." operator with a simple /// identifier as its single parameter. Otherwise, the $ operator is treated /// literally as something that must exist in <c>candidate</c>). The subtree /// in <c>candidate</c> corresponding to the placeholder is saved in /// <c>captures</c>.</param> /// <param name="captures">A table that maps placeholder names from /// <c>pattern</c> to subtrees in <c>candidate</c>. You can set your map to /// null and a map will be created for you if necessary. If you already have /// a map, you should clear it before calling this method.</param> /// <param name="unmatchedAttrs">On return, a list of trivia attributes in /// <c>candidate</c> that were not present in <c>pattern</c>.</param> /// <returns>true if <c>pattern</c> matches <c>candidate</c>, false otherwise.</returns> /// <remarks> /// Attributes in patterns are not yet supported. /// <para/> /// This method supports multi-part captures, which are matched to /// placeholders whose identifier either (A) has a #params attribute or /// (B) has the unary ".." operator applied to it (for example, if /// the placeholder is called p, this is written as <c>$(params p)</c> in /// EC#.) A placeholder that looks like this can match multiple arguments or /// multiple statements in the <c>candidate</c> (or <i>no</i> arguments, or /// no statements), and will become a #splice(...) node in <c>captures</c> /// if it matches multiple items. Multi-part captures are often useful for /// getting lists of statements before and after some required element, /// e.g. <c>{ $(params before); MatchThis($something); $(params after); }</c> /// <para/> /// If the same placeholder appears twice then the two matching items are /// combined into a single output node (calling #splice). /// <para/> /// If matching is unsuccessful, <c>captures</c> and <c>unmatchedAttrs</c> /// may contain irrelevant information gathered during the attempt to match. /// <para/> /// In EC#, the quote(...) macro can be used to create the LNode object for /// a pattern. /// </remarks> public static bool MatchesPattern(this LNode candidate, LNode pattern, ref MMap<Symbol, LNode> captures, out VList<LNode> unmatchedAttrs) { // [$capture] (...) if (!AttributesMatch(candidate, pattern, ref captures, out unmatchedAttrs)) return false; // $capture or $(..capture) LNode sub = GetCaptureIdentifier(pattern); if (sub != null) { captures = captures ?? new MMap<Symbol, LNode>(); AddCapture(captures, sub.Name, candidate); unmatchedAttrs = VList<LNode>.Empty; // The attrs (if any) were captured return true; } var kind = candidate.Kind; if (kind != pattern.Kind) return false; if (kind == LNodeKind.Id && candidate.Name != pattern.Name) return false; if (kind == LNodeKind.Literal) return object.Equals(candidate.Value, pattern.Value); else if (kind == LNodeKind.Call) { if (!MatchesPatternNested(candidate.Target, pattern.Target, ref captures, ref unmatchedAttrs)) return false; var cArgs = candidate.Args; var pArgs = pattern.Args; return ListMatches(cArgs, pArgs, ref captures, ref unmatchedAttrs); } else // kind == Id return true; }
internal static void AddMacro(MMap<Symbol, VList<MacroInfo>> macros, MacroInfo info) { foreach (string name in info.Names) { var nameS = (Symbol)name; var cases = macros[nameS, VList<MacroInfo>.Empty]; if (!cases.Any(existing => existing.Macro == info.Macro)) macros[nameS] = cases.Add(info); } }
private static bool ListMatches(VList<LNode> candidates, VList<LNode> patterns, ref MMap<Symbol, LNode> captures, ref VList<LNode> unmatchedAttrs) { if (patterns.Count != candidates.Count && !patterns.Any(IsParamsCapture)) return false; // Scan from the end of the list to the beginning (RVLists is good at this), // matching args one-by-one. Use MatchThenParams() in case of $(params capture). while (!patterns.IsEmpty) { LNode pArg = patterns.Pop(); if (IsParamsCapture(pArg)) return MatchThenParams(candidates, patterns, pArg, ref captures, ref unmatchedAttrs); if (candidates.IsEmpty) return false; if (!MatchesPatternNested(candidates.Pop(), pArg, ref captures, ref unmatchedAttrs)) return false; } return true; }
protected Precedence FindPrecedence(MMap <object, Precedence> table, object symbol, Precedence @default, bool cacheWordOp) { // You can see the official rules in the LesPrecedence documentation. // Rule 1 (for >= <= != ==) is covered by the pre-populated contents // of the table, and the pre-populated table helps interpret other // rules too. CheckParam.IsNotNull("symbol", symbol); Precedence prec; if (table.TryGetValue(symbol, out prec)) { return(prec); } string sym = symbol.ToString(); if (sym.Length <= 1 || sym[0] != '\'') { return(P.Other); // empty or non-operator } // Note: all one-character operators should have been found in the table char first = sym[1], last = sym[sym.Length - 1]; bool isInfix = table == this[OperatorShape.Infix].A; if (isInfix && last == '=') { if (first == '=' || first == '!') { return(table[symbol] = P.Compare); } else { return(table[symbol] = P.Assign); } } var twoCharOp = GSymbol.Get("'" + first + last); if (table.TryGetValue(twoCharOp, out prec)) { return(table[symbol] = prec); } var oneCharOp = GSymbol.Get("'" + last); if (table.TryGetValue(oneCharOp, out prec)) { return(table[symbol] = prec); } if (isInfix && first >= 'A' && first <= 'Z') { return(table[symbol] = P.UpperWord); } // Default precedence is used for anything else (lowercase word ops) if (cacheWordOp) { return(table[symbol] = @default); } return(@default); }
public Scope(MSet <Symbol> openNamespaces, MMap <object, object> scopedProperties, MacroProcessorTask task, bool isRoot = false) { OpenNamespaces = openNamespaces; _scopedProperties = scopedProperties; _task = task; _propertiesCopied = _namespacesCopied = isRoot; }