Ejemplo n.º 1
0
 public FSMMatch(bool success, N result, string value, LexerPosition position, int nodeId, LexerPosition newPosition, bool isLineEnding)
     : this(success, result, new ReadOnlyMemory <char>(value.ToCharArray()), position, nodeId, newPosition, isLineEnding)
 {
 }
Ejemplo n.º 2
0
        public static Node GetNode(this ExpressionType et, List <Token <TokenType> > expr, LexerPosition exprPos, ref InterpreterState state)
        {
            if (et.IsBlock())
            {
                bool hasArg = et != ExpressionType.ELSE;
                List <List <Token <TokenType> > > args = new List <List <Token <TokenType> > >();
                if (hasArg)
                {
                    args = Interpreter.GetArgs(expr);
                }
                switch (et)
                {
                case ExpressionType.ELSE:
                    return(new ElseNode(exprPos));

                case ExpressionType.IF:
                    args.ThrowIfNotSize(exprPos, 1);
                    return(new IfNode(args.First(), IfNode.IsElseIf(expr), exprPos));

                case ExpressionType.LOOP:
                    args.ThrowIfNotSize(exprPos, 1);
                    return(new LoopNode(args.First(), exprPos));

                case ExpressionType.WHILE:
                    args.ThrowIfNotSize(exprPos, 1);
                    return(new WhileNode(args.First(), exprPos));

                case ExpressionType.FUNCTION_DEFINITION:
                    return(new FunctionDefinitionNode(
                               expr[1].StringWithoutQuotes,
                               args.Select(a => a.AsString()).ToArray(),
                               exprPos
                               ));
                }
            }
            else
            {
                switch (et)
                {
                case ExpressionType.IMPORT:
                    return(new ImportNode(expr[1].StringWithoutQuotes, exprPos));

                case ExpressionType.RETURN:
                    return(new ReturnNode(expr.Skip(1).Reverse().Skip(1).Reverse().ToList(), exprPos));

                case ExpressionType.BREAK:
                    return(new BreakNode(exprPos));

                case ExpressionType.CONTINUE:
                    return(new ContinueNode(exprPos));

                case ExpressionType.FUNCTION_CALL:
                    string name      = expr[0].StringWithoutQuotes;
                    bool   isSysFunc = state.Functions.Any(f => f.Name == name);
                    if (isSysFunc)
                    {
                        return(new FunctionCallNode(
                                   state.Functions.First(f => f.Name.Equals(name)),
                                   Interpreter.GetArgs(expr),
                                   exprPos
                                   ));
                    }
                    else if (state.UserFuncs.Any(f => f.Name == name))
                    {
                        return(new FunctionCallNode(
                                   state.UserFuncs.First(f => f.Name == name),
                                   Interpreter.GetArgs(expr),
                                   exprPos
                                   ));
                    }
                    throw new InterpreterException($"Unkown function \"{name}\" at {exprPos}");

                case ExpressionType.ASSIGNMENT:
                    bool isArray = AssignmentNode.IsArrayAssignment(expr, out bool isIndexer);
                    return(new AssignmentNode(
                               expr[0].StringWithoutQuotes,
                               isIndexer ?
                               AssignmentNode.GetValueOfIndexerAssignment(expr) :
                               expr.Skip(2).Reverse().Skip(1).Reverse().ToList(),
                               isArray,
                               isIndexer,
                               isIndexer ? AssignmentNode.GetIndex(expr) : new List <Token <TokenType> >(),
                               exprPos
                               ));

                case ExpressionType.INCREMENT:
                    return(new IncrementNode(expr[0].StringWithoutQuotes, exprPos));

                case ExpressionType.DECREMENT:
                    return(new DecrementNode(expr[0].StringWithoutQuotes, exprPos));
                }
            }
            return(null);
        }
