- Fixed HDL highlights query syntax error with #match? predicate - Replaced #match? with #any-of? for exact string matching - Fixed Hack Assembly outline query invalid field name - Improved HDL syntax highlighting with comprehensive patterns - Added HDL bracket matching for all syntax types - Fixed XML scope mismatch from text.xml to source.xml - Enhanced outline queries for better code navigation
9.4 KiB
Nand2Tetris Zed Extension - Development Guide
This guide provides detailed information for developers working on or contributing to the Nand2Tetris Zed extension.
Overview
The extension provides comprehensive language support for all nand2tetris course languages through custom Tree-sitter grammars and Zed language configurations.
Architecture
Extension Structure
nand2tetris-zed/
├── extension.toml # Main extension configuration
├── languages/ # Zed language configurations
│ ├── hdl/ # Hardware Description Language
│ ├── jack/ # Jack programming language
│ ├── hack-assembly/ # Hack Assembly language
│ ├── vm/ # Virtual Machine language
│ ├── test-script/ # Test Script language
│ └── compare-output/ # Compare/Output file format
├── grammars/ # Tree-sitter grammar sources
│ ├── hdl/ # External grammar (quantonganh)
│ ├── jack/ # External grammar (nverno)
│ ├── hack-assembly/ # Custom grammar
│ ├── vm/ # Custom grammar
│ ├── test-script/ # Custom grammar
│ └── compare-output/ # Custom grammar
└── examples/ # Test files for validation
Language Support Levels
- HDL & Jack: Use external, mature Tree-sitter grammars
- Assembly, VM, Test Script, Compare/Output: Custom grammars built specifically for this extension
Grammar Development
Prerequisites
- Rust (installed via rustup)
- Node.js and npm
- tree-sitter-cli:
npm install -g tree-sitter-cli
Grammar Structure
Each custom grammar follows this structure:
grammars/[language]/
├── grammar.js # Grammar definition
├── tree-sitter.json # Tree-sitter configuration
├── package.json # npm package configuration
├── Cargo.toml # Rust package configuration
├── binding.gyp # Node.js binding configuration
├── src/ # Generated parser code
│ ├── parser.c # Generated C parser
│ ├── grammar.json # Generated grammar metadata
│ └── node-types.json # Generated node type definitions
├── bindings/ # Language bindings
│ └── rust/ # Rust bindings
│ ├── lib.rs # Library interface
│ └── build.rs # Build script
└── queries/ # Tree-sitter queries
└── highlights.scm # Syntax highlighting queries
Creating a New Grammar
-
Create directory structure:
mkdir -p grammars/my-language/{bindings/rust,queries} cd grammars/my-language -
Create
grammar.js:module.exports = grammar({ name: 'my_language', rules: { source_file: $ => repeat($._item), _item: $ => choice( $.comment, // Add your language constructs here ), comment: $ => token(seq('//', /.*/)), }, extras: $ => [ /\s/, $.comment ] }); -
Create configuration files:
tree-sitter.json(see existing examples)package.json(Node.js package)Cargo.toml(Rust package)binding.gyp(Node.js bindings)
-
Generate parser:
tree-sitter generate -
Create Rust bindings:
bindings/rust/lib.rsbindings/rust/build.rs
-
Create highlighting queries:
queries/highlights.scm
-
Test the grammar:
tree-sitter test tree-sitter parse test-file.ext
Grammar Rules Best Practices
Token Naming
- Use snake_case for rule names
- Prefix internal rules with
_ - Use semantic names that describe the construct
Rule Structure
// Good: Clear semantic meaning
instruction: $ => choice(
$.a_instruction,
$.c_instruction
),
// Bad: Generic naming
thing: $ => choice(
$.type1,
$.type2
),
Comments and Whitespace
Always handle comments and whitespace properly:
extras: $ => [
/\s/, // Whitespace
$.comment // Comments
],
String Tokens
Use token() for multi-character operators:
// Good
if_goto: $ => token('if-goto'),
// Bad (can cause parsing issues)
if_goto: $ => 'if-goto',
Language Configuration
Each language needs a config.toml file in languages/[language]/:
name = "Language Name"
grammar = "grammar_name"
scope = "source.language_name"
path_suffixes = ["ext"]
line_comments = ["// "]
block_comments = [["/*", "*/"]] # Optional
tab_size = 4
hard_tabs = false
Highlighting Queries
Create .scm files that map grammar nodes to semantic tokens:
; Comments
(comment) @comment
; Keywords
"function" @keyword.function
"return" @keyword.control
; Identifiers
(identifier) @variable
(function_name) @function
; Literals
(number) @constant.numeric
(string) @string
Query Development Tips
- Check node types: Use
tree-sitter parse --debugto see actual node structure - Test queries: Use
tree-sitter highlightto test highlighting - Use semantic tokens: Follow TextMate/LSP token conventions
- Prioritize specificity: More specific queries override general ones
Testing
Grammar Testing
cd grammars/[language]
tree-sitter test # Run test suite
tree-sitter parse example.ext # Parse specific file
tree-sitter highlight example.ext # Test highlighting
Integration Testing
- Install extension as dev extension in Zed
- Open test files and verify:
- Syntax highlighting works
- Bracket matching functions
- Code outline appears
- Indentation behaves correctly
Example Files
Create comprehensive example files in examples/ that cover:
- All language constructs
- Edge cases
- Common patterns
- Error conditions
Common Issues and Solutions
Grammar Generation Errors
Empty string rules:
Error: The rule contains an empty string
Solution: Remove empty alternatives or use optional()
Invalid node types in queries:
Query error: Invalid node type 'foo'
Solution: Check src/node-types.json for actual node names
Highlighting Issues
Tokens not highlighting:
- Verify node exists in
node-types.json - Check query syntax
- Ensure grammar generates expected nodes
Conflicting highlights:
- More specific queries take precedence
- Use
#match?predicates for conditional highlighting
Zed Integration Issues
Extension not loading:
- Check
extension.tomlsyntax - Verify all referenced grammars exist
- Check Zed logs for specific errors
Grammar compilation fails:
- Ensure Rust is installed via rustup
- Check that all required files are present
- Verify tree-sitter grammar generates successfully
Contributing Guidelines
Code Style
- Follow existing patterns in grammar definitions
- Use clear, semantic naming
- Add comprehensive comments
- Test thoroughly before submitting
Documentation
- Update README.md for user-facing changes
- Update this guide for development changes
- Include example files for new languages
- Document any breaking changes
Pull Request Process
- Create feature branch
- Implement changes with tests
- Update documentation
- Test in Zed environment
- Submit PR with clear description
Commit Messages
Use conventional commits:
feat: add support for new language construct
fix: resolve highlighting issue with comments
docs: update installation instructions
test: add comprehensive test cases
Release Process
- Version Bump: Update
extension.tomlversion - Test: Verify all grammars compile and work in Zed
- Documentation: Update README.md and CHANGELOG.md
- Tag: Create git tag for version
- Publish: Submit to Zed extension registry (when available)
Performance Considerations
Grammar Optimization
- Avoid excessive backtracking in rules
- Use
token()for multi-character sequences - Minimize conflicts between rules
- Profile with
tree-sitter parse --time
Query Optimization
- Use specific node patterns over generic ones
- Avoid complex predicates when possible
- Test query performance on large files
Debugging
Grammar Debugging
tree-sitter generate --debug
tree-sitter parse --debug-graph file.ext
tree-sitter test --debug
Query Debugging
tree-sitter query queries/highlights.scm file.ext
tree-sitter highlight file.ext
Zed Debugging
- Check
zed: open logfor extension errors - Use
--foregroundflag for verbose logging - Test with minimal example files
Resources
Support
For development questions or issues:
- Check existing GitHub issues
- Review this development guide
- Test with minimal reproducible examples
- Provide detailed error messages and logs
This extension represents a complete implementation of nand2tetris language support, demonstrating how to create comprehensive Tree-sitter grammars and integrate them into modern editors.