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> FunctionSubroutine(Token <R> token) { var call = false; var nextToken = reader.ReadToken(); var inModule = false; string functionName = null; // if the first token isn't a square, it's the name of the subroutine call if (nextToken.ID != R.LeftSquare) { call = true; // probably an in-module subroutine call if (reader.PeekType() == R.Subtype) { reader.ReadToken(); var name = reader.Read(R.Text, "subroutine name"); functionName = name.Value; inModule = true; } } else { if (reader.PeekType() == R.Subtype) { compiler.HasModule = true; inModule = true; reader.ReadToken(); } nextToken = reader.Read(R.Text, "subroutine name"); } // if there's a colon here, there's args var hasArgs = reader.Take(R.Colon); if (call) { foreach (var parselet in SubroutineArgs(token, nextToken, functionName)) { yield return(parselet); } yield break; } var subroutine = new RADefineSubroutine(nextToken); subroutine.Parameters = new Dictionary <string, SubroutineParameterType>(); // read ALL THE ARGS!! // right now we're at [$[name: or [$[name while (hasArgs && !reader.End) { var nameToken = reader.ReadLooseToken(); if (nameToken.ID == R.Text) { subroutine.Parameters.Add(nameToken.Value, SubroutineParameterType.Greedy); } else if (nameToken.ID == R.At) { nameToken = reader.ReadLoose(R.Text); subroutine.Parameters.Add(nameToken.Value, SubroutineParameterType.Loose); } else { compiler.SyntaxError(nameToken, "Expected subroutine parameter"); } nextToken = reader.ReadLooseToken(); if (nextToken.ID == R.Semicolon) { continue; } if (nextToken.ID == R.RightSquare) { break; } compiler.SyntaxError(nextToken, "Unexpected token in subroutine parameter definition"); } // if there's no args, we need to get rid of the right square before the body if (!hasArgs) { reader.ReadLoose(R.RightSquare); } // start reading the body reader.ReadLoose(R.Colon); RASequence body = null; foreach (var parselet in SubroutineBody(token, a => body = a)) { yield return(parselet); } subroutine.Body = body; if (inModule) { compiler.Module.AddActionFunction(subroutine.Name, subroutine); } AddToOutput(subroutine); }