A high-performance parser for Vim9script that generates Abstract Syntax Trees (AST).
Enable Vim9script support in vim-language-server by providing:
- Accurate Vim9 syntax parsing - Complete AST generation for all vim9script constructs
- Language Server integration - Symbol tables and completion support for LSP clients
- Cooperative parsing - Work alongside vim-vimlparser in a dispatcher pattern for hybrid VimL/Vim9 files
vim-language-server
↓
Detect language (vim9script vs legacy VimL)
↓
┌─────────────────────┬──────────────────────┐
├─ Legacy VimL ──────→ vim-vimlparser │
└─ Vim9script ───────→ vim-vim9parser │
(this project) │
↓ │
AST generation │
↓ │
Symbol Table │
↓ │
Completion candidates │
└─────────────────────┴──────────────────────┘
- Vim9script - Modern Vim scripting language (with
:vim9scriptdeclaration)
let p = vim9parser#Import()
let lines = ['var x = 1 + 2']
let reader = p.StringReader.new(lines)
let parser = p.Vim9Parser.new()
let ast = parser.Parse(reader)let compiler = p.Compiler.new()
echo join(compiler.Compile(ast), "\n")let js_compiler = p.JSCompiler.new()
let js_lines = js_compiler.Compile(ast)
echo join(js_lines, "\n")Note: Full JavaScript code generation for the entire parser is currently not automated due to vim9script execution limitations in batch mode. The JSCompiler class is available for API-level transpilation. See js/jscompiler.vim for manual compilation if needed.
Compared to legacy VimL, vim9script adds:
- Type annotations for variables and functions
- Classes and objects
- New syntax:
var,const,def,class - No more
:prefix for options access importandexportstatements- Lambda expressions:
(x) => x * 2 - Ternary operator:
condition ? true_val : false_val - Bitwise operators:
<<,>>,&,|,^
var- variable declarations with optional type annotationsconst- constant declarationsdef/enddef- function definitions with parameter and return typesclass/endclass- class definitions
if/elseif/else/endifwhile/endwhilefor/endfortry/catch/finally/endtryreturn
- Arithmetic operators:
+,-,*,/,% - Compound assignment operators:
+=,-=,*=,/=,%= - Comparison operators:
==,!=,<,>,<=,>= - Logical operators:
&&,||,! - Bitwise operators:
&,|,^,<<,>> - Ternary operator:
condition ? true_expr : false_expr - Member access:
obj.field - Array/Dict subscript:
arr[index],dict[key] - Function call:
func(arg1, arg2) - Lambda expressions:
(x, y) => x + y - String interpolation:
$"Hello, {name}!" - List comprehensions:
[for i in range(10): i * i],[for i in list if i > 5: i] - Destructuring assignment:
var [a, b] = [1, 2],var {x, y} = dict
- Numbers:
42,3.14 - Strings:
"hello",'world' - Booleans:
true,false - Null:
null - Lists:
[1, 2, 3] - Dictionaries:
{key: value}
importstatementsexportdeclarations
- JavaScript Compiler: Generate JavaScript code from Vim9 AST
JSCompilerclass for transpiling to JavaScript- Support for variables, functions, classes, control flow
- List comprehensions compile to JavaScript
.map()and.filter() - Lambda expressions compile to arrow functions
- Line Continuation: Both explicit
\continuation and operator-based continuation across linesvar x = 1 +\(explicit backslash)var x = 1 +(operator-based, continues to next line)- Function calls and subscripts continue naturally across lines
- Compound Assignment Operators:
+=,-=,*=,/=,%=are now fully supported - String Interpolation:
$"Hello, {name}!"syntax is now parsed (preserves interpolation expressions) - Error Recovery: Parser now tracks errors without throwing immediately, allowing for multiple error reporting
- Destructuring Assignment: Both list
var [a, b] = [1, 2]and dictvar {x, y} = dictpatterns - List Comprehensions:
[for i in range(10): i * i]and with filters[for i in list if i > 5: i]
- Syntax Error Fixes: Fixed multiple critical parsing errors in vim9parser.vim
- Fixed class definition indentation and missing
enddefstatements - Fixed undefined variable references in type error messages
- Fixed empty
throwstatement (now includes exception value) - Added proper
exportkeywords to parser classes
- Fixed class definition indentation and missing
- Type System: Corrected ParseType/ParseTypeString confusion throughout codebase
- Type annotations now properly distinguished from type declarations
- Generic type parsing (e.g.,
list<string>) now works correctly
- New Operators: Added support for additional Vim9 operators
- Method chaining with
->operator - Regex matching operators
=~and!~
- Method chaining with
- Advanced Features: Implemented missing Vim9 language features
- Default parameter values:
def func(x: number = 0) - String/list slicing:
str[start:end] - Proper handling of method calls and chaining
- Default parameter values:
type MyList = list<string> # Not supportedinterface Drawable # Not supported
def Draw(): void
endinterfaceenum Color # Token recognized but full semantics not implemented
RED
GREEN
BLUE
endenum@cached # Not supported
def MyFunc(): void
enddef- Symbol Table:
⚠️ MISSING - No tracking of defined functions/variables/classes (REQUIRED FOR COMPLETION) - Scope Resolution: Not tracked - Variable/function scoping is not analyzed
- Type Checking: Type annotations are parsed but not validated
- Undefined Reference Detection: References to undefined symbols are not flagged
- Incremental Parsing: Not supported - full file re-parse on every change
- Hybrid Files: Limited support for files that mix legacy VimL and vim9script
- Error Handling: Limited error messages; parser stops at first syntax error
- Comment Handling: ✅ FIXED - Comments after statements now properly skipped via SkipComments()
- StringReader: ✅ Complete - Full implementation in js/vim9parser.js
- Vim9Tokenizer: ✅ Complete - All token types and keyword detection
- Vim9Parser:
⚠️ Partial - Basic class structure, var/const/def/class/import/export parsing- ❌ Missing: Expression parsing (binary operators, function calls, subscripts)
- ❌ Missing: Statement parsing (if/while/for/try blocks)
- ❌ Missing: Type string parsing
- ❌ Missing: Full lambda and comprehension support
- JSCompiler: ✅ Complete - Compiles Vim9 AST to JavaScript code
- ✅ Supports: var/const declarations, function definitions, classes
- ✅ Supports: Arithmetic operators, comparisons, logical operators
- ✅ Supports: List literals and comprehensions
- ❌ Missing: Comment preservation in output
- ❌ Missing: Type annotation translation
-
Symbol Table Implementation
⚠️ HIGHEST PRIORITY- REQUIREMENT: Must be compatible with vim-vimlparser Buffer interface
- Implement
Vim9Bufferclass with same methods as vim-vimlparser'sBuffer:getGlobalFunctions(): Record<string, IFunction[]>getScriptFunctions(): Record<string, IFunction[]>getGlobalIdentifiers(): Record<string, IIdentifier[]>getLocalIdentifiers(): Record<string, IIdentifier[]>getFunctionLocalIdentifierItems(line): CompletionItem[]
- Extract function definitions (name, args, startLine, startCol, endLine, endCol, range)
- Extract variable declarations with scope (g:, s:, l:, a:, b:)
- Track class/import definitions for vim9script
- Why: vim-language-server expects this exact interface; without it, dispatcher pattern fails
- See: ANALYSIS.md for detailed interface specification
-
Scope Analysis
- Function-local scope vs script-level scope
- Parameter binding in function context
- Closure support for nested functions
- Why: Avoid suggesting symbols from wrong scope
-
Public LSP Interface
- Standardized API for vim-language-server integration
- Return format compatible with LSP (SymbolInformation, CompletionItem)
- Position-to-symbol lookup capability
- Why: LSP clients need consistent interface
-
Test Coverage for LSP Scenarios
- Completion in function bodies
- Completion with imported symbols
- Hover information for variables/functions
- Go-to-definition support
- Why: Verify LSP integration works end-to-end
- Incremental parsing support for large files
- Hybrid file support (VimL + Vim9 in same file)
- Dict comprehensions:
{for k in list: k: value} - Full enum support with proper semantics
- Type aliases:
type MyList = list<string>
- Extended test coverage
- Performance optimization for large files
- Better error messages and error recovery
- Code formatter based on AST
- Complete Vim9Parser class export to JavaScript
- Expression and statement parsing in JavaScript parser
- Type annotation translation to TypeScript types
- Comment preservation in compiled output
- JSCompiler enhancements for complex expressions
- Node.js module generation with proper exports
- Type checking system
- Interface support
- Language Server Protocol reference implementation
- Production-grade JavaScript transpilation
Contributions are welcome! Please feel free to submit pull requests for:
- Bug fixes
- New feature implementations
- Test cases
- Documentation improvements
This parser is designed to work alongside vim-vimlparser in a dispatcher pattern:
┌─────────────────────────────────────┐
│ vim-language-server (dispatcher) │
└────────────┬────────────────────────┘
│
├─ Detect file type
│
┌────────┴───────┐
│ │
v v
vim9script Legacy VimL
│ │
v v
vim-vim9parser vim-vimlparser
│ │
v v
vim9 AST VimL AST
│ │
└────────┬───────┘
v
Language Service Features
(Completion, Hover, Go-to-def, etc.)
- Detection: Check for
:vim9scriptat file start or in first few lines - Delegation: Route to appropriate parser
- Symbol Integration: Merge symbol tables from both parsers
- Unified LSP: Return consistent LSP responses regardless of source language
| Component | Status | Notes |
|---|---|---|
| Vim9 Parsing | ✅ Complete | All major syntax supported in Vim9script |
| vim9 AST | ✅ Complete | Node types defined (200+ node types) |
| JavaScript Output | StringReader, Tokenizer, basic Parser exported | |
| JSCompiler | ✅ Complete | Converts Vim9 AST to JavaScript |
| Symbol Table | ❌ MISSING | CRITICAL for LSP |
| Scope Analysis | ❌ MISSING | CRITICAL for Completion |
| LSP Interface | ❌ MISSING | Needs standardization |
| vim-vimlparser integration | 🚀 Pending | Requires dispatcher in vim-language-server |
The parser includes comprehensive test coverage:
- Syntax parsing tests - All major vim9script constructs
- Expression tests - Operators, precedence, types
- Feature tests - Line continuation, comprehensions, destructuring, etc.
- Compiler tests - JavaScript code generation
Run all tests: make test