public void Print(IEnumerable <ILNode> nodes, StringBuilder target, IMessageSink sink = null, ParsingMode mode = null, ILNodePrinterOptions options = null) { CheckParam.IsNotNull("target", target); var p = new Les3Printer(target, sink, options); p.Print(nodes); }
public MacroInfo(Symbol @namespace, LexicalMacroAttribute a, LexicalMacro macro, bool deprecateAllNames = false) : base(a.Syntax, a.Description, a.Names) { DeprecatedNames = a.DeprecatedNames; DeprecationMessage = a.DeprecationMessage; if (Names.Length == 0 && (a.DeprecatedNames == null || a.DeprecatedNames.Length == 0) && (a.Mode & (MacroMode.MatchEveryCall | MacroMode.MatchEveryLiteral | MacroMode.MatchEveryIdentifier)) == 0) { Names = new string[1] { macro.Method.Name } } ; if (deprecateAllNames) { DeprecatedNames = (DeprecatedNames ?? EmptyArray <string> .Value).Union(Names).ToArray(); } CheckParam.IsNotNull("macro", macro); Namespace = @namespace; Macro = macro; Mode = a.Mode; }
public MacroInfo(Symbol @namespace, LexicalMacroAttribute a, LexicalMacro macro) : base(a.Syntax, a.Description, a.Names != null && a.Names.Length > 0 ? a.Names : new[] { macro.Method.Name }) { CheckParam.IsNotNull("macro", macro); Namespace = @namespace; Macro = macro; Mode = a.Mode; }
/// <summary>Returns true if the specified child of the specified node /// can be an implicit child statement, i.e. a child statement that is /// not necessarily a braced block, e.g. the second child of a while /// loop.</summary> /// <remarks> /// This method helps the printer decide when a newline should be added /// before an unbraced child statement when there are no attributes /// dictating whether to add a newline or not. /// <para/> /// This method only cares about executable parent nodes. It returns /// false for class/space and function/property bodies, which are always /// braced blocks and therefore get a newline before every child statement /// automatically. /// </remarks> public static bool MayBeImplicitChildStatement(LNode node, int childIndex) { CheckParam.IsNotNull("node", node); if (childIndex < 0) // target or attributes { return(false); } var n = node.Name; if (!LNode.IsSpecialName(n.Name)) { return(false); } if (n == S.Braces) { return(true); } if (n == S.Try) { return(childIndex == 0); } switch (node.ArgCount) { case 1: if (n == S.Finally) { return(true); } break; case 2: if (childIndex == 0 ? n == S.DoWhile : n == S.If || n == S.While || n == S.UsingStmt || n == S.Lock || n == S.Switch || n == S.Fixed) { return(true); } break; case 3: if (childIndex != 0 && n == S.If) { return(true); } if (childIndex == 2 && n == S.ForEach) { return(true); } break; case 4: if (childIndex == 3 && (n == S.For || n == S.Catch)) { return(true); } break; } return(false); }
public virtual void Reset(IListSource <Token> tokens, ISourceFile file) { CheckParam.IsNotNull("tokens", tokens); CheckParam.IsNotNull("file", file); _tokensRoot = _tokens = tokens; _sourceFile = file; F = new LNodeFactory(file); InputPosition = 0; // reads LT(0) }
/// <summary>Reinitializes the object. This method is called by the constructor.</summary> /// <remarks>See the constructor for documentation of the parameters.</remarks> protected virtual void Reset(List list, Func <Token, Token> getEofToken, MatchType eof, ISourceFile file, int startIndex = 0) { CheckParam.IsNotNull <object>("list", list); _getEofToken = getEofToken; EOF = eof; _tokenList = list; _listCount = list.Count; // to avoid 1st-chance exceptions _sourceFile = file; InputPosition = startIndex; }
/// <summary> /// Expands environment variables (e.g. %TEMP%) and @files in a list of /// command-line arguments, and adds any options of the form "--opt" or /// "--opt=value" to a dictionary. /// </summary> /// <param name="args">The original arguments to process.</param> /// <param name="options">Any long options (arguments that start with "--") /// will be added to this dictionary, and removed from <c>args</c>. This /// parameter cannot be null. /// By default, long options are not case sensitive. In that case, the /// user's option name is converted to lower case. /// <para/> /// Long options are expected to have the form --ID or --ID=value, where ID /// matches the regex "[a-zA-Z_0-9-]+". If there is no "=" or ":", that's /// okay too. For example, --Id{foo} is equivalent to --Id={foo}; both yield /// in the name-value pair ("id", "{foo}"). If there is no value (no equals /// or colon), the value associated with the option is null.</param> /// <param name="atFolder">If a parameter has the form @filename, the folder /// specified by atFolder will be searched for an options text file with the /// user-specified filename, and the contents of the file will be expanded /// into the list of arguments (split using SplitCommandLineArguments). The /// expanded list can contain new @filenames, which are also processed. To /// search in the current directory, use "". The @filename may use an absolute /// path, which overrides this folder. To disable @filename expansion, set /// this parameter to null. Whether the feature is enabled or disabled, /// @filenames are <i>not</i> removed from <c>args</c>, in case you want to /// be aware of the filenames afterward.</param> /// <param name="shortOptions">A map from one-letter options that start with /// "-" rather than "--", to the name of the corresponding long option (this /// option can be null to ignore all short options.) For example, if this /// contains (<c>'a', "all"</c>), and the input <c>args</c> contains "-a:foo", /// the pair ("all", "foo") will be added to <c>options</c>. If a value in /// this map is null, the key itself is used. Short options can be combined; /// for example <c>-abc:foo</c> is equivalent to <c>-a -b -c:foo</c>. Short /// options are always case-sensitive; to define an option that is not case /// sensitive, place two entries in the dictionary e.g. ('a', "all") and /// ('A', "all"). If the user specifies a short option letter that is not /// recognized, the entire command will be ignored and left in args. For /// example, if <c>shortOptions</c> contains only ('a', "all") but <c>args</c> /// contains "-ab=foo", the command is ignored and left in <c>args</c>. /// Rationale: -ab=foo might be a filename. /// <para/> /// On the other hand, if -a is a valid option then <c>-a123</c> is also /// valid even when there is no option called '1'; the number "123" is /// treated as an argument to -a. Now, if '1' is a registered short option /// but '2' is not, then <c>-a123</c> is equivalent to <c>-a -1=23</c>. /// </param> /// <param name="twoArgOptions">A set of options in which the argument can /// be separated by a space from the option. For example, if the input is /// "--out foo.txt" and you want to recognize "foo.txt" as the argument to /// "--out", add the string "out" to this set. If you want to treat <i>all</i> /// options this way, use <c>InvertibleSet{string}.All</c>. Note: /// If the input is "--out:foo bar", "foo" is recognized as the argument to /// "--out" and "bar" is left alone, i.e. it is treated as unrelated. /// Short options participate automatically. For example if "-f" means /// "--foo", and twoArgOptions contains "foo", then "-f arg" is interpreted /// like "--foo=arg". /// <para/> /// The argument will not be treated as an argument if it starts with a /// dash, e.g. in <c>--foo -*</c>, <c>-*</c> will not be treated as an /// argument to <c>--foo</c>, even if <c>-*</c> is not a registered option. /// </param> /// <param name="argLimit">A limit placed on the number of arguments when /// expanding @files. Such a file may refer to itself, and this is the only /// protection provided against infinite recursive expansion.</param> /// <param name="expandEnvVars">If true, environment variable references /// such as <c>%TEMP%</c> are expanded by calling the standard method /// <see cref="Environment.ExpandEnvironmentVariables"/>.</param> /// <param name="caseSensitiveLongOpts">If true, long options are case- /// sensitive. By default, long options are not case sensitive.</param> /// <remarks> /// Two types of options are recognized, short (-s) and long (--long), and /// only one argument is supported per option. The documentation is above. /// <para/> /// You can choose whether to permit duplicate options or not. If you use /// a standard <see cref="Dictionary{K,V}"/> to hold the options, an /// exception will occur when this method calls Add() to add the duplicate. /// The exception is caught, the first ocurrance is kept, and a warning /// message is printed to <see cref="MessageSink.Default"/>. /// <para/> /// To allow duplicates, store options in a different data structure such as /// <c>List(KeyValuePair(string, string))</c> or <c>BMultiMap(string,string)</c>. /// <para/> /// DOS-style slash-options like /foo are not supported. Since Windows /// recognizes the forward slash as a path separator, forward-slash options /// can be recognized as paths. If you want to recognize them as options /// instead, you can preprocess the argument list, replacing every command /// that starts with "/" with a "--" command: /// <code> /// for (int i = 0; args.Count > i; i++) /// if (args[i].StartsWith("/")) /// args[i] = "--" + args[i].Substring(1); /// </code> /// <para/> /// Globs (e.g. *.txt) are not recognized or expanded, but environment /// variables are expanded when <c>expandEnvVars</c> is true. /// <para/> /// Quote marks are not processed. An argument of <c>"--a"</c>, with quote /// marks, is not recognized as an option (these quote marks should be /// removed before calling this method, e.g. /// <see cref="G.SplitCommandLineArguments"/> handles this.) /// </remarks> public static void ProcessCommandLineArguments(IList <string> args, ICollection <KeyValuePair <string, string> > options, string atFolder, IDictionary <char, string> shortOptions = null, InvertibleSet <string> twoArgOptions = null, int argLimit = 0xFFFF, bool expandEnvVars = true, bool caseSensitiveLongOpts = false) { CheckParam.IsNotNull("args", args); CheckParam.IsNotNull("options", options); for (int i = 0; i < args.Count; i++) { ProcessArgument(args, i, options, atFolder, shortOptions, twoArgOptions, argLimit, expandEnvVars, caseSensitiveLongOpts); } args.RemoveAll(s => s == null); }
public virtual void Reset(IListSource <Token> tokens, ISourceFile file, IParsingOptions parsingOptions) { CheckParam.IsNotNull("tokens", tokens); CheckParam.IsNotNull("file", file); _tokensRoot = _tokens = tokens; _sourceFile = file; _literalParser = parsingOptions?.LiteralParser ?? EcsLiteralHandlers.Value; F = new LNodeFactory(file); InputPosition = 0; // reads LT(0) _tentativeErrors = new TentativeState(false); }
protected override void Reset(IList <Token> list, Func <Token, Token> getEofToken, int eof, ISourceFile file, int startIndex = 0) { if (list is TokenTree) { // Token trees can come from token literals, and the user of a // token tree expects to be able to parse that tree, but this parser // expects a flat token list, so we need to flatten the tree again. list = ((TokenTree)list).Flatten(); } CheckParam.IsNotNull("file", file); base.Reset(list, getEofToken, eof, file, startIndex); F = new LNodeFactory(file); }
public BraceMatchingTagger(ITextView textView, ITextBuffer sourceBuffer, IClassifier classifier, IEnumerable <KeyValuePair <char, char> > matchingCharacters) { CheckParam.IsNotNull("textView", textView); CheckParam.IsNotNull("sourceBuffer", sourceBuffer); CheckParam.IsNotNull("aggregator", classifier); CheckParam.IsNotNull("matchingCharacters", matchingCharacters); this.TextView = textView; this.SourceBuffer = sourceBuffer; this.Classifier = classifier; this.MatchingCharacters = matchingCharacters.ToList().AsReadOnly(); this.TextView.Caret.PositionChanged += Caret_PositionChanged; this.TextView.LayoutChanged += TextView_LayoutChanged; }
/// <summary>Unregisters a language service.</summary> /// <param name="service">Service to unregister</param> /// <param name="fileExtensions">File extensions affected (null to use the service's own list)</param> /// <returns>The number of file extensions unregistered, or 0 if none.</returns> /// <remarks>The service for a file extension is not removed unless the given service reference is equal to the registered service.</remarks> public static int Unregister(IParsingService service, IEnumerable <string> fileExtensions = null) { CheckParam.IsNotNull("service", service); fileExtensions = fileExtensions ?? service.FileExtensions; int oldCount = _registeredLanguages.Count; foreach (var fileExt in fileExtensions) { if (_registeredLanguages.TryGetValue(fileExt, null) == service) { _registeredLanguages = _registeredLanguages.Without(fileExt); } } return(oldCount - _registeredLanguages.Count); }
/// <summary>Registers a parsing service.</summary> /// <param name="service">Service to register.</param> /// <param name="fileExtensions">File extensions affected (null to use the service's own list)</param> /// <returns>The number of new file extensions registered, or 0 if none.</returns> /// <remarks>This method does not replace existing registrations.</remarks> public static int Register(IParsingService service, IEnumerable <string> fileExtensions = null) { CheckParam.IsNotNull("service", service); int oldCount = _registeredLanguages.Count; foreach (var fileExt_ in fileExtensions ?? service.FileExtensions) { var fileExt = fileExt_; // make writable if (fileExt.StartsWith(".")) { fileExt = fileExt.Substring(1); } _registeredLanguages = _registeredLanguages.With(fileExt, service, false); } return(_registeredLanguages.Count - oldCount); }
/// <summary>Given a normal operator symbol like <c>(Symbol)"'++"</c>, gets /// the suffix form of the name, such as <c>(Symbol)"'suf++"</c>.</summary> /// <remarks>op must be a Symbol, but the parameter has type object to avoid casting Token.Value in the parser.</remarks> public Symbol ToSuffixOpName(object symbol) { CheckParam.IsNotNull(nameof(symbol), symbol); _suffixOpNames = _suffixOpNames ?? new Dictionary <object, Symbol>(); Symbol name; if (_suffixOpNames.TryGetValue(symbol, out name)) { return(name); } CheckParam.Arg(nameof(symbol), symbol.ToString().StartsWith("'"), symbol); var was = symbol.ToString(); return(_suffixOpNames[symbol] = GSymbol.Get("'suf" + symbol.ToString().Substring(1))); }
/// <summary>Reinitializes BaseLexer, as if you called the constructor again.</summary> protected virtual void Reset(ICharSource source, string fileName = "", int inputPosition = 0, bool newSourceFile = true) { CheckParam.IsNotNull("source", source); _source = source; _fileName = fileName; _block = UString.Empty; InputPosition = inputPosition; _lineNumber = 1; _lineStartAt = inputPosition; if (newSourceFile) { _sourceFile = new LexerSourceFile(source, fileName); } else { _sourceFile = null; } }
/// <summary>Reinitializes the object. This method is called by the constructor.</summary> /// <remarks> /// See the constructor for documentation of the parameters. /// <para/> /// This method can be used to avoid memory allocations when you /// need to parse many small strings in a row. If that's your goal, you /// should set the <c>newSourceFile</c> parameter to false if possible.</remarks> public virtual void Reset(CharSrc chars, string fileName = "", int inputPosition = 0, bool newSourceFile = true) { CheckParam.IsNotNull <object>("source", chars); _charSource = chars; _fileName = fileName; _block = UString.Empty; InputPosition = inputPosition; _lineNumber = 1; _lineStartAt = inputPosition; if (newSourceFile) { _sourceFile = new LexerSourceFile <CharSrc>(chars, fileName); } else { _sourceFile = null; } }
/// <summary>Searches <see cref="Printers"/> for a printer for the value and uses it /// to convert the value to a string. When a printer can be found both by type marker /// Symbol and by Type, the printer for the matching type marker is used (takes priority). /// The complete search order is (1) type marker (if any), (2) exact type, (3) base /// classes and (4) interfaces, in that order.</summary> /// <param name="literal">A literal that you want to convert to a string.</param> /// <returns>Either the type marker for the literal, or an error message. /// On return, the string form of the literal is appended to the StringBuilder. /// If an error occurs, it is possible that some kind of output was added to /// the StringBuilder anyway.</returns> /// <remarks> /// Note: this uses `Type.GetInterfaces` to obtain the list of interfaces, and this /// list is officially not "in a particular order". It appears that the list is /// constructed with some kind of depth-first search, so in simple cases derived /// interfaces are searched before base interfaces, but if there are "diamonds" in /// the interface hierarchy then it will not be uncommon for a lower-level interface /// to be checked before a higher-level one. Sorry. /// <para/> /// If a printer returns an error, this method tries to find other printers that might /// be able to print the value. If no printer succeeds, the <i>first</i> error that /// occurred is returned. /// <para/> /// When the literal is null and there is no printer associated with literal.TypeMarker, /// this funtion produces no output and returns literal.TypeMarker. /// <para/> /// On success, the return value indicates which type marker is recommended based /// on the data type of the literal. This is not guaranteed to match the TypeMarker /// originally stored in the literal. It is recommended that language printers /// use the type marker stored in the literal (regardless of what this method /// returns) unless <c>literal.TypeMarker == null</c>. /// </remarks> public Either <Symbol, ILogMessage> TryPrint(ILNode literal, StringBuilder sb) { CheckParam.IsNotNull(nameof(sb), sb); ILogMessage firstError = null; var tm = literal.TypeMarker; if (tm != null && TryPrint(literal, tm, sb, ref tm, ref firstError)) { return(tm); } if (literal.Value == null) { return(tm); } Type type = literal.Value.GetType(); if (TryPrint(literal, type, sb, ref tm, ref firstError)) { return(tm); } for (var type2 = type; type2.BaseType != null; type2 = type2.BaseType) { var @base = type2.BaseType; if (TryPrint(literal, @base, sb, ref tm, ref firstError)) { return(tm); } } foreach (var iface in type.GetInterfaces()) { if (TryPrint(literal, iface, sb, ref tm, ref firstError)) { return(tm); } } return(new Either <Symbol, ILogMessage>(firstError ?? new LogMessage(Severity.Error, literal, "There is no printer for type '{0}'".Localized(literal.Value.GetType())))); }
private static bool IsInCommentOrLiteral(IClassifier classifier, SnapshotPoint point, PositionAffinity affinity) { CheckParam.IsNotNull("aggregator", classifier); // TODO: handle affinity SnapshotSpan span = new SnapshotSpan(point, 1); var classifications = classifier.GetClassificationSpans(span); var relevant = classifications.FirstOrDefault(classificationSpan => classificationSpan.Span.Contains(point)); if (relevant == null || relevant.ClassificationType == null) { return(false); } var @class = relevant.ClassificationType; return(@class.IsOfType(PredefinedClassificationTypeNames.Comment) || @class.IsOfType(PredefinedClassificationTypeNames.Literal) || @class.IsOfType(PredefinedClassificationTypeNames.String) || @class.IsOfType(PredefinedClassificationTypeNames.Identifier) || @class.IsOfType("LoycOtherLiteral")); }
public StdComplexCallNode(LNode target, RVList <LNode> args, SourceRange range, NodeStyle style = NodeStyle.Default) : base(args, range, style) { CheckParam.IsNotNull("target", target); _target = target; }
public StdComplexCallNode(LNode target, RVList <LNode> args, LNode ras) : base(args, ras) { CheckParam.IsNotNull("target", target); _target = target; }
protected override void Reset(IList <Token> list, Token eofToken, ISourceFile file, int startIndex = 0) { CheckParam.IsNotNull("file", file); base.Reset(list, eofToken, file, startIndex); F = new LNodeFactory(file); }
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("'" + last); 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; }
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 static LNode Replace(LNode stmt, Pair <LNode, LNode>[] patterns, out int replacementCount) { CheckParam.IsNotNull("stmt", stmt); return(Replace(new VList <LNode>(stmt), patterns, out replacementCount)[0]); }