Skip to content

Commit 714f80d

Browse files
committed
implement smarty comments by extending html
1 parent 811b994 commit 714f80d

16 files changed

+4336
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
build
3+
Cargo.lock
4+
package-lock.json
5+
/target/

Cargo.toml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "tree-sitter-htmlsmarty"
3+
description = "htmlsmarty grammar for the tree-sitter parsing library"
4+
version = "0.0.1"
5+
keywords = ["incremental", "parsing", "htmlsmarty"]
6+
categories = ["parsing", "text-editors"]
7+
repository = "https://github.com/tree-sitter/tree-sitter-htmlsmarty"
8+
edition = "2018"
9+
license = "MIT"
10+
11+
build = "bindings/rust/build.rs"
12+
include = [
13+
"bindings/rust/*",
14+
"grammar.js",
15+
"queries/*",
16+
"src/*",
17+
]
18+
19+
[lib]
20+
path = "bindings/rust/lib.rs"
21+
22+
[dependencies]
23+
tree-sitter = "~0.20.10"
24+
25+
[build-dependencies]
26+
cc = "1.0"

binding.gyp

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "tree_sitter_htmlsmarty_binding",
5+
"include_dirs": [
6+
"<!(node -e \"require('nan')\")",
7+
"src"
8+
],
9+
"sources": [
10+
"bindings/node/binding.cc",
11+
"src/parser.c",
12+
# If your language uses an external scanner, add it here.
13+
],
14+
"cflags_c": [
15+
"-std=c99",
16+
]
17+
}
18+
]
19+
}

bindings/node/binding.cc

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "tree_sitter/parser.h"
2+
#include <node.h>
3+
#include "nan.h"
4+
5+
using namespace v8;
6+
7+
extern "C" TSLanguage * tree_sitter_htmlsmarty();
8+
9+
namespace {
10+
11+
NAN_METHOD(New) {}
12+
13+
void Init(Local<Object> exports, Local<Object> module) {
14+
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
15+
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
16+
tpl->InstanceTemplate()->SetInternalFieldCount(1);
17+
18+
Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
19+
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
20+
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_htmlsmarty());
21+
22+
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("htmlsmarty").ToLocalChecked());
23+
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
24+
}
25+
26+
NODE_MODULE(tree_sitter_htmlsmarty_binding, Init)
27+
28+
} // namespace

bindings/node/index.js

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
try {
2+
module.exports = require("../../build/Release/tree_sitter_htmlsmarty_binding");
3+
} catch (error1) {
4+
if (error1.code !== 'MODULE_NOT_FOUND') {
5+
throw error1;
6+
}
7+
try {
8+
module.exports = require("../../build/Debug/tree_sitter_htmlsmarty_binding");
9+
} catch (error2) {
10+
if (error2.code !== 'MODULE_NOT_FOUND') {
11+
throw error2;
12+
}
13+
throw error1
14+
}
15+
}
16+
17+
try {
18+
module.exports.nodeTypeInfo = require("../../src/node-types.json");
19+
} catch (_) {}

bindings/rust/build.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
fn main() {
2+
let src_dir = std::path::Path::new("src");
3+
4+
let mut c_config = cc::Build::new();
5+
c_config.include(&src_dir);
6+
c_config
7+
.flag_if_supported("-Wno-unused-parameter")
8+
.flag_if_supported("-Wno-unused-but-set-variable")
9+
.flag_if_supported("-Wno-trigraphs");
10+
let parser_path = src_dir.join("parser.c");
11+
c_config.file(&parser_path);
12+
13+
// If your language uses an external scanner written in C,
14+
// then include this block of code:
15+
16+
/*
17+
let scanner_path = src_dir.join("scanner.c");
18+
c_config.file(&scanner_path);
19+
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
20+
*/
21+
22+
c_config.compile("parser");
23+
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
24+
25+
// If your language uses an external scanner written in C++,
26+
// then include this block of code:
27+
28+
let mut cpp_config = cc::Build::new();
29+
cpp_config.cpp(true);
30+
cpp_config.include(&src_dir);
31+
cpp_config
32+
.flag_if_supported("-Wno-unused-parameter")
33+
.flag_if_supported("-Wno-unused-but-set-variable");
34+
let scanner_path = src_dir.join("scanner.cc");
35+
cpp_config.file(&scanner_path);
36+
cpp_config.compile("scanner");
37+
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
38+
}

