private IEnumerable <Parselet> LeftSquare(Token <R> token) { var tagToken = reader.ReadToken(); switch (tagToken.ID) { default: compiler.SyntaxError(tagToken, "Expected function name, subroutine, regex or a script."); break; case R.Text: yield return(Parselet.GetParselet("FunctionText", tagToken, AddToOutput)); break; case R.Regex: yield return(Parselet.GetParselet("FunctionRegex", tagToken, AddToOutput)); break; case R.At: AddToOutput(compiler.ReadScript()); break; case R.Dollar: yield return(Parselet.GetParselet("FunctionSubroutine", tagToken, AddToOutput)); break; } }
private IEnumerable <Parselet> BlockWeight(Token <R> token) { Token <R> funcToken = null; var actions = new List <RantAction>(); while (!reader.End) { funcToken = reader.ReadToken(); if (funcToken.ID == R.RightParen) { reader.SkipSpace(); if (!actions.Any()) { compiler.SyntaxError(funcToken, "Expected weight value"); } RantAction weightAction; // probably a number if (actions[0] is RAText) { if (actions.Count > 1) { if (!(actions[1] is RAText) || ((RAText)actions[1]).Text != "." || actions.Count != 3) { compiler.SyntaxError(actions[1].Range, "Invalid block weight value."); } weightAction = new RAText(actions[0].Range, (actions[0] as RAText).Text + (actions[1] as RAText).Text + (actions[2] as RAText).Text); } else { weightAction = actions[0]; } } else { weightAction = new RASequence(actions, funcToken); } AddToOutput(weightAction); yield break; } yield return(Parselet.GetParselet(funcToken, actions.Add)); } // TODO: this token is "our" (the one that result is us being yielded) token. maybe have the 'fromToken' passed? compiler.SyntaxError(token, "Unterminated function: unexpected end of file"); }
private IEnumerable <Parselet> LeftCurly(Token <R> token) { reader.SkipSpace(); // LOOK AT ME. I'M THE COMPILER NOW Token <R> readToken = null; var actions = new List <RantAction>(); var sequences = new List <RantAction>(); List <_ <int, double> > constantWeights = null; List <_ <int, RantAction> > dynamicWeights = null; while (!reader.End) { readToken = reader.ReadToken(); // TODO: kinda stupid having this handle it's own whitespace when we have a parselet for whitespace if (readToken.ID == R.Whitespace) { switch (reader.PeekType()) { case R.RightCurly: case R.Pipe: continue; } } else if (readToken.ID == R.LeftParen) // weight { RantAction weightAction = null; // i like this AddToOutput thing because it's just a delegate that takes in a RantAction. // it can do anything with the RantAction, in this case it sets it to our weightAction // :> yield return(Parselet.GetParselet("BlockWeight", readToken, a => weightAction = a)); constantWeights = constantWeights ?? new List <_ <int, double> >(); dynamicWeights = dynamicWeights ?? new List <_ <int, RantAction> >(); if (weightAction is RAText) // constant { var strWeight = (weightAction as RAText).Text; double d; if (!Util.ParseDouble(strWeight, out d)) { compiler.SyntaxError(weightAction.Range, $"Invalid weight value '{strWeight}'."); } constantWeights.Add(_.Create(sequences.Count, d)); } else // dynamic { // TODO: there's some weird issue going on with doubles being seen as dynamic weights dynamicWeights.Add(_.Create(sequences.Count, weightAction)); } continue; } else if (readToken.ID == R.Pipe) { // add action to block and continue sequences.Add(actions.Count == 1 ? actions[0] : new RASequence(actions, readToken)); reader.SkipSpace(); actions.Clear(); continue; } else if (readToken.ID == R.RightCurly) { // add action to block and return sequences.Add(actions.Count == 1 ? actions[0] : new RASequence(actions, readToken)); AddToOutput(new RABlock(Stringe.Range(token, readToken), sequences, dynamicWeights, constantWeights)); yield break; } yield return(Parselet.GetParselet(readToken, actions.Add)); } compiler.SyntaxError(token, "Unterminated block: unexpected end of file."); }