public void ParseTest(string expression) { var provider = new UnicodeCharSetProvider(UnicodeRanges.FromUnicodeName); var result = CharsetParser.Parse(expression).Compute(provider); this.output.WriteLine(result.ToString()); }
public SemanticParserGrammarBuilder(IUnicodeMapper <TInput> mapper, TInput?eof) { string GetGrammarKeyForDisplay() { return($"typeof({typeof(TAstNode).FullName})"); } string MemberInfoForDisplay(MethodBase member) { return(member == null ? "(assembly)" : $"{member.DeclaringType.FullName}.{member.Name}"); } var errors = new List <Exception>(); try { var parts = SemanticParserGrammar <TAstNode, TInput, TPosition> .FindGrammarParts() .OrderByDescending(p => p.Key.GetType().Name) .ThenBy(p => (p.Key as GrammarSymbolAttribute)?.SymbolName ?? (p.Key as CharsetAttribute)?.CharsetName ?? "") .ToList(); // Compute charsets var charsetQueue = new Queue <KeyValuePair <string, CharsetNode> >(parts .Select(p => p.Key) .OfType <CharsetAttribute>() .Select(a => new KeyValuePair <string, CharsetNode>(a.CharsetName, CharsetParser.Parse(a.CharsetExpression)))); var charsets = charsetQueue .SelectMany(p => p.Value.GetCharsetNames()) .Except(charsetQueue.Select(p => p.Key), StringComparer.OrdinalIgnoreCase) .ToDictionary(n => n, UnicodeRanges.FromUnicodeName, StringComparer.OrdinalIgnoreCase); var provider = new UnicodeCharSetProvider(charsets); var skipCount = 0; while (charsetQueue.Count > 0) { var current = charsetQueue.Dequeue(); if (current.Value.GetCharsetNames().All(charsets.ContainsKey)) { charsets.Add(current.Key, current.Value.Compute(provider)); skipCount = 0; } else { charsetQueue.Enqueue(current); if (skipCount++ > charsetQueue.Count) { errors.Add(new InvalidOperationException($"The charsets cannot be computed because {String.Join(", ", charsetQueue.Select(p => p.Key))} contain circular references")); break; } } } // Gather symbol information var startsymbol = parts.Select(p => p.Key).OfType <StartSymbolAttribute>().SingleOrDefault(); if (startsymbol == null) { errors.Add(new InvalidOperationException($"Start symbol has not been defined: [assembly: StartSymbol({GetGrammarKeyForDisplay()}, ...)]")); } foreach (var symbol in parts .Select(p => p.Key) .OfType <GrammarSymbolAttribute>() .GroupBy(a => a.SymbolName, a => a.SymbolKind, StringComparer.OrdinalIgnoreCase)) { if (symbol.Distinct().Skip(1).Any()) { errors.Add(new InvalidOperationException($"The symbol {symbol.Key} must not be defined as both terminal and nonterminal")); } else if (StringComparer.OrdinalIgnoreCase.Equals(symbol.Key, startsymbol?.SymbolName) && (symbol.First() != SymbolKind.Nonterminal)) { errors.Add(new InvalidOperationException($"The start symbol {symbol.Key} must be a nonterminal")); } this.symbolsByName.Add(symbol.Key, this.symbolsByName.Count + 1); } SymbolId GetSymbol(string symbolName) { if (this.symbolsByName.TryGetValue(symbolName, out var id)) { return(id); } errors.Add(new InvalidOperationException($"The symbol {symbolName} has not been defined. If the symbol name is correct, define it as virtual: [assembly: VirtualSymbol({GetGrammarKeyForDisplay()}, ...)]")); return(SymbolId.Eof); } MethodBase PopulateGenericArguments(MethodBase methodBase, GrammarSymbolAttribute attribute) { var genericTypeParameters = attribute.GenericTypeParameters; if (methodBase?.DeclaringType.IsGenericTypeDefinition == true) { var typeGenericArguments = methodBase.DeclaringType.GetGenericArguments(); if (genericTypeParameters.Length < typeGenericArguments.Length) { errors.Add(new InvalidOperationException($"Missing type generic arguments for {attribute} on {MemberInfoForDisplay(methodBase)}")); return(methodBase); } var genericType = methodBase.DeclaringType.MakeGenericType(genericTypeParameters.Take(typeGenericArguments.Length).ToArray()); genericTypeParameters = genericTypeParameters.Skip(typeGenericArguments.Length).ToArray(); IReadOnlyDictionary <Type, Type> genericArgumentMap = genericType.GetGenericArguments().Select((t, ix) => new KeyValuePair <Type, Type>(typeGenericArguments[ix], t)).ToDictionary(p => p.Key, p => p.Value); var mappedParameters = methodBase.GetParameters().Select(p => genericArgumentMap.GetValueOrDefault(p.ParameterType, p.ParameterType)).ToArray(); if (methodBase is ConstructorInfo) { methodBase = genericType.GetConstructor(mappedParameters); } else { methodBase = genericType.GetMethod(methodBase.Name, BindingFlags.Static | BindingFlags.Public, null, mappedParameters, null); } } if (methodBase is MethodInfo method && method.IsGenericMethodDefinition) { if (method.GetGenericArguments().Length != genericTypeParameters.Length) { errors.Add(new InvalidOperationException($"Invalid number of method generic arguments for {attribute} on {MemberInfoForDisplay(methodBase)}")); } methodBase = method.MakeGenericMethod(genericTypeParameters); } else if (genericTypeParameters.Length > 0) { errors.Add(new InvalidOperationException($"Excess generic arguments for {attribute} on {MemberInfoForDisplay(methodBase)}")); } return(methodBase); }