Skip to content

Commit

Permalink
✨ Add highlights and rust bindings (Wilfred#13)
Browse files Browse the repository at this point in the history
* Add highlights.scm and minor grammar change

* `queries/highlights.scm` added and `package.json` changed to support
  syntax highlight
* primitive_type node made public for specific highlight case
* typo fixed in grammar definition
* grammar renamed 'Solidity' -> 'solidity' for consistency with other
  packages

* ♻ implement suggested refactors from pr Wilfred#12

* add target to npm ignore

* set edition back to 2018

* add cargo lock to ignore

* extend rust gitignore

* add lowercase to package name

* build fixes

* add rust build/test pipeline

* just use node

* install the cli

* do a global cli install

* add some descriptions to rust action

Co-authored-by: p13nty <[email protected]>
  • Loading branch information
JoranHonig and p13nty authored Jun 18, 2021
1 parent 34d6045 commit 113dfea
Show file tree
Hide file tree
Showing 20 changed files with 483 additions and 46 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

name: 🦀 Build and Test rust bindings

jobs:
build_and_test:
name: Rust project
runs-on: ubuntu-latest
steps:

- name: 📥 Download the repository
uses: actions/checkout@v2
- name: 🦀 Install rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable

- name: 📥 Setup node
uses: actions/setup-node@v1
with:
node-version: 12

- name: 📥 Install js dependencies
run: |
npm install yarn
npm install tree-sitter-cli -g
yarn
- name: 🌲 Generate the parser
run: tree-sitter generate

- name: 🛠 Build rust bindings
uses: actions-rs/cargo@v1
with:
command: build
args: --release --all-features

# Run the tests
- name: 🧪 Now run the rust tests
uses: actions-rs/cargo@v1
with:
command: test
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ node_modules/
src/
.vscode/
binding.gyp
index.js
index.js

# Rust
Cargo.lock
target
build
6 changes: 5 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
corpus
examples
build
script
script

# Rust
target
Cargo.lock
26 changes: 26 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "tree-sitter-solidity"
description = "Solidity grammar for the tree-sitter parsing library"
version = "0.0.2"
keywords = ["incremental", "parsing", "Solidity"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/JoranHonig/tree-sitter-solidity"
edition = "2018"
license = "MIT"

build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.js",
"queries/*",
"src/*",
]

[lib]
path = "bindings/rust/lib.rs"

[dependencies]
tree-sitter = "0.19.5"

[build-dependencies]
cc = "1.0"
28 changes: 28 additions & 0 deletions bindings/node/binding.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"

using namespace v8;

extern "C" TSLanguage * tree_sitter_Solidity();

namespace {

NAN_METHOD(New) {}

void Init(Local<Object> exports, Local<Object> module) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);

Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_Solidity());

Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("Solidity").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}

NODE_MODULE(tree_sitter_Solidity_binding, Init)

} // namespace
40 changes: 40 additions & 0 deletions bindings/rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
fn main() {
let src_dir = std::path::Path::new("src");

let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);

// If your language uses an external scanner written in C,
// then include this block of code:

/*
let scanner_path = src_dir.join("scanner.c");
c_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
*/

c_config.compile("parser");
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());

// If your language uses an external scanner written in C++,
// then include this block of code:

/*
let mut cpp_config = cc::Build::new();
cpp_config.cpp(true);
cpp_config.include(&src_dir);
cpp_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable");
let scanner_path = src_dir.join("scanner.cc");
cpp_config.file(&scanner_path);
cpp_config.compile("scanner");
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
*/
}
58 changes: 58 additions & 0 deletions bindings/rust/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//! This crate provides Solidity language support for the [tree-sitter][] parsing library.
//!
//! The bindings in https://github.com/tree-sitter/tree-sitter-javascript/blob/master/bindings/rust were used
//! as a template for the tree-sitter-solidity rust bindings.
//!
//! Typically, you will use the [language][language func] function to add this language to a
//! tree-sitter [Parser][], and then use the parser to parse some code:
//!
//! ```
//! let code = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_solidity::language()).expect("Error loading Solidity grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
//! [language func]: fn.language.html
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
//! [tree-sitter]: https://tree-sitter.github.io/
use tree_sitter::Language;

extern "C" {
fn tree_sitter_solidity() -> Language;
}

/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { tree_sitter_solidity() }
}

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

/// 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: &'static 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]
fn test_can_load_grammar() {
let mut parser = tree_sitter::Parser::new();
parser
.set_language(super::language())
.expect("Error loading Solidity language");
}
}
20 changes: 10 additions & 10 deletions grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const PREC = {

// The following is the core grammar for Solidity. It accepts Solidity smart contracts between the versions 0.4.x and 0.7.x.
module.exports = grammar({
name: 'Solidity',
name: 'solidity',

// Extras is an array of tokens that is allowed anywhere in the document.
extras: $ => [
Expand Down Expand Up @@ -644,7 +644,7 @@ module.exports = grammar({
$.binary_expression,
$.unary_expression,
$.update_expression,
$.call_expresion,
$.call_expression,
// TODO: $.function_call_options_expression,
$.payable_conversion_expression,
$.meta_type_expression,
Expand All @@ -660,7 +660,7 @@ module.exports = grammar({
$.member_expression,
$.array_access,
$.slice_access,
$._primitive_type,
$.primitive_type,
$.assignment_expression,
$.augmented_assignment_expression,
$._user_defined_type,
Expand All @@ -671,8 +671,8 @@ module.exports = grammar({
$.new_expression,
),

// TODO: back this up with official dcumentation
type_cast_expression: $ => prec.left(seq($._primitive_type, '(', $._expression,')')),
// TODO: back this up with official documentation
type_cast_expression: $ => prec.left(seq($.primitive_type, '(', $._expression,')')),

ternary_expression: $ => prec.left(seq($._expression, "?", $._expression, ':', $._expression)),

Expand Down Expand Up @@ -811,15 +811,15 @@ module.exports = grammar({
field('right', $._expression)
)),

call_expresion: $ => seq(
call_expression: $ => seq(
seq($._expression, $._call_arguments),
),

payable_conversion_expression: $ => seq('payable', $._call_arguments),
meta_type_expression: $ => seq('type', '(', $.type_name, ')'),

type_name: $ => prec(0, choice(
$._primitive_type,
$.primitive_type,
$._user_defined_type,
$._mapping,
$._array_type,
Expand Down Expand Up @@ -871,11 +871,11 @@ module.exports = grammar({
),

_mapping_key: $ => choice(
$._primitive_type,
$.primitive_type,
$._user_defined_type
),

_primitive_type: $ => prec.left(choice(
primitive_type: $ => prec.left(choice(
seq('address', optional('payable')),
'bool',
'string',
Expand Down Expand Up @@ -1045,4 +1045,4 @@ function optionalDashSeparation(rule) {
),
);
}


19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "tree-sitter-solidity",
"version": "1.0.5",
"description": "A tree sitter parser for Solidity",
"main": "index.js",
"main": "bindings/node",
"scripts": {
"test": "tree-sitter generate && tree-sitter test"
},
Expand All @@ -13,5 +13,17 @@
},
"devDependencies": {
"tree-sitter-cli": "^0.16.9"
}
},
"tree-sitter": [
{
"scope": "source.sol",
"file-types": [
"sol"
],
"highlights": [
"queries/highlights.scm"
],
"injection-regex": "^(sol|solidity)$"
}
]
}
Loading

0 comments on commit 113dfea

Please sign in to comment.