Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,169 changes: 0 additions & 2,169 deletions Dart.g

This file was deleted.

4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: _internal
environment:
sdk: '>=3.0.0-0 <3.2.0'
sdk: '>=3.2.0 <4.0.0'

dependencies:
path: ^1.8.3
path: ^1.9.1
8 changes: 4 additions & 4 deletions tester/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: tree_sitter_dart_tester
environment:
sdk: '>=3.0.0-0 <3.2.0'
sdk: '>=3.1.5 <4.0.0'
dependencies:
glob: ^2.1.1
path: ^1.8.3
glob: ^2.1.3
path: ^1.9.1

dev_dependencies:
dcli: ^2.1.0
dcli: ^7.1.1
11 changes: 11 additions & 0 deletions tree_sitter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 0.1.3 (Unreleased)
- Added `@Native` annotation support for the Dart language grammar
- Added `Parser.fromLanguage()` constructor for use with native bindings
- Added `treeSitterDart()` function for efficient static linking (Dart 3.0+)
- Updated examples and tests to demonstrate both dynamic and native binding approaches
- Configured ffigen to generate `@Native` annotations for tree-sitter C API bindings
- Updated api_config.yaml and parser_config.yaml to enable ffi-native code generation
- Regenerated bindings with `@Native` annotations (requires Dart SDK 3.0+)
- Updated SDK constraint to <4.0.0 for compatibility with newer Dart versions
- Fixed TSInputEncoding enum to match tree-sitter 0.26.x API changes

## 0.1.2
- Fix issue with string encoding length

Expand Down
65 changes: 59 additions & 6 deletions tree_sitter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,76 @@ Then set the library location using:
TreeSitterConfig.setLibraryPath('/path/to/libtree-sitter.so');
```

Next create a parser for your language by first creating a dynamic library for your language's grammar.
## Usage

### Option 1: Native Binding (Recommended for Dart 3.0+)

Use the `@Native` annotation binding for efficient static linking:

```dart
import 'package:tree_sitter/tree_sitter.dart';

void main() {
// Use the native binding for the Dart language grammar
final parser = Parser.fromLanguage(treeSitterDart());
final program = "class A {}";
final tree = parser.parse(program);
print(tree.root.string);
}
```

This approach provides:
- Better performance through static linking
- Compile-time symbol validation
- Zero runtime overhead for library loading
- Simplified deployment

### Option 2: Dynamic Library Loading (Traditional)

Load the language grammar dynamically at runtime:

Then load and use the parser:
```dart
import 'package:ffi/ffi.dart';
import 'package:dylib/dylib.dart';
import 'package:tree_sitter/tree_sitter.dart';

void main() {
final parser =
Parser(sharedLibrary: 'libdart.dylib', entryPoint: 'tree_sitter_dart');
final parser = Parser(
sharedLibrary: resolveDylibPath('dart', path: Directory.current.path),
entryPoint: 'tree_sitter_dart');
final program = "class A {}";
final tree = parser.parse(program);
print(tree.root.string);
}
```

You can access other apis via the top level `treeSitterApi` ffi wrapper
## Regenerating Bindings

The tree-sitter C API bindings are configured to use `@Native` annotations for better performance (Dart 3.0+). To regenerate the bindings after updating the tree-sitter library:

```bash
# Make sure the tree-sitter submodule is initialized
git submodule update --init --recursive

# Build tree-sitter library
cd tree-sitter && make && cd ..

# Regenerate bindings
dart run ffigen --config api_config.yaml
dart run ffigen --config parser_config.yaml
```

This will generate updated bindings in `lib/src/generated_bindings.dart` and `lib/src/parser_generated_bindings.dart` with `@Native` annotations enabled.

**Note:** The generated bindings use `@Native` without asset IDs, which means they rely on `DynamicLibrary.process()` for symbol resolution. You'll need to preload the libraries when running tests:

```bash
export LD_PRELOAD="./libtree-sitter.so:./libdart.so"
dart test
```

## Advanced Usage

You can access other APIs via the top level `treeSitterApi` ffi wrapper.

Or you can help contribute to an idiomatic dart api on top of the ffi wrapper.
Many of the apis are started but not complete.
Expand Down
14 changes: 13 additions & 1 deletion tree_sitter/api_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,16 @@ functions:
- 'ts_tree_delete'
- 'ts_tree_cursor_delete'
- 'ts_query_delete'
- 'ts_query_cursor_delete'
- 'ts_query_cursor_delete'
silence-enum-warning: true
# Configure ffigen to generate @Native annotations (Dart 3.0+)
# This enables efficient static linking instead of dynamic library loading
# Note: assetId is omitted to allow fallback to process lookup
ffi-native:
llvm-path:
- '/usr/lib/llvm-18'
- '/usr/lib/llvm-17'
- '/usr/lib/llvm-16'
- '/usr/lib/llvm-14'
- '/usr/lib/llvm-11'
- '/usr/local/opt/llvm'
26 changes: 25 additions & 1 deletion tree_sitter/example/tree_sitter.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
// ignore_for_file: avoid_print

import 'dart:io';

import 'package:dylib/dylib.dart';
import 'package:tree_sitter/tree_sitter.dart';

void main() {
print('=== Example 1: Using dynamic library loading (traditional) ===');
exampleWithDynamicLoading();

print('\n=== Example 2: Using @Native annotation (Dart 3.0+) ===');
exampleWithNativeBinding();
}

void exampleWithDynamicLoading() {
final parser = Parser(
sharedLibrary: resolveDylibPath('dart', path: Directory.current.path),
entryPoint: 'tree_sitter_dart');
// const program = "class A {}";
const program = r"""
void main() {
test('', () {
Expand All @@ -20,3 +29,18 @@ void main() {
print(tree.root.string);
print(parser.getText(tree.root.child(0).namedChild(0)));
}

void exampleWithNativeBinding() {
// Use the @Native binding for efficient static linking (Dart 3.0+)
final parser = Parser.fromLanguage(treeSitterDart());
const program = r"""
class MyClass {
void myMethod() {
print('Hello from Dart!');
}
}
""";
final tree = parser.parse(program);
print(tree.root.string);
print('Root node type: ${tree.root.nodeType}');
}
35 changes: 35 additions & 0 deletions tree_sitter/lib/src/dart_language.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// Native binding for tree-sitter-dart language grammar.
///
/// This module provides a `@Native` binding to the tree_sitter_dart()
/// function which returns the Dart language grammar for use with
/// tree-sitter parsers.
library;

import 'dart:ffi';

import '../tree_sitter.dart' show TSLanguage;

/// Get the tree-sitter Language for Dart grammar.
///
/// This function returns a pointer to the TSLanguage struct that defines
/// the Dart grammar. It uses Dart's `@Native` annotation for efficient
/// static linking to the native C function.
///
/// This is the preferred method for accessing the Dart language grammar
/// when using Dart 3.0+, as it provides better performance through
/// static linking compared to dynamic library loading.
///
/// Example:
/// ```dart
/// import 'package:tree_sitter/tree_sitter.dart';
///
/// void main() {
/// // Use the native binding with Parser.fromLanguage
/// final parser = Parser.fromLanguage(treeSitterDart());
/// final tree = parser.parse('class A {}');
/// print(tree.root.string);
/// }
/// ```
@Native<Pointer<TSLanguage> Function()>(
symbol: 'tree_sitter_dart', isLeaf: true)
external Pointer<TSLanguage> treeSitterDart();
Loading