mirror of https://github.com/Wilfred/difftastic/
Add 'vendor/tree-sitter-bash/' from commit '4094e3a0405aabb1314c0c41f29e38e70af86fa5'
git-subtree-dir: vendor/tree-sitter-bash git-subtree-mainline:pull/70/head7d1bf1e5f4git-subtree-split:4094e3a040
commit
678c1c5773
@ -0,0 +1,2 @@
|
||||
/src/** linguist-vendored
|
||||
/examples/* linguist-vendored
|
||||
@ -0,0 +1,22 @@
|
||||
name: Build & Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14
|
||||
- run: npm install
|
||||
- run: node_modules/.bin/tree-sitter test
|
||||
@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
build
|
||||
*.log
|
||||
package-lock.json
|
||||
test.sh
|
||||
Cargo.lock
|
||||
target
|
||||
@ -0,0 +1,3 @@
|
||||
[submodule "examples/bash-it"]
|
||||
path = examples/bash-it
|
||||
url = https://github.com/Bash-it/bash-it.git
|
||||
@ -0,0 +1,6 @@
|
||||
corpus
|
||||
build
|
||||
examples
|
||||
script
|
||||
target
|
||||
Cargo.lock
|
||||
@ -0,0 +1,34 @@
|
||||
language: node_js
|
||||
|
||||
sudo: false
|
||||
|
||||
node_js:
|
||||
- node
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
env: COMPILER=clang++
|
||||
osx_image: xcode9.2
|
||||
compiler: clang
|
||||
- os: linux
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^v.*$/
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
script: npm run pre-build && npm run pre-build:upload -u ${PREBUILD_UPLOAD}
|
||||
skip_cleanup: true
|
||||
on:
|
||||
all_branches: true
|
||||
tags: true
|
||||
|
||||
env:
|
||||
global:
|
||||
secure: jAdfI37gohXm5VvR5h2AoWVwUMS9hUPxZIP4VR2iOkTSZLaaZczvL04IRNv3bQY6WUYxcVB6xoKbOPMKE1cHvXM8L2W6G1InPxU14P6fKd2MGWxH6PWmCoXHWFQ1AzWkYsMgMokHT2vs4iZ2bLHE9uV3RVuAISO/APsw7AxEpEijljvPkL+Se0nTnCfTbw4ObGxEMRW7TnjKa2W7K8m4QbbGd+r9CzCxBakjdIePQx81IUAAIGwphkY/avNJeUvR1XLnAM38K9Yj0ioSfeV6/QshK/28DLmvilq9sV4LDLVlhgP6h1FB4HW3PEVvYWnWBKa9cUdIAIncya2ibvu2cRHYVbud4Ho6lMCk/QUuiPYLCfnOfa4byVj3DInOY1yCpu+YnqjVOUHV5wQLEvnArLCuJa7dlJSmYquzVr5NkOz9gMmFAyuznL3YdJYY98QH/5GO5FwE8jXiYMoQ+hW52gUB6vZaJqYJu+IwyEhVXj8SVyV3Z77fFmJpdo0FX8R4Mm/3ucVXfWAXifFQbosRM4czVJ3RNTn2Xwf5Vp0ayih4huhwB9reByNPnYJABNUQpiAS3ZRsd+fcmMstkHZOk9EpSq33kubqcN+kub3sGNOJTt9243FOd6BghNNjhC2lqTWZsefyJUuL3Xm5YjJrJWfyif6RPnJZHinn3jfn464=
|
||||
@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "tree-sitter-bash"
|
||||
description = "bash grammar for the tree-sitter parsing library"
|
||||
version = "0.19.0"
|
||||
keywords = ["incremental", "parsing", "bash"]
|
||||
categories = ["parsing", "text-editors"]
|
||||
repository = "https://github.com/tree-sitter/tree-sitter-bash"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
authors = [
|
||||
"Max Brunsfeld <maxbrunsfeld@gmail.com",
|
||||
]
|
||||
|
||||
build = "bindings/rust/build.rs"
|
||||
include = [
|
||||
"bindings/rust/*",
|
||||
"grammar.js",
|
||||
"queries/*",
|
||||
"src/*",
|
||||
]
|
||||
|
||||
[lib]
|
||||
path = "bindings/rust/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
tree-sitter = "0.19"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Max Brunsfeld
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,28 @@
|
||||
tree-sitter-bash
|
||||
================
|
||||
|
||||
[](https://travis-ci.org/tree-sitter/tree-sitter-bash)
|
||||
[](https://ci.appveyor.com/project/maxbrunsfeld/tree-sitter-bash/branch/master)
|
||||
|
||||
Bash grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter).
|
||||
|
||||
### Development
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
npm install
|
||||
|
||||
Build and run the tests:
|
||||
|
||||
npm run build
|
||||
npm run test
|
||||
|
||||
Run the build and tests in watch mode:
|
||||
|
||||
npm run test:watch
|
||||
|
||||
#### References
|
||||
|
||||
* [Bash man page](http://man7.org/linux/man-pages/man1/bash.1.html#SHELL_GRAMMAR)
|
||||
* [Shell command language specification](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html)
|
||||
* [mvdnan/sh - a shell parser in go](https://github.com/mvdan/sh)
|
||||
@ -0,0 +1,28 @@
|
||||
image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
NODEJS_VERSION: "8"
|
||||
PREBUILD_UPLOAD:
|
||||
secure: oNyyLE7/Oq3TUGZPz6DkLFPUuQzc8FiFS1iuPp7LZ2fyOP/UF4Np4NzJmWcXVyY/
|
||||
|
||||
platform:
|
||||
- x64
|
||||
- x86
|
||||
|
||||
install:
|
||||
- ps: Install-Product node $env:NODEJS_VERSION $env:Platform
|
||||
- node --version
|
||||
- npm --version
|
||||
- npm install
|
||||
|
||||
test_script:
|
||||
- npm run test-windows
|
||||
|
||||
build: off
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^v.*$/
|
||||
|
||||
deploy_script: IF "%APPVEYOR_REPO_TAG%" == "true" (npm run pre-build && npm run pre-build:upload -u %PREBUILD_UPLOAD%)
|
||||
@ -0,0 +1,19 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tree_sitter_bash_binding",
|
||||
"include_dirs": [
|
||||
"<!(node -e \"require('nan')\")",
|
||||
"src"
|
||||
],
|
||||
"sources": [
|
||||
"src/parser.c",
|
||||
"bindings/node/binding.cc",
|
||||
"src/scanner.cc",
|
||||
],
|
||||
"cflags_c": [
|
||||
"-std=c99",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
#include "tree_sitter/parser.h"
|
||||
#include <node.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
|
||||
extern "C" TSLanguage * tree_sitter_bash();
|
||||
|
||||
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_bash());
|
||||
|
||||
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("bash").ToLocalChecked());
|
||||
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
|
||||
}
|
||||
|
||||
NODE_MODULE(tree_sitter_bash_binding, Init)
|
||||
|
||||
} // namespace
|
||||
@ -0,0 +1,19 @@
|
||||
try {
|
||||
module.exports = require("../../build/Release/tree_sitter_bash_binding");
|
||||
} catch (error1) {
|
||||
if (error1.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error1;
|
||||
}
|
||||
try {
|
||||
module.exports = require("../../build/Debug/tree_sitter_bash_binding");
|
||||
} catch (error2) {
|
||||
if (error2.code !== 'MODULE_NOT_FOUND') {
|
||||
throw error2;
|
||||
}
|
||||
throw error1
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
module.exports.nodeTypeInfo = require("../../src/node-types.json");
|
||||
} catch (_) {}
|
||||
@ -0,0 +1,25 @@
|
||||
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);
|
||||
c_config.compile("parser");
|
||||
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
|
||||
|
||||
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());
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//! This crate provides bash language support for the [tree-sitter][] parsing library.
|
||||
//!
|
||||
//! 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_bash::language()).expect("Error loading bash 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_bash() -> 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_bash() }
|
||||
}
|
||||
|
||||
/// 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 bash language");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,267 @@
|
||||
===============================
|
||||
Commands
|
||||
===============================
|
||||
|
||||
whoami
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word))))
|
||||
|
||||
===============================
|
||||
Commands with arguments
|
||||
===============================
|
||||
|
||||
cat file1.txt
|
||||
git diff --word-diff=color -- file1.txt file2.txt
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word) (word) (word) (word) (word)))
|
||||
|
||||
===============================
|
||||
Quoted command names
|
||||
===============================
|
||||
|
||||
"$a/$b" c
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (string (simple_expansion (variable_name)) (simple_expansion (variable_name))))
|
||||
(word)))
|
||||
|
||||
===============================
|
||||
Commands with numeric arguments
|
||||
===============================
|
||||
|
||||
exit 1
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (word)))
|
||||
|
||||
===================================
|
||||
Commands with environment variables
|
||||
===================================
|
||||
|
||||
VAR1=1 ./script/test
|
||||
VAR1=a VAR2="ok" git diff --word-diff=color
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(variable_assignment (variable_name) (word))
|
||||
(command_name (word)))
|
||||
(command
|
||||
(variable_assignment (variable_name) (word))
|
||||
(variable_assignment (variable_name) (string))
|
||||
(command_name (word))
|
||||
(word)
|
||||
(word)))
|
||||
|
||||
===================================
|
||||
Empty environment variables
|
||||
===================================
|
||||
|
||||
VAR1=
|
||||
VAR2= echo
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment (variable_name))
|
||||
(command (variable_assignment (variable_name)) (command_name (word))))
|
||||
|
||||
===============================
|
||||
File redirects
|
||||
===============================
|
||||
|
||||
whoami > /dev/null
|
||||
cat a b > /dev/null
|
||||
2>&1 whoami
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(file_redirect (word)))
|
||||
(redirected_statement
|
||||
(command (command_name (word)) (word) (word))
|
||||
(file_redirect (word)))
|
||||
(command
|
||||
(file_redirect (file_descriptor) (word))
|
||||
(command_name (word))))
|
||||
|
||||
===============================
|
||||
File redirects (noclobber override)
|
||||
===============================
|
||||
|
||||
whoami >| /dev/null
|
||||
cat a b >| /dev/null
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(file_redirect (word)))
|
||||
(redirected_statement
|
||||
(command (command_name (word)) (word) (word))
|
||||
(file_redirect (word))))
|
||||
|
||||
===============================
|
||||
Heredoc redirects
|
||||
===============================
|
||||
|
||||
node <<JS
|
||||
console.log("hi")
|
||||
JS
|
||||
|
||||
bash -c <<JS
|
||||
echo hi
|
||||
JS
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(heredoc_redirect (heredoc_start)))
|
||||
(heredoc_body)
|
||||
(redirected_statement
|
||||
(command (command_name (word)) (word))
|
||||
(heredoc_redirect (heredoc_start)))
|
||||
(heredoc_body))
|
||||
|
||||
===============================
|
||||
Heredocs with variables
|
||||
===============================
|
||||
|
||||
node <<JS
|
||||
a $B ${C}
|
||||
JS
|
||||
|
||||
exit
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(heredoc_redirect (heredoc_start)))
|
||||
(heredoc_body
|
||||
(simple_expansion (variable_name))
|
||||
(expansion (variable_name)))
|
||||
(command (command_name (word))))
|
||||
|
||||
=================================
|
||||
Heredocs with file redirects
|
||||
================================
|
||||
|
||||
cat <<EOF > $tmpfile
|
||||
a $B ${C}
|
||||
EOF
|
||||
|
||||
wc -l $tmpfile
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(heredoc_redirect (heredoc_start))
|
||||
(file_redirect (simple_expansion (variable_name))))
|
||||
(heredoc_body
|
||||
(simple_expansion (variable_name))
|
||||
(expansion (variable_name)))
|
||||
(command
|
||||
(command_name (word))
|
||||
(word)
|
||||
(simple_expansion (variable_name))))
|
||||
|
||||
=================================
|
||||
Heredocs with pipes
|
||||
================================
|
||||
|
||||
one <<EOF | grep two
|
||||
three
|
||||
EOF
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(pipeline
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(heredoc_redirect (heredoc_start)))
|
||||
(command (command_name (word)) (word)))
|
||||
(heredoc_body))
|
||||
|
||||
======================================
|
||||
Heredocs with escaped expansions
|
||||
======================================
|
||||
|
||||
cat << EOF
|
||||
DEV_NAME=\$(lsblk)
|
||||
EOF
|
||||
|
||||
---
|
||||
|
||||
(program (redirected_statement (command (command_name (word))) (heredoc_redirect (heredoc_start))) (heredoc_body))
|
||||
|
||||
======================================
|
||||
Quoted Heredocs
|
||||
======================================
|
||||
|
||||
cat << 'EOF'
|
||||
a=$b
|
||||
EOF
|
||||
|
||||
cat << "EOF"
|
||||
a=$b
|
||||
EOF
|
||||
|
||||
cat <<"END OF FILE"
|
||||
hello,
|
||||
world
|
||||
END OF FILE
|
||||
|
||||
cat << \EOF
|
||||
EOF
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement (command (command_name (word))) (heredoc_redirect (heredoc_start))) (heredoc_body)
|
||||
(redirected_statement (command (command_name (word))) (heredoc_redirect (heredoc_start))) (heredoc_body (simple_expansion (variable_name)))
|
||||
(redirected_statement (command (command_name (word))) (heredoc_redirect (heredoc_start))) (heredoc_body)
|
||||
(redirected_statement (command (command_name (word))) (heredoc_redirect (heredoc_start))) (heredoc_body))
|
||||
|
||||
==========================================
|
||||
Heredocs with indented closing delimiters
|
||||
==========================================
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: ${0##*/} FOO BAR
|
||||
EOF
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(function_definition
|
||||
(word)
|
||||
(compound_statement
|
||||
(redirected_statement
|
||||
(command (command_name (word)))
|
||||
(heredoc_redirect (heredoc_start)))
|
||||
(heredoc_body (expansion (special_variable_name) (word))))))
|
||||
@ -0,0 +1,13 @@
|
||||
================================
|
||||
Variables with CRLF line endings
|
||||
================================
|
||||
|
||||
A=one
|
||||
|
||||
B=two
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment (variable_name) (word))
|
||||
(variable_assignment (variable_name) (word)))
|
||||
@ -0,0 +1,372 @@
|
||||
=============================
|
||||
Literal words
|
||||
=============================
|
||||
|
||||
echo a
|
||||
echo a b
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word) (word)))
|
||||
|
||||
=============================
|
||||
Words with special characters
|
||||
=============================
|
||||
|
||||
echo {o[k]}
|
||||
echo }}}
|
||||
echo ]]] ===
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (concatenation (word) (word)))
|
||||
(command (command_name (word)) (concatenation))
|
||||
(command (command_name (word)) (concatenation) (word)))
|
||||
|
||||
=============================
|
||||
Simple variable expansions
|
||||
=============================
|
||||
|
||||
echo $abc
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (simple_expansion (variable_name))))
|
||||
|
||||
=============================
|
||||
Special variable expansions
|
||||
=============================
|
||||
|
||||
echo $# $* $@ $!
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(simple_expansion (special_variable_name))
|
||||
(simple_expansion (special_variable_name))
|
||||
(simple_expansion (special_variable_name))
|
||||
(simple_expansion (special_variable_name))))
|
||||
|
||||
=============================
|
||||
Variable expansions
|
||||
=============================
|
||||
|
||||
echo ${}
|
||||
echo ${#}
|
||||
echo ${var1#*#}
|
||||
echo ${!abc}
|
||||
echo ${abc}
|
||||
echo ${abc:-def}
|
||||
echo ${abc:- }
|
||||
echo ${abc:
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (expansion))
|
||||
(command (command_name (word)) (expansion))
|
||||
(command (command_name (word)) (expansion (variable_name) (word)))
|
||||
(command (command_name (word)) (expansion (variable_name)))
|
||||
(command (command_name (word)) (expansion (variable_name)))
|
||||
(command (command_name (word)) (expansion (variable_name) (word)))
|
||||
(command (command_name (word)) (expansion (variable_name)))
|
||||
(command (command_name (word)) (expansion (variable_name))))
|
||||
|
||||
===================================
|
||||
Variable expansions with operators
|
||||
===================================
|
||||
|
||||
A="${B[0]# }"
|
||||
C="${D/#* -E /}"
|
||||
F="${G%% *}"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(string (expansion (subscript (variable_name) (word)))))
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(string (expansion (variable_name) (regex))))
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(string (expansion (variable_name) (word) (word)))))
|
||||
|
||||
===================================
|
||||
Variable expansions in strings
|
||||
===================================
|
||||
|
||||
A="${A:-$B/c}"
|
||||
A="${b=$c/$d}"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(string
|
||||
(expansion
|
||||
(variable_name)
|
||||
(concatenation (simple_expansion (variable_name)) (word)))))
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(string
|
||||
(expansion
|
||||
(variable_name)
|
||||
(concatenation
|
||||
(simple_expansion (variable_name))
|
||||
(word)
|
||||
(simple_expansion (variable_name)))))))
|
||||
|
||||
===================================
|
||||
Variable expansions with regexes
|
||||
===================================
|
||||
|
||||
A=${B//:;;/$'\n'}
|
||||
|
||||
# escaped space
|
||||
C=${D/;\ *;|}
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment (variable_name) (expansion (variable_name) (regex)))
|
||||
(comment)
|
||||
(variable_assignment (variable_name) (expansion (variable_name) (regex))))
|
||||
|
||||
===================================
|
||||
Other variable expansion operators
|
||||
===================================
|
||||
|
||||
cat ${BAR} ${ABC=def} ${GHI:?jkl}
|
||||
[ "$a" != "${a#[Bc]}" ]
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(expansion (variable_name))
|
||||
(expansion (variable_name) (word))
|
||||
(expansion (variable_name) (word)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(string (expansion (variable_name) (concatenation (word)))))))
|
||||
|
||||
=============================
|
||||
Words ending with '$'
|
||||
=============================
|
||||
|
||||
grep ^${var}$
|
||||
|
||||
---
|
||||
|
||||
(program (command
|
||||
(command_name (word))
|
||||
(concatenation (word) (expansion (variable_name)))))
|
||||
|
||||
=============================
|
||||
Command substitutions
|
||||
=============================
|
||||
|
||||
echo `echo hi`
|
||||
echo `echo hi; echo there`
|
||||
echo $(echo $(echo hi))
|
||||
echo $(< some-file)
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(command_substitution (command (command_name (word)) (word))))
|
||||
(command
|
||||
(command_name (word))
|
||||
(command_substitution (command (command_name (word)) (word)) (command (command_name (word)) (word))))
|
||||
(command
|
||||
(command_name (word))
|
||||
(command_substitution (command
|
||||
(command_name (word))
|
||||
(command_substitution (command
|
||||
(command_name (word))
|
||||
(word))))))
|
||||
(command
|
||||
(command_name (word))
|
||||
(command_substitution (file_redirect (word)))))
|
||||
|
||||
=============================
|
||||
Process substitutions
|
||||
=============================
|
||||
|
||||
wc -c <(echo abc && echo def)
|
||||
wc -c <(echo abc; echo def)
|
||||
echo abc > >(wc -c)
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(word)
|
||||
(process_substitution (list
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word)))))
|
||||
(command
|
||||
(command_name (word))
|
||||
(word)
|
||||
(process_substitution
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word))))
|
||||
(redirected_statement
|
||||
(command
|
||||
(command_name (word))
|
||||
(word))
|
||||
(file_redirect (process_substitution
|
||||
(command (command_name (word)) (word))))))
|
||||
|
||||
=============================
|
||||
Single quoted strings
|
||||
=============================
|
||||
|
||||
echo 'a b' 'c d'
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (raw_string) (raw_string)))
|
||||
|
||||
=============================
|
||||
Double quoted strings
|
||||
=============================
|
||||
|
||||
echo "a" "b"
|
||||
echo "a ${b} c" "d $e"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word))
|
||||
(string)
|
||||
(string))
|
||||
(command (command_name (word))
|
||||
(string (expansion (variable_name)))
|
||||
(string (simple_expansion (variable_name)))))
|
||||
|
||||
=========================================
|
||||
Strings containing command substitutions
|
||||
=========================================
|
||||
|
||||
find "`dirname $file`" -name "$base"'*'
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(string (command_substitution (command (command_name (word)) (simple_expansion (variable_name)))))
|
||||
(word)
|
||||
(concatenation
|
||||
(string (simple_expansion (variable_name)))
|
||||
(raw_string))))
|
||||
|
||||
=========================================
|
||||
Strings containing escape sequence
|
||||
=========================================
|
||||
|
||||
echo "\"The great escape\`\${var}"
|
||||
|
||||
---
|
||||
|
||||
(program (command (command_name (word)) (string)))
|
||||
|
||||
======================================
|
||||
Strings containing special characters
|
||||
======================================
|
||||
|
||||
echo "s/$/'/"
|
||||
echo "#"
|
||||
echo "s$"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (string))
|
||||
(command (command_name (word)) (string))
|
||||
(command (command_name (word)) (string)))
|
||||
|
||||
========================================
|
||||
Strings with ANSI-C quoting
|
||||
========================================
|
||||
|
||||
echo $'Here\'s johnny!\r\n'
|
||||
|
||||
---
|
||||
|
||||
(program (command (command_name (word)) (ansii_c_string)))
|
||||
|
||||
=========================================
|
||||
Arrays and array expansions
|
||||
=========================================
|
||||
|
||||
a=()
|
||||
b=(1 2 3)
|
||||
|
||||
echo ${a[@]}
|
||||
echo ${#b[@]}
|
||||
|
||||
a[$i]=50
|
||||
a+=(foo "bar" $(baz))
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment (variable_name) (array))
|
||||
(variable_assignment (variable_name) (array (word) (word) (word)))
|
||||
(command (command_name (word)) (expansion (subscript (variable_name) (word))))
|
||||
(command (command_name (word)) (expansion (subscript (variable_name) (word))))
|
||||
(variable_assignment
|
||||
(subscript (variable_name) (simple_expansion (variable_name)))
|
||||
(word))
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(array
|
||||
(word)
|
||||
(string)
|
||||
(command_substitution (command (command_name (word)))))))
|
||||
|
||||
==============================
|
||||
Escaped characters in strings
|
||||
==============================
|
||||
|
||||
echo -ne "\033k$1\033\\" > /dev/stderr
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
(command (command_name (word)) (word) (string (simple_expansion (variable_name))))
|
||||
(file_redirect (word))))
|
||||
|
||||
================================================================================
|
||||
Words containing bare '#'
|
||||
================================================================================
|
||||
|
||||
curl -# localhost #comment without space
|
||||
nix build nixpkgs#hello -v # comment with space
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(program
|
||||
(command (command_name (word)) (word) (word))
|
||||
(comment)
|
||||
(command (command_name (word)) (word) (word) (word))
|
||||
(comment))
|
||||
@ -0,0 +1,96 @@
|
||||
===============================
|
||||
Comments
|
||||
===============================
|
||||
|
||||
#!/bin/bash
|
||||
# hi
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(comment)
|
||||
(comment))
|
||||
|
||||
===============================
|
||||
Escaped newlines
|
||||
===============================
|
||||
|
||||
abc \
|
||||
d \
|
||||
e
|
||||
|
||||
f=g \
|
||||
h=i \
|
||||
j \
|
||||
--k
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name (word))
|
||||
(word)
|
||||
(word))
|
||||
(command
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(word))
|
||||
(variable_assignment
|
||||
(variable_name)
|
||||
(word))
|
||||
(command_name (word))
|
||||
(word)))
|
||||
|
||||
=============================
|
||||
escaped newline immediately after a char
|
||||
=============================
|
||||
|
||||
echo a \
|
||||
b
|
||||
|
||||
echo a\
|
||||
b
|
||||
|
||||
echo a\
|
||||
b\
|
||||
c
|
||||
|
||||
|
||||
-----------------------------
|
||||
|
||||
(program
|
||||
(command
|
||||
(command_name
|
||||
(word))
|
||||
(word)
|
||||
(word))
|
||||
(command
|
||||
(command_name
|
||||
(word))
|
||||
(word)
|
||||
(word))
|
||||
(command
|
||||
(command_name
|
||||
(word))
|
||||
(word)
|
||||
(word)
|
||||
(word)))
|
||||
|
||||
=============================
|
||||
Escaped whitespace
|
||||
============================
|
||||
|
||||
echo 1 \ 2 \ 3
|
||||
|
||||
---
|
||||
|
||||
(program (command (command_name (word)) (word) (word) (word)))
|
||||
|
||||
====================================
|
||||
Files without trailing terminators
|
||||
====================================
|
||||
|
||||
echo hi
|
||||
---
|
||||
|
||||
(program (command (command_name (word)) (word)))
|
||||
@ -0,0 +1,610 @@
|
||||
===================================
|
||||
Pipelines
|
||||
===================================
|
||||
|
||||
whoami | cat
|
||||
cat foo | grep -v bar
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(pipeline
|
||||
(command
|
||||
name: (command_name (word)))
|
||||
(command
|
||||
name: (command_name (word))))
|
||||
(pipeline
|
||||
(command
|
||||
name: (command_name (word))
|
||||
argument: (word))
|
||||
(command
|
||||
name: (command_name (word))
|
||||
argument: (word)
|
||||
argument: (word))))
|
||||
|
||||
===================================
|
||||
Lists
|
||||
===================================
|
||||
|
||||
a | b && c && d; d e f || e g
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(list
|
||||
(list
|
||||
(pipeline
|
||||
(command (command_name (word)))
|
||||
(command (command_name (word))))
|
||||
(command (command_name (word))))
|
||||
(command (command_name (word))))
|
||||
(list
|
||||
(command (command_name (word)) (word) (word))
|
||||
(command (command_name (word)) (word))))
|
||||
|
||||
====================================
|
||||
While statements
|
||||
====================================
|
||||
|
||||
while something happens; do
|
||||
echo a
|
||||
echo b
|
||||
done
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(while_statement
|
||||
condition: (command
|
||||
name: (command_name (word))
|
||||
argument: (word))
|
||||
body: (do_group
|
||||
(command name: (command_name (word)) argument: (word))
|
||||
(command name: (command_name (word)) argument: (word)))))
|
||||
|
||||
====================================
|
||||
Until statements
|
||||
====================================
|
||||
|
||||
until something happens; do
|
||||
echo a
|
||||
echo b
|
||||
done
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(while_statement
|
||||
condition: (command
|
||||
name: (command_name (word))
|
||||
argument: (word))
|
||||
body: (do_group
|
||||
(command name: (command_name (word)) argument: (word))
|
||||
(command name: (command_name (word)) argument: (word)))))
|
||||
|
||||
====================================
|
||||
While statements with IO redirects
|
||||
====================================
|
||||
|
||||
while read line; do
|
||||
echo $line
|
||||
done < <(cat file)
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(redirected_statement
|
||||
body: (while_statement
|
||||
condition: (command
|
||||
name: (command_name (word))
|
||||
argument: (word))
|
||||
body: (do_group
|
||||
(command
|
||||
name: (command_name (word))
|
||||
argument: (simple_expansion (variable_name)))))
|
||||
redirect: (file_redirect
|
||||
destination: (process_substitution (command
|
||||
name: (command_name (word))
|
||||
argument: (word))))))
|
||||
|
||||
====================================
|
||||
For statements
|
||||
====================================
|
||||
|
||||
for a in 1 2 $(seq 5 10); do
|
||||
echo $a
|
||||
done
|
||||
|
||||
for ARG; do
|
||||
echo $ARG
|
||||
ARG=''
|
||||
done
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(for_statement
|
||||
variable: (variable_name)
|
||||
value: (word)
|
||||
value: (word)
|
||||
value: (command_substitution (command
|
||||
name: (command_name (word))
|
||||
argument: (word)
|
||||
argument: (word)))
|
||||
body: (do_group
|
||||
(command
|
||||
name: (command_name (word))
|
||||
argument: (simple_expansion (variable_name)))))
|
||||
(for_statement
|
||||
variable: (variable_name)
|
||||
body: (do_group
|
||||
(command
|
||||
name: (command_name (word))
|
||||
argument: (simple_expansion (variable_name)))
|
||||
(variable_assignment
|
||||
name: (variable_name)
|
||||
value: (raw_string)))))
|
||||
|
||||
====================================
|
||||
Select statements
|
||||
====================================
|
||||
|
||||
select choice in X Y $(ls); do
|
||||
echo $choice
|
||||
break
|
||||
done
|
||||
|
||||
select ARG; do
|
||||
echo $ARG
|
||||
ARG=''
|
||||
done
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(for_statement
|
||||
(variable_name)
|
||||
(word)
|
||||
(word)
|
||||
(command_substitution (command (command_name (word))))
|
||||
(do_group
|
||||
(command
|
||||
(command_name (word))
|
||||
(simple_expansion (variable_name)))
|
||||
(command (command_name (word)))))
|
||||
(for_statement
|
||||
(variable_name)
|
||||
(do_group
|
||||
(command
|
||||
(command_name (word))
|
||||
(simple_expansion (variable_name)))
|
||||
(variable_assignment (variable_name) (raw_string)))))
|
||||
|
||||
====================================
|
||||
C-style for statements
|
||||
====================================
|
||||
|
||||
for (( c=1; c<=5; c++ ))
|
||||
do
|
||||
echo $c
|
||||
done
|
||||
|
||||
for (( c=1; c<=5; c++ )) {
|
||||
echo $c
|
||||
}
|
||||
|
||||
for (( ; ; ))
|
||||
do
|
||||
echo 'forever'
|
||||
done
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(c_style_for_statement
|
||||
(word)
|
||||
(binary_expression (word) (word))
|
||||
(word)
|
||||
(do_group
|
||||
(command (command_name (word)) (simple_expansion (variable_name)))))
|
||||
(c_style_for_statement
|
||||
(word)
|
||||
(binary_expression (word) (word))
|
||||
(word)
|
||||
(compound_statement
|
||||
(command (command_name (word)) (simple_expansion (variable_name)))))
|
||||
(c_style_for_statement
|
||||
(do_group
|
||||
(command (command_name (word)) (raw_string)))))
|
||||
|
||||
====================================
|
||||
If statements
|
||||
====================================
|
||||
|
||||
if cat some_file | grep -v ok; then
|
||||
echo one
|
||||
elif cat other_file | grep -v ok; then
|
||||
echo two
|
||||
else
|
||||
exit
|
||||
fi
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(if_statement
|
||||
(pipeline
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word) (word)))
|
||||
(command (command_name (word)) (word))
|
||||
(elif_clause
|
||||
(pipeline
|
||||
(command (command_name (word)) (word))
|
||||
(command (command_name (word)) (word) (word)))
|
||||
(command (command_name (word)) (word)))
|
||||
(else_clause
|
||||
(command (command_name (word))))))
|
||||
|
||||
====================================
|
||||
If statements with conditional expressions
|
||||
====================================
|
||||
|
||||
if [ "$(uname)" == 'Darwin' ]; then
|
||||
echo one
|
||||
fi
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(if_statement
|
||||
(test_command (binary_expression
|
||||
(string (command_substitution (command (command_name (word)))))
|
||||
(raw_string)))
|
||||
(command (command_name (word)) (word))))
|
||||
|
||||
====================================
|
||||
Case statements
|
||||
====================================
|
||||
|
||||
case "opt" in
|
||||
a)
|
||||
echo a
|
||||
;;
|
||||
|
||||
b)
|
||||
echo b
|
||||
;&
|
||||
|
||||
c)
|
||||
echo c;;
|
||||
esac
|
||||
|
||||
case "$Z" in
|
||||
ab*|cd*) ef
|
||||
esac
|
||||
|
||||
case $dest in
|
||||
*.[1357])
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(case_statement (string)
|
||||
(case_item (word)
|
||||
(command (command_name (word)) (word)))
|
||||
(case_item (word)
|
||||
(command (command_name (word)) (word)))
|
||||
(case_item (word)
|
||||
(command (command_name (word)) (word))))
|
||||
(case_statement (string (simple_expansion (variable_name)))
|
||||
(case_item (word) (word)
|
||||
(command (command_name (word)))))
|
||||
(case_statement (simple_expansion (variable_name))
|
||||
(case_item (concatenation (word) (word))
|
||||
(command (command_name (word)) (simple_expansion (special_variable_name))))))
|
||||
|
||||
=============================
|
||||
Test commands
|
||||
=============================
|
||||
|
||||
if [[ "$lsb_dist" != 'Ubuntu' || $(ver_to_int "$lsb_release") < $(ver_to_int '14.04') ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(if_statement
|
||||
(test_command (binary_expression
|
||||
(binary_expression
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(raw_string))
|
||||
(command_substitution (command
|
||||
(command_name (word))
|
||||
(string (simple_expansion (variable_name))))))
|
||||
(command_substitution (command (command_name (word)) (raw_string)))))
|
||||
(command (command_name (word)) (word))))
|
||||
|
||||
|
||||
=============================
|
||||
Test commands with ternary
|
||||
=============================
|
||||
|
||||
if (( 1 < 2 ? 1 : 2 )); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(if_statement
|
||||
(test_command
|
||||
(ternary_expression
|
||||
(binary_expression (word) (word))
|
||||
(word) (word)))
|
||||
(command
|
||||
(command_name (word)) (word))))
|
||||
|
||||
=============================
|
||||
Test commands with regexes
|
||||
=============================
|
||||
|
||||
[[ "35d8b" =~ ^[0-9a-fA-F] ]]
|
||||
[[ $CMD =~ (^|;)update_terminal_cwd($|;) ]]
|
||||
[[ ! " ${completions[*]} " =~ " $alias_cmd " ]]
|
||||
! [[ "$a" =~ ^a|b\ *c|d$ ]]
|
||||
[[ "$1" =~ ^${var}${var}*=..* ]]
|
||||
[[ "$1" =~ ^\-${var}+ ]]
|
||||
[[ ${var1} == *${var2}* ]]
|
||||
[[ "$server" =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]
|
||||
[[ "$primary_wins" =~ ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) ]]
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string)
|
||||
(regex)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(simple_expansion (variable_name))
|
||||
(regex)))
|
||||
(test_command
|
||||
(unary_expression
|
||||
(binary_expression
|
||||
(string (expansion (subscript (variable_name) (word))))
|
||||
(string (simple_expansion (variable_name))))))
|
||||
(negated_command
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(regex))))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(regex)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(regex)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(expansion (variable_name))
|
||||
(regex)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(regex)))
|
||||
(test_command
|
||||
(binary_expression
|
||||
(string (simple_expansion (variable_name)))
|
||||
(regex))))
|
||||
|
||||
===============================
|
||||
Subshells
|
||||
===============================
|
||||
|
||||
(
|
||||
./start-server --port=80
|
||||
) &
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(subshell (command (command_name (word)) (word))))
|
||||
|
||||
===============================
|
||||
Function definitions
|
||||
===============================
|
||||
|
||||
do_something() {
|
||||
echo ok
|
||||
}
|
||||
|
||||
run_subshell_command() (
|
||||
true
|
||||
)
|
||||
|
||||
run_test_command() [[ -e foo ]]
|
||||
|
||||
function do_something_else() {
|
||||
a | xargs -I{} find xml/{} -type f
|
||||
}
|
||||
|
||||
function do_yet_another_thing {
|
||||
echo ok
|
||||
} 2>&1
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(function_definition
|
||||
(word)
|
||||
(compound_statement (command (command_name (word)) (word))))
|
||||
(function_definition
|
||||
(word)
|
||||
(subshell (command (command_name (word)))))
|
||||
(function_definition
|
||||
(word)
|
||||
(test_command (unary_expression (test_operator) (word))))
|
||||
(function_definition
|
||||
(word)
|
||||
(compound_statement
|
||||
(pipeline
|
||||
(command (command_name (word)))
|
||||
(command
|
||||
(command_name (word))
|
||||
(concatenation (word))
|
||||
(word)
|
||||
(concatenation (word))
|
||||
(word)
|
||||
(word)))))
|
||||
(redirected_statement (function_definition
|
||||
(word)
|
||||
(compound_statement (command (command_name (word)) (word))))
|
||||
(file_redirect (file_descriptor) (word))))
|
||||
|
||||
=========================================
|
||||
Variable declaration: declare & typeset
|
||||
=========================================
|
||||
|
||||
declare var1
|
||||
typeset -i -r var2=42 var3=10
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(declaration_command (variable_name))
|
||||
(declaration_command (word) (word)
|
||||
(variable_assignment (variable_name) (word))
|
||||
(variable_assignment (variable_name) (word))))
|
||||
|
||||
=========================================
|
||||
Variable declaration: readonly
|
||||
=========================================
|
||||
|
||||
readonly var1
|
||||
readonly var2=42
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(declaration_command (variable_name))
|
||||
(declaration_command (variable_assignment (variable_name) (word))))
|
||||
|
||||
=========================================
|
||||
Variable declaration: local
|
||||
=========================================
|
||||
|
||||
local a=42 b
|
||||
local -r c
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(declaration_command
|
||||
(variable_assignment (variable_name) (word))
|
||||
(variable_name))
|
||||
(declaration_command
|
||||
(word)
|
||||
(variable_name)))
|
||||
|
||||
=========================================
|
||||
Variable declaration: export
|
||||
=========================================
|
||||
|
||||
export PATH
|
||||
export FOOBAR PATH="$PATH:/usr/foobar/bin"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(declaration_command (variable_name))
|
||||
(declaration_command
|
||||
(variable_name)
|
||||
(variable_assignment (variable_name) (string (simple_expansion (variable_name))))))
|
||||
|
||||
===========================================================
|
||||
Variable declaration: command substitution with semi-colon
|
||||
===========================================================
|
||||
|
||||
_path=$(
|
||||
while statement; do
|
||||
cd ".."
|
||||
done;
|
||||
echo $PWD
|
||||
)
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(variable_assignment (variable_name)
|
||||
(command_substitution
|
||||
(while_statement
|
||||
(command (command_name (word)))
|
||||
(do_group (command (command_name (word)) (string))))
|
||||
(command (command_name (word)) (simple_expansion (variable_name))))))
|
||||
|
||||
===========================================
|
||||
Expressions passed to declaration commands
|
||||
===========================================
|
||||
|
||||
export "$(echo ${key} | tr [:lower:] [:upper:])=${p_key#*=}"
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(declaration_command
|
||||
(string
|
||||
(command_substitution
|
||||
(pipeline
|
||||
(command (command_name (word)) (expansion (variable_name)))
|
||||
(command (command_name (word)) (concatenation (word)) (concatenation (word)))))
|
||||
(expansion (variable_name) (word)))))
|
||||
|
||||
=========================================
|
||||
Unset commands
|
||||
=========================================
|
||||
|
||||
unset A
|
||||
unset "$variable_name"
|
||||
unsetenv -f ONE TWO
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(unset_command (variable_name))
|
||||
(unset_command (string (simple_expansion (variable_name))))
|
||||
(unset_command (word) (variable_name) (variable_name)))
|
||||
|
||||
===========================================
|
||||
Compound statements
|
||||
===========================================
|
||||
|
||||
a () {
|
||||
ls || { echo "b"; return 0; }
|
||||
echo c
|
||||
}
|
||||
|
||||
{ echo "a"
|
||||
echo "b"
|
||||
} >&2
|
||||
|
||||
---
|
||||
|
||||
(program
|
||||
(function_definition (word) (compound_statement
|
||||
(list
|
||||
(command (command_name (word)))
|
||||
(compound_statement
|
||||
(command (command_name (word)) (string))
|
||||
(command (command_name (word)) (word))))
|
||||
(command (command_name (word)) (word))))
|
||||
(redirected_statement
|
||||
(compound_statement (command (command_name (word)) (string)) (command (command_name (word)) (string)))
|
||||
(file_redirect (word))))
|
||||
@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$(uname)" == 'Darwin' ]; then
|
||||
OS='Mac'
|
||||
elif [ "$(expr substr $(uname -s) 1 5)" == 'Linux' ]; then
|
||||
OS='Linux'
|
||||
else
|
||||
echo "Your platform ($(uname -a)) is not supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(basename $0)" == 'atom-beta' ]; then
|
||||
BETA_VERSION=true
|
||||
else
|
||||
BETA_VERSION=
|
||||
fi
|
||||
|
||||
export ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT=true
|
||||
|
||||
while getopts ":wtfvh-:" opt; do
|
||||
case "$opt" in
|
||||
-)
|
||||
case "${OPTARG}" in
|
||||
wait)
|
||||
WAIT=1
|
||||
;;
|
||||
help|version)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
foreground|benchmark|benchmark-test|test)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
w)
|
||||
WAIT=1
|
||||
;;
|
||||
h|v)
|
||||
REDIRECT_STDERR=1
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
f|t)
|
||||
EXPECT_OUTPUT=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ $REDIRECT_STDERR ]; then
|
||||
exec 2> /dev/null
|
||||
fi
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
export ELECTRON_ENABLE_LOGGING=1
|
||||
fi
|
||||
|
||||
if [ $OS == 'Mac' ]; then
|
||||
if [ -L "$0" ]; then
|
||||
SCRIPT="$(readlink "$0")"
|
||||
else
|
||||
SCRIPT="$0"
|
||||
fi
|
||||
ATOM_APP="$(dirname "$(dirname "$(dirname "$(dirname "$SCRIPT")")")")"
|
||||
if [ "$ATOM_APP" == . ]; then
|
||||
unset ATOM_APP
|
||||
else
|
||||
ATOM_PATH="$(dirname "$ATOM_APP")"
|
||||
ATOM_APP_NAME="$(basename "$ATOM_APP")"
|
||||
fi
|
||||
|
||||
if [ -n "$BETA_VERSION" ]; then
|
||||
ATOM_EXECUTABLE_NAME="Atom Beta"
|
||||
else
|
||||
ATOM_EXECUTABLE_NAME="Atom"
|
||||
fi
|
||||
|
||||
if [ -z "${ATOM_PATH}" ]; then
|
||||
# If ATOM_PATH isn't set, check /Applications and then ~/Applications for Atom.app
|
||||
if [ -x "/Applications/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH="/Applications"
|
||||
elif [ -x "$HOME/Applications/$ATOM_APP_NAME" ]; then
|
||||
ATOM_PATH="$HOME/Applications"
|
||||
else
|
||||
# We haven't found an Atom.app, use spotlight to search for Atom
|
||||
ATOM_PATH="$(mdfind "kMDItemCFBundleIdentifier == 'com.github.atom'" | grep -v ShipIt | head -1 | xargs -0 dirname)"
|
||||
|
||||
# Exit if Atom can't be found
|
||||
if [ ! -x "$ATOM_PATH/$ATOM_APP_NAME" ]; then
|
||||
echo "Cannot locate ${ATOM_APP_NAME}, it is usually located in /Applications. Set the ATOM_PATH environment variable to the directory containing ${ATOM_APP_NAME}."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH/$ATOM_APP_NAME/Contents/MacOS/$ATOM_EXECUTABLE_NAME" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
open -a "$ATOM_PATH/$ATOM_APP_NAME" -n --args --executed-from="$(pwd)" --pid=$$ --path-environment="$PATH" "$@"
|
||||
fi
|
||||
elif [ $OS == 'Linux' ]; then
|
||||
SCRIPT=$(readlink -f "$0")
|
||||
USR_DIRECTORY=$(readlink -f $(dirname $SCRIPT)/..)
|
||||
|
||||
if [ -n "$BETA_VERSION" ]; then
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom-beta/atom"
|
||||
else
|
||||
ATOM_PATH="$USR_DIRECTORY/share/atom/atom"
|
||||
fi
|
||||
|
||||
ATOM_HOME="${ATOM_HOME:-$HOME/.atom}"
|
||||
mkdir -p "$ATOM_HOME"
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
[ -x "$ATOM_PATH" ] || ATOM_PATH="$TMPDIR/atom-build/Atom/atom"
|
||||
|
||||
if [ $EXPECT_OUTPUT ]; then
|
||||
"$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@"
|
||||
exit $?
|
||||
else
|
||||
(
|
||||
nohup "$ATOM_PATH" --executed-from="$(pwd)" --pid=$$ "$@" > "$ATOM_HOME/nohup.out" 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
cat "$ATOM_HOME/nohup.out"
|
||||
exit $?
|
||||
fi
|
||||
) &
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exits this process when Atom is used as $EDITOR
|
||||
on_die() {
|
||||
exit 0
|
||||
}
|
||||
trap 'on_die' SIGQUIT SIGTERM
|
||||
|
||||
# If the wait flag is set, don't exit this process until Atom tells it to.
|
||||
if [ $WAIT ]; then
|
||||
while true; do
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
@ -0,0 +1 @@
|
||||
Subproject commit c3d9c46ef832f808c929a22b36c8ef6dd45cb98a
|
||||
@ -0,0 +1,165 @@
|
||||
#!/bin/bash
|
||||
|
||||
# look for old 0.x cruft, and get rid of it.
|
||||
# Should already be sitting in the npm folder.
|
||||
|
||||
# This doesn't have to be quite as cross-platform as install.sh.
|
||||
# There are some bash-isms, because maintaining *two*
|
||||
# fully-portable posix/bourne sh scripts is too much for
|
||||
# one project with a sane maintainer.
|
||||
|
||||
# If readlink isn't available, then this is just too tricky.
|
||||
# However, greadlink is fine, so Solaris can join the party, too.
|
||||
readlink="readlink"
|
||||
which $readlink >/dev/null 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
readlink="greadlink"
|
||||
which $readlink >/dev/null 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Can't find the readlink or greadlink command. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "x$npm_config_prefix" != "x" ]; then
|
||||
PREFIXES=$npm_config_prefix
|
||||
else
|
||||
node="$NODE"
|
||||
if [ "x$node" = "x" ]; then
|
||||
node=`which node`
|
||||
fi
|
||||
if [ "x$node" = "x" ]; then
|
||||
echo "Can't find node to determine prefix. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
PREFIX=`dirname $node`
|
||||
PREFIX=`dirname $PREFIX`
|
||||
echo "cleanup prefix=$PREFIX"
|
||||
PREFIXES=$PREFIX
|
||||
|
||||
altprefix=`"$node" -e process.installPrefix`
|
||||
if [ "x$altprefix" != "x" ] && [ "x$altprefix" != "x$PREFIX" ]; then
|
||||
echo "altprefix=$altprefix"
|
||||
PREFIXES="$PREFIX $altprefix"
|
||||
fi
|
||||
fi
|
||||
|
||||
# now prefix is where npm would be rooted by default
|
||||
# go hunting.
|
||||
|
||||
packages=
|
||||
for prefix in $PREFIXES; do
|
||||
packages="$packages
|
||||
"`ls "$prefix"/lib/node/.npm 2>/dev/null | grep -v .cache`
|
||||
done
|
||||
|
||||
packages=`echo $packages`
|
||||
|
||||
filelist=()
|
||||
fid=0
|
||||
|
||||
for prefix in $PREFIXES; do
|
||||
# remove any links into the .npm dir, or links to
|
||||
# version-named shims/symlinks.
|
||||
for folder in share/man bin lib/node; do
|
||||
find $prefix/$folder -type l | while read file; do
|
||||
target=`$readlink $file | grep '/\.npm/'`
|
||||
if [ "x$target" != "x" ]; then
|
||||
# found one!
|
||||
filelist[$fid]="$file"
|
||||
let 'fid++'
|
||||
# also remove any symlinks to this file.
|
||||
base=`basename "$file"`
|
||||
base=`echo "$base" | awk -F@ '{print $1}'`
|
||||
if [ "x$base" != "x" ]; then
|
||||
find "`dirname $file`" -type l -name "$base"'*' \
|
||||
| while read l; do
|
||||
target=`$readlink "$l" | grep "$base"`
|
||||
if [ "x$target" != "x" ]; then
|
||||
filelist[$fid]="$1"
|
||||
let 'fid++'
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Scour for shim files. These are relics of 0.2 npm installs.
|
||||
# note: grep -r is not portable.
|
||||
find $prefix/$folder -type f \
|
||||
| xargs grep -sl '// generated by npm' \
|
||||
| while read file; do
|
||||
filelist[$fid]="$file"
|
||||
let 'fid++'
|
||||
done
|
||||
done
|
||||
|
||||
# now remove the package modules, and the .npm folder itself.
|
||||
if [ "x$packages" != "x" ]; then
|
||||
for pkg in $packages; do
|
||||
filelist[$fid]="$prefix/lib/node/$pkg"
|
||||
let 'fid++'
|
||||
for i in $prefix/lib/node/$pkg\@*; do
|
||||
filelist[$fid]="$i"
|
||||
let 'fid++'
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
for folder in lib/node/.npm lib/npm share/npm; do
|
||||
if [ -d $prefix/$folder ]; then
|
||||
filelist[$fid]="$prefix/$folder"
|
||||
let 'fid++'
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# now actually clean, but only if there's anything TO clean
|
||||
if [ "${#filelist[@]}" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "This script will find and eliminate any shims, symbolic"
|
||||
echo "links, and other cruft that was installed by npm 0.x."
|
||||
echo ""
|
||||
|
||||
if [ "x$packages" != "x" ]; then
|
||||
echo "The following packages appear to have been installed with"
|
||||
echo "an old version of npm, and will be removed forcibly:"
|
||||
for pkg in $packages; do
|
||||
echo " $pkg"
|
||||
done
|
||||
echo "Make a note of these. You may want to install them"
|
||||
echo "with npm 1.0 when this process is completed."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
OK=
|
||||
if [ "x$1" = "x-y" ]; then
|
||||
OK="yes"
|
||||
fi
|
||||
|
||||
while [ "$OK" != "y" ] && [ "$OK" != "yes" ] && [ "$OK" != "no" ]; do
|
||||
echo "Is this OK?"
|
||||
echo " enter 'yes' or 'no'"
|
||||
echo " or 'show' to see a list of files "
|
||||
read OK
|
||||
if [ "x$OK" = "xshow" ] || [ "x$OK" = "xs" ]; then
|
||||
for i in "${filelist[@]}"; do
|
||||
echo "$i"
|
||||
done
|
||||
fi
|
||||
done
|
||||
if [ "$OK" = "no" ]; then
|
||||
echo "Aborting"
|
||||
exit 1
|
||||
fi
|
||||
for i in "${filelist[@]}"; do
|
||||
rm -rf "$i"
|
||||
done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo 'All clean!'
|
||||
|
||||
exit 0
|
||||
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ $DEBUG != "" ]]; then
|
||||
set -x
|
||||
fi
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
if ! [ -x node_modules/.bin/marked-man ]; then
|
||||
ps=0
|
||||
if [ -f .building_marked-man ]; then
|
||||
pid=$(cat .building_marked-man)
|
||||
ps=$(ps -p $pid | grep $pid | wc -l) || true
|
||||
fi
|
||||
|
||||
if [ -f .building_marked-man ] && [ $ps != 0 ]; then
|
||||
while [ -f .building_marked-man ]; do
|
||||
sleep 1
|
||||
done
|
||||
else
|
||||
# a race to see which make process will be the one to install marked-man
|
||||
echo $$ > .building_marked-man
|
||||
sleep 1
|
||||
if [ $(cat .building_marked-man) == $$ ]; then
|
||||
make node_modules/.bin/marked-man
|
||||
rm .building_marked-man
|
||||
else
|
||||
while [ -f .building_marked-man ]; do
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! [ -x node_modules/.bin/marked ]; then
|
||||
ps=0
|
||||
if [ -f .building_marked ]; then
|
||||
pid=$(cat .building_marked)
|
||||
ps=$(ps -p $pid | grep $pid | wc -l) || true
|
||||
fi
|
||||
|
||||
if [ -f .building_marked ] && [ $ps != 0 ]; then
|
||||
while [ -f .building_marked ]; do
|
||||
sleep 1
|
||||
done
|
||||
else
|
||||
# a race to see which make process will be the one to install marked
|
||||
echo $$ > .building_marked
|
||||
sleep 1
|
||||
if [ $(cat .building_marked) == $$ ]; then
|
||||
make node_modules/.bin/marked
|
||||
rm .building_marked
|
||||
else
|
||||
while [ -f .building_marked ]; do
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
src=$1
|
||||
dest=$2
|
||||
name=$(basename ${src%.*})
|
||||
date=$(date -u +'%Y-%m-%d %H:%M:%S')
|
||||
version=$(node cli.js -v)
|
||||
|
||||
mkdir -p $(dirname $dest)
|
||||
|
||||
html_replace_tokens () {
|
||||
local url=$1
|
||||
sed "s|@NAME@|$name|g" \
|
||||
| sed "s|@DATE@|$date|g" \
|
||||
| sed "s|@URL@|$url|g" \
|
||||
| sed "s|@VERSION@|$version|g" \
|
||||
| perl -p -e 's/<h1([^>]*)>([^\(]*\([0-9]\)) -- (.*?)<\/h1>/<h1>\2<\/h1> <p>\3<\/p>/g' \
|
||||
| perl -p -e 's/npm-npm/npm/g' \
|
||||
| perl -p -e 's/([^"-])(npm-)?README(?!\.html)(\(1\))?/\1<a href="..\/..\/doc\/README.html">README<\/a>/g' \
|
||||
| perl -p -e 's/<title><a href="[^"]+README.html">README<\/a><\/title>/<title>README<\/title>/g' \
|
||||
| perl -p -e 's/([^"-])([^\(> ]+)(\(1\))/\1<a href="..\/cli\/\2.html">\2\3<\/a>/g' \
|
||||
| perl -p -e 's/([^"-])([^\(> ]+)(\(3\))/\1<a href="..\/api\/\2.html">\2\3<\/a>/g' \
|
||||
| perl -p -e 's/([^"-])([^\(> ]+)(\(5\))/\1<a href="..\/files\/\2.html">\2\3<\/a>/g' \
|
||||
| perl -p -e 's/([^"-])([^\(> ]+)(\(7\))/\1<a href="..\/misc\/\2.html">\2\3<\/a>/g' \
|
||||
| perl -p -e 's/\([1357]\)<\/a><\/h1>/<\/a><\/h1>/g' \
|
||||
| (if [ $(basename $(dirname $dest)) == "doc" ]; then
|
||||
perl -p -e 's/ href="\.\.\// href="/g'
|
||||
else
|
||||
cat
|
||||
fi)
|
||||
}
|
||||
|
||||
man_replace_tokens () {
|
||||
sed "s|@VERSION@|$version|g" \
|
||||
| perl -p -e 's/(npm\\-)?([a-zA-Z\\\.\-]*)\(1\)/npm help \2/g' \
|
||||
| perl -p -e 's/(npm\\-)?([a-zA-Z\\\.\-]*)\(([57])\)/npm help \3 \2/g' \
|
||||
| perl -p -e 's/(npm\\-)?([a-zA-Z\\\.\-]*)\(3\)/npm apihelp \2/g' \
|
||||
| perl -p -e 's/npm\(1\)/npm help npm/g' \
|
||||
| perl -p -e 's/npm\(3\)/npm apihelp npm/g'
|
||||
}
|
||||
|
||||
case $dest in
|
||||
*.[1357])
|
||||
./node_modules/.bin/marked-man --roff $src \
|
||||
| man_replace_tokens > $dest
|
||||
exit $?
|
||||
;;
|
||||
*.html)
|
||||
url=${dest/html\//}
|
||||
(cat html/dochead.html && \
|
||||
cat $src | ./node_modules/.bin/marked &&
|
||||
cat html/docfoot.html)\
|
||||
| html_replace_tokens $url \
|
||||
> $dest
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
echo "Invalid destination type: $dest" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@ -0,0 +1,270 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A word about this shell script:
|
||||
#
|
||||
# It must work everywhere, including on systems that lack
|
||||
# a /bin/bash, map 'sh' to ksh, ksh97, bash, ash, or zsh,
|
||||
# and potentially have either a posix shell or bourne
|
||||
# shell living at /bin/sh.
|
||||
#
|
||||
# See this helpful document on writing portable shell scripts:
|
||||
# http://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
|
||||
#
|
||||
# The only shell it won't ever work on is cmd.exe.
|
||||
|
||||
if [ "x$0" = "xsh" ]; then
|
||||
# run as curl | sh
|
||||
# on some systems, you can just do cat>npm-install.sh
|
||||
# which is a bit cuter. But on others, &1 is already closed,
|
||||
# so catting to another script file won't do anything.
|
||||
# Follow Location: headers, and fail on errors
|
||||
curl -f -L -s https://www.npmjs.org/install.sh > npm-install-$$.sh
|
||||
ret=$?
|
||||
if [ $ret -eq 0 ]; then
|
||||
(exit 0)
|
||||
else
|
||||
rm npm-install-$$.sh
|
||||
echo "Failed to download script" >&2
|
||||
exit $ret
|
||||
fi
|
||||
sh npm-install-$$.sh
|
||||
ret=$?
|
||||
rm npm-install-$$.sh
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
# See what "npm_config_*" things there are in the env,
|
||||
# and make them permanent.
|
||||
# If this fails, it's not such a big deal.
|
||||
configures="`env | grep 'npm_config_' | sed -e 's|^npm_config_||g'`"
|
||||
|
||||
npm_config_loglevel="error"
|
||||
if [ "x$npm_debug" = "x" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
echo "Running in debug mode."
|
||||
echo "Note that this requires bash or zsh."
|
||||
set -o xtrace
|
||||
set -o pipefail
|
||||
npm_config_loglevel="verbose"
|
||||
fi
|
||||
export npm_config_loglevel
|
||||
|
||||
# make sure that node exists
|
||||
node=`which node 2>&1`
|
||||
ret=$?
|
||||
if [ $ret -eq 0 ] && [ -x "$node" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
echo "npm cannot be installed without node.js." >&2
|
||||
echo "Install node first, and then try again." >&2
|
||||
echo "" >&2
|
||||
echo "Maybe node is installed, but not in the PATH?" >&2
|
||||
echo "Note that running as sudo can change envs." >&2
|
||||
echo ""
|
||||
echo "PATH=$PATH" >&2
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
# set the temp dir
|
||||
TMP="${TMPDIR}"
|
||||
if [ "x$TMP" = "x" ]; then
|
||||
TMP="/tmp"
|
||||
fi
|
||||
TMP="${TMP}/npm.$$"
|
||||
rm -rf "$TMP" || true
|
||||
mkdir "$TMP"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "failed to mkdir $TMP" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACK="$PWD"
|
||||
|
||||
ret=0
|
||||
tar="${TAR}"
|
||||
if [ -z "$tar" ]; then
|
||||
tar="${npm_config_tar}"
|
||||
fi
|
||||
if [ -z "$tar" ]; then
|
||||
tar=`which tar 2>&1`
|
||||
ret=$?
|
||||
fi
|
||||
|
||||
if [ $ret -eq 0 ] && [ -x "$tar" ]; then
|
||||
echo "tar=$tar"
|
||||
echo "version:"
|
||||
$tar --version
|
||||
ret=$?
|
||||
fi
|
||||
|
||||
if [ $ret -eq 0 ]; then
|
||||
(exit 0)
|
||||
else
|
||||
echo "No suitable tar program found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Try to find a suitable make
|
||||
# If the MAKE environment var is set, use that.
|
||||
# otherwise, try to find gmake, and then make.
|
||||
# If no make is found, then just execute the necessary commands.
|
||||
|
||||
# XXX For some reason, make is building all the docs every time. This
|
||||
# is an annoying source of bugs. Figure out why this happens.
|
||||
MAKE=NOMAKE
|
||||
|
||||
if [ "x$MAKE" = "x" ]; then
|
||||
make=`which gmake 2>&1`
|
||||
if [ $? -eq 0 ] && [ -x "$make" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
make=`which make 2>&1`
|
||||
if [ $? -eq 0 ] && [ -x "$make" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
make=NOMAKE
|
||||
fi
|
||||
fi
|
||||
else
|
||||
make="$MAKE"
|
||||
fi
|
||||
|
||||
if [ -x "$make" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
# echo "Installing without make. This may fail." >&2
|
||||
make=NOMAKE
|
||||
fi
|
||||
|
||||
# If there's no bash, then don't even try to clean
|
||||
if [ -x "/bin/bash" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
clean="no"
|
||||
fi
|
||||
|
||||
node_version=`"$node" --version 2>&1`
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "You need node to run this program." >&2
|
||||
echo "node --version reports: $node_version" >&2
|
||||
echo "with exit code = $ret" >&2
|
||||
echo "Please install node before continuing." >&2
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
t="${npm_install}"
|
||||
if [ -z "$t" ]; then
|
||||
# switch based on node version.
|
||||
# note that we can only use strict sh-compatible patterns here.
|
||||
case $node_version in
|
||||
0.[01234567].* | v0.[01234567].*)
|
||||
echo "You are using an outdated and unsupported version of" >&2
|
||||
echo "node ($node_version). Please update node and try again." >&2
|
||||
exit 99
|
||||
;;
|
||||
*)
|
||||
echo "install npm@latest"
|
||||
t="latest"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# need to echo "" after, because Posix sed doesn't treat EOF
|
||||
# as an implied end of line.
|
||||
url=`(curl -SsL https://registry.npmjs.org/npm/$t; echo "") \
|
||||
| sed -e 's/^.*tarball":"//' \
|
||||
| sed -e 's/".*$//'`
|
||||
|
||||
ret=$?
|
||||
if [ "x$url" = "x" ]; then
|
||||
ret=125
|
||||
# try without the -e arg to sed.
|
||||
url=`(curl -SsL https://registry.npmjs.org/npm/$t; echo "") \
|
||||
| sed 's/^.*tarball":"//' \
|
||||
| sed 's/".*$//'`
|
||||
ret=$?
|
||||
if [ "x$url" = "x" ]; then
|
||||
ret=125
|
||||
fi
|
||||
fi
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "Failed to get tarball url for npm/$t" >&2
|
||||
exit $ret
|
||||
fi
|
||||
|
||||
|
||||
echo "fetching: $url" >&2
|
||||
|
||||
cd "$TMP" \
|
||||
&& curl -SsL "$url" \
|
||||
| $tar -xzf - \
|
||||
&& cd "$TMP"/* \
|
||||
&& (ver=`"$node" bin/read-package-json.js package.json version`
|
||||
isnpm10=0
|
||||
if [ $ret -eq 0 ]; then
|
||||
if [ -d node_modules ]; then
|
||||
if "$node" node_modules/semver/bin/semver -v "$ver" -r "1"
|
||||
then
|
||||
isnpm10=1
|
||||
fi
|
||||
else
|
||||
if "$node" bin/semver -v "$ver" -r ">=1.0"; then
|
||||
isnpm10=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
ret=0
|
||||
if [ $isnpm10 -eq 1 ] && [ -f "scripts/clean-old.sh" ]; then
|
||||
if [ "x$skipclean" = "x" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
clean=no
|
||||
fi
|
||||
if [ "x$clean" = "xno" ] \
|
||||
|| [ "x$clean" = "xn" ]; then
|
||||
echo "Skipping 0.x cruft clean" >&2
|
||||
ret=0
|
||||
elif [ "x$clean" = "xy" ] || [ "x$clean" = "xyes" ]; then
|
||||
NODE="$node" /bin/bash "scripts/clean-old.sh" "-y"
|
||||
ret=$?
|
||||
else
|
||||
NODE="$node" /bin/bash "scripts/clean-old.sh" </dev/tty
|
||||
ret=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "Aborted 0.x cleanup. Exiting." >&2
|
||||
exit $ret
|
||||
fi) \
|
||||
&& (if [ "x$configures" = "x" ]; then
|
||||
(exit 0)
|
||||
else
|
||||
echo "./configure $configures"
|
||||
echo "$configures" > npmrc
|
||||
fi) \
|
||||
&& (if [ "$make" = "NOMAKE" ]; then
|
||||
(exit 0)
|
||||
elif "$make" uninstall install; then
|
||||
(exit 0)
|
||||
else
|
||||
make="NOMAKE"
|
||||
fi
|
||||
if [ "$make" = "NOMAKE" ]; then
|
||||
"$node" cli.js rm npm -gf
|
||||
"$node" cli.js install -gf
|
||||
fi) \
|
||||
&& cd "$BACK" \
|
||||
&& rm -rf "$TMP" \
|
||||
&& echo "It worked"
|
||||
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
echo "It failed" >&2
|
||||
fi
|
||||
exit $ret
|
||||
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# script for creating a zip and tarball for inclusion in node
|
||||
|
||||
unset CDPATH
|
||||
|
||||
set -e
|
||||
|
||||
rm -rf release *.tgz || true
|
||||
mkdir release
|
||||
node ./cli.js pack --loglevel error >/dev/null
|
||||
mv *.tgz release
|
||||
cd release
|
||||
tar xzf *.tgz
|
||||
|
||||
mkdir node_modules
|
||||
mv package node_modules/npm
|
||||
|
||||
# make the zip for windows users
|
||||
cp node_modules/npm/bin/*.cmd .
|
||||
zipname=npm-$(node ../cli.js -v).zip
|
||||
zip -q -9 -r -X "$zipname" *.cmd node_modules
|
||||
|
||||
# make the tar for node's deps
|
||||
cd node_modules
|
||||
tarname=npm-$(node ../../cli.js -v).tgz
|
||||
tar czf "$tarname" npm
|
||||
|
||||
cd ..
|
||||
mv "node_modules/$tarname" .
|
||||
|
||||
rm -rf *.cmd
|
||||
rm -rf node_modules
|
||||
|
||||
echo "release/$tarname"
|
||||
echo "release/$zipname"
|
||||
@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Change the cli shebang to point at the specified node
|
||||
# Useful for when the program is moved around after install.
|
||||
# Also used by the default 'make install' in node to point
|
||||
# npm at the newly installed node, rather than the first one
|
||||
# in the PATH, which would be the default otherwise.
|
||||
|
||||
# bash /path/to/npm/scripts/relocate.sh $nodepath
|
||||
# If $nodepath is blank, then it'll use /usr/bin/env
|
||||
|
||||
dir="$(dirname "$(dirname "$0")")"
|
||||
cli="$dir"/bin/npm-cli.js
|
||||
tmp="$cli".tmp
|
||||
|
||||
node="$1"
|
||||
if [ "x$node" = "x" ]; then
|
||||
node="/usr/bin/env node"
|
||||
fi
|
||||
node="#!$node"
|
||||
|
||||
sed -e 1d "$cli" > "$tmp"
|
||||
echo "$node" > "$cli"
|
||||
cat "$tmp" >> "$cli"
|
||||
rm "$tmp"
|
||||
chmod ogu+x $cli
|
||||
@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
function usage {
|
||||
cat <<-EOF
|
||||
USAGE
|
||||
|
||||
$0 [-dgGhv] [-f focus-string] [-s seed]
|
||||
|
||||
OPTIONS
|
||||
|
||||
-h print this message
|
||||
|
||||
-b run make under scan-build static analyzer
|
||||
|
||||
-d run tests in a debugger (either lldb or gdb)
|
||||
|
||||
-g run tests with valgrind's memcheck tool
|
||||
|
||||
-G run tests with valgrind's memcheck tool, including a full leak check
|
||||
|
||||
-v run tests with verbose output
|
||||
|
||||
-f run only tests whose description contain the given string
|
||||
|
||||
-s set the seed used to control random behavior
|
||||
|
||||
-z pipe tests' stderr to \`dot(1)\` to render an SVG log
|
||||
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
profile=
|
||||
leak_check=no
|
||||
mode=normal
|
||||
verbose=
|
||||
args=()
|
||||
target=tests
|
||||
export BUILDTYPE=Test
|
||||
cmd="out/${BUILDTYPE}/${target}"
|
||||
run_scan_build=
|
||||
|
||||
if [ "$(uname -s)" == "Darwin" ]; then
|
||||
export LINK="clang++ -fsanitize=address"
|
||||
fi
|
||||
|
||||
while getopts "bdf:s:gGhpvS" option; do
|
||||
case ${option} in
|
||||
h)
|
||||
usage
|
||||
exit
|
||||
;;
|
||||
d)
|
||||
mode=debug
|
||||
;;
|
||||
g)
|
||||
mode=valgrind
|
||||
;;
|
||||
G)
|
||||
mode=valgrind
|
||||
leak_check=full
|
||||
;;
|
||||
p)
|
||||
profile=true
|
||||
;;
|
||||
f)
|
||||
args+=("--only=${OPTARG}")
|
||||
;;
|
||||
v)
|
||||
verbose=true
|
||||
;;
|
||||
s)
|
||||
export TREE_SITTER_SEED=${OPTARG}
|
||||
;;
|
||||
S)
|
||||
mode=SVG
|
||||
;;
|
||||
b)
|
||||
run_scan_build=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -n $verbose ]]; then
|
||||
args+=("--reporter=spec")
|
||||
else
|
||||
args+=("--reporter=singleline")
|
||||
fi
|
||||
|
||||
if [[ -n "$run_scan_build" ]]; then
|
||||
. script/util/scan-build.sh
|
||||
scan_build make -j2 $target
|
||||
else
|
||||
make -j2 $target
|
||||
fi
|
||||
args=${args:-""}
|
||||
|
||||
if [[ -n $profile ]]; then
|
||||
export CPUPROFILE=/tmp/${target}-$(date '+%s').prof
|
||||
fi
|
||||
|
||||
case ${mode} in
|
||||
valgrind)
|
||||
valgrind \
|
||||
--suppressions=./script/util/valgrind.supp \
|
||||
--dsymutil=yes \
|
||||
--leak-check=${leak_check} \
|
||||
$cmd "${args[@]}" 2>&1 | \
|
||||
grep --color -E '\w+_tests?.cc:\d+|$'
|
||||
;;
|
||||
|
||||
debug)
|
||||
if which -s lldb; then
|
||||
lldb $cmd -- "${args[@]}"
|
||||
elif which -s gdb; then
|
||||
gdb $cmd -- "${args[@]}"
|
||||
else
|
||||
echo "No debugger found"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
SVG)
|
||||
echo "<!DOCTYPE html><style>svg { width: 100%; margin-bottom: 20px; }</style>" > index.html
|
||||
$cmd "${args[@]}" 2> >(grep -v 'Assertion failed' | dot -Tsvg >> index.html)
|
||||
echo "Wrote index.html"
|
||||
;;
|
||||
|
||||
normal)
|
||||
time $cmd "${args[@]}"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n $profile ]]; then
|
||||
pprof $cmd $CPUPROFILE
|
||||
fi
|
||||
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
git log --reverse --format='%aN <%aE>' | perl -wnE '
|
||||
BEGIN {
|
||||
say "# Authors sorted by whether or not they\x27re me";
|
||||
}
|
||||
|
||||
print $seen{$_} = $_ unless $seen{$_}
|
||||
' > AUTHORS
|
||||
@ -0,0 +1,559 @@
|
||||
const SPECIAL_CHARACTERS = [
|
||||
"'", '"',
|
||||
'<', '>',
|
||||
'{', '}',
|
||||
'\\[', '\\]',
|
||||
'(', ')',
|
||||
'`', '$',
|
||||
'|', '&', ';',
|
||||
'\\',
|
||||
'\\s',
|
||||
];
|
||||
|
||||
module.exports = grammar({
|
||||
name: 'bash',
|
||||
|
||||
inline: $ => [
|
||||
$._statement,
|
||||
$._terminator,
|
||||
$._literal,
|
||||
$._statements2,
|
||||
$._primary_expression,
|
||||
$._simple_variable_name,
|
||||
$._special_variable_name,
|
||||
],
|
||||
|
||||
externals: $ => [
|
||||
$.heredoc_start,
|
||||
$._simple_heredoc_body,
|
||||
$._heredoc_body_beginning,
|
||||
$._heredoc_body_middle,
|
||||
$._heredoc_body_end,
|
||||
$.file_descriptor,
|
||||
$._empty_value,
|
||||
$._concat,
|
||||
$.variable_name, // Variable name followed by an operator like '=' or '+='
|
||||
$.regex,
|
||||
'}',
|
||||
']',
|
||||
'<<',
|
||||
'<<-',
|
||||
'\n',
|
||||
],
|
||||
|
||||
extras: $ => [
|
||||
$.comment,
|
||||
/\s/,
|
||||
/\\\r?\n/,
|
||||
/\\( |\t|\v|\f)/
|
||||
],
|
||||
|
||||
supertypes: $ => [
|
||||
$._statement,
|
||||
$._expression,
|
||||
$._primary_expression,
|
||||
],
|
||||
|
||||
word: $ => $.word,
|
||||
|
||||
rules: {
|
||||
program: $ => optional($._statements),
|
||||
|
||||
_statements: $ => prec(1, seq(
|
||||
repeat(seq(
|
||||
$._statement,
|
||||
optional(seq('\n', $.heredoc_body)),
|
||||
$._terminator
|
||||
)),
|
||||
$._statement,
|
||||
optional(seq('\n', $.heredoc_body)),
|
||||
optional($._terminator)
|
||||
)),
|
||||
|
||||
_statements2: $ => repeat1(seq(
|
||||
$._statement,
|
||||
optional(seq('\n', $.heredoc_body)),
|
||||
$._terminator
|
||||
)),
|
||||
|
||||
_terminated_statement: $ => seq(
|
||||
$._statement,
|
||||
$._terminator
|
||||
),
|
||||
|
||||
// Statements
|
||||
|
||||
_statement: $ => choice(
|
||||
$.redirected_statement,
|
||||
$.variable_assignment,
|
||||
$.command,
|
||||
$.declaration_command,
|
||||
$.unset_command,
|
||||
$.test_command,
|
||||
$.negated_command,
|
||||
$.for_statement,
|
||||
$.c_style_for_statement,
|
||||
$.while_statement,
|
||||
$.if_statement,
|
||||
$.case_statement,
|
||||
$.pipeline,
|
||||
$.list,
|
||||
$.subshell,
|
||||
$.compound_statement,
|
||||
$.function_definition
|
||||
),
|
||||
|
||||
redirected_statement: $ => prec(-1, seq(
|
||||
field('body', $._statement),
|
||||
field('redirect', repeat1(choice(
|
||||
$.file_redirect,
|
||||
$.heredoc_redirect,
|
||||
$.herestring_redirect
|
||||
)))
|
||||
)),
|
||||
|
||||
for_statement: $ => seq(
|
||||
choice('for', 'select'),
|
||||
field('variable', $._simple_variable_name),
|
||||
optional(seq(
|
||||
'in',
|
||||
field('value', repeat1($._literal))
|
||||
)),
|
||||
$._terminator,
|
||||
field('body', $.do_group)
|
||||
),
|
||||
|
||||
c_style_for_statement: $ => seq(
|
||||
'for',
|
||||
'((',
|
||||
field('initializer', optional($._expression)),
|
||||
$._terminator,
|
||||
field('condition', optional($._expression)),
|
||||
$._terminator,
|
||||
field('update', optional($._expression)),
|
||||
'))',
|
||||
optional(';'),
|
||||
field('body', choice(
|
||||
$.do_group,
|
||||
$.compound_statement
|
||||
))
|
||||
),
|
||||
|
||||
while_statement: $ => seq(
|
||||
choice('while', 'until'),
|
||||
field('condition', $._terminated_statement),
|
||||
field('body', $.do_group)
|
||||
),
|
||||
|
||||
do_group: $ => seq(
|
||||
'do',
|
||||
optional($._statements2),
|
||||
'done'
|
||||
),
|
||||
|
||||
if_statement: $ => seq(
|
||||
'if',
|
||||
field('condition', $._terminated_statement),
|
||||
'then',
|
||||
optional($._statements2),
|
||||
repeat($.elif_clause),
|
||||
optional($.else_clause),
|
||||
'fi'
|
||||
),
|
||||
|
||||
elif_clause: $ => seq(
|
||||
'elif',
|
||||
$._terminated_statement,
|
||||
'then',
|
||||
optional($._statements2)
|
||||
),
|
||||
|
||||
else_clause: $ => seq(
|
||||
'else',
|
||||
optional($._statements2)
|
||||
),
|
||||
|
||||
case_statement: $ => seq(
|
||||
'case',
|
||||
field('value', $._literal),
|
||||
optional($._terminator),
|
||||
'in',
|
||||
$._terminator,
|
||||
optional(seq(
|
||||
repeat($.case_item),
|
||||
alias($.last_case_item, $.case_item),
|
||||
)),
|
||||
'esac'
|
||||
),
|
||||
|
||||
case_item: $ => seq(
|
||||
field('value', $._literal),
|
||||
repeat(seq('|', field('value', $._literal))),
|
||||
')',
|
||||
optional($._statements),
|
||||
prec(1, choice(
|
||||
field('termination', ';;'),
|
||||
field('fallthrough', choice(';&', ';;&'))
|
||||
))
|
||||
),
|
||||
|
||||
last_case_item: $ => seq(
|
||||
field('value', $._literal),
|
||||
repeat(seq('|', field('value', $._literal))),
|
||||
')',
|
||||
optional($._statements),
|
||||
optional(prec(1, ';;'))
|
||||
),
|
||||
|
||||
function_definition: $ => seq(
|
||||
choice(
|
||||
seq(
|
||||
'function',
|
||||
field('name', $.word),
|
||||
optional(seq('(', ')'))
|
||||
),
|
||||
seq(
|
||||
field('name', $.word),
|
||||
'(', ')'
|
||||
)
|
||||
),
|
||||
field(
|
||||
'body',
|
||||
choice(
|
||||
$.compound_statement,
|
||||
$.subshell,
|
||||
$.test_command)
|
||||
)
|
||||
),
|
||||
|
||||
compound_statement: $ => seq(
|
||||
'{',
|
||||
optional($._statements2),
|
||||
'}'
|
||||
),
|
||||
|
||||
subshell: $ => seq(
|
||||
'(',
|
||||
$._statements,
|
||||
')'
|
||||
),
|
||||
|
||||
pipeline: $ => prec.left(1, seq(
|
||||
$._statement,
|
||||
choice('|', '|&'),
|
||||
$._statement
|
||||
)),
|
||||
|
||||
list: $ => prec.left(-1, seq(
|
||||
$._statement,
|
||||
choice('&&', '||'),
|
||||
$._statement
|
||||
)),
|
||||
|
||||
// Commands
|
||||
|
||||
negated_command: $ => seq(
|
||||
'!',
|
||||
choice(
|
||||
$.command,
|
||||
$.test_command,
|
||||
$.subshell
|
||||
)
|
||||
),
|
||||
|
||||
test_command: $ => seq(
|
||||
choice(
|
||||
seq('[', $._expression, ']'),
|
||||
seq('[[', $._expression, ']]'),
|
||||
seq('((', $._expression, '))')
|
||||
)
|
||||
),
|
||||
|
||||
declaration_command: $ => prec.left(seq(
|
||||
choice('declare', 'typeset', 'export', 'readonly', 'local'),
|
||||
repeat(choice(
|
||||
$._literal,
|
||||
$._simple_variable_name,
|
||||
$.variable_assignment
|
||||
))
|
||||
)),
|
||||
|
||||
unset_command: $ => prec.left(seq(
|
||||
choice('unset', 'unsetenv'),
|
||||
repeat(choice(
|
||||
$._literal,
|
||||
$._simple_variable_name
|
||||
))
|
||||
)),
|
||||
|
||||
command: $ => prec.left(seq(
|
||||
repeat(choice(
|
||||
$.variable_assignment,
|
||||
$.file_redirect
|
||||
)),
|
||||
field('name', $.command_name),
|
||||
repeat(field('argument', choice(
|
||||
$._literal,
|
||||
seq(
|
||||
choice('=~', '=='),
|
||||
choice($._literal, $.regex)
|
||||
)
|
||||
)))
|
||||
)),
|
||||
|
||||
command_name: $ => $._literal,
|
||||
|
||||
variable_assignment: $ => seq(
|
||||
field('name', choice(
|
||||
$.variable_name,
|
||||
$.subscript
|
||||
)),
|
||||
choice(
|
||||
'=',
|
||||
'+='
|
||||
),
|
||||
field('value', choice(
|
||||
$._literal,
|
||||
$.array,
|
||||
$._empty_value
|
||||
))
|
||||
),
|
||||
|
||||
subscript: $ => seq(
|
||||
field('name', $.variable_name),
|
||||
'[',
|
||||
field('index', $._literal),
|
||||
optional($._concat),
|
||||
']',
|
||||
optional($._concat)
|
||||
),
|
||||
|
||||
file_redirect: $ => prec.left(seq(
|
||||
field('descriptor', optional($.file_descriptor)),
|
||||
choice('<', '>', '>>', '&>', '&>>', '<&', '>&', '>|'),
|
||||
field('destination', $._literal)
|
||||
)),
|
||||
|
||||
heredoc_redirect: $ => seq(
|
||||
choice('<<', '<<-'),
|
||||
$.heredoc_start
|
||||
),
|
||||
|
||||
heredoc_body: $ => choice(
|
||||
$._simple_heredoc_body,
|
||||
seq(
|
||||
$._heredoc_body_beginning,
|
||||
repeat(choice(
|
||||
$.expansion,
|
||||
$.simple_expansion,
|
||||
$.command_substitution,
|
||||
$._heredoc_body_middle
|
||||
)),
|
||||
$._heredoc_body_end
|
||||
)
|
||||
),
|
||||
|
||||
herestring_redirect: $ => seq(
|
||||
'<<<',
|
||||
$._literal
|
||||
),
|
||||
|
||||
// Expressions
|
||||
|
||||
_expression: $ => choice(
|
||||
$._literal,
|
||||
$.unary_expression,
|
||||
$.ternary_expression,
|
||||
$.binary_expression,
|
||||
$.postfix_expression,
|
||||
$.parenthesized_expression
|
||||
),
|
||||
|
||||
binary_expression: $ => prec.left(choice(
|
||||
seq(
|
||||
field('left', $._expression),
|
||||
field('operator', choice(
|
||||
'=', '==', '=~', '!=',
|
||||
'+', '-', '+=', '-=',
|
||||
'<', '>', '<=', '>=',
|
||||
'||', '&&',
|
||||
$.test_operator
|
||||
)),
|
||||
field('right', $._expression)
|
||||
),
|
||||
seq(
|
||||
field('left', $._expression),
|
||||
field('operator', choice('==', '=~')),
|
||||
field('right', $.regex)
|
||||
)
|
||||
)),
|
||||
|
||||
ternary_expression: $ => prec.left(
|
||||
seq(
|
||||
field('condition', $._expression),
|
||||
'?',
|
||||
field('consequence', $._expression),
|
||||
':',
|
||||
field('alternative', $._expression),
|
||||
)
|
||||
),
|
||||
|
||||
unary_expression: $ => prec.right(seq(
|
||||
choice('!', $.test_operator),
|
||||
$._expression
|
||||
)),
|
||||
|
||||
postfix_expression: $ => seq(
|
||||
$._expression,
|
||||
choice('++', '--'),
|
||||
),
|
||||
|
||||
parenthesized_expression: $ => seq(
|
||||
'(',
|
||||
$._expression,
|
||||
')'
|
||||
),
|
||||
|
||||
// Literals
|
||||
|
||||
_literal: $ => choice(
|
||||
$.concatenation,
|
||||
$._primary_expression,
|
||||
alias(prec(-2, repeat1($._special_character)), $.word)
|
||||
),
|
||||
|
||||
_primary_expression: $ => choice(
|
||||
$.word,
|
||||
$.string,
|
||||
$.raw_string,
|
||||
$.ansii_c_string,
|
||||
$.expansion,
|
||||
$.simple_expansion,
|
||||
$.string_expansion,
|
||||
$.command_substitution,
|
||||
$.process_substitution
|
||||
),
|
||||
|
||||
concatenation: $ => prec(-1, seq(
|
||||
choice(
|
||||
$._primary_expression,
|
||||
$._special_character,
|
||||
),
|
||||
repeat1(prec(-1, seq(
|
||||
$._concat,
|
||||
choice(
|
||||
$._primary_expression,
|
||||
$._special_character,
|
||||
)
|
||||
))),
|
||||
optional(seq($._concat, '$'))
|
||||
)),
|
||||
|
||||
_special_character: $ => token(prec(-1, choice('{', '}', '[', ']'))),
|
||||
|
||||
string: $ => seq(
|
||||
'"',
|
||||
repeat(seq(
|
||||
choice(
|
||||
seq(optional('$'), $._string_content),
|
||||
$.expansion,
|
||||
$.simple_expansion,
|
||||
$.command_substitution
|
||||
),
|
||||
optional($._concat)
|
||||
)),
|
||||
optional('$'),
|
||||
'"'
|
||||
),
|
||||
|
||||
_string_content: $ => token(prec(-1, /([^"`$\\]|\\(.|\r?\n))+/)),
|
||||
|
||||
array: $ => seq(
|
||||
'(',
|
||||
repeat($._literal),
|
||||
')'
|
||||
),
|
||||
|
||||
raw_string: $ => /'[^']*'/,
|
||||
|
||||
ansii_c_string: $ => /\$'([^']|\\')*'/,
|
||||
|
||||
simple_expansion: $ => seq(
|
||||
'$',
|
||||
choice(
|
||||
$._simple_variable_name,
|
||||
$._special_variable_name,
|
||||
alias('!', $.special_variable_name),
|
||||
alias('#', $.special_variable_name)
|
||||
)
|
||||
),
|
||||
|
||||
string_expansion: $ => seq('$', choice($.string, $.raw_string)),
|
||||
|
||||
expansion: $ => seq(
|
||||
'${',
|
||||
optional(choice('#', '!')),
|
||||
optional(choice(
|
||||
seq(
|
||||
$.variable_name,
|
||||
'=',
|
||||
optional($._literal)
|
||||
),
|
||||
seq(
|
||||
choice(
|
||||
$.subscript,
|
||||
$._simple_variable_name,
|
||||
$._special_variable_name
|
||||
),
|
||||
optional(seq(
|
||||
token(prec(1, '/')),
|
||||
optional($.regex)
|
||||
)),
|
||||
repeat(choice(
|
||||
$._literal,
|
||||
':', ':?', '=', ':-', '%', '-', '#'
|
||||
))
|
||||
),
|
||||
)),
|
||||
'}'
|
||||
),
|
||||
|
||||
command_substitution: $ => choice(
|
||||
seq('$(', $._statements, ')'),
|
||||
seq('$(', $.file_redirect, ')'),
|
||||
prec(1, seq('`', $._statements, '`'))
|
||||
),
|
||||
|
||||
process_substitution: $ => seq(
|
||||
choice('<(', '>('),
|
||||
$._statements,
|
||||
')'
|
||||
),
|
||||
|
||||
comment: $ => token(prec(-10, /#.*/)),
|
||||
|
||||
_simple_variable_name: $ => alias(/\w+/, $.variable_name),
|
||||
|
||||
_special_variable_name: $ => alias(choice('*', '@', '?', '-', '$', '0', '_'), $.special_variable_name),
|
||||
|
||||
word: $ => token(seq(
|
||||
choice(
|
||||
noneOf('#', ...SPECIAL_CHARACTERS),
|
||||
seq('\\', noneOf('\\s'))
|
||||
),
|
||||
repeat(choice(
|
||||
noneOf(...SPECIAL_CHARACTERS),
|
||||
seq('\\', noneOf('\\s'))
|
||||
))
|
||||
)),
|
||||
|
||||
test_operator: $ => token(prec(1, seq('-', /[a-zA-Z]+/))),
|
||||
|
||||
_terminator: $ => choice(';', ';;', '\n', '&')
|
||||
}
|
||||
});
|
||||
|
||||
function noneOf(...characters) {
|
||||
const negatedString = characters.map(c => c == '\\' ? '\\\\' : c).join('')
|
||||
return new RegExp('[^' + negatedString + ']')
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "tree-sitter-bash",
|
||||
"version": "0.19.0",
|
||||
"description": "Bash grammar for tree-sitter",
|
||||
"main": "bindings/node",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"lexer"
|
||||
],
|
||||
"author": "Max Brunsfeld",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nan": "^2.14.0",
|
||||
"prebuild-install": "^5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prebuild": "^10.0.0",
|
||||
"tree-sitter-cli": "^0.19.1"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "prebuild-install || node-gyp rebuild",
|
||||
"pre-build": "prebuild --all --strip --verbose",
|
||||
"pre-build:upload": "prebuild --upload-all",
|
||||
"test": "tree-sitter test && script/parse-examples.sh",
|
||||
"test-windows": "tree-sitter test"
|
||||
},
|
||||
"repository": "https://github.com/tree-sitter/tree-sitter-bash",
|
||||
"tree-sitter": [
|
||||
{
|
||||
"scope": "source.bash",
|
||||
"file-types": [
|
||||
"sh",
|
||||
"bash"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
[
|
||||
(string)
|
||||
(raw_string)
|
||||
(heredoc_body)
|
||||
(heredoc_start)
|
||||
] @string
|
||||
|
||||
(command_name) @function
|
||||
|
||||
(variable_name) @property
|
||||
|
||||
[
|
||||
"case"
|
||||
"do"
|
||||
"done"
|
||||
"elif"
|
||||
"else"
|
||||
"esac"
|
||||
"export"
|
||||
"fi"
|
||||
"for"
|
||||
"function"
|
||||
"if"
|
||||
"in"
|
||||
"unset"
|
||||
"while"
|
||||
"then"
|
||||
] @keyword
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(function_definition name: (word) @function)
|
||||
|
||||
(file_descriptor) @number
|
||||
|
||||
[
|
||||
(command_substitution)
|
||||
(process_substitution)
|
||||
(expansion)
|
||||
]@embedded
|
||||
|
||||
[
|
||||
"$"
|
||||
"&&"
|
||||
">"
|
||||
">>"
|
||||
"<"
|
||||
"|"
|
||||
] @operator
|
||||
|
||||
(
|
||||
(command (_) @constant)
|
||||
(#match? @constant "^-")
|
||||
)
|
||||
@ -0,0 +1,15 @@
|
||||
examples/bash-it/completion/available/docker-compose.completion.bash
|
||||
examples/bash-it/completion/available/docker-machine.completion.bash
|
||||
examples/bash-it/completion/available/docker.completion.bash
|
||||
examples/bash-it/completion/available/drush.completion.bash
|
||||
examples/bash-it/completion/available/git.completion.bash
|
||||
examples/bash-it/completion/available/svn.completion.bash
|
||||
examples/bash-it/completion/available/tmux.completion.bash
|
||||
examples/bash-it/plugins/available/extract.plugin.bash
|
||||
examples/bash-it/plugins/available/git.plugin.bash
|
||||
examples/bash-it/plugins/available/go.plugin.bash
|
||||
examples/bash-it/themes/colors.theme.bash
|
||||
examples/bash-it/themes/doubletime/doubletime.theme.bash
|
||||
examples/bash-it/themes/hawaii50/hawaii50.theme.bash
|
||||
examples/bash-it/themes/nwinkler_random_colors/nwinkler_random_colors.theme.bash
|
||||
examples/bash-it/themes/powerline/powerline.base.bash
|
||||
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
known_failures="$(cat script/known-failures.txt)"
|
||||
|
||||
tree-sitter parse -q -t \
|
||||
examples/**/*.bash \
|
||||
examples/**/*.sh \
|
||||
$(for failure in $known_failures; do echo "!${failure}"; done)
|
||||
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
tree-sitter parse -q -t \
|
||||
examples/**/*.sh \
|
||||
examples/**/*.bash \
|
||||
| egrep 'ERROR|MISSING' \
|
||||
| tee >(cut -d' ' -f1 | sort > script/known-failures.txt)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,398 @@
|
||||
#include <tree_sitter/parser.h>
|
||||
#include <string>
|
||||
#include <cwctype>
|
||||
|
||||
namespace {
|
||||
|
||||
using std::string;
|
||||
|
||||
enum TokenType {
|
||||
HEREDOC_START,
|
||||
SIMPLE_HEREDOC_BODY,
|
||||
HEREDOC_BODY_BEGINNING,
|
||||
HEREDOC_BODY_MIDDLE,
|
||||
HEREDOC_BODY_END,
|
||||
FILE_DESCRIPTOR,
|
||||
EMPTY_VALUE,
|
||||
CONCAT,
|
||||
VARIABLE_NAME,
|
||||
REGEX,
|
||||
CLOSING_BRACE,
|
||||
CLOSING_BRACKET,
|
||||
HEREDOC_ARROW,
|
||||
HEREDOC_ARROW_DASH,
|
||||
NEWLINE,
|
||||
};
|
||||
|
||||
struct Scanner {
|
||||
void skip(TSLexer *lexer) {
|
||||
lexer->advance(lexer, true);
|
||||
}
|
||||
|
||||
void advance(TSLexer *lexer) {
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
|
||||
unsigned serialize(char *buffer) {
|
||||
if (heredoc_delimiter.length() + 3 >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) return 0;
|
||||
buffer[0] = heredoc_is_raw;
|
||||
buffer[1] = started_heredoc;
|
||||
buffer[2] = heredoc_allows_indent;
|
||||
heredoc_delimiter.copy(&buffer[3], heredoc_delimiter.length());
|
||||
return heredoc_delimiter.length() + 3;
|
||||
}
|
||||
|
||||
void deserialize(const char *buffer, unsigned length) {
|
||||
if (length == 0) {
|
||||
heredoc_is_raw = false;
|
||||
started_heredoc = false;
|
||||
heredoc_allows_indent = false;
|
||||
heredoc_delimiter.clear();
|
||||
} else {
|
||||
heredoc_is_raw = buffer[0];
|
||||
started_heredoc = buffer[1];
|
||||
heredoc_allows_indent = buffer[2];
|
||||
heredoc_delimiter.assign(&buffer[3], &buffer[length]);
|
||||
}
|
||||
}
|
||||
|
||||
bool scan_heredoc_start(TSLexer *lexer) {
|
||||
while (iswspace(lexer->lookahead)) skip(lexer);
|
||||
|
||||
lexer->result_symbol = HEREDOC_START;
|
||||
heredoc_is_raw = lexer->lookahead == '\'';
|
||||
started_heredoc = false;
|
||||
heredoc_delimiter.clear();
|
||||
|
||||
if (lexer->lookahead == '\\') {
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
int32_t quote = 0;
|
||||
if (heredoc_is_raw || lexer->lookahead == '"') {
|
||||
quote = lexer->lookahead;
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
while (iswalpha(lexer->lookahead) || (quote != 0 && iswspace(lexer->lookahead))) {
|
||||
heredoc_delimiter += lexer->lookahead;
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
if (lexer->lookahead == quote) {
|
||||
advance(lexer);
|
||||
}
|
||||
|
||||
return !heredoc_delimiter.empty();
|
||||
}
|
||||
|
||||
bool scan_heredoc_end_identifier(TSLexer *lexer) {
|
||||
current_leading_word.clear();
|
||||
// Scan the first 'n' characters on this line, to see if they match the heredoc delimiter
|
||||
while (
|
||||
lexer->lookahead != '\0' &&
|
||||
lexer->lookahead != '\n' &&
|
||||
current_leading_word.length() < heredoc_delimiter.length()
|
||||
) {
|
||||
current_leading_word += lexer->lookahead;
|
||||
advance(lexer);
|
||||
}
|
||||
return current_leading_word == heredoc_delimiter;
|
||||
}
|
||||
|
||||
bool scan_heredoc_content(TSLexer *lexer, TokenType middle_type, TokenType end_type) {
|
||||
bool did_advance = false;
|
||||
|
||||
for (;;) {
|
||||
switch (lexer->lookahead) {
|
||||
case '\0': {
|
||||
if (did_advance) {
|
||||
heredoc_is_raw = false;
|
||||
started_heredoc = false;
|
||||
heredoc_allows_indent = false;
|
||||
heredoc_delimiter.clear();
|
||||
lexer->result_symbol = end_type;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case '\\': {
|
||||
did_advance = true;
|
||||
advance(lexer);
|
||||
advance(lexer);
|
||||
break;
|
||||
}
|
||||
|
||||
case '$': {
|
||||
if (heredoc_is_raw) {
|
||||
did_advance = true;
|
||||
advance(lexer);
|
||||
break;
|
||||
} else if (did_advance) {
|
||||
lexer->result_symbol = middle_type;
|
||||
started_heredoc = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
case '\n': {
|
||||
did_advance = true;
|
||||
advance(lexer);
|
||||
if (heredoc_allows_indent) {
|
||||
while (iswspace(lexer->lookahead)) {
|
||||
advance(lexer);
|
||||
}
|
||||
}
|
||||
if (scan_heredoc_end_identifier(lexer)) {
|
||||
heredoc_is_raw = false;
|
||||
started_heredoc = false;
|
||||
heredoc_allows_indent = false;
|
||||
heredoc_delimiter.clear();
|
||||
lexer->result_symbol = end_type;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
did_advance = true;
|
||||
advance(lexer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool scan(TSLexer *lexer, const bool *valid_symbols) {
|
||||
if (valid_symbols[CONCAT]) {
|
||||
if (!(
|
||||
lexer->lookahead == 0 ||
|
||||
iswspace(lexer->lookahead) ||
|
||||
lexer->lookahead == '\\' ||
|
||||
lexer->lookahead == '>' ||
|
||||
lexer->lookahead == '<' ||
|
||||
lexer->lookahead == ')' ||
|
||||
lexer->lookahead == '(' ||
|
||||
lexer->lookahead == ';' ||
|
||||
lexer->lookahead == '&' ||
|
||||
lexer->lookahead == '|' ||
|
||||
lexer->lookahead == '`' ||
|
||||
lexer->lookahead == '#' ||
|
||||
(lexer->lookahead == '}' && valid_symbols[CLOSING_BRACE]) ||
|
||||
(lexer->lookahead == ']' && valid_symbols[CLOSING_BRACKET])
|
||||
)) {
|
||||
lexer->result_symbol = CONCAT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[EMPTY_VALUE]) {
|
||||
if (iswspace(lexer->lookahead)) {
|
||||
lexer->result_symbol = EMPTY_VALUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[HEREDOC_BODY_BEGINNING] && !heredoc_delimiter.empty() && !started_heredoc) {
|
||||
return scan_heredoc_content(lexer, HEREDOC_BODY_BEGINNING, SIMPLE_HEREDOC_BODY);
|
||||
}
|
||||
|
||||
if (valid_symbols[HEREDOC_BODY_MIDDLE] && !heredoc_delimiter.empty() && started_heredoc) {
|
||||
return scan_heredoc_content(lexer, HEREDOC_BODY_MIDDLE, HEREDOC_BODY_END);
|
||||
}
|
||||
|
||||
if (valid_symbols[HEREDOC_START]) {
|
||||
return scan_heredoc_start(lexer);
|
||||
}
|
||||
|
||||
if (valid_symbols[VARIABLE_NAME] || valid_symbols[FILE_DESCRIPTOR] || valid_symbols[HEREDOC_ARROW]) {
|
||||
for (;;) {
|
||||
if (
|
||||
lexer->lookahead == ' ' ||
|
||||
lexer->lookahead == '\t' ||
|
||||
lexer->lookahead == '\r' ||
|
||||
(lexer->lookahead == '\n' && !valid_symbols[NEWLINE])
|
||||
) {
|
||||
skip(lexer);
|
||||
} else if (lexer->lookahead == '\\') {
|
||||
skip(lexer);
|
||||
if (lexer->lookahead == '\r') {
|
||||
skip(lexer);
|
||||
}
|
||||
if (lexer->lookahead == '\n') {
|
||||
skip(lexer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[HEREDOC_ARROW] && lexer->lookahead == '<') {
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '<') {
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '-') {
|
||||
advance(lexer);
|
||||
heredoc_allows_indent = true;
|
||||
lexer->result_symbol = HEREDOC_ARROW_DASH;
|
||||
} else if (lexer->lookahead == '<') {
|
||||
return false;
|
||||
} else {
|
||||
heredoc_allows_indent = false;
|
||||
lexer->result_symbol = HEREDOC_ARROW;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_number = true;
|
||||
if (iswdigit(lexer->lookahead)) {
|
||||
advance(lexer);
|
||||
} else if (iswalpha(lexer->lookahead) || lexer->lookahead == '_') {
|
||||
is_number = false;
|
||||
advance(lexer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (iswdigit(lexer->lookahead)) {
|
||||
advance(lexer);
|
||||
} else if (iswalpha(lexer->lookahead) || lexer->lookahead == '_') {
|
||||
is_number = false;
|
||||
advance(lexer);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_number &&
|
||||
valid_symbols[FILE_DESCRIPTOR] &&
|
||||
(lexer->lookahead == '>' || lexer->lookahead == '<')) {
|
||||
lexer->result_symbol = FILE_DESCRIPTOR;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (valid_symbols[VARIABLE_NAME]) {
|
||||
if (lexer->lookahead == '+') {
|
||||
lexer->mark_end(lexer);
|
||||
advance(lexer);
|
||||
if (lexer->lookahead == '=') {
|
||||
lexer->result_symbol = VARIABLE_NAME;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (lexer->lookahead == '=' || lexer->lookahead == '[') {
|
||||
lexer->result_symbol = VARIABLE_NAME;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (valid_symbols[REGEX]) {
|
||||
while (iswspace(lexer->lookahead)) skip(lexer);
|
||||
|
||||
if (
|
||||
lexer->lookahead != '"' &&
|
||||
lexer->lookahead != '\'' &&
|
||||
lexer->lookahead != '$'
|
||||
) {
|
||||
struct State {
|
||||
bool done;
|
||||
uint32_t paren_depth;
|
||||
uint32_t bracket_depth;
|
||||
uint32_t brace_depth;
|
||||
};
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
State state = {false, 0, 0, 0};
|
||||
while (!state.done) {
|
||||
switch (lexer->lookahead) {
|
||||
case '\0':
|
||||
return false;
|
||||
case '(':
|
||||
state.paren_depth++;
|
||||
break;
|
||||
case '[':
|
||||
state.bracket_depth++;
|
||||
break;
|
||||
case '{':
|
||||
state.brace_depth++;
|
||||
break;
|
||||
case ')':
|
||||
if (state.paren_depth == 0) state.done = true;
|
||||
state.paren_depth--;
|
||||
break;
|
||||
case ']':
|
||||
if (state.bracket_depth == 0) state.done = true;
|
||||
state.bracket_depth--;
|
||||
break;
|
||||
case '}':
|
||||
if (state.brace_depth == 0) state.done = true;
|
||||
state.brace_depth--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!state.done) {
|
||||
bool was_space = iswspace(lexer->lookahead);
|
||||
advance(lexer);
|
||||
if (!was_space) lexer->mark_end(lexer);
|
||||
}
|
||||
}
|
||||
|
||||
lexer->result_symbol = REGEX;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string heredoc_delimiter;
|
||||
bool heredoc_is_raw;
|
||||
bool started_heredoc;
|
||||
bool heredoc_allows_indent;
|
||||
string current_leading_word;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned tree_sitter_bash_external_scanner_serialize(void *payload, char *state) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
return scanner->serialize(state);
|
||||
}
|
||||
|
||||
void tree_sitter_bash_external_scanner_deserialize(void *payload, const char *state, unsigned length) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
scanner->deserialize(state, length);
|
||||
}
|
||||
|
||||
void tree_sitter_bash_external_scanner_destroy(void *payload) {
|
||||
Scanner *scanner = static_cast<Scanner *>(payload);
|
||||
delete scanner;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,223 @@
|
||||
#ifndef TREE_SITTER_PARSER_H_
|
||||
#define TREE_SITTER_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ts_builtin_sym_error ((TSSymbol)-1)
|
||||
#define ts_builtin_sym_end 0
|
||||
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
|
||||
|
||||
typedef uint16_t TSStateId;
|
||||
|
||||
#ifndef TREE_SITTER_API_H_
|
||||
typedef uint16_t TSSymbol;
|
||||
typedef uint16_t TSFieldId;
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
TSFieldId field_id;
|
||||
uint8_t child_index;
|
||||
bool inherited;
|
||||
} TSFieldMapEntry;
|
||||
|
||||
typedef struct {
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
} TSFieldMapSlice;
|
||||
|
||||
typedef struct {
|
||||
bool visible;
|
||||
bool named;
|
||||
bool supertype;
|
||||
} TSSymbolMetadata;
|
||||
|
||||
typedef struct TSLexer TSLexer;
|
||||
|
||||
struct TSLexer {
|
||||
int32_t lookahead;
|
||||
TSSymbol result_symbol;
|
||||
void (*advance)(TSLexer *, bool);
|
||||
void (*mark_end)(TSLexer *);
|
||||
uint32_t (*get_column)(TSLexer *);
|
||||
bool (*is_at_included_range_start)(const TSLexer *);
|
||||
bool (*eof)(const TSLexer *);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSParseActionTypeShift,
|
||||
TSParseActionTypeReduce,
|
||||
TSParseActionTypeAccept,
|
||||
TSParseActionTypeRecover,
|
||||
} TSParseActionType;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t type;
|
||||
TSStateId state;
|
||||
bool extra;
|
||||
bool repetition;
|
||||
} shift;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t child_count;
|
||||
TSSymbol symbol;
|
||||
int16_t dynamic_precedence;
|
||||
uint16_t production_id;
|
||||
} reduce;
|
||||
uint8_t type;
|
||||
} TSParseAction;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
} TSLexMode;
|
||||
|
||||
typedef union {
|
||||
TSParseAction action;
|
||||
struct {
|
||||
uint8_t count;
|
||||
bool reusable;
|
||||
} entry;
|
||||
} TSParseActionEntry;
|
||||
|
||||
struct TSLanguage {
|
||||
uint32_t version;
|
||||
uint32_t symbol_count;
|
||||
uint32_t alias_count;
|
||||
uint32_t token_count;
|
||||
uint32_t external_token_count;
|
||||
uint32_t state_count;
|
||||
uint32_t large_state_count;
|
||||
uint32_t production_id_count;
|
||||
uint32_t field_count;
|
||||
uint16_t max_alias_sequence_length;
|
||||
const uint16_t *parse_table;
|
||||
const uint16_t *small_parse_table;
|
||||
const uint32_t *small_parse_table_map;
|
||||
const TSParseActionEntry *parse_actions;
|
||||
const char * const *symbol_names;
|
||||
const char * const *field_names;
|
||||
const TSFieldMapSlice *field_map_slices;
|
||||
const TSFieldMapEntry *field_map_entries;
|
||||
const TSSymbolMetadata *symbol_metadata;
|
||||
const TSSymbol *public_symbol_map;
|
||||
const uint16_t *alias_map;
|
||||
const TSSymbol *alias_sequences;
|
||||
const TSLexMode *lex_modes;
|
||||
bool (*lex_fn)(TSLexer *, TSStateId);
|
||||
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
|
||||
TSSymbol keyword_capture_token;
|
||||
struct {
|
||||
const bool *states;
|
||||
const TSSymbol *symbol_map;
|
||||
void *(*create)(void);
|
||||
void (*destroy)(void *);
|
||||
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
|
||||
unsigned (*serialize)(void *, char *);
|
||||
void (*deserialize)(void *, const char *, unsigned);
|
||||
} external_scanner;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lexer Macros
|
||||
*/
|
||||
|
||||
#define START_LEXER() \
|
||||
bool result = false; \
|
||||
bool skip = false; \
|
||||
bool eof = false; \
|
||||
int32_t lookahead; \
|
||||
goto start; \
|
||||
next_state: \
|
||||
lexer->advance(lexer, skip); \
|
||||
start: \
|
||||
skip = false; \
|
||||
lookahead = lexer->lookahead;
|
||||
|
||||
#define ADVANCE(state_value) \
|
||||
{ \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define SKIP(state_value) \
|
||||
{ \
|
||||
skip = true; \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ACCEPT_TOKEN(symbol_value) \
|
||||
result = true; \
|
||||
lexer->result_symbol = symbol_value; \
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
#define END_STATE() return result;
|
||||
|
||||
/*
|
||||
* Parse Table Macros
|
||||
*/
|
||||
|
||||
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
|
||||
|
||||
#define STATE(id) id
|
||||
|
||||
#define ACTIONS(id) id
|
||||
|
||||
#define SHIFT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = state_value \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_REPEAT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = state_value, \
|
||||
.repetition = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_EXTRA() \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.extra = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define REDUCE(symbol_val, child_count_val, ...) \
|
||||
{{ \
|
||||
.reduce = { \
|
||||
.type = TSParseActionTypeReduce, \
|
||||
.symbol = symbol_val, \
|
||||
.child_count = child_count_val, \
|
||||
__VA_ARGS__ \
|
||||
}, \
|
||||
}}
|
||||
|
||||
#define RECOVER() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeRecover \
|
||||
}}
|
||||
|
||||
#define ACCEPT_INPUT() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeAccept \
|
||||
}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_PARSER_H_
|
||||
Loading…
Reference in New Issue