private ScriptBlockStatement ParseBlockStatement(ScriptStatement parentStatement, bool parseEndOfStatementAfterEnd = true) { Debug.Assert(!(parentStatement is ScriptBlockStatement)); Blocks.Push(parentStatement); _blockLevel++; EnterExpression(); var blockStatement = Open <ScriptBlockStatement>(); ScriptStatement statement; bool hasEnd; while (TryParseStatement(parentStatement, parseEndOfStatementAfterEnd, out statement, out hasEnd)) { // statement may be null if we have parsed an else continuation of a previous block if (statement != null) { blockStatement.Statements.Add(statement); } if (hasEnd) { break; } } // Don't emit an EOS for an end statement that doesn't expect it if (!parseEndOfStatementAfterEnd && statement is ScriptEndStatement endStatement) { endStatement.ExpectEos = false; } if (!hasEnd) { // If there are any end block not matching, we have an error if (_blockLevel > 1) { if (_isLiquid) { var syntax = ScriptSyntaxAttribute.Get(parentStatement); LogError(parentStatement, parentStatement?.Span ?? CurrentSpan, $"The `end{syntax.TypeName}` was not found"); } else { // unit test: 201-if-else-error2.txt LogError(parentStatement, GetSpanForToken(Previous), $"The <end> statement was not found"); } } } LeaveExpression(); _blockLevel--; Blocks.Pop(); return(Close(blockStatement)); }
private void LogError(ScriptNode node, SourceSpan span, string message, bool isFatal = false) { var syntax = ScriptSyntaxAttribute.Get(node); string inMessage = " in"; if (message.EndsWith("after")) { inMessage = string.Empty; } LogError(span, $"Error while parsing {syntax.TypeName}: {message}{inMessage}: {syntax.Example}", isFatal); }
private ScriptBlockStatement ParseBlockStatement(ScriptStatement parentStatement) { #if DEBUG Debug.Assert(!(parentStatement is ScriptBlockStatement)); #endif Blocks.Push(parentStatement); _blockLevel++; EnterExpression(); ScriptBlockStatement blockStatement = Open <ScriptBlockStatement>(); ScriptStatement statement; bool hasEnd; while (TryParseStatement(parentStatement, out statement, out hasEnd)) { // statement may be null if we have parsed an else continuation of a previous block if (statement != null) { blockStatement.Statements.Add(statement); } if (hasEnd) { break; } } if (!hasEnd) { // If there are any end block not matching, we have an error if (_blockLevel > 1) { if (_isLiquid) { ScriptSyntaxAttribute syntax = ScriptSyntaxAttribute.Get(parentStatement); LogError(parentStatement, parentStatement?.Span ?? CurrentSpan, string.Format(RS.EndLiquidStatementNotFound, syntax.Name)); } else { // unit test: 201-if-else-error2.txt LogError(parentStatement, GetSpanForToken(Previous), RS.EndStatementNotFound); } } } LeaveExpression(); _blockLevel--; Blocks.Pop(); return(Close(blockStatement)); }
private void LogError(ScriptNode node, SourceSpan span, string message, bool isFatal = false) { ScriptSyntaxAttribute syntax = ScriptSyntaxAttribute.Get(node); // #todo string inSeparator = " >>> "; if (message.EndsWith("after")) { inSeparator = string.Empty; } LogError(span, string.Format(RS.ParseError, syntax.Name, message, inSeparator, syntax.Example), isFatal); }
public override void Evaluate(TemplateContext context) { // Check that the Target is actually a function var functionCall = Target as ScriptFunctionCall; if (functionCall == null) { var parameterLessFunction = context.Evaluate(Target, true); if (!(parameterLessFunction is IScriptCustomFunction)) { var targetPrettyname = ScriptSyntaxAttribute.Get(Target); throw new ScriptRuntimeException(Target.Span, $"Expecting a direct function instead of the expression [{Target}/{targetPrettyname.Name}]"); } context.BlockDelegates.Push(Body); context.Result = ScriptFunctionCall.Call(context, this, parameterLessFunction); } else { context.BlockDelegates.Push(Body); context.Result = context.Evaluate(functionCall); } }
private ScriptExpression ParseObjectInitializer() { var scriptObject = Open <ScriptObjectInitializerExpression>(); // Should happen before the NextToken to consume any EOL after _allowNewLineLevel++; NextToken(); // Skip { // unit test: 140-object-initializer-accessor.txt bool expectingEndOfInitializer = false; while (true) { if (Current.Type == TokenType.CloseBrace) { break; } if (!expectingEndOfInitializer && (Current.Type == TokenType.Identifier || Current.Type == TokenType.String)) { var positionBefore = Current; var variableOrLiteral = ParseExpression(scriptObject); var variable = variableOrLiteral as ScriptVariable; var literal = variableOrLiteral as ScriptLiteral; if (variable == null && literal == null) { LogError(positionBefore, $"Unexpected member type `{variableOrLiteral}/{ScriptSyntaxAttribute.Get(variableOrLiteral).Name}` found for object initializer member name"); break; } if (literal != null && !(literal.Value is string)) { LogError(positionBefore, $"Invalid literal member `{literal.Value}/{literal.Value?.GetType()}` found for object initializer member name. Only literal string or identifier name are allowed"); break; } if (variable != null) { if (variable.Scope != ScriptVariableScope.Global) { // unit test: 140-object-initializer-error3.txt LogError("Expecting a simple identifier for member names"); break; } } if (Current.Type != TokenType.Colon) { // unit test: 140-object-initializer-error4.txt LogError($"Unexpected token `{Current.Type}` Expecting a colon : after identifier `{variable.Name}` for object initializer member name"); break; } // TODO: record as trivia NextToken(); // Skip : if (!StartAsExpression()) { // unit test: 140-object-initializer-error5.txt LogError($"Unexpected token `{Current.Type}`. Expecting an expression for the value of the member instead of `{GetAsText(Current)}`"); break; } var expression = ParseExpression(scriptObject); // Erase any previous declaration of this member scriptObject.Members[variableOrLiteral] = expression; if (Current.Type == TokenType.Comma) { // Record trailing Commas if (_isKeepTrivia) { expression.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Comma, _lexer.Text), false); } NextToken(); if (_isKeepTrivia && _trivias.Count > 0) { expression.AddTrivias(_trivias, false); _trivias.Clear(); } } else { expectingEndOfInitializer = true; } } else { // unit test: 140-object-initializer-error1.txt LogError($"Unexpected token `{Current.Type}` while parsing object initializer. Expecting a simple identifier for the member name instead of `{GetAsText(Current)}`"); break; } } // Should happen before NextToken() to stop on the next EOF _allowNewLineLevel--; NextToken(); // Skip } return(Close(scriptObject)); }
private ScriptExpression ParseObjectInitializer() { var scriptObject = Open <ScriptObjectInitializerExpression>(); // Should happen before the NextToken to consume any EOL after allowNewLineLevel++; NextToken(); // Skip { // unit test: 140-object-initializer-accessor.txt bool expectingEndOfInitializer = false; while (true) { if (Current.Type == TokenType.CloseBrace) { break; } if (!expectingEndOfInitializer && (Current.Type == TokenType.Identifier || Current.Type == TokenType.String)) { var positionBefore = Current; var variableOrLiteral = ParseExpression(scriptObject); var variable = variableOrLiteral as ScriptVariable; var literal = variableOrLiteral as ScriptLiteral; if (variable == null && literal == null) { LogError(positionBefore, $"Unexpected member type [{variableOrLiteral}/{ScriptSyntaxAttribute.Get(variableOrLiteral).Name}] found for object initializer member name"); break; } if (literal != null && !(literal.Value is string)) { LogError(positionBefore, $"Invalid literal member [{literal.Value}/{literal.Value?.GetType()}] found for object initializer member name. Only literal string or identifier name are allowed"); break; } if (variable != null) { if (IsKeyword(variable.Name)) { // unit test: 140-object-initializer-error2.txt LogError(positionBefore, $"Invalid Keyword [{variable}] found for object initializer member name"); break; } if (variable.Scope != ScriptVariableScope.Global) { // unit test: 140-object-initializer-error3.txt LogError("Expecting a simple identifier for member names"); break; } } if (Current.Type != TokenType.Colon) { // unit test: 140-object-initializer-error4.txt LogError($"Unexpected token [{Current.Type}] Expecting a colon : after identifier [{variable.Name}] for object initializer member name"); break; } NextToken(); // Skip : if (!StartAsExpression()) { // unit test: 140-object-initializer-error5.txt LogError($"Unexpected token [{Current.Type}]. Expecting an expression for the value of the member instead of [{GetAsText(Current)}]"); break; } var expression = ParseExpression(scriptObject); // Erase any previous declaration of this member scriptObject.Members[variableOrLiteral] = expression; if (Current.Type == TokenType.Comma) { NextToken(); } else { expectingEndOfInitializer = true; } } else { // unit test: 140-object-initializer-error1.txt LogError($"Unexpected token [{Current.Type}] while parsing object initializer. Expecting a simple identifier for the member name instead of [{GetAsText(Current)}]"); break; } } // Should happen before NextToken() to stop on the next EOF allowNewLineLevel--; NextToken(); // Skip } return(Close(scriptObject)); }
private ScriptExpression ParseObjectInitializer() { ScriptObjectInitializerExpression scriptObject = Open <ScriptObjectInitializerExpression>(); // Should happen before the NextToken to consume any EOL after _allowNewLineLevel++; NextToken(); // Skip { // unit test: 140-object-initializer-accessor.txt bool expectingEndOfInitializer = false; while (true) { if (Current.Type == TokenType.CloseBrace) { break; } if (!expectingEndOfInitializer && (Current.Type == TokenType.Identifier || Current.Type == TokenType.String)) { Token positionBefore = Current; ScriptExpression variableOrLiteral = ParseExpression(scriptObject); var variable = variableOrLiteral as ScriptVariable; var literal = variableOrLiteral as ScriptLiteral; if (variable == null && literal == null) { LogError(positionBefore, string.Format(RS.InvalidObjectInitMemberNameType, variableOrLiteral, ScriptSyntaxAttribute.Get(variableOrLiteral).Name)); break; } if (literal != null && !(literal.Value is string)) { LogError(positionBefore, string.Format(RS.InvalidObjectInitMemberName, literal.Value, literal.Value?.GetType())); break; } if (variable != null) { if (variable.Scope != ScriptVariableScope.Global) { // unit test: 140-object-initializer-error3.txt LogError(RS.InvalidMemberName); break; } } if (Current.Type != TokenType.Colon) { // unit test: 140-object-initializer-error4.txt LogError(string.Format(RS.UnexpectedTokenInObjectMemberName, Current.Type, variable.Name)); break; } // TODO: record as trivia NextToken(); // Skip : if (!StartAsExpression()) { // unit test: 140-object-initializer-error5.txt LogError(string.Format(RS.InvalidMemberValue, Current.Type, GetAsText(Current))); break; } ScriptExpression expression = ParseExpression(scriptObject); // Erase any previous declaration of this member scriptObject.Members[variableOrLiteral] = expression; if (Current.Type == TokenType.Comma) { // Record trailing Commas if (_isKeepTrivia) { expression.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Comma, _lexer.Text), false); } NextToken(); if (_isKeepTrivia && _trivias.Count > 0) { expression.AddTrivias(_trivias, false); _trivias.Clear(); } } else { expectingEndOfInitializer = true; } } else { // unit test: 140-object-initializer-error1.txt LogError(string.Format(RS.UnexpectedTokenInObjectInit, Current.Type, GetAsText(Current))); break; } } // Should happen before NextToken() to stop on the next EOF _allowNewLineLevel--; NextToken(); // Skip } return(Close(scriptObject)); }