Skip to content

Commit

Permalink
feat: update Rust bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
amaanq committed May 13, 2023
1 parent f0a9e62 commit 850e976
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 9 deletions.
41 changes: 41 additions & 0 deletions bindings/rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# tree-sitter-hare

This crate provides a Hare grammar for the [tree-sitter][] parsing library. To
use this crate, add it to the `[dependencies]` section of your `Cargo.toml`
file. (Note that you will probably also need to depend on the
[`tree-sitter`][tree-sitter crate] crate to use the parsed result in any useful
way.)

```toml
[dependencies]
tree-sitter = "~0.20.10"
tree-sitter-hare = "0.0.1"
```

Typically, you will use the [language][language func] function to add this
grammar to a tree-sitter [Parser][], and then use the parser to parse some code:

```rust
let code = r#"
export fn open_file(fs: *fs, path: str, flags: flags...) (io::file | error) = {
match (fs.openfile) {
case null =>
return errors::unsupported;
case let f: *openfilefunc =>
return f(fs, path, flags...);
};
};
"#;
let mut parser = Parser::new();
parser.set_language(tree_sitter_hare::language()).expect("Error loading Hare grammar");
let parsed = parser.parse(code, None);
```

If you have any questions, please reach out to us in the [tree-sitter
discussions] page.

[language func]: https://docs.rs/tree-sitter-hare/*/tree_sitter_hare/fn.language.html
[parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
[tree-sitter]: https://tree-sitter.github.io/
[tree-sitter crate]: https://crates.io/crates/tree-sitter
[tree-sitter discussions]: https://github.com/tree-sitter/tree-sitter/discussions
2 changes: 1 addition & 1 deletion bindings/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ fn main() {
let src_dir = std::path::Path::new("src");

let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config.include(src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
Expand Down
147 changes: 139 additions & 8 deletions bindings/rust/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ------------------------------------------------------------------------------------------------
// Copyright © 2023 Amaan Qureshi <amaanq12@gmail.com>
// Copyright © 2023, Amaan Qureshi <amaanq12@gmail.com>
// See the LICENSE file in this repo for license details.
// ------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -33,18 +33,29 @@ pub fn language() -> Language {
unsafe { tree_sitter_hare() }
}

/// The source of the Rust tree-sitter grammar description.
pub const GRAMMAR: &str = include_str!("../../grammar.js");

/// The folds query for this language.
pub const FOLDS_QUERY: &str = include_str!("../../queries/folds.scm");

/// The syntax highlighting query for this language.
pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");

/// The indents query for this language.
pub const INDENTS_QUERY: &str = include_str!("../../queries/indents.scm");

/// The injection query for this language.
pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");

/// The symbol tagging query for this language.
pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");

/// The content of the [`node-types.json`][] file for this grammar.
///
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");

// Uncomment these to include any queries that this grammar contains

// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");

#[cfg(test)]
mod tests {
#[test]
Expand All @@ -54,4 +65,124 @@ mod tests {
.set_language(super::language())
.expect("Error loading Hare grammar");
}

#[test]
fn test_some_code() {
let code = r#"
// License: MPL-2.0
// (c) 2021 Bor Grošelj Simić <bor.groseljsimic@telemach.net>
// (c) 2021 Drew DeVault <sir@cmpwn.com>
def U: u8 = 0o1;
def L: u8 = 0o2;
def N: u8 = 0o4;
def S: u8 = 0o10;
def P: u8 = 0o20;
def C: u8 = 0o40;
def B: u8 = 0o100;
def X: u8 = 0o200;
// LUT of bitfields with character attributes
const cclass: []u8 = [
// 0 1 2 3 4 5 6 7
C, C, C, C, C, C, C, C, // 0
C, S|C, S|C, S|C, S|C, S|C, C, C, // 10
C, C, C, C, C, C, C, C, // 20
C, C, C, C, C, C, C, C, // 30
S|B, P, P, P, P, P, P, P, // 40
P, P, P, P, P, P, P, P, // 50
N|X, N|X, N|X, N|X, N|X, N|X, N|X, N|X, // 60
N|X, N|X, P, P, P, P, P, P, // 70
P, U|X, U|X, U|X, U|X, U|X, U|X, U, // 100
U, U, U, U, U, U, U, U, // 110
U, U, U, U, U, U, U, U, // 120
U, U, U, P, P, P, P, P, // 130
P, L|X, L|X, L|X, L|X, L|X, L|X, L, // 140
L, L, L, L, L, L, L, L, // 150
L, L, L, L, L, L, L, L, // 160
L, L, L, P, P, P, P, C, // 170
];
// Returns true if an ASCII character is a letter.
export fn isalpha(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & (U | L) > 0;
// Returns true if an ASCII character is uppercase.
export fn isupper(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & U > 0;
// Returns true if an ASCII character is lowercase.
export fn islower(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & L > 0;
// Returns true if an ASCII character is a digit.
export fn isdigit(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & N > 0;
// Returns true if an ASCII character is a hexadecimal digit.
export fn isxdigit(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & X > 0;
// Returns true if an ASCII character is a white-space character -
// one of '\f', '\n', '\r', '\t', '\v', ' '.
export fn isspace(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & S > 0;
// Returns true if an ASCII character is punctuation.
export fn ispunct(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & P > 0;
// Returns true if an ASCII character is alphanumeric.
export fn isalnum(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & (U | L | N) > 0;
// Returns true if an ASCII character is printable.
export fn isprint(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & (P | U | L | N | B ) > 0;
// Returns true if an ASCII character is any printable character other than
// space.
export fn isgraph(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & (P | U | L | N) > 0;
// Returns true if an ASCII character is a control character.
export fn iscntrl(c: rune) bool =
if (!valid(c)) false else cclass[c: u32] & C > 0;
// Returns true if a rune is a space or a tab.
export fn isblank(c: rune) bool = (c == ' ' || c == '\t');
// Returns the uppercase form of an ASCII character, or the original character
// if it was not a lowercase letter (or was not ASCII).
export fn toupper(c: rune) rune = {
return if (islower(c)) {
yield (c: u32 - 'a' + 'A'): rune;
} else c;
};
// Returns the lowercase form of an ASCII character, or the original character
// if it was not an uppercase letter (or was not ASCII).
export fn tolower(c: rune) rune = {
return if (isupper(c)) {
yield (c: u32 - 'A' + 'a'): rune;
} else c;
};
@test fn ctype() void = {
// Just some simple tests
assert(isspace(' ') && !isspace('x') && !isspace('こ'));
assert(isalnum('a') && isalnum('8') && !isalnum('こ'));
assert(!ispunct('\0') && iscntrl('\b'));
assert(tolower('A') == 'a' && tolower('こ') == 'こ');
assert(isblank(' ') && isblank('\t') && !isblank('6'));
};
"#;

let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading Hare grammar");

parser.parse(code, None).unwrap();
}
}

0 comments on commit 850e976

Please sign in to comment.