public void InitializeOpenedInsightWindow(ITextEditor editor, IInsightWindow insightWindow) { EventHandler<TextChangeEventArgs> on_document_changed = delegate{ // whenever the document is changed, recalculate EndOffset var remaining_doc = editor.Document.CreateReader(insightWindow.StartOffset, editor.Document.TextLength - insightWindow.StartOffset); var lexer = new BVE5CommonLexer(remaining_doc); var line = editor.Document.GetLineForOffset(insightWindow.StartOffset); lexer.SetInitialLocation(line.LineNumber, insightWindow.StartOffset - editor.Document.PositionToOffset(line.LineNumber, 1)); Token token; lexer.Advance(); while((token = lexer.Current) != null && token.Kind != TokenKind.EOF){ if(token.Kind == TokenKind.EOL){ MarkInsightWindowEndOffset(insightWindow, editor, token.StartLoc); break; } lexer.Advance(); } }; insightWindow.DocumentChanged += on_document_changed; insightWindow.SelectedItemChanged += delegate { HighlightParameter(insightWindow, highlighted_parameter); }; on_document_changed(null, null); }
// any-string(including file path) LiteralExpression ParseString(BVE5CommonLexer lexer) { Token token = lexer.Current; Debug.Assert(token.Kind == TokenKind.StringLiteral, "Really meant a string?"); lexer.Advance(); return AstNode.MakeLiteral(token.Literal, token.StartLoc, lexer.Current.StartLoc); }
// number ':' number ':' number TimeFormatLiteral ParseTimeLiteral(BVE5CommonLexer lexer) { Token token = lexer.Current; Debug.Assert(token.Kind == TokenKind.IntegerLiteral, "Really meant a time literal?"); int[] nums = new int[3]; Token start_token = lexer.Current; for(int i = 0; i < 3; ++i){ if(token.Kind == TokenKind.EOF){ AddError(ErrorCode.UnexpectedEOF, token.Line, token.Column, "Unexpected EOF!"); if(enable_strict_parsing) return null; else break; } nums[i] = Convert.ToInt32(token.Literal); lexer.Advance(); if(i == 2) break; token = lexer.Current; if(token.Kind == TokenKind.EOF){ AddError(ErrorCode.UnexpectedEOF, token.Line, token.Column, "Unexpected EOF!"); if(enable_strict_parsing) return null; else break; }else if(token.Literal != ":"){ AddError(ErrorCode.SyntaxError, token.Line, token.Column, "Expected ':' but got " + token.Literal); if(enable_strict_parsing) return null; } lexer.Advance(); token = lexer.Current; } return AstNode.MakeTimeFormat(nums[0], nums[1], nums[2], start_token.StartLoc, token.StartLoc); }
// sequence '\n' Statement ParseStatement(BVE5CommonLexer lexer) { var command_invoke = ParseCommandInvoke(lexer); Token token = lexer.Current; if(token.Kind != TokenKind.EOL){ AddError(ErrorCode.SyntaxError, token.Line, token.Column, "Expected EOL but got " + token.Literal + "."); if(enable_strict_parsing) return null; }else{ lexer.Advance(); } return AstNode.MakeStatement(command_invoke, command_invoke.StartLocation, token.EndLoc); }
// number LiteralExpression ParseLiteral(BVE5CommonLexer lexer) { Token token = lexer.Current; Debug.Assert(token.Kind == TokenKind.IntegerLiteral || token.Kind == TokenKind.FloatLiteral, "Really meant a literal?"); lexer.Advance(); if(token.Kind == TokenKind.FloatLiteral) return AstNode.MakeLiteral(Convert.ToDouble(token.Literal), token.StartLoc, token.EndLoc); else return AstNode.MakeLiteral(Convert.ToInt32(token.Literal), token.StartLoc, token.EndLoc); }
SyntaxTree ParseImpl(string src, string fileName, bool parseHeader) { lock(parse_lock){ if(!src.EndsWith("\n")) src += "\n"; using(var reader = new StringReader(src)){ var lexer = new BVE5CommonLexer(reader); lexer.Advance(); string version_str = "unknown"; if(parseHeader){ var token = lexer.Current; lexer.Advance(); var meta_header_match = MetaHeaderRegexp.Match(token.Literal); if(!meta_header_match.Success){ AddError(ErrorCode.InvalidFileHeader, 1, 1, "Invalid " + FileKind + " file!"); return null; }else{ version_str = meta_header_match.Groups[1].Value; } } if(lexer.Current.Kind == TokenKind.EOL) lexer.Advance(); BVE5Language.Ast.Statement stmt = null; var stmts = new List<BVE5Language.Ast.Statement>(); while(lexer.Current != Token.EOF){ stmt = ParseStatement(lexer); if(enable_strict_parsing && !has_error_reported || !enable_strict_parsing) stmts.Add(stmt); if(has_error_reported) has_error_reported = false; } return AstNode.MakeSyntaxTree(stmts, fileName, version_str, FileKind, new TextLocation(1, 1), stmts.Last().EndLocation, Errors.ToList()); } } }
// argument {',' argument} InvocationExpression ParseCommandInvoke(BVE5CommonLexer lexer) { Token token = lexer.Current; var start_loc = token.StartLoc; Expression expr = null; var children = new List<Expression>(); while(token.Kind != TokenKind.EOF && token.Kind != TokenKind.EOL){ expr = ParseArgument(lexer); children.Add(expr); token = lexer.Current; if(token.Literal == ","){ lexer.Advance(); token = lexer.Current; } } return AstNode.MakeInvoke(AstNode.MakeIdent(FileKind.ToString(), start_loc, start_loc), children, start_loc, token.StartLoc); }
// literal Expression ParseArgument(BVE5CommonLexer lexer) { if(has_error_reported) return null; Token token = lexer.Current; switch(token.Kind){ case TokenKind.StringLiteral: return ParseString(lexer); case TokenKind.IntegerLiteral: case TokenKind.FloatLiteral: var la = lexer.Peek; if(la.Literal == ":") return ParseTimeLiteral(lexer); else return ParseLiteral(lexer); default: AddError(ErrorCode.SyntaxError, token.Line, token.Column, "An argument must be a string, a literal or a time format literal!"); return null; } }