bindings/rust/lib.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//! This crate provides htmlsmarty language support for the [tree-sitter][] parsing library.
2+
//!
3+
//! Typically, you will use the [language][language func] function to add this language to a
4+
//! tree-sitter [Parser][], and then use the parser to parse some code:
5+
//!
6+
//! ```
7+
//! let code = "";
8+
//! let mut parser = tree_sitter::Parser::new();
9+
//! parser.set_language(tree_sitter_htmlsmarty::language()).expect("Error loading htmlsmarty grammar");
10+
//! let tree = parser.parse(code, None).unwrap();
11+
//! ```
12+
//!
13+
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
14+
//! [language func]: fn.language.html
15+
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
16+
//! [tree-sitter]: https://tree-sitter.github.io/
17+
18+
use tree_sitter::Language;
19+
20+
extern "C" {
21+
fn tree_sitter_htmlsmarty() -> Language;
22+
}
23+
24+
/// Get the tree-sitter [Language][] for this grammar.
25+
///
26+
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
27+
pub fn language() -> Language {
28+
unsafe { tree_sitter_htmlsmarty() }
29+
}
30+
31+
/// The content of the [`node-types.json`][] file for this grammar.
32+
///
33+
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
34+
pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json");
35+
36+
// Uncomment these to include any queries that this grammar contains
37+
38+
// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
39+
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
40+
// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
41+
// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
42+
43+
#[cfg(test)]
44+
mod tests {
45+
#[test]
46+
fn test_can_load_grammar() {
47+
let mut parser = tree_sitter::Parser::new();
48+
parser
49+
.set_language(super::language())
50+
.expect("Error loading htmlsmarty language");
51+
}
52+
}

grammar.js

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const html = require("tree-sitter-html/grammar");
2+
3+
module.exports = grammar(html, {
4+
name: "htmlsmarty",
5+
6+
extras: $ => [
7+
$.comment,
8+
// TODO: technically this would be possible too, and a whole lot easier (only needs adjusting text, nothing else)
9+
// but i dont know if this would then properly work with indentation for eg. smarty_if
10+
//$.smarty_comment,
11+
/\s+/,
12+
],
13+
14+
rules: {
15+
smarty_comment: ($) => seq(
16+
"{*",
17+
/[^*]*\*+([^}*][^*]*\*+)*/,
18+
"}"
19+
),
20+
21+
// in text
22+
// FIXME: see comment in test/corpus/unpaired.txt for why this is broken in the edge case of
23+
// `text {<valid-tag/>`
24+
text: $ => /([^<>{]|\{[^*<>])+/,
25+
26+
_node: $ => choice(
27+
$.doctype,
28+
$.text,
29+
$.smarty_comment,
30+
$.element,
31+
$.script_element,
32+
$.style_element,
33+
$.erroneous_end_tag
34+
),
35+
36+
// in attribute lists
37+
_attribute: $ => choice(
38+
$.attribute,
39+
$.smarty_comment,
40+
),
41+
42+
attribute_name: $ => /([^<>"'/=\s{]|\{[^*<>"'/=\s{])+/,
43+
44+
sq_attribute_value_fragment: $ => repeat1(choice(
45+
/([^'{]|\{[^*'])+/,
46+
$.smarty_comment
47+
)),
48+
dq_attribute_value_fragment: $ => repeat1(choice(
49+
/([^"{]|\{[^*"])+/,
50+
$.smarty_comment
51+
)),
52+
53+
quoted_attribute_value: $ => choice(
54+
seq("'", optional(alias($.sq_attribute_value_fragment, $.attribute_value)), optional("{"), "'"),
55+
seq('"', optional(alias($.dq_attribute_value_fragment, $.attribute_value)), optional("{"), '"'),
56+
),
57+
58+
59+
start_tag: $ => seq(
60+
'<',
61+
alias($._start_tag_name, $.tag_name),
62+
repeat($._attribute),
63+
'>'
64+
),
65+
66+
script_start_tag: $ => seq(
67+
'<',
68+
alias($._script_start_tag_name, $.tag_name),
69+
repeat($._attribute),
70+
'>'
71+
),
72+
73+
style_start_tag: $ => seq(
74+
'<',
75+
alias($._style_start_tag_name, $.tag_name),
76+
repeat($._attribute),
77+
'>'
78+
),
79+
80+
self_closing_tag: $ => seq(
81+
'<',
82+
alias($._start_tag_name, $.tag_name),
83+
repeat($._attribute),
84+
'/>'
85+
),
86+
}
87+
});

package.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "tree-sitter-htmlsmarty",
3+
"version": "0.1.0",
4+
"description": "A tree-sitter grammar for the smarty template language",
5+
"main": "bindings/node",
6+
"scripts": {
7+
"test": "tree-sitter test"
8+
},
9+
"keywords": [
10+
"smarty",
11+
"html",
12+
"tree-sitter",
13+
"parser",
14+
"grammar"
15+
],
16+
"author": "deltragon",
17+
"license": "MIT",
18+
"dependencies": {
19+
"nan": "^2.15.0",
20+
"tree-sitter-html": "0.19.0"
21+
},
22+
"repository": {
23+
"type": "git",
24+
"url": "git://github.com/deltragon/tree-sitter-htmlsmarty.git"
25+
},
26+
"devDependencies": {
27+
"tree-sitter-cli": "^0.20.4"
28+
}
29+
}

0 commit comments

Comments
 (0)