Ejemplo n.º 3
0
 public AssignmentNode(string name, List <Token <TokenType> > valueTokens, bool isArrayAssignment, bool isIndexer, List <Token <TokenType> > indexTokens, LexerPosition linePosition) : base(linePosition)
 {
     this.name              = name;
     this.valueTokens       = valueTokens;
     this.isArrayAssignment = isArrayAssignment;
     this.isIndexer         = isIndexer;
     this.indexTokens       = indexTokens;
 }
Ejemplo n.º 4
0
        public FSMMatch <N> Run(ReadOnlyMemory <char> source, LexerPosition lexerPosition)
        {
            ConsumeIgnored(source, lexerPosition);

            // End of token stream
            if (lexerPosition.Index >= source.Length)
            {
                return(new FSMMatch <N>(false));
            }

            // Make a note of where current token starts
            var position = lexerPosition.Clone();

            FSMMatch <N> result      = null;
            var          currentNode = Nodes[0];

            while (lexerPosition.Index < source.Length)
            {
                var currentCharacter = source.At(lexerPosition);
                var currentValue     = source.Slice(position.Index, lexerPosition.Index - position.Index + 1);
                currentNode = Move(currentNode, currentCharacter, currentValue);
                if (currentNode == null)
                {
                    // No more viable transitions, so exit loop
                    break;
                }

                if (currentNode.IsEnd)
                {
                    // Remember the possible match
                    result = new FSMMatch <N>(true, currentNode.Value, currentValue, position, currentNode.Id, lexerPosition, currentNode.IsLineEnding);
                }

                lexerPosition.Index++;
                lexerPosition.Column++;
            }

            if (result != null)
            {
                // Backtrack
                var length = result.Result.Value.Length;
                lexerPosition.Index  = result.Result.Position.Index + length;
                lexerPosition.Column = result.Result.Position.Column + length;

                if (HasCallback(result.NodeId))
                {
                    result = Callbacks[result.NodeId](result);
                }

                return(result);
            }

            if (lexerPosition.Index >= source.Length)
            {
                // Failed on last character, so need to backtrack
                lexerPosition.Index  -= 1;
                lexerPosition.Column -= 1;
            }

            var errorChar = source.Slice(lexerPosition.Index, 1);
            var ko        = new FSMMatch <N>(false, default(N), errorChar, lexerPosition, -1, lexerPosition, false);

            return(ko);
        }
Ejemplo n.º 5
0
 public FSMMatch(bool success, N result, ReadOnlyMemory <char> value, LexerPosition position, int nodeId, LexerPosition newPosition)
 {
     Properties  = new Dictionary <string, object>();
     IsSuccess   = success;
     NodeId      = nodeId;
     IsEOS       = false;
     Result      = new Token <N>(result, value, position);
     NewPosition = newPosition;
 }
Ejemplo n.º 6
0
 public IncrementNode(string varName, LexerPosition linePosition) : base(linePosition)
 {
     variableName = varName;
 }
