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);
        }
Exemple #2
0
        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;
            }
        }
Exemple #3
0
        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.");
     }
 }
Exemple #9
0
        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);
        }
Exemple #10
0
        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;
    }
Exemple #13
0
        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));
        }
Exemple #14
0
        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 }));
        }
Exemple #15
0
        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);
        }
Exemple #16
0
        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));
        }
Exemple #18
0
        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));
        }
Exemple #19
0
        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);
        }
Exemple #20
0
        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);
        }
Exemple #21
0
        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));
        }
Exemple #22
0
 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);
 }
Exemple #24
0
        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);
        }
Exemple #25
0
        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;
            }
        }
Exemple #26
0
        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);
                }
            }
        }
Exemple #28
0
        // 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);
        }
Exemple #29
0
        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;
 }
Exemple #31
0
        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);
        }
Exemple #32
0
        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);
        }
Exemple #33
0
        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);
        }
Exemple #35
0
 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);
        }
Exemple #38
0
        // 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;
 }