internal static StringSegment ParseArguments(this StringSegment literal, out List <JsToken> arguments, char termination) { arguments = new List <JsToken>(); while (!literal.IsNullOrEmpty()) { JsToken listValue; literal = literal.AdvancePastWhitespace(); if (literal.GetChar(0) == termination) { literal = literal.Advance(1); break; } if (literal.StartsWith("...")) { literal = literal.Advance(3); literal = literal.ParseJsExpression(out listValue); if (!(listValue is JsIdentifier) && !(listValue is JsArrayExpression)) { throw new SyntaxErrorException($"Spread operator expected array but instead found {listValue.DebugToken()}"); } listValue = new JsSpreadElement(listValue); } else { literal = literal.ParseJsExpression(out listValue); } arguments.Add(listValue); literal = literal.AdvancePastWhitespace(); if (literal.IsNullOrEmpty()) { break; } if (literal.GetChar(0) == termination) { literal = literal.Advance(1); break; } literal = literal.AdvancePastWhitespace(); var c = literal.SafeGetChar(0); if (c.IsEnd() || c == termination) { literal = literal.Advance(1); break; } if (c != ',') { throw new SyntaxErrorException($"Unterminated arguments expression near: {literal.DebugLiteral()}"); } literal = literal.Advance(1); literal = literal.AdvancePastWhitespace(); } literal = literal.AdvancePastWhitespace(); return(literal); }
public static StringSegment ParseBinaryExpression(this StringSegment literal, out JsExpression expr, bool filterExpression) { literal = literal.AdvancePastWhitespace(); literal = literal.ParseJsToken(out var lhs, filterExpression: filterExpression); if (literal.IsNullOrEmpty()) { expr = lhs is JsExpression jsExpr ? jsExpr : throw new SyntaxErrorException($"Expected Expression but was {lhs.DebugToken()}"); } else { literal = literal.ParseJsBinaryOperator(out var op); if (op == null) { throw new SyntaxErrorException($"Expected binary operator near: {literal.DebugLiteral()}"); } var prec = JsTokenUtils.GetBinaryPrecedence(op.Token); if (prec > 0) { literal = literal.ParseJsToken(out JsToken rhs, filterExpression: filterExpression); var stack = new Stack <JsToken>(); stack.Push(lhs); stack.Push(op); stack.Push(rhs); var precedences = new List <int> { prec }; while (true) { literal = literal.AdvancePastWhitespace(); if (filterExpression && literal.Length > 2 && (literal.GetChar(0) == '|' && literal.GetChar(1) != '|')) { break; } prec = literal.GetNextBinaryPrecedence(); if (prec == 0) { break; } while ((stack.Count > 2) && prec <= precedences[precedences.Count - 1]) { rhs = stack.Pop(); var operand = (JsBinaryOperator)stack.Pop(); precedences.RemoveAt(precedences.Count - 1); lhs = stack.Pop(); stack.Push(CreateJsExpression(lhs, operand, rhs)); } literal = literal.ParseJsBinaryOperator(out op); if (literal.IsNullOrEmpty()) { throw new SyntaxErrorException($"Expected expression near: '{literal.DebugLiteral()}'"); } literal = literal.ParseJsToken(out var token, filterExpression: filterExpression); stack.Push(op); stack.Push(token); precedences.Add(prec); } var i = stack.Count - 1; var ret = stack.Pop(); while (stack.Count > 0) { op = (JsBinaryOperator)stack.Pop(); lhs = stack.Pop(); ret = CreateJsExpression(lhs, op, ret); } expr = (JsExpression)ret; } else { expr = lhs is JsExpression jsExpr ? jsExpr : throw new SyntaxErrorException($"Expected Expression but was {lhs.DebugToken()}"); } } return(literal); }
internal static StringSegment ParseWhitespaceArgument(this StringSegment literal, out JsToken argument) { // replace everything after ':' up till new line and rewrite as single string to method var endStringPos = literal.IndexOf("\n"); var endStatementPos = literal.IndexOf("}}"); if (endStringPos == -1 || (endStatementPos != -1 && endStatementPos < endStringPos)) { endStringPos = endStatementPos; } if (endStringPos == -1) { throw new SyntaxErrorException($"Whitespace sensitive syntax did not find a '\\n' new line to mark the end of the statement, near {literal.DebugLiteral()}"); } var originalArg = literal.Subsegment(0, endStringPos).Trim().ToString(); var rewrittenArgs = originalArg.Replace("{", "{{").Replace("}", "}}"); var strArg = new JsLiteral(rewrittenArgs); argument = strArg; return(literal.Subsegment(endStringPos)); }