tabry 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tabry/shells/bash.rb +12 -5
- data/sh/bash/README.md +2 -1
- data/tabry.gemspec +19 -2
- data/treesitter/Cargo.toml +26 -0
- data/treesitter/README.md +4 -0
- data/treesitter/binding.gyp +19 -0
- data/treesitter/bindings/node/binding.cc +28 -0
- data/treesitter/bindings/node/index.js +19 -0
- data/treesitter/bindings/rust/build.rs +40 -0
- data/treesitter/bindings/rust/lib.rs +52 -0
- data/treesitter/corpus/arg.txt +96 -0
- data/treesitter/corpus/at.txt +79 -0
- data/treesitter/corpus/comment.txt +13 -0
- data/treesitter/corpus/desc.txt +25 -0
- data/treesitter/corpus/examples_from_language_reference.txt +410 -0
- data/treesitter/corpus/flag.txt +48 -0
- data/treesitter/corpus/flag_desc_inline.txt +37 -0
- data/treesitter/corpus/opts.txt +21 -0
- data/treesitter/corpus/rapture.txt +61 -0
- data/treesitter/grammar.js +171 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/argument_titles.yml +8 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/arguments_and_possible_options__arg_.yml +23 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/flags__flag__flagarg__reqd_flagarg_.yml +37 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/getting_started.yml +13 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/includes.yml +57 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/multi_line_descriptions.yml +7 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/optional_args_and_varargs__opt_arg__varargs__opt_varargs_.yml +16 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/options.yml +24 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/subcommands__sub__1.yml +23 -0
- data/treesitter/jest_fixtures/examples_from_language_reference/subcommands__sub__2.yml +15 -0
- data/treesitter/package.json +21 -0
- data/treesitter/parser_compile.sh +1 -0
- data/treesitter/src/grammar.json +615 -0
- data/treesitter/src/node-types.json +563 -0
- data/treesitter/src/parser.c +4706 -0
- data/treesitter/src/tree_sitter/parser.h +223 -0
- data/treesitter/tabry-compile.js +394 -0
- data/treesitter/tabry-compile.test.js +51 -0
- metadata +36 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 853b43dede9ba1a93e3581eefd4dbe883ec0cbef4cf493776183df0d363fed3e
|
4
|
+
data.tar.gz: f8bb31ead64b56da0f0bbabe051219fca8e40ade773b730b4295d990b5fe03b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 463f392cad04097474a34abd6bf78d9bf3dfb88a7af8867f3879bcce514ec07c5d8d9acddcb01e8cb6dbb286545085ccd72fdaeb2686d7e1f738eae2405752b4
|
7
|
+
data.tar.gz: 1f877f562de0e3b3d08421b087cc66d00efc2875807da22b88fec70068aaa55b512840eb12e3414a9813e6932017a7737cb5ad5e91df19024627095536cb1275
|
data/lib/tabry/shells/bash.rb
CHANGED
@@ -1,17 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Used to generate a tab-completion function for a Tabry CLI using absolute
|
4
|
+
# paths to the tabry-bash script in this repo and to the Tabry JSON/YML file.
|
5
|
+
# Using uniquely-named tab-completion functions and absolute paths means you can
|
6
|
+
# have different Tabry-based CLIs using different versions of Tabry without any
|
7
|
+
# conflicts.
|
8
|
+
# See sh/bash/README.md and "Adding Tab Completion to your CLI" in main README
|
9
|
+
|
1
10
|
module Tabry
|
2
11
|
module Shells
|
3
12
|
module Bash
|
4
13
|
# NOTE! This code uses sh/bash/tabry_bash_core.sh and is described in
|
5
14
|
# sh/bash/README.md; see that README for more info
|
6
15
|
def self.generate(cmd_name, tabry_file_path)
|
7
|
-
capitalized_cmd_name = cmd_name.upcase.gsub(/[^a-zA-Z0-9_]/,
|
16
|
+
capitalized_cmd_name = cmd_name.upcase.gsub(/[^a-zA-Z0-9_]/, "_")
|
8
17
|
tabry_file = Shellwords.escape(File.expand_path(tabry_file_path))
|
9
18
|
path_to_tabry = Shellwords.escape(File.expand_path("#{__dir__}/../../../"))
|
10
19
|
|
11
20
|
core = File.read("#{__dir__}/../../../sh/bash/tabry_bash_core.sh")
|
12
21
|
core.gsub! "_tabry_completions_internal()", "_tabry_#{capitalized_cmd_name}_completions_internal()"
|
13
22
|
|
14
|
-
|
23
|
+
<<~END_BASH_CODE_TEMPLATE + core
|
15
24
|
# The following Autocomplete is for a Tabry-powered command. It was
|
16
25
|
# generated by the command itself. See the documentation located in
|
17
26
|
# #{path_to_tabry}/sh/bash/README.md
|
@@ -19,10 +28,8 @@ module Tabry
|
|
19
28
|
TABRY_IMPORTS_PATH=#{tabry_file} _tabry_#{capitalized_cmd_name}_completions_internal #{path_to_tabry}/bin/tabry-bash
|
20
29
|
}
|
21
30
|
complete -F _tabry_#{capitalized_cmd_name}_completions #{Shellwords.escape cmd_name}
|
22
|
-
|
31
|
+
END_BASH_CODE_TEMPLATE
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
26
35
|
end
|
27
|
-
|
28
|
-
|
data/sh/bash/README.md
CHANGED
@@ -23,11 +23,12 @@ This file and bash function contained within is used in two ways:
|
|
23
23
|
added on, to make tab completion specific for the program. This is generated
|
24
24
|
for each command when the user runs "mycommand completion bash", which calls
|
25
25
|
`Tabry::Shells::Bash.generate`. A new function for each CLI so different CLIs
|
26
|
-
can use different versions of
|
26
|
+
can use different versions of tabry without interfering with each other.
|
27
27
|
The name `_tabry_completions_internal_` is replaced in
|
28
28
|
`lib/tabry/shells/bash.rb` in the `generate` method, so if modifying
|
29
29
|
`tabry_bash_core.sh`, you should if make sure the substitution still works
|
30
30
|
properly.
|
31
|
+
See also "Adding Tab Completion to your CLI" in the main README.
|
31
32
|
* You can also use Tabry to add tab completion to other non-Tabry CLIs. In this
|
32
33
|
case, the `_tabry_completions_internal_` function is used as-is; it is
|
33
34
|
sourced from `tabry_bash.sh`. See `tabry_bash.sh` for details and
|
data/tabry.gemspec
CHANGED
@@ -6,14 +6,31 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "tabry"
|
9
|
-
s.version = "0.1.
|
9
|
+
s.version = "0.1.2"
|
10
10
|
s.summary = "Tab completion and CLIs extraordinaire"
|
11
11
|
s.authors = ["Evan Battaglia"]
|
12
12
|
s.email = "battaglia.evan@gmail.com"
|
13
13
|
s.homepage = "https://github.com/evanbattaglia/tabry"
|
14
14
|
s.license = "MIT"
|
15
15
|
|
16
|
-
|
16
|
+
treesitter_files = %w[
|
17
|
+
binding.gyp
|
18
|
+
bindings/**/*
|
19
|
+
Cargo.toml
|
20
|
+
corpus/**/*
|
21
|
+
grammar.js
|
22
|
+
jest_fixtures/**/*
|
23
|
+
package.json
|
24
|
+
parser_compile.sh
|
25
|
+
README.md
|
26
|
+
src/**/*
|
27
|
+
tabry-compile.js
|
28
|
+
tabry-compile.test.js
|
29
|
+
]
|
30
|
+
|
31
|
+
s.files = Dir.glob("{lib,bin,sh,spec}/**/*") + %w[tabry.gemspec] +
|
32
|
+
treesitter_files.map { |path| Dir.glob("treesitter/#{path}") }
|
33
|
+
|
17
34
|
# TODO: more cargo cult possibly:
|
18
35
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
36
|
s.require_paths = ["lib"]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
[package]
|
2
|
+
name = "tree-sitter-tabry"
|
3
|
+
description = "tabry grammar for the tree-sitter parsing library"
|
4
|
+
version = "0.0.1"
|
5
|
+
keywords = ["incremental", "parsing", "tabry"]
|
6
|
+
categories = ["parsing", "text-editors"]
|
7
|
+
repository = "https://github.com/tree-sitter/tree-sitter-tabry"
|
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.0"
|
24
|
+
|
25
|
+
[build-dependencies]
|
26
|
+
cc = "1.0"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"targets": [
|
3
|
+
{
|
4
|
+
"target_name": "tree_sitter_tabry_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
|
+
}
|
@@ -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_tabry();
|
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_tabry());
|
21
|
+
|
22
|
+
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("tabry").ToLocalChecked());
|
23
|
+
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
|
24
|
+
}
|
25
|
+
|
26
|
+
NODE_MODULE(tree_sitter_tabry_binding, Init)
|
27
|
+
|
28
|
+
} // namespace
|
@@ -0,0 +1,19 @@
|
|
1
|
+
try {
|
2
|
+
module.exports = require("../../build/Release/tree_sitter_tabry_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_tabry_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 (_) {}
|
@@ -0,0 +1,40 @@
|
|
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
|
+
/*
|
29
|
+
let mut cpp_config = cc::Build::new();
|
30
|
+
cpp_config.cpp(true);
|
31
|
+
cpp_config.include(&src_dir);
|
32
|
+
cpp_config
|
33
|
+
.flag_if_supported("-Wno-unused-parameter")
|
34
|
+
.flag_if_supported("-Wno-unused-but-set-variable");
|
35
|
+
let scanner_path = src_dir.join("scanner.cc");
|
36
|
+
cpp_config.file(&scanner_path);
|
37
|
+
cpp_config.compile("scanner");
|
38
|
+
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
|
39
|
+
*/
|
40
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
//! This crate provides tabry 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_tabry::language()).expect("Error loading tabry 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_tabry() -> 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_tabry() }
|
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 tabry language");
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
==============
|
2
|
+
Arg with two opts
|
3
|
+
==============
|
4
|
+
|
5
|
+
arg {
|
6
|
+
opts const "hello \"world\""
|
7
|
+
opts const abc
|
8
|
+
}
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
(source_file
|
13
|
+
(arg_statement
|
14
|
+
(arg_type)
|
15
|
+
(block
|
16
|
+
(opts_const_statement (string))
|
17
|
+
(opts_const_statement (string)))))
|
18
|
+
|
19
|
+
==============
|
20
|
+
Named args
|
21
|
+
==============
|
22
|
+
|
23
|
+
arg foo
|
24
|
+
arg foo @whatever
|
25
|
+
arg foo @whatever {
|
26
|
+
opts const abc
|
27
|
+
}
|
28
|
+
|
29
|
+
---
|
30
|
+
|
31
|
+
(source_file
|
32
|
+
(arg_statement
|
33
|
+
(arg_type)
|
34
|
+
(arg_name_list (string)))
|
35
|
+
(arg_statement
|
36
|
+
(arg_type)
|
37
|
+
(arg_name_list (string))
|
38
|
+
(at_identifier))
|
39
|
+
(arg_statement
|
40
|
+
(arg_type)
|
41
|
+
(arg_name_list (string))
|
42
|
+
(at_identifier)
|
43
|
+
(block
|
44
|
+
(opts_const_statement (string)))))
|
45
|
+
|
46
|
+
============
|
47
|
+
Name and description
|
48
|
+
============
|
49
|
+
|
50
|
+
arg foo "my description"
|
51
|
+
|
52
|
+
---
|
53
|
+
|
54
|
+
(source_file
|
55
|
+
(arg_statement
|
56
|
+
(arg_type)
|
57
|
+
(arg_name_list (string))
|
58
|
+
(string)))
|
59
|
+
|
60
|
+
============
|
61
|
+
Names and description
|
62
|
+
============
|
63
|
+
|
64
|
+
arg (foo bar) "my description"
|
65
|
+
|
66
|
+
---
|
67
|
+
|
68
|
+
(source_file
|
69
|
+
(arg_statement
|
70
|
+
(arg_type)
|
71
|
+
(arg_name_list (string) (string))
|
72
|
+
(string)))
|
73
|
+
|
74
|
+
============
|
75
|
+
Optional arg
|
76
|
+
============
|
77
|
+
|
78
|
+
opt arg
|
79
|
+
opt arg foo @whatever {
|
80
|
+
opts const abc
|
81
|
+
}
|
82
|
+
|
83
|
+
---
|
84
|
+
|
85
|
+
(source_file
|
86
|
+
(arg_statement
|
87
|
+
(arg_modifier)
|
88
|
+
(arg_type))
|
89
|
+
(arg_statement
|
90
|
+
(arg_modifier)
|
91
|
+
(arg_type)
|
92
|
+
(arg_name_list (string))
|
93
|
+
(at_identifier)
|
94
|
+
(block
|
95
|
+
(opts_const_statement (string)))))
|
96
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
==========
|
2
|
+
At include
|
3
|
+
==========
|
4
|
+
|
5
|
+
sub ok {
|
6
|
+
arg {
|
7
|
+
include @foo
|
8
|
+
opts const abc
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
(source_file
|
15
|
+
(sub_statement
|
16
|
+
(sub_name_list (string))
|
17
|
+
(block
|
18
|
+
(arg_statement
|
19
|
+
(arg_type)
|
20
|
+
(block
|
21
|
+
(include_statement
|
22
|
+
(at_identifier))
|
23
|
+
(opts_const_statement
|
24
|
+
(string)))))))
|
25
|
+
|
26
|
+
=============
|
27
|
+
At definition
|
28
|
+
=============
|
29
|
+
|
30
|
+
defopts @bar {
|
31
|
+
opts const def
|
32
|
+
}
|
33
|
+
|
34
|
+
defargs @foo {
|
35
|
+
arg
|
36
|
+
}
|
37
|
+
|
38
|
+
---
|
39
|
+
|
40
|
+
(source_file
|
41
|
+
(defopts_statement
|
42
|
+
(at_identifier)
|
43
|
+
(block
|
44
|
+
(opts_const_statement (string))))
|
45
|
+
(defargs_statement
|
46
|
+
(at_identifier)
|
47
|
+
(block
|
48
|
+
(arg_statement
|
49
|
+
(arg_type)))))
|
50
|
+
|
51
|
+
=================
|
52
|
+
Inline at include
|
53
|
+
=================
|
54
|
+
|
55
|
+
sub whatever @foo {
|
56
|
+
flagarg foo @wombat
|
57
|
+
arg @bar {
|
58
|
+
opts const abc
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
---
|
63
|
+
|
64
|
+
(source_file
|
65
|
+
(sub_statement
|
66
|
+
(sub_name_list (string))
|
67
|
+
(at_identifier)
|
68
|
+
(block
|
69
|
+
(flagarg_statement
|
70
|
+
(flag_name_list (string))
|
71
|
+
(at_identifier))
|
72
|
+
(arg_statement
|
73
|
+
(arg_type)
|
74
|
+
(at_identifier)
|
75
|
+
(block
|
76
|
+
(opts_const_statement
|
77
|
+
(string)))))))
|
78
|
+
|
79
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
==========
|
2
|
+
Desc
|
3
|
+
==========
|
4
|
+
|
5
|
+
sub ok {
|
6
|
+
desc foo
|
7
|
+
arg {
|
8
|
+
desc "bar"
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
---
|
13
|
+
|
14
|
+
(source_file
|
15
|
+
(sub_statement
|
16
|
+
(sub_name_list
|
17
|
+
(string))
|
18
|
+
(block
|
19
|
+
(desc_statement
|
20
|
+
(string))
|
21
|
+
(arg_statement
|
22
|
+
(arg_type)
|
23
|
+
(block
|
24
|
+
(desc_statement
|
25
|
+
(string)))))))
|