Start work on heredocs

This commit is contained in:
Max Brunsfeld 2017-07-14 13:54:05 -07:00
parent d2ac184c81
commit 6be8857926
6 changed files with 1559 additions and 1139 deletions

View File

@ -8,7 +8,8 @@
], ],
"sources": [ "sources": [
"src/parser.c", "src/parser.c",
"src/binding.cc" "src/binding.cc",
"src/scanner.cc",
], ],
"cflags_c": [ "cflags_c": [
"-std=c99", "-std=c99",

View File

@ -101,6 +101,29 @@ cat a b 2> /dev/null
(file_redirect (file_descriptor) (file_descriptor)) (file_redirect (file_descriptor) (file_descriptor))
(command_name)))) (command_name))))
===============================
Heredoc redirects
===============================
node <<JS
console.log("hi")
JS
bash -c <<JS
echo hi
JS
---
(program
(command (simple_command
(command_name)
(heredoc_redirect (heredoc))))
(command (simple_command
(command_name)
(argument)
(heredoc_redirect (heredoc)))))
=============================== ===============================
Variable expansions Variable expansions
=============================== ===============================

View File

@ -3,6 +3,10 @@ module.exports = grammar({
inline: $ => [$.control_operator], inline: $ => [$.control_operator],
externals: $ => [
$.heredoc
],
rules: { rules: {
program: $ => repeat($.command), program: $ => repeat($.command),
@ -29,9 +33,10 @@ module.exports = grammar({
$.operator_expansion $.operator_expansion
)) ))
)), )),
repeat( repeat(choice(
$.file_redirect $.file_redirect,
) $.heredoc_redirect
))
), ),
pipeline: $ => prec.left(seq( pipeline: $ => prec.left(seq(
@ -83,6 +88,11 @@ module.exports = grammar({
) )
), ),
heredoc_redirect: $ => seq(
choice('<<', '<<-'),
$.heredoc
),
file_descriptor: $ => token(prec(1, /\d+/)), file_descriptor: $ => token(prec(1, /\d+/)),
leading_word: $ => /[^\s=|;:{}]+/, leading_word: $ => /[^\s=|;:{}]+/,

View File

@ -105,8 +105,17 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL", "type": "SYMBOL",
"name": "file_redirect" "name": "file_redirect"
},
{
"type": "SYMBOL",
"name": "heredoc_redirect"
}
]
} }
} }
] ]
@ -349,6 +358,28 @@
} }
] ]
}, },
"heredoc_redirect": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "<<"
},
{
"type": "STRING",
"value": "<<-"
}
]
},
{
"type": "SYMBOL",
"name": "heredoc"
}
]
},
"file_descriptor": { "file_descriptor": {
"type": "TOKEN", "type": "TOKEN",
"content": { "content": {
@ -389,7 +420,12 @@
} }
], ],
"conflicts": [], "conflicts": [],
"externals": [], "externals": [
{
"type": "SYMBOL",
"name": "heredoc"
}
],
"inline": [ "inline": [
"control_operator" "control_operator"
] ]

File diff suppressed because it is too large Load Diff

90
src/scanner.cc Normal file
View File

@ -0,0 +1,90 @@
#include <tree_sitter/parser.h>
#include <string>
#include <cwctype>
namespace {
using std::wstring;
enum TokenType {
HEREDOC
};
struct Scanner {
void skip(TSLexer *lexer) {
lexer->advance(lexer, true);
}
void advance(TSLexer *lexer) {
lexer->advance(lexer, false);
}
void reset() {}
bool serialize(TSExternalTokenState state) { return true; }
void deserialize(TSExternalTokenState state) {}
bool scan(TSLexer *lexer, const bool *valid_symbols) {
wstring heredoc_content;
while (iswalpha(lexer->lookahead)) {
heredoc_content += lexer->lookahead;
advance(lexer);
}
if (lexer->lookahead != '\n') return false;
wstring leading_word;
for (;;) {
advance(lexer);
while (iswalpha(lexer->lookahead)) {
leading_word += lexer->lookahead;
advance(lexer);
}
if (leading_word == heredoc_content || lexer->lookahead == '\0') break;
if (lexer->lookahead == '\n') leading_word.clear();
}
return true;
}
};
}
extern "C" {
void *tree_sitter_bash_external_scanner_create() {
return new Scanner();
}
bool tree_sitter_bash_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->scan(lexer, valid_symbols);
}
void tree_sitter_bash_external_scanner_reset(void *payload) {
Scanner *scanner = static_cast<Scanner *>(payload);
scanner->reset();
}
bool tree_sitter_bash_external_scanner_serialize(void *payload, TSExternalTokenState state) {
Scanner *scanner = static_cast<Scanner *>(payload);
return scanner->serialize(state);
}
void tree_sitter_bash_external_scanner_deserialize(void *payload, TSExternalTokenState state) {
Scanner *scanner = static_cast<Scanner *>(payload);
scanner->deserialize(state);
}
void tree_sitter_bash_external_scanner_destroy(void *payload) {
Scanner *scanner = static_cast<Scanner *>(payload);
delete scanner;
}
}