Ejemplo n.º 7
0
 public static T At <T>(this ReadOnlyMemory <T> memory, LexerPosition position)
 {
     return(memory.Span[position.Index]);
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Perform a simple lexical styling of the given range of content.  This will *not*
        /// correctly style many constructs, and it's not smart enough to understand
        /// context.  But it's fast enough that it can style most content while you type, and
        /// it's accurate enough that it's good enough for a first pass.  Various background
        /// threads will be responsible for running the full parser and re-styling the content
        /// more accurately afterward.
        /// </summary>
        /// <param name="editor">The editor that holds the content.</param>
        /// <param name="startPos">The starting character position within the text to style.</param>
        /// <param name="endPos">The ending character position within the text to style.</param>
        /// <param name="filename">The name of the file being styled (for generating errors)</param>
        public static void StyleRange(Scintilla editor, TextEditorControl owner, int startPos, int endPos, string filename)
        {
            try
            {
                // Ensure startPos/endPos actually refer to the document.
                ValidateStartAndEndPos(editor, ref startPos, ref endPos);

                // Get the real range of lines to style.
                int startLine = editor.LineFromPosition(startPos);
                int endLine   = editor.LineFromPosition(endPos);

                // Remove all the error/warning marks in this range.
                owner.ClearLineMarks(startLine + 1, endLine - startLine + 1);

                // Now find the actual document start and end of the range we're going to color.
                int trueStartPos = editor.Lines[startLine].Position;
                int trueEndPos   = editor.Lines[endLine].EndPosition;

                // Get the text itself in that range.
                string textSlice = editor.GetTextRange(trueStartPos, trueEndPos - trueStartPos);

                // Ask the real Smile Lexer to begin lexical analysis on it.
                SmileLibInterop.Lexer lexer = new SmileLibInterop.Lexer(textSlice,
                                                                        0, textSlice.Length, filename, startLine + 1, 1, true);

                editor.StartStyling(trueStartPos);

                Token token;
                int   lastPos       = 0;
                Token previousToken = null;
                while ((token = lexer.Next()).Kind != TokenKind.EOI)
                {
                    LexerPosition lexerPosition = token.Position;
                    int           tokenStartPos = lexerPosition.LineStart + lexerPosition.Column - 1;
                    int           tokenLength   = lexerPosition.Length;

                    if (tokenStartPos > lastPos)
                    {
                        // Token somehow skipped over some content, so style it plain.
                        editor.SetStyling(tokenStartPos - lastPos, (int)StyleKind.Default);
                        editor.IndicatorClearRange(trueStartPos + lastPos, tokenStartPos - lastPos);

                        System.Diagnostics.Debug.WriteLine($"Warning: Lexer skipped {tokenStartPos - lastPos} characters at {lastPos}.");
                    }
                    else if (tokenStartPos < lastPos)
                    {
                        // For some reason, the previous token had too many characters in it,
                        // so shorten this one by a bit to make up for that mistake.
                        tokenLength -= lastPos - tokenStartPos;

                        System.Diagnostics.Debug.WriteLine($"Warning: Lexer grabbed too many characters ({lastPos - tokenStartPos} extra) at {lastPos}.");
                    }

                    if (tokenLength > 0)
                    {
                        StyleKind styleKind = GetDefaultStyleKindForToken(previousToken, token);
                        editor.SetStyling(tokenLength, (int)styleKind);

                        if (styleKind == StyleKind.Meta_Error)
                        {
                            editor.IndicatorCurrent = (int)IndicatorKind.Error;
                            editor.IndicatorFillRange(trueStartPos + tokenStartPos, tokenLength);
                            owner.SetLineMark(lexerPosition.Line, IndicatorKind.Error);
                        }
                        else
                        {
                            editor.IndicatorClearRange(trueStartPos + tokenStartPos, tokenLength);
                        }
                    }

                    lastPos       = tokenStartPos + tokenLength;
                    previousToken = IsSemanticToken(token) ? token : previousToken;
                }
            }
            catch (Exception e)
            {
                // Should never get here, but just in case, we swallow errors
                // and hope a later pass will restyle the content better.
                System.Diagnostics.Debug.WriteLine("Warning: LexicalStyler.StyleRange() crashed: " + e.Message);
            }
        }
Ejemplo n.º 9
0
 public FunctionDefinitionNode(string name, string[] args, LexerPosition linePosition) : base(linePosition)
 {
     Name = name ?? throw new ArgumentNullException();
     Args = args ?? throw new ArgumentNullException();
 }
Ejemplo n.º 10
0
 public BreakNode(LexerPosition linePosition) : base(linePosition)
 {
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Perform a simple lexical styling of the given collection of lexical tokens.
        /// </summary>
        /// <param name="editor">The editor that holds the content.</param>
        /// <param name="tokens">The tokens to be restyled.</param>
        public static void StyleTokens(Scintilla editor, TextEditorControl owner, IEnumerable <Token> tokens)
        {
            try
            {
                bool  isFirst       = true;
                int   lastPos       = 0;
                int   trueStartPos  = 0;
                Token previousToken = null;
                foreach (Token token in tokens)
                {
                    LexerPosition lexerPosition = token.Position;
                    int           tokenStartPos = lexerPosition.LineStart + lexerPosition.Column - 1;
                    int           tokenEndPos   = tokenStartPos + lexerPosition.Length;
                    ValidateStartAndEndPos(editor, ref tokenStartPos, ref tokenEndPos);
                    int tokenLength = tokenEndPos - tokenStartPos;

                    if (isFirst)
                    {
                        editor.StartStyling(tokenStartPos);
                        trueStartPos = lastPos = tokenStartPos;
                        isFirst      = false;
                    }

                    if (tokenStartPos > lastPos)
                    {
                        // Token somehow skipped over some content, so style it plain.
                        editor.SetStyling(tokenStartPos - lastPos, (int)StyleKind.Default);
                        editor.IndicatorClearRange(trueStartPos + lastPos, tokenStartPos - lastPos);

                        System.Diagnostics.Debug.WriteLine($"Warning: Lexer skipped {tokenStartPos - lastPos} characters at {lastPos}.");
                    }
                    else if (tokenStartPos < lastPos)
                    {
                        // For some reason, the previous token had too many characters in it,
                        // so shorten this one by a bit to make up for that mistake.
                        tokenLength -= lastPos - tokenStartPos;

                        System.Diagnostics.Debug.WriteLine($"Warning: Lexer grabbed too many characters ({lastPos - tokenStartPos} extra) at {lastPos}.");
                    }

                    if (tokenLength > 0)
                    {
                        StyleKind styleKind = GetDefaultStyleKindForToken(previousToken, token);
                        editor.SetStyling(tokenLength, (int)styleKind);

                        if (styleKind == StyleKind.Meta_Error)
                        {
                            editor.IndicatorCurrent = (int)IndicatorKind.Error;
                            editor.IndicatorFillRange(trueStartPos + tokenStartPos, tokenLength);
                            owner.SetLineMark(lexerPosition.Line, IndicatorKind.Error);
                        }
                        else
                        {
                            editor.IndicatorClearRange(trueStartPos + tokenStartPos, tokenLength);
                        }
                    }

                    lastPos       = tokenStartPos + tokenLength;
                    previousToken = IsSemanticToken(token) ? token : previousToken;
                }
            }
            catch (Exception e)
            {
                // Should never get here, but just in case, we swallow errors
                // and hope a later pass will restyle the content better.
                System.Diagnostics.Debug.WriteLine("Warning: LexicalStyler.StyleTokens() crashed: " + e.Message);
            }
        }
Ejemplo n.º 12
0
 public ElseNode(LexerPosition linePosition) : base(linePosition)
 {
 }
Ejemplo n.º 13
0
 public BlockNode(LexerPosition linePosition) : base(linePosition)
 {
 }
Ejemplo n.º 14
0
 public WhileNode(List <Token <TokenType> > condition, LexerPosition linePosition) : base(linePosition)
 {
     this.condition = condition.AsString();
 }
Ejemplo n.º 15
0
 public ContinueNode(LexerPosition linePosition) : base(linePosition)
 {
 }
Ejemplo n.º 16
0
 public ImportNode(string lib, LexerPosition linePosition) : base(linePosition)
 {
     Library = lib;
 }
Ejemplo n.º 17
0
        private T BuildTree <T>(Queue <Token <TokenType> > tokens, ref InterpreterState state, bool getNodesOnly = false) where T : BlockNode, new()
        {
            T root = new T();             // Create a new node

            while (tokens.Count > 0)
            {
                TokenList expr = new TokenList();
                // If we hit EOS we are done
                Token <TokenType> token = tokens.Dequeue();
                if (token == null || token.IsEOS)
                {
#if DEBUG
                    WriteLineColor("EOS", Cyan);
#endif
                    break;
                }
                // While i is in bounds of tokens AND we have not hit an "expression ending" (; or {)
                while (tokens.Count() > 0 && !token.IsEnding() && !token.IsEOS)
                {
                    expr.Add(token);
                    token = tokens.Dequeue();
                }
                expr.Add(token);
                // If expression starts with }, remove it
                if (expr.Count > 0 && expr[0].TokenID == RBRACE)
                {
                    expr = expr.Skip(1).ToList();
                }
                // Dont run empty expression
                if (expr.Count == 0)
                {
                    continue;
                }
#if DEBUG
                expr.TokenDump();
#endif
                LexerPosition exprPos = expr[0].Position.Adjust();
                state.Location = exprPos;
                bool built = false;
                // Loop over every expression type
                foreach (ExpressionType type in Enum.GetValues(typeof(ExpressionType)).Cast <ExpressionType>())
                {
                    if (type.Matches(expr))
                    {
                        Node node = type.GetNode(expr, exprPos, ref state);
                        if (type.IsBlock())
                        {
                            BlockNode tmp = (BlockNode)node;
                            Queue <Token <TokenType> > block = GetBlock(ref tokens);
                            BuildTree <RootNode>(block, ref state, getNodesOnly).Children.ForEach(c => tmp.Add(c));
                            node = tmp;
                        }
                        if (type.WillRun() || getNodesOnly)
                        {
                            root.Add(node);
                        }
                        if (!getNodesOnly)
                        {
                            if (node is FunctionDefinitionNode funcDefNode)
                            {
                                state.UserFuncs.Add(new UserFunction(
                                                        funcDefNode.Name,
                                                        funcDefNode.Args,
                                                        funcDefNode.Children
                                                        ));
                            }
                            if (node is ImportNode impNode)
                            {
                                state.Import(impNode.Library);
                            }
                        }
                        built = true;
                        break;
                    }
                }
                if (!built)                 // Unknown Expression
                {
                    throw new InterpreterException($"Unknown expression at {exprPos}");
                }
            }

            return(root);
        }
Ejemplo n.º 18
0
		public ReturnNode(List<Token<TokenType>> valueTokens, LexerPosition linePosition) : base(linePosition)
		{
			this.valueTokens = valueTokens;
		}
Ejemplo n.º 19
0
 public LoopNode(List <Token <TokenType> > timesUnparsed, LexerPosition linePosition) : base(linePosition)
 {
     this.timesUnparsed = timesUnparsed;
 }
Ejemplo n.º 20
0
 public FunctionCallNode(UserFunction userFunc, List <List <Token <TokenType> > > args, LexerPosition linePosition) : base(linePosition)
 {
     func          = null;
     this.userFunc = userFunc;
     isUserFunc    = true;
     this.args     = args;
     name          = userFunc.Name;
 }
Ejemplo n.º 21
0
 public FSMMatch <N> Run(string source, LexerPosition position)
 {
     return(Run(new ReadOnlyMemory <char>(source.ToCharArray()), position));
 }
Ejemplo n.º 22
0
 public FunctionCallNode(_7sFunction func, List <List <Token <TokenType> > > args, LexerPosition linePosition) : base(linePosition)
 {
     this.func  = func ?? throw new InterpreterException($"Unknown function at {linePosition}");
     this.args  = args;
     isUserFunc = false;
     name       = func.Name;
 }
Ejemplo n.º 23
0
 public IfNode(List <Token <TokenType> > condition, bool isElseIf, LexerPosition linePosition) : base(linePosition)
 {
     this.condition = (isElseIf ? condition.Take(condition.Count - 1).ToList() : condition).AsString();
     this.isElseIf  = isElseIf;
 }
Ejemplo n.º 24
0
 protected Node(LexerPosition linePosition) => this.linePosition = linePosition;