public override IEnumerator <Parser> Parse(RantCompiler compiler, CompileContext context, TokenReader reader, Action <RST> actionCallback) { var tableName = reader.ReadLoose(R.Text, "acc-table-name"); var query = new Query(); query.Name = tableName.Value; query.Carrier = new Carrier(); query.Exclusive = reader.TakeLoose(R.Dollar); bool subtypeRead = false; bool pluralSubtypeRead = false; bool complementRead = false; bool endOfQueryReached = false; while (!reader.End && !endOfQueryReached) { var token = reader.ReadLooseToken(); switch (token.Type) { // read subtype case R.Period: if (reader.Take(R.Period)) // Plural subtype { if (pluralSubtypeRead) { compiler.SyntaxError(token, false, "err-compiler-multiple-pl-subtypes"); reader.Read(R.Text, "acc-pl-subtype-name"); break; } query.PluralSubtype = reader.Read(R.Text, "acc-pl-subtype-name").Value; pluralSubtypeRead = true; break; } // if there's already a subtype, throw an error and ignore it if (subtypeRead) { compiler.SyntaxError(token, false, "err-compiler-multiple-subtypes"); reader.Read(R.Text, "acc-subtype-name"); break; } query.Subtype = reader.Read(R.Text, "acc-subtype-name").Value; subtypeRead = true; break; // complement case R.LeftSquare: { if (complementRead) { compiler.SyntaxError(token, false, "err-compiler-multiple-complements"); } var seq = new List <RST>(); compiler.AddContext(CompileContext.QueryComplement); compiler.SetNextActionCallback(seq.Add); yield return(Get <SequenceParser>()); compiler.SetNextActionCallback(actionCallback); query.Complement = new RstSequence(seq, token.ToLocation()); complementRead = true; } break; // read class filter case R.Hyphen: { ClassFilter classFilter; if ((classFilter = query.GetClassFilters().FirstOrDefault()) == null) { classFilter = new ClassFilter(); query.AddFilter(classFilter); } var filterSwitches = new List <ClassFilterRule>(); do { reader.SkipSpace(); bool blacklist = false; // check if it's a blacklist filter if (reader.PeekType() == R.Exclamation) { blacklist = true; reader.ReadToken(); } var classFilterName = reader.Read(R.Text, "acc-class-filter-rule"); if (classFilterName.Value == null) { continue; } var rule = new ClassFilterRule(classFilterName.Value, !blacklist); filterSwitches.Add(rule); } while (reader.TakeLoose(R.Pipe)); //fyi: this feature is undocumented classFilter.AddRuleSwitch(filterSwitches.ToArray()); break; } // read regex filter case R.Without: case R.Question: { reader.SkipSpace(); bool blacklist = token.Type == R.Without; var regexFilter = reader.Read(R.Regex, "acc-regex-filter-rule"); var options = RegexOptions.Compiled | RegexOptions.ExplicitCapture; if (reader.IsNext(R.RegexFlags)) { var flagsToken = reader.ReadToken(); foreach (char flag in flagsToken.Value) { switch (flag) { case 'i': options |= RegexOptions.IgnoreCase; break; case 'm': options |= RegexOptions.Multiline; break; } } } if (regexFilter.Value == null) { break; } query.AddFilter(new RegexFilter(new Regex(regexFilter.Value, options), !blacklist)); } break; // read syllable range case R.LeftParen: // There are four possible types of values in a syllable range: // (a), (a-), (-b), (a-b) // either (a), (a-), or (a-b) if (reader.PeekLooseToken().Type == R.Text) { var firstNumberToken = reader.ReadLooseToken(); int firstNumber; if (!Util.ParseInt(firstNumberToken.Value, out firstNumber)) { compiler.SyntaxError(firstNumberToken, false, "err-compiler-bad-sylrange-value"); } // (a-) or (a-b) if (reader.PeekLooseToken().Type == R.Hyphen) { reader.ReadLooseToken(); // (a-b) if (reader.PeekLooseToken().Type == R.Text) { var secondNumberToken = reader.ReadLooseToken(); int secondNumber; if (!Util.ParseInt(secondNumberToken.Value, out secondNumber)) { compiler.SyntaxError(secondNumberToken, false, "err-compiler-bad-sylrange-value"); } query.AddFilter(new RangeFilter(firstNumber, secondNumber)); } // (a-) else { query.AddFilter(new RangeFilter(firstNumber, null)); } } // (a) else { query.AddFilter(new RangeFilter(firstNumber, firstNumber)); } } // (-b) else if (reader.PeekLooseToken().Type == R.Hyphen) { reader.ReadLooseToken(); var secondNumberToken = reader.ReadLoose(R.Text, "acc-syllable-range-value"); int secondNumber; if (!Util.ParseInt(secondNumberToken.Value, out secondNumber)) { compiler.SyntaxError(secondNumberToken, false, "err-compiler-bad-sylrange-value"); } query.AddFilter(new RangeFilter(null, secondNumber)); } // () else if (reader.PeekLooseToken().Type == R.RightParen) { compiler.SyntaxError(token, false, "err-compiler-empty-sylrange"); } // (something else) else { var errorToken = reader.ReadLooseToken(); compiler.SyntaxError(errorToken, false, "err-compiler-unknown-sylrange-token", errorToken.Value); reader.TakeAllWhile(t => !reader.IsNext(R.RightParen)); } reader.ReadLoose(R.RightParen); break; // read carriers case R.DoubleColon: ReadCarriers(reader, query.Carrier, compiler); // this should be the last part of the query, so go to the end endOfQueryReached = true; break; // end of query case R.RightAngle: endOfQueryReached = true; break; case R.Whitespace: break; default: compiler.SyntaxError(token, false, "err-compiler-unexpected-token"); break; } } if (!endOfQueryReached) { compiler.SyntaxError(reader.PrevToken, true, "err-compiler-eof"); } if (tableName.Value != null) { actionCallback(new RstQuery(query, tableName.ToLocation())); } }
public override IEnumerator <Parser> Parse(RantCompiler compiler, CompileContext context, TokenReader reader, Action <RST> actionCallback) { var nextType = reader.PeekType(); var tagStart = reader.PrevToken; // replacer switch (nextType) { case R.Regex: { var regex = reader.Read(R.Regex, "acc-replacer-regex"); var options = RegexOptions.Compiled | RegexOptions.ExplicitCapture; if (reader.IsNext(R.RegexFlags)) { var flagsToken = reader.ReadToken(); foreach (char flag in flagsToken.Value) { switch (flag) { case 'i': options |= RegexOptions.IgnoreCase; break; case 'm': options |= RegexOptions.Multiline; break; } } } reader.Read(R.Colon); var arguments = new List <RST>(); var iterator = ReadArguments(compiler, reader, arguments); while (iterator.MoveNext()) { yield return(iterator.Current); } compiler.SetNextActionCallback(actionCallback); if (arguments.Count != 2) { compiler.SyntaxError(tagStart, reader.PrevToken, false, "err-compiler-replacer-argcount"); yield break; } actionCallback(new RstReplacer(regex.ToLocation(), new Regex(regex.Value, options), arguments[0], arguments[1])); } break; case R.Dollar: { reader.ReadToken(); var e = ParseSubroutine(compiler, context, reader, actionCallback); while (e.MoveNext()) { yield return(e.Current); } } break; default: { var e = ParseFunction(compiler, context, reader, actionCallback); while (e.MoveNext()) { yield return(e.Current); } } break; } }