private IEnumerator <Parser> ReadArguments(RantCompiler compiler, TokenReader reader, List <RST> arguments) { var actions = new List <RST>(); Action <RST> argActionCallback = action => actions.Add(action); compiler.SetNextActionCallback(argActionCallback); compiler.AddContext(CompileContext.FunctionEndContext); compiler.AddContext(CompileContext.ArgumentSequence); while (compiler.NextContext == CompileContext.ArgumentSequence) { reader.SkipSpace(); var startToken = reader.PeekToken(); yield return(Get <SequenceParser>()); // Don't wrap single nodes in a sequence, it's unnecessary if (actions.Count == 1) { arguments.Add(actions[0]); } else { arguments.Add(new RstSequence(actions, startToken.ToLocation())); } actions.Clear(); } compiler.LeaveContext(); }
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())); } }
private IEnumerator <Parser> ParseSubroutine(RantCompiler compiler, CompileContext context, TokenReader reader, Action <RST> actionCallback) { // subroutine definition if (reader.TakeLoose(R.LeftSquare, false)) { if (reader.TakeLoose(R.Period)) { compiler.HasModule = true; } var subroutineName = reader.ReadLoose(R.Text, "acc-subroutine-name"); var subroutine = new RstDefineSubroutine(subroutineName.ToLocation()) { Parameters = new Dictionary <string, SubroutineParameterType>(), Name = subroutineName.Value }; if (reader.PeekLooseToken().Type == R.Colon) { reader.ReadLooseToken(); do { var type = SubroutineParameterType.Greedy; if (reader.TakeLoose(R.At)) { type = SubroutineParameterType.Loose; } subroutine.Parameters[reader.ReadLoose(R.Text, "acc-arg-name").Value] = type; } while (reader.TakeLoose(R.Semicolon, false)); } reader.ReadLoose(R.RightSquare); var bodyStart = reader.ReadLoose(R.Colon); var actions = new List <RST>(); Action <RST> bodyActionCallback = action => actions.Add(action); compiler.AddContext(CompileContext.SubroutineBody); compiler.SetNextActionCallback(bodyActionCallback); yield return(Get <SequenceParser>()); compiler.SetNextActionCallback(actionCallback); if (actions.Count == 1) { subroutine.Body = actions[0]; } else { subroutine.Body = new RstSequence(actions, bodyStart.ToLocation()); } actionCallback(subroutine); } else { // subroutine call var subroutineName = reader.Read(R.Text, "acc-subroutine-name"); string moduleFunctionName = null; if (reader.TakeLoose(R.Period, false)) { moduleFunctionName = reader.Read(R.Text, "module function name").Value; } var arguments = new List <RST>(); if (reader.PeekType() == R.Colon) { reader.ReadToken(); var iterator = ReadArguments(compiler, reader, arguments); while (iterator.MoveNext()) { yield return(iterator.Current); } compiler.SetNextActionCallback(actionCallback); } else { reader.Read(R.RightSquare); } var subroutine = new RstCallSubroutine(subroutineName.Value, subroutineName.ToLocation(), moduleFunctionName) { Arguments = arguments }; actionCallback(subroutine); } }
public override IEnumerator <Parser> Parse(RantCompiler compiler, CompileContext context, TokenReader reader, Action <RST> actionCallback) { var blockStartToken = reader.PrevLooseToken; var items = new List <RST>(); var actions = new List <RST>(); // "why are these not lists or arrays" i yell into the void, too lazy to find out why List <_ <int, double> > constantWeights = null; List <_ <int, RST> > dynamicWeights = null; int blockNumber = 0; void itemCallback(RST action) => actions.Add(action); compiler.AddContext(CompileContext.BlockEndSequence); compiler.AddContext(CompileContext.BlockSequence); while (compiler.NextContext == CompileContext.BlockSequence) { // block weight if (reader.PeekLooseToken().Type == R.LeftParen) { constantWeights = constantWeights ?? (constantWeights = new List <_ <int, double> >()); dynamicWeights = dynamicWeights ?? (dynamicWeights = new List <_ <int, RST> >()); var firstToken = reader.ReadLooseToken(); var sequence = new List <RST>(); void weightCallback(RST rst) => sequence.Add(rst); compiler.SetNextActionCallback(weightCallback); compiler.AddContext(CompileContext.BlockWeight); yield return(Get <SequenceParser>()); // Constant if (sequence.TrueForAll(rst => rst is RstText)) { var sb = new StringBuilder(); foreach (var rst in sequence) { sb.Append((rst as RstText).Text); } string txt = sb.ToString(); if (!Util.ParseDouble(txt, out double doubleValue)) { compiler.SyntaxError(reader.PrevLooseToken, false, "err-compiler-invalid-constweight"); } else { constantWeights.Add(new _ <int, double>(blockNumber, doubleValue)); } } // Dynamic else { if (sequence.Count == 0) { compiler.SyntaxError(firstToken, false, "err-compiler-empty-weight"); } else { dynamicWeights.Add(new _ <int, RST>(blockNumber, new RstSequence(sequence, sequence[0].Location))); } } } reader.SkipSpace(); compiler.SetNextActionCallback(itemCallback); var startToken = reader.PeekToken(); yield return(Get <SequenceParser>()); // Don't wrap single nodes in a sequence, it's unnecessary items.Add(actions.Count == 1 ? actions[0] : new RstSequence(actions, startToken.ToLocation())); actions.Clear(); blockNumber++; } compiler.LeaveContext(); compiler.SetNextActionCallback(actionCallback); actionCallback(new RstBlock(blockStartToken.ToLocation(), items, dynamicWeights, constantWeights)); }