private ParserState ParseDialogBlock(ParserState state)
        {
            string dialog      = state.ConsumeBlock(Sym.DialogOpen, Sym.DialogClose);
            var    dialogState = new ParserState(new BlockNode(BlockMode.Dialog), dialog);

            dialogState = ParseDialog(dialogState);
            state.CurNode.AddChild(dialogState.RootNode);
            return(state);
        }
        private ParserState ParseCodeBlock(ParserState state)
        {
            string code      = state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose);
            var    codeState = new ParserState(new BlockNode(BlockMode.Code), code);

            codeState = ParseCode(codeState);
            state.CurNode.AddChild(codeState.RootNode);
            return(state);
        }
        private ParserState ParseFunction(ParserState state, string funcName)
        {
            var builder = Utils.GetTempStringBuilder();
            var args    = new List <Node>();

            while (!(state.Char() == Sym.cLineBreak || state.Done()))
            {
                if (state.MatchAhead(Sym.CodeOpen))
                {
                    var codeState = new ParserState(new BlockNode(BlockMode.Code), state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose));
                    codeState = ParseCode(codeState);
                    args.Add(codeState.RootNode);
                    builder.Length = 0;
                }
                else if (state.MatchAhead(Sym.String))
                {
                    var str = state.ConsumeBlock(Sym.String, Sym.String);
                    args.Add(new LiteralNode(str));
                    builder.Length = 0;
                }
                else if (state.Char() == ' ' && builder.Length > 0)
                {
                    args.Add(StringToValueNode(builder.ToString().Trim()));
                    builder.Length = 0;
                }
                else
                {
                    builder.Append(state.Char());
                }
                state.Step();
            }

            if (builder.Length > 0)
            {
                args.Add(StringToValueNode(builder.ToString().Trim()));
                builder.Length = 0;
            }
            Utils.Release(builder);

            state.CurNode.AddChild(new FuncNode(funcName, args.ToArray()));
            return(state);
        }
        private Node Parse(string script)
        {
            var state = new ParserState(new BlockNode(BlockMode.Dialog), script);

            if (state.MatchAhead(Sym.DialogOpen))
            {
                var dialog = state.ConsumeBlock(Sym.DialogOpen, Sym.DialogClose);
                state = new ParserState(new BlockNode(BlockMode.Dialog), dialog);
                state = ParseDialog(state);
            }
            // NOTE: This causes problems when you lead with a code block
            //else if (state.MatchAhead(Sym.CodeOpen))
            //{
            //    state = ParseCodeBlock(state);
            //}
            else
            {
                state = ParseDialog(state);
            }

            return(state.RootNode);
        }