public static bool PeekAndParse(CharStream cs, out FTL.AST.Pattern pattern) { // A quoted-pattern is the easiest to detect, so we'll try that first if (cs.PeekNext() == '"') { pattern = ParseQuoted(cs); return(true); } // it might still be an unquoted-pattern, but this is trickier to detect // first let's try to detect a placeable and block-text if (Placeable.Peek(cs) || AnyText.PeekBlockText(cs)) { pattern = ParseUnquoted(cs); return(true); } // if not any of the above, the only thing left is unquoted-text int bufferPos = cs.Position; WhiteSpace.Parse(cs); char next = cs.PeekNext(); cs.Rewind(bufferPos); if (!CharStream.IsEOF(next) && !CharStream.IsNL(next)) { pattern = ParseUnquoted(cs); return(true); } pattern = null; return(false); }
public static FTL.AST.CallExpression Parse(CharStream cs, FTL.AST.StringPrimitive builtin) { if (!Builtin.IsValid(builtin.Value)) { throw cs.CreateException( string.Format("{0} is not a valid builtin, while one was expected", builtin.Value), null); } cs.SkipCharacter(PREFIX); FTL.AST.ArgumentsList arguments = new FTL.AST.ArgumentsList(); while (cs.PeekNext() != POSTFIX) { WhiteSpace.Parse(cs); arguments.AddArgument(Argument.Parse(cs)); WhiteSpace.Parse(cs); if (cs.PeekNext() != ',') { break; // exit early, as no more arguments are expected } cs.SkipNext(); // skip ',' } // make sure last non-ws char is ')', // otherwise something went wrong cs.SkipCharacter(POSTFIX); return(new FTL.AST.CallExpression(builtin, arguments)); }
public static bool PeekAndParse(CharStream cs, out FTL.AST.MemberList memberList) { // if next char is not a newline, we can just as well skip already char next = cs.PeekNext(); if (CharStream.IsEOF(next) || !CharStream.IsNL(next)) { memberList = null; return(false); } // let's keep peeking further, requiring our buffer int bufferPos = cs.Position; NewLine.Parse(cs); WhiteSpace.Parse(cs); // we'll always want to rewind no matter what bool isMemberList = Member.Peek(cs); cs.Rewind(bufferPos); if (isMemberList) { memberList = Parse(cs); return(true); } memberList = null; return(false); }
public static FTL.AST.Member Parse(CharStream cs) { WhiteSpace.Parse(cs); bool isDefault = false; if (cs.PeekNext() == '*') { cs.SkipNext(); isDefault = true; } // Parse the MemberKey cs.SkipCharacter('['); FTL.AST.INode key = Memberkey.Parse(cs); cs.SkipCharacter(']'); // skip optional space WhiteSpace.Parse(cs); // Parse the actual pattern FTL.AST.Pattern pattern = Pattern.Parse(cs); // and return it all return(new FTL.AST.Member(key, pattern, isDefault)); }
public static bool PeekBlockText(CharStream cs) { char next = cs.PeekNext(); // if next char isn't a NewLine Character, we know for sure we // are not dealing with a block-text if (CharStream.IsEOF(next) || !CharStream.IsNL(next)) { return(false); } // from here on out, we're still not sure if we're dealing with a block-text // thus we start buffering so we can go back in time // here we check if we have the following pattern: `NL __ '|'` int bufferPos = cs.Position; NewLine.Parse(cs); WhiteSpace.Parse(cs); // if the next unbuffered char is not '|' we're not dealing with a block-text // and can return; next = cs.PeekNext(); cs.Rewind(bufferPos); return(next == '|'); }
public static FTL.AST.INode Parse(CharStream cs) { FTL.AST.INode expression = Expresson.Parse(cs); int bufferPos = cs.Position; WhiteSpace.Parse(cs); if (cs.PeekNext() != SEPERATOR[0]) { // it's not a select expression, so let's return early cs.Rewind(bufferPos); return(expression); } // it must be a select expression cs.SkipString(SEPERATOR); WhiteSpace.Parse(cs); // we expect now a memberList (REQUIRED) FTL.AST.MemberList memberList = MemberList.Parse(cs); // skip extra new-line in case one is available if (CharStream.IsNL(cs.PeekNext())) { NewLine.Parse(cs); } // return it all return(new FTL.AST.SelectExpression(expression, memberList)); }
// ([^{"] | '\{' | '\"')+ public static FTL.AST.QuotedText ParseQuoted(CharStream cs) { s_Buffer.Clear(); WhiteSpace.Parse(cs); bool allowSC = false; char next = cs.PeekNext(); while (!CharStream.IsEOF(next) && !CharStream.IsNL(next) && (allowSC || (next != '{' && next != '"'))) { s_Buffer.Add(next); cs.SkipNext(); allowSC = !allowSC && next == '\\'; next = cs.PeekNext(); } if (s_Buffer.Count == 0) { throw cs.CreateException( "no quoted text could be parsed, while this was expected", null); } return(new FTL.AST.QuotedText(new string(s_Buffer.ToArray()))); }
public static FTL.AST.INode Parse(CharStream cs) { FTL.AST.INode result; // if it's an identifier, it could be either simply be an identifier, // or it could actually be a keyword-argument if (Identifier.PeekAndParse(cs, out result)) { int bufferPos = cs.Position; // ignore any whitespace WhiteSpace.Parse(cs); // if we now encounter a `=` char, we'll assume it's a keyword-argument, // and finish the parsing of that element, // otherwise we'll assume it's simply an identifier and return early if (cs.PeekNext() != '=') { cs.Rewind(bufferPos); return(Expresson.ParseWithIdentifier(cs, result as FTL.AST.StringPrimitive)); } cs.SkipNext(); WhiteSpace.Parse(cs); FTL.AST.Pattern pattern = Pattern.ParseQuoted(cs); return(new FTL.AST.KeywordArgument( result as L20n.FTL.AST.StringPrimitive, pattern)); } // it's not an identifier, so is must be any non-identifier expression return(Expresson.ParseNoneIdentifier(cs)); }
private static FTL.AST.Section Parse(CharStream cs) { cs.SkipString(PREFIX); WhiteSpace.Parse(cs); var keyword = Keyword.Parse(cs); WhiteSpace.Parse(cs); cs.SkipString(POSTFIX); return(new FTL.AST.Section(keyword)); }
protected override (bool isSuccess, Cursol cursol, T parsed) ParseCore(Cursol cursol) { var current = cursol; bool isSuccess; do { (isSuccess, current, _) = WhiteSpace.Parse(current); } while (isSuccess); return(Parser.Parse(current)); }
public static bool PeekAndParse(CharStream cs, out FTL.AST.INode result) { if (!Peek(cs)) { result = null; return(false); } // skip prefix and optional space cs.SkipCharacter(PREFIX); FTL.AST.Placeable placeable = new FTL.AST.Placeable(); // parse all placeable-expressions do { WhiteSpace.Parse(cs); // optional newline if (CharStream.IsNL(cs.PeekNext())) { NewLine.Parse(cs); WhiteSpace.Parse(cs); } placeable.AddExpression(PlaceableExpression.Parse(cs)); WhiteSpace.Parse(cs); if (cs.PeekNext() != ',') { break; } // keep going, until we have no more commas cs.SkipNext(); } while(true); // skip optional space WhiteSpace.Parse(cs); // optional newline if (CharStream.IsNL(cs.PeekNext())) { NewLine.Parse(cs); WhiteSpace.Parse(cs); } cs.SkipCharacter(POSTFIX); result = placeable; return(true); }
public void WhiteSpaceTests() { var stream = NCS(" \t\t "); // This will read everything WhiteSpace.Parse(stream); // This will not read anything, but it's optional // so it will not give an exception WhiteSpace.Parse(stream); stream = NCS(" a <- foo"); // This will read until 'a' WhiteSpace.Parse(stream); WhiteSpace.Parse(stream); Assert.AreEqual("a <- foo", stream.ReadUntilEnd()); }
private static FTL.AST.Message Parse(CharStream cs, Context ctx, FTL.AST.StringPrimitive identifier) { WhiteSpace.Parse(cs); cs.SkipCharacter('='); WhiteSpace.Parse(cs); FTL.AST.Pattern pattern = null; // check if we have a Pattern available bool hasPattern = Pattern.PeekAndParse(cs, out pattern); FTL.AST.MemberList memberList; bool parsedMemberList = MemberList.PeekAndParse(cs, out memberList); if (!parsedMemberList && !hasPattern) { throw cs.CreateException( "member-list was expected, as no pattern was found", null); } return(new FTL.AST.Message(identifier, pattern, memberList)); }
public static FTL.AST.MemberList Parse(CharStream cs) { // starts with a newline and optional newline NewLine.Parse(cs); WhiteSpace.Parse(cs); FTL.AST.MemberList memberList = new FTL.AST.MemberList(); // parse first required member, as we always need at least 1 memberList.AddMember(Member.Parse(cs)); char next; int bufferPos; do { next = cs.PeekNext(); if (CharStream.IsEOF(next) || !CharStream.IsNL(next)) { break; } bufferPos = cs.Position; NewLine.Parse(cs); WhiteSpace.Parse(cs); if (!Member.Peek(cs)) { cs.Rewind(bufferPos); break; } memberList.AddMember(Member.Parse(cs)); } while(true); return(memberList); }
// NL __ '|' __ (unquoted-text | placeable)+ public static bool PeekAndParseBlock(CharStream cs, out FTL.AST.INode result) { char next = cs.PeekNext(); // if next char isn't a NewLine Character, we know for sure we // are not dealing with a block-text if (CharStream.IsEOF(next) || !CharStream.IsNL(next)) { result = null; return(false); } // from here on out, we're still not sure if we're dealing with a block-text // thus we start buffering so we can go back in time // here we check if we have the following pattern: `NL __ '|'` int bufferPos = cs.Position; NewLine.Parse(cs); WhiteSpace.Parse(cs); // if the next unbuffered char is not '|' we're not dealing with a block-text // and can return; if (cs.PeekNext() != '|') { cs.Rewind(bufferPos); result = null; return(false); } // we know for sure we're dealing with a block-text, // buffer can be flushed and we can start checking for more lines as well; FTL.AST.INode line; FTL.AST.BlockText blockText = new FTL.AST.BlockText(); do { cs.SkipNext(); // skip '|' WhiteSpace.Parse(cs); if (!Placeable.PeekAndParse(cs, out line)) { // it's not a placeable, so it must be unquoted-text line = ParseUnquoted(cs); } // add line blockText.AddLine(line); // peek if next char is a newline char // otherwise we can stop early with trying next = cs.PeekNext(); if (CharStream.IsEOF(next) || !CharStream.IsNL(next)) { break; } // check if we have more lines bufferPos = cs.Position; NewLine.Parse(cs); WhiteSpace.Parse(cs); // as long as the next char is '|' // we'll keep looping if (cs.PeekNext() != '|') { cs.Rewind(bufferPos); break; } } while(true); result = blockText; return(true); }