Skip to content

Commit bafd09b

Browse files
williamthomefacebook-github-bot
authored andcommitted
Allow exprs in the source_file grammar rule (#9)
Summary: Closes #3. Currently, only "top level" forms of a module are allowed at the beginning of the source_file rule, but this makes this tree-sitter not usable, for example, in Markdown code blocks. Allowing any fragment of an expression makes this tree-sitter usable for other languages to inject Erlang code, for example, a new language in the Phoenix (Elixir) style, that embeeds Erlang code in HTML. --- Notes: 1. The tree generated for fragmented code is `(source_file (...exprs))`. Maybe the tree as is today as `(source_file (...forms))` should be for a file/module structure and `(fragment (...exprs))` should be for fragmented parts of code 2. The term "fragment" is what comes to my mind, but could be any other 3. I'm not sure about the conflicts order introduced by this PR --- ## Before this PR ![tree-sitter-erlang-before](https://github.com/user-attachments/assets/b922e440-8ca0-432e-845d-82ad6c532299) ## After this PR ![tree-sitter-erlang-after](https://github.com/user-attachments/assets/0a835a76-1a90-4d7c-b171-9e46c9c47301) Pull Request resolved: #9 Test Plan: Imported from GitHub, without a `Test Plan:` line. - CI - cd tree-sitter-erlang - make Ensure all tests pass, and no generated files change - cd .. - cargo xtask codegen Check that no checked in files change - Compare lint output before and after ``` cargo run --bin elp -- lint --project ~/fbsource/whatsapp/server/erl --include-erlc-diagnostics --include-edoc-diagnostics --read-config --include-tests --include-ct-diagnostics &> /tmp/run-elp-lint.txt ``` Check out master ``` cargo run --bin elp -- lint --project ~/fbsource/whatsapp/server/erl --include-erlc-diagnostics --include-edoc-diagnostics --read-config --include-tests --include-ct-diagnostics &> /tmp/run-elp-lint-master.txt ``` `diff /tmp/run-elp-lint.txt /tmp/run-elp-lint-master.txt` should show no differences Reviewed By: michalmuskala Differential Revision: D69120163 Pulled By: alanz fbshipit-source-id: 73f02ac6b61dbd0bec100d2dcfaa52b7694304cb
1 parent 90f1fcb commit bafd09b

File tree

6 files changed

+43437
-31721
lines changed

6 files changed

+43437
-31721
lines changed

grammar.js

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,16 @@ const PREC = {
2525
ADD_OP: 5, // add_op is left-associative
2626
DOTDOT: 6, // `..` in Type
2727
DARROW: 7, // `=>` in Type, Expr
28-
CEQ: 8, // `:=` in Type, Expr
29-
BANG: 13, // `:=` in Expr
30-
ORELSE: 14, // `:=` in Expr
31-
ANDALSO: 15, // `:=` in Expr
32-
LIST_OP: 16, // `:=` in Expr
33-
COMP_OP: 17, // `:=` in Expr
28+
BANG: 13, // `!` in Expr
29+
ORELSE: 14, // `orelse` in Expr
30+
ANDALSO: 15, // `andalso` in Expr
31+
LIST_OP: 16, // `++` / `--` in Expr
32+
COMP_OP: 17, // Comparison operators in Expr
3433

3534
// For remote vs binary :
36-
CALL: 80,
3735
REMOTE: 1,
3836
BIT_EXPR: 2,
37+
CALL: 80,
3938

4039
COND_MATCH: 81, // `?=` in maybe expr. Should has lowest priority https://www.erlang.org/eeps/eep-0049#operator-priority
4140

@@ -46,6 +45,12 @@ const PREC = {
4645
DYN_GUARD_AND: 4,
4746
DYN_EXPR_GUARD: 5,
4847
DYN_EXPR: 6,
48+
49+
// Distinguishing between top level forms and expressions.
50+
// Given a form *has* to be at the top level (only), we give the
51+
// form construct a higher precedence each time.
52+
PP_IF: 20, // Conflict between `pp_if` and `_prefix_op`
53+
ATTR_NAME: 20, // Conflict between `attr_name` and `_prefix_op`
4954
};
5055

5156
///////////////////////////////////////////////////////////////////////////////
@@ -182,11 +187,19 @@ module.exports = grammar({
182187
[$._macro_def_replacement, $.replacement_guard_and, $.replacement_expr_guard],
183188
// Fun type vs regular function `fun()` vs `fun() -> ...`
184189
[$.fun_type, $.expr_args],
190+
// Introduced by the exprs choice in the source_file
191+
[$._expr, $._map_expr_base, $._record_expr_base],
192+
[$._expr, $._map_expr_base],
193+
[$._expr, $._record_expr_base],
194+
[$._function_or_macro_clause, $._macro_body_expr],
185195
],
186196

187197
rules: {
188198

189-
source_file: $ => field('forms_only', repeat($._form)),
199+
source_file: $ => choice(
200+
field('forms_only', repeat($._form)),
201+
field('exprs', repeat(seq($._expr, optional("."))))
202+
),
190203

191204
// -------------------------------------------------------------
192205

@@ -258,7 +271,7 @@ module.exports = grammar({
258271
pp_ifndef: $ => seq('-', atom_const('ifndef'), '(', field("name", $._macro_name), ')', '.'),
259272
pp_else: $ => seq('-', atom_const('else'), '.'),
260273
pp_endif: $ => seq('-', atom_const('endif'), '.'),
261-
pp_if: $ => seq('-', atom_const('if'), field("cond", $._expr), '.'),
274+
pp_if: $ => prec(PREC.PP_IF, seq('-', atom_const('if'), field("cond", $._expr), '.')),
262275
pp_elif: $ => seq('-', atom_const('elif'), field("cond", $._expr), '.'),
263276

264277
pp_define: $ => seq(
@@ -436,7 +449,7 @@ module.exports = grammar({
436449

437450
wild_attribute: $ => seq(field("name", $.attr_name), field("value", $._expr), '.'),
438451

439-
attr_name: $ => seq('-', field("name", $._name)),
452+
attr_name: $ => prec(PREC.ATTR_NAME, seq('-', field("name", $._name))),
440453

441454
fun_decl: $ => prec.right(seq(
442455
field("clause", $._function_or_macro_clause),

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"install": "node-gyp-build",
77
"prestart": "tree-sitter build --wasm",
88
"start": "tree-sitter playground",
9+
"parse": "npx tree-sitter-cli parse",
910
"test": "node --test bindings/node/*_test.js"
1011
},
1112
"authors": [

src/grammar.json

Lines changed: 113 additions & 55 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/node-types.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)