public override object Evaluate(TemplateContext context) { object result = null; for (int i = 0; i < Statements.Count; i++) { ScriptStatement statement = Statements[i]; var expressionStatement = statement as ScriptExpressionStatement; bool isAssign = expressionStatement?.Expression is ScriptAssignExpression; result = context.Evaluate(statement); // Top-level assignment expression don't output anything if (isAssign) { result = null; } else if (result != null && context.FlowState != ScriptFlowState.Return && context.EnableOutput) { context.Write(Span, result); result = null; } // If flow state is different, we need to exit this loop if (context.FlowState != ScriptFlowState.None) { break; } } return(result); }
private void OnItemClicked(string colName, ScriptStatement command) { int index = ScriptService.Current.Statements.IndexOf(command); switch (colName) { case nameof(ScriptStatement.Insert): Logger.Debug($"Insert ! {index}"); var scriptStatement = new ScriptStatement(); Statements.Insert(index + 1, scriptStatement); ScriptService.Current.Insert(index + 1, scriptStatement); break; case nameof(ScriptStatement.Up): Logger.Debug($"Up ! {index}"); Statements.Swap(index, index - 1); ScriptService.Current.Swap(index, index - 1); break; case nameof(ScriptStatement.Down): Logger.Debug($"Down ! {index}"); Statements.Swap(index, index + 1); ScriptService.Current.Swap(index, index + 1); break; case nameof(ScriptStatement.Trash): Logger.Debug($"Trash ! {index}"); Statements.Remove(index); ScriptService.Current.Remove(index); break; } }
public void GetCreateScript_GetDropScript_ValidConnectionString() { var statement1 = new ScriptStatement("Test1"); var statement2 = new ScriptStatement("Test2"); var fakeCreateResult = new ScriptElementCollection(); fakeCreateResult.AddElement(statement1); fakeCreateResult.AddElement(statement2); var fakeDropResult = new ScriptElementCollection(); fakeDropResult.AddElement(statement2); fakeDropResult.AddElement(statement1); _innerScriptBuilderMock.Expect(mock => mock.GetCreateScript()).Return(fakeCreateResult); _innerScriptBuilderMock.Expect(mock => mock.GetDropScript()).Return(fakeDropResult); var createScriptResult = _builder.GetCreateScript(); var dropScriptResult = _builder.GetDropScript(); Assert.That(((ScriptElementCollection)createScriptResult).Elements.Count, Is.EqualTo(2)); Assert.That(((ScriptStatement)((ScriptElementCollection)createScriptResult).Elements[0]).Statement, Is.EqualTo("USE MyDataBase")); Assert.That(((ScriptElementCollection)createScriptResult).Elements[1], Is.SameAs(fakeCreateResult)); Assert.That(((ScriptElementCollection)dropScriptResult).Elements.Count, Is.EqualTo(2)); Assert.That(((ScriptStatement)((ScriptElementCollection)dropScriptResult).Elements[0]).Statement, Is.EqualTo("USE MyDataBase")); Assert.That(((ScriptElementCollection)dropScriptResult).Elements[1], Is.SameAs(fakeDropResult)); }
private ScriptStatement ParseLiquidExpressionStatement(ScriptStatement parent) { Token startToken = Current; CheckNotInCase(parent, startToken); ScriptExpressionStatement expressionStatement = ParseExpressionStatement(); ScriptExpressionStatement statement = expressionStatement; // NOTE: We were previously performing the following checks // but as liquid doesn't have a strict syntax, we are instead not enforcing any kind of rules // so that the parser can still read custom liquid tags/object expressions, assuming that // they are not using fancy argument syntaxes (which are unfortunately allowed in liquid) //var functionCall = expressionStatement.Expression as ScriptFunctionCall; //// Otherwise it is an expression statement //if (functionCall != null) //{ // if (!_isLiquidTagSection) // { // LogError(startToken, $"The `{functionCall}` statement must be in a tag section `{{% ... %}}`"); // } //} //else if (_isLiquidTagSection) //{ // LogError(startToken, $"Expecting the expression `{GetAsText(startToken)}` to be in an object section `{{{{ ... }}}}`"); //} //else if (!(expressionStatement.Expression is IScriptVariablePath || expressionStatement.Expression is ScriptPipeCall)) //{ // LogError(statement, $"The <{expressionStatement.Expression}> is not allowed in this context"); //} return(statement); }
public ScriptForEachStatement(AstNodeArgs args) : base(args) { _name = (TokenAst)ChildNodes[1]; _expr = (ScriptExpr)ChildNodes[3]; _statement = (ScriptStatement)ChildNodes[4]; }
public ScriptTryCatchFinallyStatement(AstNodeArgs args) : base(args) { _tryBlock = ChildNodes[1] as ScriptStatement; _expName = ((TokenAst) ChildNodes[3]).Text; _catchBlock = ChildNodes[4] as ScriptStatement; _finallyBlock = ChildNodes[6] as ScriptStatement; }
private void CheckNotInCase(ScriptStatement parent, Token token) { if (parent is ScriptCaseStatement) { // 205-case-when-statement-error1.txt LogError(token, string.Format(RS.UnexpectedTokenInCase, GetAsText(token))); } }
private void CheckNotInCase(ScriptStatement parent, Token token) { if (parent is ScriptCaseStatement) { // 205-case-when-statement-error1.txt LogError(token, $"Unexpected statement/expression `{GetAsText(token)}` in the body of a `case` statement. Only `when`/`else` are expected."); } }
protected void AddCommand() { var scriptStatement = new ScriptStatement { Param1 = Model.Expression, Param2 = Model.Result }; scriptStatement.Name = Model.CaptureType == CaptureType.Regex ? nameof(CheckRegexCommand) : nameof(CheckJsonCommand); ScriptService.Current.Statements.Add(scriptStatement); }
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)); }
public ScriptIfStatement(AstNodeArgs args) : base(args) { _condition = (ScriptCondition) ChildNodes[1]; _statement = (ScriptStatement)ChildNodes[2]; //Else exists if (ChildNodes.Count == 4 && ChildNodes[3].ChildNodes.Count == 2 && ChildNodes[3].ChildNodes[1] is ScriptStatement) { _elseStatement = (ScriptStatement)ChildNodes[3].ChildNodes[1]; } }
public ScriptForStatement(AstNodeArgs args) : base(args) { _init = (ScriptExpr)args.ChildNodes[1]; _cond = (ScriptExpr)args.ChildNodes[2]; _next = (ScriptExpr)args.ChildNodes[3]; _statement = (ScriptStatement)args.ChildNodes[4]; var body = _statement as ScriptCompoundStatement; if (body != null) body.ShouldCreateScope = false; }
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)); }
public void AppendToScript_ScriptNotEmpty() { var scriptStatement = new ScriptStatement("Test"); var script = new List <ScriptStatement> { scriptStatement }; Assert.That(script.Count, Is.EqualTo(1)); _statement.AppendToScript(script); Assert.That(script, Is.EqualTo(new[] { scriptStatement, _statement })); }
private void OnSelectedItemChanged(ScriptStatement statement) { if (!string.IsNullOrEmpty(statement.Name) && ScriptService.CommandsByName.TryGetValue(statement.Name, out var commandInfo)) { StatementModel.Name = commandInfo.Name; StatementModel.ParamName1 = commandInfo.ParamName1; StatementModel.ParamName2 = commandInfo.ParamName2; } StatementModel.CurrentStatement = statement; StatementModel.Param1 = statement.Param1; StatementModel.Param2 = statement.Param2; InvokeAsync(StateHasChanged); }
public override void SetUp() { base.SetUp(); _converter = new ScriptToStringConverter(); _fakeCreateElements = new ScriptElementCollection(); _fakeDropElements = new ScriptElementCollection(); _scriptBuilderStub = MockRepository.GenerateStub <IScriptBuilder>(); _scriptBuilderStub.Stub(stub => stub.GetCreateScript()).Return(_fakeCreateElements); _scriptBuilderStub.Stub(stub => stub.GetDropScript()).Return(_fakeDropElements); _scriptElement1 = new ScriptStatement("Test1"); _scriptElement2 = new ScriptStatement("Test2"); }
public void AppendToScript_NonEmptyScript_LastStatementIsBatchStatement() { var statement1 = new ScriptStatement("1"); var statement2 = new ScriptStatement("GO"); _script.Add(statement1); _script.Add(statement2); _batchDelimiterStatement.AppendToScript(_script); Assert.That(_script.Count, Is.EqualTo(2)); Assert.That(_script[0], Is.SameAs(statement1)); Assert.That(_script[1], Is.EqualTo(statement2)); }
private ScriptBlockStatement ParseBlockStatement(ScriptStatement parentStatement) { Blocks.Push(parentStatement); _blockLevel++; if (Options.StatementDepthLimit.HasValue && !_isStatementDepthLimitReached && _blockLevel > Options.StatementDepthLimit.Value) { LogError(parentStatement, GetSpanForToken(Previous), $"The statement depth limit `{Options.StatementDepthLimit.Value}` was reached when parsing this statement"); _isStatementDepthLimitReached = true; } var blockStatement = parentStatement is ScriptBlockStatement ? (ScriptBlockStatement)parentStatement : 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 (!HasErrors && !hasEnd) { // If there are any end block not matching, we have an error if (_blockLevel > 1) { // unit test: 201-if-else-error2.txt LogError(parentStatement, GetSpanForToken(Previous), $"The <end> statement was not found"); } } _blockLevel--; Blocks.Pop(); return(Close(blockStatement)); }
protected void Create() { Logger.Info($"Creating a new statement: {StatementModel.Name}"); if (string.IsNullOrEmpty(StatementModel.Name)) { Logger.Warn("Statement not created, command name is null or empty."); return; } var scriptCommand = new ScriptStatement { Name = StatementModel.Name, Param1 = StatementModel.Param1, Param2 = StatementModel.Param2 }; ScriptService.Add(scriptCommand); Statements.Add(scriptCommand); InvokeAsync(StateHasChanged); }
public override void SetUp() { base.SetUp(); _builder1Mock = MockRepository.GenerateStrictMock <IScriptBuilder>(); _builder2Mock = MockRepository.GenerateStrictMock <IScriptBuilder>(); _fakeStatement1 = new ScriptStatement("Fake1"); _fakeStatement2 = new ScriptStatement("Fake2"); _fakeStatement3 = new ScriptStatement("Fake3"); _fakeResultCollection1 = new ScriptElementCollection(); _fakeResultCollection1.AddElement(_fakeStatement1); _fakeResultCollection2 = new ScriptElementCollection(); _fakeResultCollection2.AddElement(_fakeStatement2); _fakeResultCollection2.AddElement(_fakeStatement3); }
private ScriptBlockStatement ParseBlockStatement(ScriptStatement parentStatement) { Blocks.Push(parentStatement); blockLevel++; var blockStatement = parentStatement is ScriptBlockStatement ? (ScriptBlockStatement)parentStatement : 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 (!HasErrors && !hasEnd) { // If there are any end block not matching, we have an error if (blockLevel > 1) { // unit test: 201-if-else-error2.txt LogError(parentStatement, GetSpanForToken(Previous), $"The <end> statement was not found"); } } blockLevel--; Blocks.Pop(); return(Close(blockStatement)); }
private bool ExpectEndOfStatement(ScriptStatement statement) { if (_isLiquid) { if (Current.Type == TokenType.CodeExit || (_isLiquidTagSection && Current.Type == TokenType.LiquidTagExit)) { return(true); } } else if (Current.Type == TokenType.NewLine || Current.Type == TokenType.CodeExit || Current.Type == TokenType.SemiColon || Current.Type == TokenType.Eof) { if (Current.Type == TokenType.NewLine || Current.Type == TokenType.SemiColon) { PushTokenToTrivia(); NextToken(); } return(true); } // If we are not finding an end of statement, log a fatal error LogError(statement, string.Format(RS.UnexpectedTokenAfterEnd, GetAsText(Current)), true); return(false); }
private bool ExpectEndOfStatement(ScriptStatement statement) { if (_isLiquid) { if (Current.Type == TokenType.CodeExit || (_isLiquidTagSection && Current.Type == TokenType.LiquidTagExit)) { return(true); } } else if (Current.Type == TokenType.NewLine || Current.Type == TokenType.CodeExit || Current.Type == TokenType.SemiColon || Current.Type == TokenType.Eof) { if (Current.Type == TokenType.NewLine || Current.Type == TokenType.SemiColon) { PushTokenToTrivia(); NextToken(); } return(true); } // If we are not finding an end of statement, log a fatal error LogError(statement, $"Invalid token found `{GetAsText(Current)}`. Expecting <EOL>/end of line after", true); return(false); }
private bool TryParseStatement(ScriptStatement parent, out ScriptStatement statement, out bool hasEnd) { hasEnd = false; bool nextStatement = true; statement = null; if (HasErrors) { return(false); } continueParsing: switch (Current.Type) { case TokenType.Eof: // Early exit nextStatement = false; break; case TokenType.Raw: statement = ParseRawStatement(); break; case TokenType.CodeEnter: if (_inCodeSection) { LogError("Unexpected token while already in a code block"); } _inCodeSection = true; NextToken(); goto continueParsing; case TokenType.FrontMatterMarker: if (_inFrontMatter) { _inFrontMatter = false; _inCodeSection = false; // When we expect to parse only the front matter, don't try to tokenize the following text // Keep the current token as the code exit of the front matter if (CurrentParsingMode != ScriptMode.FrontMatterOnly) { NextToken(); } if (CurrentParsingMode == ScriptMode.FrontMatterAndContent || CurrentParsingMode == ScriptMode.FrontMatterOnly) { // Once the FrontMatter has been parsed, we can switch to default parsing mode. CurrentParsingMode = ScriptMode.Default; nextStatement = false; } } else { LogError($"Unexpected frontmatter marker `{_lexer.Options.FrontMatterMarker}` while not inside a frontmatter"); NextToken(); } break; case TokenType.CodeExit: if (!_inCodeSection) { LogError("Unexpected code block exit '}}' while no code block enter '{{' has been found"); } else if (CurrentParsingMode == ScriptMode.ScriptOnly) { LogError("Unexpected code clock exit '}}' while parsing in script only mode. '}}' is not allowed."); } _inCodeSection = false; NextToken(); goto continueParsing; default: if (_inCodeSection) { switch (Current.Type) { case TokenType.NewLine: case TokenType.SemiColon: NextToken(); goto continueParsing; case TokenType.Identifier: case TokenType.IdentifierSpecial: var identifier = GetAsText(Current); switch (identifier) { case "end": hasEnd = true; nextStatement = false; NextToken(); break; case "wrap": statement = ParseWrapStatement(); break; case "if": statement = ParseIfStatement(); break; case "else": var parentCondition = parent as ScriptConditionStatement; if (parentCondition == null) { nextStatement = false; // unit test: 201-if-else-error3.txt LogError("A else condition must be preceded by another if/else condition"); } else { var nextCondition = ParseElseStatement(); parentCondition.Else = nextCondition; hasEnd = true; } break; case "for": if (PeekToken().Type == TokenType.Dot) { statement = ParseExpressionStatement(); } else { statement = ParseForStatement(); } break; case "with": statement = ParseWithStatement(); break; case "import": statement = ParseImportStatement(); break; case "readonly": statement = ParseReadOnlyStatement(); break; case "while": if (PeekToken().Type == TokenType.Dot) { statement = ParseExpressionStatement(); } else { statement = ParseWhileStatement(); } break; case "break": statement = Open <ScriptBreakStatement>(); NextToken(); Close(statement); // This has to be done at execution time, because of the wrap statement //if (!IsInLoop()) //{ // LogError(statement, "Unexpected statement outside of a loop"); //} ExpectEndOfStatement(statement); break; case "continue": statement = Open <ScriptContinueStatement>(); NextToken(); Close(statement); // This has to be done at execution time, because of the wrap statement //if (!IsInLoop()) //{ // LogError(statement, "Unexpected statement outside of a loop"); //} ExpectEndOfStatement(statement); break; case "func": statement = ParseFunctionStatement(false); break; case "ret": statement = ParseReturnStatement(); break; case "capture": statement = ParseCaptureStatement(); break; default: // Otherwise it is an expression statement statement = ParseExpressionStatement(); break; } break; default: if (StartAsExpression()) { statement = ParseExpressionStatement(); } else { nextStatement = false; LogError($"Unexpected token {Current.Type}"); } break; } } else { nextStatement = false; LogError($"Unexpected token {Current.Type} while not in a code block {{ ... }}"); // LOG an ERROR. Don't expect any other tokens outside a code section } break; } return(nextStatement); }
private void ParseScribanStatement(string identifier, ScriptStatement parent, ref ScriptStatement statement, ref bool hasEnd, ref bool nextStatement) { var startToken = Current; switch (identifier) { case "end": hasEnd = true; nextStatement = false; if (_isKeepTrivia) { _trivias.Add(new ScriptTrivia(CurrentSpan, ScriptTriviaType.End, _lexer.Text)); } NextToken(); var matchingStatement = FindFirstStatementExpectingEnd(); ExpectEndOfStatement(matchingStatement); if (_isKeepTrivia) { FlushTrivias(matchingStatement, false); } break; case "wrap": CheckNotInCase(parent, startToken); statement = ParseWrapStatement(); break; case "if": CheckNotInCase(parent, startToken); statement = ParseIfStatement(false, false); break; case "case": CheckNotInCase(parent, startToken); statement = ParseCaseStatement(); break; case "when": var whenStatement = ParseWhenStatement(); var whenParent = parent as ScriptConditionStatement; if (parent is ScriptWhenStatement) { ((ScriptWhenStatement)whenParent).Next = whenStatement; } else if (parent is ScriptCaseStatement) { statement = whenStatement; } else { nextStatement = false; // unit test: TODO LogError(startToken, "A `when` condition must be preceded by another `when`/`else`/`case` condition"); } hasEnd = true; break; case "else": var nextCondition = ParseElseStatement(false); var parentCondition = parent as ScriptConditionStatement; if (parent is ScriptIfStatement || parent is ScriptWhenStatement) { if (parent is ScriptIfStatement) { ((ScriptIfStatement)parentCondition).Else = nextCondition; } else { ((ScriptWhenStatement)parentCondition).Next = nextCondition; } } else { nextStatement = false; // unit test: 201-if-else-error3.txt LogError(startToken, "A else condition must be preceded by another if/else/when condition"); } hasEnd = true; break; case "for": CheckNotInCase(parent, startToken); if (PeekToken().Type == TokenType.Dot) { statement = ParseExpressionStatement(); } else { statement = ParseForStatement <ScriptForStatement>(); } break; case "tablerow": CheckNotInCase(parent, startToken); if (PeekToken().Type == TokenType.Dot) { statement = ParseExpressionStatement(); } else { statement = ParseForStatement <ScriptTableRowStatement>(); } break; case "with": CheckNotInCase(parent, startToken); statement = ParseWithStatement(); break; case "import": CheckNotInCase(parent, startToken); statement = ParseImportStatement(); break; case "readonly": CheckNotInCase(parent, startToken); statement = ParseReadOnlyStatement(); break; case "while": CheckNotInCase(parent, startToken); if (PeekToken().Type == TokenType.Dot) { statement = ParseExpressionStatement(); } else { statement = ParseWhileStatement(); } break; case "break": CheckNotInCase(parent, startToken); statement = Open <ScriptBreakStatement>(); NextToken(); ExpectEndOfStatement(statement); Close(statement); // This has to be done at execution time, because of the wrap statement //if (!IsInLoop()) //{ // LogError(statement, "Unexpected statement outside of a loop"); //} break; case "continue": CheckNotInCase(parent, startToken); statement = Open <ScriptContinueStatement>(); NextToken(); ExpectEndOfStatement(statement); Close(statement); // This has to be done at execution time, because of the wrap statement //if (!IsInLoop()) //{ // LogError(statement, "Unexpected statement outside of a loop"); //} break; case "func": CheckNotInCase(parent, startToken); statement = ParseFunctionStatement(false); break; case "ret": CheckNotInCase(parent, startToken); statement = ParseReturnStatement(); break; case "capture": CheckNotInCase(parent, startToken); statement = ParseCaptureStatement(); break; default: CheckNotInCase(parent, startToken); // Otherwise it is an expression statement statement = ParseExpressionStatement(); break; } }
private static PrototypeMember ParseFunctionStatement(ScriptProcessor processor, ScriptStatement statement) { string code = statement.Code; List<string> signature = code.Remove(code.IndexOf("(")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string identifier; bool isStatic = false; bool isIndexerGet = false; bool isIndexerSet = false; // Read static: if (signature.Contains(FUNCTION_SIGNATURE_STATIC)) { isStatic = true; signature.Remove(FUNCTION_SIGNATURE_STATIC); } // Read indexer: if (signature.Contains(FUNCTION_SIGNATURE_INDEXER)) { int indexerIndex = signature.IndexOf(FUNCTION_SIGNATURE_INDEXER); if (indexerIndex + 1 == signature.Count) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_EXPECTED_TYPE); string indexerType = signature[indexerIndex + 1]; if (indexerType == FUNCTION_SIGNATURE_GET) { isIndexerGet = true; signature.RemoveAt(indexerIndex + 1); } else if (indexerType == FUNCTION_SIGNATURE_SET) { isIndexerSet = true; signature.RemoveAt(indexerIndex + 1); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_INVALID_TYPE, new object[] { indexerType }); } signature.Remove(FUNCTION_SIGNATURE_INDEXER); } if (signature.Count != 2) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_FUNCTION_SIGNATURE); identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); SFunction function = new SFunction(processor, signature[0] + code.Remove(0, code.IndexOf("("))); return new PrototypeMember(identifier, function, isStatic, false, isIndexerGet, isIndexerSet); }
private void ParseLiquidStatement(string identifier, ScriptStatement parent, ref ScriptStatement statement, ref bool hasEnd, ref bool nextStatement) { Token startToken = Current; if (!_isLiquidTagSection) { statement = ParseLiquidExpressionStatement(parent); return; } if (identifier != "when" && identifier != "case" && !identifier.StartsWith("end") && parent is ScriptCaseStatement) { // 205-case-when-statement-error1.txt LogError(startToken, string.Format(RS.UnexpectedTokenInCase, GetAsText(startToken))); } ScriptStatement startStatement = null; string pendingStart = null; switch (identifier) { case "endif": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`if`/`else`"; // Handle after the switch break; case "endifchanged": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`ifchanged`"; // Handle after the switch break; case "endunless": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`unless`"; break; case "endfor": startStatement = FindFirstStatementExpectingEnd() as ScriptForStatement; pendingStart = "`for`"; break; case "endcase": startStatement = FindFirstStatementExpectingEnd() as ScriptCaseStatement; pendingStart = "`case`"; break; case "endcapture": startStatement = FindFirstStatementExpectingEnd() as ScriptCaptureStatement; pendingStart = "`capture`"; break; case "endtablerow": startStatement = FindFirstStatementExpectingEnd() as ScriptTableRowStatement; pendingStart = "`tablerow`"; break; case "case": statement = ParseCaseStatement(); break; case "when": ScriptWhenStatement whenStatement = ParseWhenStatement(); var whenParent = parent as ScriptConditionStatement; if (parent is ScriptWhenStatement) { ((ScriptWhenStatement)whenParent).Next = whenStatement; } else if (parent is ScriptCaseStatement) { statement = whenStatement; } else { nextStatement = false; // unit test: TODO LogError(startToken, RS.WhenConditionSyntaxError); } hasEnd = true; break; case "if": statement = ParseIfStatement(false, false); break; case "ifchanged": statement = ParseLiquidIfChanged(); break; case "unless": CheckNotInCase(parent, startToken); statement = ParseIfStatement(true, false); break; case "else": case "elsif": ScriptConditionStatement nextCondition = ParseElseStatement(identifier == "elsif"); var parentCondition = parent as ScriptConditionStatement; if (parent is ScriptIfStatement || parent is ScriptWhenStatement) { if (parent is ScriptIfStatement) { ((ScriptIfStatement)parentCondition).Else = nextCondition; } else { if (identifier == "elsif") { LogError(startToken, RS.ElseIfConditionSyntaxError); } ((ScriptWhenStatement)parentCondition).Next = nextCondition; } } else { nextStatement = false; // unit test: 201-if-else-error3.txt LogError(startToken, RS.ElseConditionSyntaxError); } hasEnd = true; break; case "for": statement = ParseForStatement <ScriptForStatement>(); break; case "tablerow": statement = ParseForStatement <ScriptTableRowStatement>(); break; case "cycle": statement = ParseLiquidCycleStatement(); break; case "break": statement = Open <ScriptBreakStatement>(); NextToken(); ExpectEndOfStatement(statement); Close(statement); break; case "continue": statement = Open <ScriptContinueStatement>(); NextToken(); ExpectEndOfStatement(statement); Close(statement); break; case "assign": if (_isKeepTrivia) { _trivias.Clear(); } NextToken(); // skip assign Token token = _token; // Try to parse an expression ScriptExpressionStatement expressionStatement = ParseExpressionStatement(); // If we don't have an assign expression, this is not a valid assign if (!(expressionStatement.Expression is ScriptAssignExpression)) { LogError(token, RS.ExpectAssignmentExpression); } statement = expressionStatement; break; case "capture": statement = ParseCaptureStatement(); break; case "increment": statement = ParseLiquidIncDecStatement(false); break; case "decrement": statement = ParseLiquidIncDecStatement(true); break; case "include": statement = ParseLiquidIncludeStatement(); break; default: statement = ParseLiquidExpressionStatement(parent); break; } if (pendingStart != null) { if (_isKeepTrivia) { _trivias.Add(new ScriptTrivia(CurrentSpan, ScriptTriviaType.End)); } NextToken(); hasEnd = true; nextStatement = false; if (startStatement == null) { LogError(startToken, string.Format(RS.IdentifierPendingStartMissing, pendingStart, identifier)); } ExpectEndOfStatement(startStatement); if (_isKeepTrivia) { FlushTrivias(startStatement, false); } } }
// TODO: C# 7: put proper Tuple handling in place. private static Tuple<PrototypeMember, string> ParseVarStatement(ScriptProcessor processor, ScriptStatement statement) { var code = statement.Code; var signature = code.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string identifier; var assignment = ""; var isReadOnly = false; var isStatic = false; // Read static: if (signature.Contains(VAR_SIGNATURE_STATIC)) { isStatic = true; signature.Remove(VAR_SIGNATURE_STATIC); } // Read readonly: if (signature.Contains(VAR_SIGNATURE_READONLY)) { isReadOnly = true; signature.Remove(VAR_SIGNATURE_READONLY); } if (signature[0] != "var" || signature.Count < 2) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION); identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); if (signature.Count > 2) { if (signature[2].StartsWith("=")) { assignment = code.Remove(0, code.IndexOf("=") + 1).Trim(); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION); } } var member = new PrototypeMember(identifier, processor.Undefined, isStatic, isReadOnly, false, false); return new Tuple<PrototypeMember, string>(member, assignment); }
private void ParseLiquidStatement(string identifier, ScriptNode parent, ref ScriptStatement statement, ref bool hasEnd, ref bool nextStatement) { var startToken = Current; if (!_isLiquidTagSection) { statement = ParseLiquidExpressionStatement(parent); return; } if (identifier != "when" && identifier != "case" && !identifier.StartsWith("end") && parent is ScriptCaseStatement) { // 205-case-when-statement-error1.txt LogError(startToken, $"Unexpected statement/expression `{GetAsText(startToken)}` in the body of a `case` statement. Only `when`/`else` are expected."); } ScriptStatement startStatement = null; string pendingStart = null; switch (identifier) { case "endif": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`if`/`else`"; // Handle after the switch break; case "endifchanged": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`ifchanged`"; // Handle after the switch break; case "endunless": startStatement = FindFirstStatementExpectingEnd() as ScriptIfStatement; pendingStart = "`unless`"; break; case "endfor": startStatement = FindFirstStatementExpectingEnd() as ScriptForStatement; pendingStart = "`for`"; break; case "endcase": startStatement = FindFirstStatementExpectingEnd() as ScriptCaseStatement; pendingStart = "`case`"; break; case "endcapture": startStatement = FindFirstStatementExpectingEnd() as ScriptCaptureStatement; pendingStart = "`capture`"; break; case "endtablerow": startStatement = FindFirstStatementExpectingEnd() as ScriptTableRowStatement; pendingStart = "`tablerow`"; break; case "case": statement = ParseCaseStatement(); break; case "when": var whenStatement = ParseWhenStatement(); var whenParent = parent as ScriptConditionStatement; if (parent is ScriptWhenStatement) { ((ScriptWhenStatement)whenParent).Next = whenStatement; } else if (parent is ScriptCaseStatement) { statement = whenStatement; } else { nextStatement = false; // unit test: TODO LogError(startToken, "A `when` condition must be preceded by another `when`/`else`/`case` condition"); } hasEnd = true; break; case "if": statement = ParseIfStatement(false); break; case "ifchanged": statement = ParseLiquidIfChanged(); break; case "unless": CheckNotInCase(parent, startToken); statement = ParseIfStatement(true); break; case "else": case "elsif": var nextCondition = ParseElseStatement(identifier == "elsif"); var parentCondition = parent as ScriptConditionStatement; if (parent is ScriptIfStatement || parent is ScriptWhenStatement) { if (parent is ScriptIfStatement) { ((ScriptIfStatement)parentCondition).Else = nextCondition; } else { if (identifier == "elseif") { LogError(startToken, "A elsif condition is not allowed within a when/case condition"); } ((ScriptWhenStatement)parentCondition).Next = nextCondition; } } else if (identifier == "else" && parent is ScriptForStatement forStatement) { forStatement.Else = (ScriptElseStatement)nextCondition; } else { nextStatement = false; // unit test: 201-if-else-error3.txt LogError(startToken, identifier == "else" ? "A else condition must be preceded by another if/else/unless condition or a for loop." : "A else condition must be preceded by another if/else/unless."); } hasEnd = true; break; case "for": var localForStatement = ParseForStatement <ScriptForStatement>(); localForStatement.SetContinue = true; statement = localForStatement; break; case "tablerow": statement = ParseForStatement <ScriptTableRowStatement>(); break; case "cycle": statement = ParseLiquidCycleStatement(); break; case "break": var breakStatement = Open <ScriptBreakStatement>(); statement = breakStatement; ExpectAndParseKeywordTo(breakStatement.BreakKeyword); ExpectEndOfStatement(); Close(statement); break; case "continue": var continueStatement = Open <ScriptContinueStatement>(); statement = continueStatement; ExpectAndParseKeywordTo(continueStatement.ContinueKeyword); // Parse continue keyword ExpectEndOfStatement(); FlushTriviasToLastTerminal(); Close(statement); break; case "assign": { if (_isKeepTrivia) { _trivias.Clear(); } NextToken(); // skip assign var token = _token; // Try to parse an expression var expressionStatement = ParseExpressionStatement(); // If we don't have an assign expression, this is not a valid assign if (!(expressionStatement is ScriptExpressionStatement exprStatementFinal && exprStatementFinal.Expression is ScriptAssignExpression)) { LogError(token, "Expecting an assign expression: <variable> = <expression>"); } statement = expressionStatement; } break; case "capture": statement = ParseCaptureStatement(); break; case "increment": statement = ParseLiquidIncDecStatement(false); break; case "decrement": statement = ParseLiquidIncDecStatement(true); break; case "include": statement = ParseLiquidIncludeStatement(); break; default: statement = ParseLiquidExpressionStatement(parent); break; } if (pendingStart != null) { var endStatement = Open <ScriptEndStatement>(); NextToken(); statement = Close(endStatement); hasEnd = true; nextStatement = true; if (startStatement == null) { LogError(startToken, $"Unable to find a pending {pendingStart} for this `{identifier}`"); } } }
public ScriptSwitchCaseStatement(AstNodeArgs args) : base(args) { _cond = ChildNodes[1] as ScriptExpr; _statement = ChildNodes[3] as ScriptStatement; }
private bool TryParseStatement(ScriptNode parent, bool parseEndOfStatementAfterEnd, out ScriptStatement statement, out bool hasEnd) { hasEnd = false; bool nextStatement = true; statement = null; continueParsing: if (_hasFatalError) { return(false); } if (_pendingStatements.Count > 0) { statement = _pendingStatements.Dequeue(); return(true); } switch (Current.Type) { case TokenType.Eof: // Early exit nextStatement = false; break; case TokenType.Raw: case TokenType.Escape: statement = ParseRawStatement(); if (parent is ScriptCaseStatement) { // In case we have a raw statement within directly a case // we don't keep it statement = null; goto continueParsing; } break; case TokenType.CodeEnter: case TokenType.LiquidTagEnter: case TokenType.CodeExit: case TokenType.LiquidTagExit: case TokenType.EscapeEnter: case TokenType.EscapeExit: statement = ParseEscapeStatement(); break; case TokenType.FrontMatterMarker: if (_inFrontMatter) { _inFrontMatter = false; _inCodeSection = false; // Parse the frontmatter end-marker ExpectAndParseTokenTo(_frontmatter.EndMarker, TokenType.FrontMatterMarker); Close(_frontmatter); _frontmatter.TextPositionAfterEndMarker = Current.Start; if (CurrentParsingMode == ScriptMode.FrontMatterAndContent || CurrentParsingMode == ScriptMode.FrontMatterOnly) { // Once the FrontMatter has been parsed, we can switch to default parsing mode. CurrentParsingMode = ScriptMode.Default; nextStatement = false; } } else { LogError($"Unexpected frontmatter marker `{_lexer.Options.FrontMatterMarker}` while not inside a frontmatter"); NextToken(); } break; default: if (_inCodeSection) { switch (Current.Type) { case TokenType.NewLine: case TokenType.SemiColon: PushTokenToTrivia(); NextToken(); goto continueParsing; case TokenType.Identifier: case TokenType.IdentifierSpecial: var identifier = GetAsText(Current); if (_isLiquid) { ParseLiquidStatement(identifier, parent, ref statement, ref hasEnd, ref nextStatement); } else { ParseScribanStatement(identifier, parent, parseEndOfStatementAfterEnd, ref statement, ref hasEnd, ref nextStatement); } break; default: if (IsStartOfExpression()) { statement = ParseExpressionStatement(); } else { nextStatement = false; LogError($"Unexpected token {GetAsText(Current)}"); } break; } } else { nextStatement = false; LogError($"Unexpected token {GetAsText(Current)} while not in a code block {{ ... }}"); // LOG an ERROR. Don't expect any other tokens outside a code section } break; } return(nextStatement); }
private static PrototypeMember ParseFunctionStatement(ScriptProcessor processor, ScriptStatement headerStatement, ScriptStatement bodyStatement) { var header = headerStatement.Code; var signature = header.Remove(header.IndexOf("(")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string identifier; var isStatic = false; var isIndexerGet = false; var isIndexerSet = false; var functionType = FunctionUsageType.Default; var significantCount = 0; // Read static: if (signature.Contains(FUNCTION_SIGNATURE_STATIC)) { isStatic = true; signature.Remove(FUNCTION_SIGNATURE_STATIC); } // Read indexer: if (signature.Contains(FUNCTION_SIGNATURE_INDEXER)) { significantCount++; var indexerIndex = signature.IndexOf(FUNCTION_SIGNATURE_INDEXER); if (indexerIndex + 1 == signature.Count) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_EXPECTED_TYPE); var indexerType = signature[indexerIndex + 1]; if (indexerType == FUNCTION_SIGNATURE_GET) { isIndexerGet = true; signature.RemoveAt(indexerIndex + 1); } else if (indexerType == FUNCTION_SIGNATURE_SET) { isIndexerSet = true; signature.RemoveAt(indexerIndex + 1); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_INVALID_TYPE, indexerType); } signature.Remove(FUNCTION_SIGNATURE_INDEXER); } // Read property: if (signature.Contains(FUNCTION_SIGNATURE_PROPERTY)) { significantCount++; var propertyIndex = signature.IndexOf(FUNCTION_SIGNATURE_PROPERTY); if (propertyIndex + 1 == signature.Count) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_EXPECTED_TYPE); var propertyType = signature[propertyIndex + 1]; if (propertyType == FUNCTION_SIGNATURE_GET) { functionType = FunctionUsageType.PropertyGetter; signature.RemoveAt(propertyIndex + 1); } else if (propertyType == FUNCTION_SIGNATURE_SET) { functionType = FunctionUsageType.PropertySetter; signature.RemoveAt(propertyIndex + 1); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_INVALID_TYPE, propertyType); } signature.Remove(FUNCTION_SIGNATURE_PROPERTY); } // Only one (or none) significant signature types can be added to a signature. if (significantCount > 1) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INCOMPATIBLE_SIGNATURE); if (signature.Count != 2) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_FUNCTION_SIGNATURE); identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); // After the valid identifier check is done, we add the getter/setter prefix. It wouldn't pass the test. if (functionType == FunctionUsageType.PropertyGetter) identifier = PROPERTY_GET_PREFIX + identifier; if (functionType == FunctionUsageType.PropertySetter) identifier = PROPERTY_SET_PREFIX + identifier; var function = new SFunction(processor, signature[0] + " " + header.Remove(0, header.IndexOf("(")) + bodyStatement.Code) { FunctionUsage = functionType }; return new PrototypeMember(identifier, function, isStatic, false, isIndexerGet, isIndexerSet); }
private static PrototypeMember ParseFunctionStatement(ScriptProcessor processor, ScriptStatement headerStatement, ScriptStatement bodyStatement) { var header = headerStatement.Code; var signature = header.Remove(header.IndexOf("(")).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string identifier; var isStatic = false; var isIndexerGet = false; var isIndexerSet = false; var functionType = FunctionUsageType.Default; var significantCount = 0; // Read static: if (signature.Contains(FUNCTION_SIGNATURE_STATIC)) { isStatic = true; signature.Remove(FUNCTION_SIGNATURE_STATIC); } // Read indexer: if (signature.Contains(FUNCTION_SIGNATURE_INDEXER)) { significantCount++; var indexerIndex = signature.IndexOf(FUNCTION_SIGNATURE_INDEXER); if (indexerIndex + 1 == signature.Count) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_EXPECTED_TYPE); } var indexerType = signature[indexerIndex + 1]; if (indexerType == FUNCTION_SIGNATURE_GET) { isIndexerGet = true; signature.RemoveAt(indexerIndex + 1); } else if (indexerType == FUNCTION_SIGNATURE_SET) { isIndexerSet = true; signature.RemoveAt(indexerIndex + 1); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_INDEXER_INVALID_TYPE, indexerType); } signature.Remove(FUNCTION_SIGNATURE_INDEXER); } // Read property: if (signature.Contains(FUNCTION_SIGNATURE_PROPERTY)) { significantCount++; var propertyIndex = signature.IndexOf(FUNCTION_SIGNATURE_PROPERTY); if (propertyIndex + 1 == signature.Count) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_EXPECTED_TYPE); } var propertyType = signature[propertyIndex + 1]; if (propertyType == FUNCTION_SIGNATURE_GET) { functionType = FunctionUsageType.PropertyGetter; signature.RemoveAt(propertyIndex + 1); } else if (propertyType == FUNCTION_SIGNATURE_SET) { functionType = FunctionUsageType.PropertySetter; signature.RemoveAt(propertyIndex + 1); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_FUNCTION_PROPERTY_INVALID_TYPE, propertyType); } signature.Remove(FUNCTION_SIGNATURE_PROPERTY); } // Only one (or none) significant signature types can be added to a signature. if (significantCount > 1) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INCOMPATIBLE_SIGNATURE); } if (signature.Count != 2) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_FUNCTION_SIGNATURE); } identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); } // After the valid identifier check is done, we add the getter/setter prefix. It wouldn't pass the test. if (functionType == FunctionUsageType.PropertyGetter) { identifier = PROPERTY_GET_PREFIX + identifier; } if (functionType == FunctionUsageType.PropertySetter) { identifier = PROPERTY_SET_PREFIX + identifier; } var function = new SFunction(processor, signature[0] + " " + header.Remove(0, header.IndexOf("(")) + bodyStatement.Code) { FunctionUsage = functionType }; return(new PrototypeMember(identifier, function, isStatic, false, isIndexerGet, isIndexerSet)); }
private List <ScriptStatement> BreakIntoStatements(string query, bool ansiQuotes, bool noBackslashEscapes) { string str1 = this.delimiter; int num1 = 0; List <ScriptStatement> list = new List <ScriptStatement>(); List <int> lineNumbers = this.BreakScriptIntoLines(query); MySqlTokenizer tokenizer = new MySqlTokenizer(query); tokenizer.AnsiQuotes = ansiQuotes; tokenizer.BackslashEscapes = !noBackslashEscapes; for (string str2 = tokenizer.NextToken(); str2 != null; str2 = tokenizer.NextToken()) { if (!tokenizer.Quoted) { if (str2.ToLower(CultureInfo.InvariantCulture) == "delimiter") { tokenizer.NextToken(); this.AdjustDelimiterEnd(query, tokenizer); str1 = query.Substring(tokenizer.StartIndex, tokenizer.StopIndex - tokenizer.StartIndex + 1).Trim(); num1 = tokenizer.StopIndex; } else { if (str1.StartsWith(str2) && tokenizer.StartIndex + str1.Length <= query.Length && query.Substring(tokenizer.StartIndex, str1.Length) == str1) { str2 = str1; tokenizer.Position = tokenizer.StartIndex + str1.Length; tokenizer.StopIndex = tokenizer.Position; } int num2 = str2.IndexOf(str1, StringComparison.InvariantCultureIgnoreCase); if (num2 != -1) { int num3 = tokenizer.StopIndex - str2.Length + num2; if (tokenizer.StopIndex == query.Length - 1) { ++num3; } string str3 = query.Substring(num1, num3 - num1); ScriptStatement scriptStatement = new ScriptStatement(); scriptStatement.text = str3.Trim(); scriptStatement.line = FindLineNumber(num1, lineNumbers); scriptStatement.position = num1 - lineNumbers[scriptStatement.line]; list.Add(scriptStatement); num1 = num3 + str1.Length; } } } } if (num1 < query.Length - 1) { string str2 = query.Substring(num1).Trim(); if (!string.IsNullOrEmpty(str2)) { ScriptStatement scriptStatement = new ScriptStatement(); scriptStatement.text = str2; scriptStatement.line = FindLineNumber(num1, lineNumbers); scriptStatement.position = num1 - lineNumbers[scriptStatement.line]; list.Add(scriptStatement); } } return(list); }
public ScriptExpressionAsStatement(ScriptStatement statement) { Statement = statement; }
public ScriptWhileStatement(AstNodeArgs args) : base(args) { Condition = args.ChildNodes[1] as ScriptCondition; Statement = args.ChildNodes[2] as ScriptStatement; }
private bool TryParseStatement(ScriptStatement parent, out ScriptStatement statement, out bool hasEnd) { hasEnd = false; bool nextStatement = true; statement = null; continueParsing: if (_hasFatalError) { return(false); } if (_pendingStatements.Count > 0) { statement = _pendingStatements.Dequeue(); return(true); } switch (Current.Type) { case TokenType.Eof: // Early exit nextStatement = false; break; case TokenType.Raw: case TokenType.Escape: statement = ParseRawStatement(); if (parent is ScriptCaseStatement) { // In case we have a raw statement within directly a case // we don't keep it statement = null; goto continueParsing; } break; case TokenType.CodeEnter: case TokenType.LiquidTagEnter: if (_inCodeSection) { LogError("Unexpected token while already in a code block"); } _isLiquidTagSection = Current.Type == TokenType.LiquidTagEnter; _inCodeSection = true; // If we have any pending trivias before processing this code enter and we want to keep trivia // we need to generate a RawStatement to store these trivias if (_isKeepTrivia && (_trivias.Count > 0 || Previous.Type == TokenType.CodeEnter)) { var rawStatement = Open <ScriptRawStatement>(); Close(rawStatement); if (_trivias.Count > 0) { rawStatement.Trivias.After.AddRange(rawStatement.Trivias.Before); rawStatement.Trivias.Before.Clear(); var firstTriviaSpan = rawStatement.Trivias.After[0].Span; var lastTriviaSpan = rawStatement.Trivias.After[rawStatement.Trivias.After.Count - 1].Span; rawStatement.Span = new SourceSpan(firstTriviaSpan.FileName, firstTriviaSpan.Start, lastTriviaSpan.End); } else { // Else Add an empty trivia rawStatement.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Empty, null), false); } statement = rawStatement; } NextToken(); if (Current.Type == TokenType.CodeExit) { var nopStatement = Open <ScriptNopStatement>(); Close(nopStatement); if (statement == null) { statement = nopStatement; } else { _pendingStatements.Enqueue(nopStatement); } } // If we have a ScriptRawStatement previously defined, we need to break out of the loop to record it if (statement == null) { goto continueParsing; } break; case TokenType.FrontMatterMarker: if (_inFrontMatter) { _inFrontMatter = false; _inCodeSection = false; // When we expect to parse only the front matter, don't try to tokenize the following text // Keep the current token as the code exit of the front matter if (CurrentParsingMode != ScriptMode.FrontMatterOnly) { NextToken(); } if (CurrentParsingMode == ScriptMode.FrontMatterAndContent || CurrentParsingMode == ScriptMode.FrontMatterOnly) { // Once the FrontMatter has been parsed, we can switch to default parsing mode. CurrentParsingMode = ScriptMode.Default; nextStatement = false; } } else { LogError($"Unexpected frontmatter marker `{_lexer.Options.FrontMatterMarker}` while not inside a frontmatter"); NextToken(); } break; case TokenType.CodeExit: case TokenType.LiquidTagExit: if (!_inCodeSection) { LogError("Unexpected code block exit '}}' while no code block enter '{{' has been found"); } else if (CurrentParsingMode == ScriptMode.ScriptOnly) { LogError("Unexpected code clock exit '}}' while parsing in script only mode. '}}' is not allowed."); } _isLiquidTagSection = false; _inCodeSection = false; // We clear any trivia that might not have been takend by a node // so that they don't end up after this token if (_isKeepTrivia) { _trivias.Clear(); } NextToken(); // If next token is directly a code enter or an eof but we want to keep trivia // and with have trivias // we need to generate a RawStatement to store these trivias if (_isKeepTrivia && (Current.Type == TokenType.CodeEnter || Current.Type == TokenType.Eof)) { var rawStatement = Open <ScriptRawStatement>(); Close(rawStatement); if (_trivias.Count > 0) { var firstTriviaSpan = rawStatement.Trivias.Before[0].Span; var lastTriviaSpan = rawStatement.Trivias.Before[rawStatement.Trivias.Before.Count - 1].Span; rawStatement.Span = new SourceSpan(firstTriviaSpan.FileName, firstTriviaSpan.Start, lastTriviaSpan.End); } else { // Else Add an empty trivia rawStatement.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Empty, null), false); } statement = rawStatement; } else { goto continueParsing; } break; default: if (_inCodeSection) { switch (Current.Type) { case TokenType.NewLine: case TokenType.SemiColon: PushTokenToTrivia(); NextToken(); goto continueParsing; case TokenType.Identifier: case TokenType.IdentifierSpecial: var identifier = GetAsText(Current); if (_isLiquid) { ParseLiquidStatement(identifier, parent, ref statement, ref hasEnd, ref nextStatement); } else { ParseScribanStatement(identifier, parent, ref statement, ref hasEnd, ref nextStatement); } break; default: if (StartAsExpression()) { statement = ParseExpressionStatement(); } else { nextStatement = false; LogError($"Unexpected token {Current.Type}"); } break; } } else { nextStatement = false; LogError($"Unexpected token {Current.Type} while not in a code block {{ ... }}"); // LOG an ERROR. Don't expect any other tokens outside a code section } break; } return(nextStatement); }
// TODO: C# 7: put proper Tuple handling in place. private static Tuple <PrototypeMember, string> ParseVarStatement(ScriptProcessor processor, ScriptStatement statement) { var code = statement.Code; var signature = code.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); string identifier; var assignment = ""; var isReadOnly = false; var isStatic = false; // Read static: if (signature.Contains(VAR_SIGNATURE_STATIC)) { isStatic = true; signature.Remove(VAR_SIGNATURE_STATIC); } // Read readonly: if (signature.Contains(VAR_SIGNATURE_READONLY)) { isReadOnly = true; signature.Remove(VAR_SIGNATURE_READONLY); } if (signature[0] != "var" || signature.Count < 2) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION); } identifier = signature[1]; if (!ScriptProcessor.IsValidIdentifier(identifier)) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); } if (signature.Count > 2) { if (signature[2].StartsWith("=")) { assignment = code.Remove(0, code.IndexOf("=") + 1).Trim(); } else { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_CLASS_INVALID_VAR_DECLARATION); } } var member = new PrototypeMember(identifier, processor.Undefined, isStatic, isReadOnly, false, false); return(new Tuple <PrototypeMember, string>(member, assignment)); }
public Expression GetStatementExpression(ExpressContext expressContext, ParameterExpression stringBuilderParameter, ScriptStatement scriptStatement, ParameterFinder parameterFinder) { var appendMethodInfo = typeof(StringBuilder).GetMethod("Append", new[] { typeof(string) }); switch (scriptStatement) { case ScriptRawStatement scriptRawStatement: var constant = Expression.Constant(scriptRawStatement.ToString()); var methodCall = Expression.Call(stringBuilderParameter, appendMethodInfo, constant); return(methodCall); case ScriptExpressionStatement scriptExpressionStatement: var expressionBody = expressionGenerator.GetExpressionBody(scriptExpressionStatement.Expression, parameterFinder, null); expressionBody = AddToString(expressionBody); var scriptmethodCall = Expression.Call(stringBuilderParameter, appendMethodInfo, expressionBody); return(scriptmethodCall); case ScriptIfStatement scriptIfStatement: var predicateExpression = expressionGenerator.GetExpressionBody(scriptIfStatement.Condition, parameterFinder, null); var trueStatementBlock = GetStatementExpression(expressContext, stringBuilderParameter, scriptIfStatement.Then, parameterFinder); if (scriptIfStatement.Else != null) { var elseStatment = GetStatementExpression(expressContext, stringBuilderParameter, scriptIfStatement.Else, parameterFinder); ConditionalExpression ifThenElseExpr = Expression.IfThenElse(predicateExpression, trueStatementBlock, elseStatment); return(ifThenElseExpr); } else { ConditionalExpression ifThenExpr = Expression.IfThen(predicateExpression, trueStatementBlock); return(ifThenExpr); } case ScriptElseStatement scriptElseStatement: var elseStatmentExpression = GetStatementExpression(expressContext, stringBuilderParameter, scriptElseStatement.Body, parameterFinder); return(elseStatmentExpression); case ScriptBlockStatement scriptBlockStatement: List <Expression> statements = new List <Expression>(); foreach (var statement in scriptBlockStatement.Statements) { try { statements.Add(GetStatementExpression(expressContext, stringBuilderParameter, statement, parameterFinder)); } catch (SpanException ex) { logger.LogError(ex, "Failed to build: {statement}", statement); expressContext.Messages.Add(new LogMessage(ParserMessageType.Error, ex.Span, ex.Message)); } catch (Exception ex) { logger.LogError(ex, "Statement Failed to build: {statement}", statement); expressContext.Messages.Add(new LogMessage(ParserMessageType.Error, scriptBlockStatement.Span, $"Statement Failed to build: {statement?.GetType()}")); } } var blockExpression = Expression.Block(statements); return(blockExpression); case ScriptForStatement scriptForStatement: // foreach(item in items) var itemsExpression = expressionGenerator.GetExpressionBody(scriptForStatement.Iterator, parameterFinder, null); var itemVariableName = (scriptForStatement.Variable as ScriptVariableGlobal).Name; var itemType = itemsExpression.Type.GenericTypeArguments[0]; ParameterExpression itemVariable = Expression.Parameter(itemType, itemVariableName); using (var scopedParameterFinder = parameterFinder.CreateScope()) { scopedParameterFinder.AddLocalVariable(itemVariable); var body = GetStatementExpression(expressContext, stringBuilderParameter, scriptForStatement.Body, scopedParameterFinder); var foreachExpression = ExpressionHelpers.ForEach(itemsExpression, itemVariable, body); return(foreachExpression); } default: throw new NotImplementedException("Unknown ScriptStatement"); } }
public ScriptSwitchDefaultStatement(AstNodeArgs args) : base(args) { Statement = ChildNodes[2] as ScriptStatement; }