aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Spek <p.spek@tyil.nl>2023-05-15 08:18:12 +0200
committerPatrick Spek <p.spek@tyil.nl>2023-05-15 08:20:07 +0200
commita90e94c845cded2aeda7b70ea3ec5d6b6085f44a (patch)
tree62ae27de9a8502cce1ace16ee9e6fce281f67136
parent0b1146b6aef61a4369922b67a29e42c992f5de6b (diff)
Remove bpt from the codebase again
The power of the templating tool were not as big as I had hoped. The inclusion of another license also doesn't really seem like it is worth the trouble considering the tool didn't really get me the high level of templating I had desired. The quest for templating continues...
-rw-r--r--CHANGELOG.md6
-rw-r--r--LICENSES/MIT.txt22
-rw-r--r--lib/util.bash51
-rw-r--r--lib/vendor/bpt.bash1244
4 files changed, 6 insertions, 1317 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e752aa..976c578 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -69,12 +69,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `sync` subcomman will now `stash` any changes before it attempts to
`pull`. Afterwards, `stash pop` will be ran to apply the last `stash`ed
changes again.
-- The `file_template` function has been altered to be able to use various
- templating engines. Currently it supports `satpl` (which stands for sed-awk
- template, the "original" templating mechanism used in Bashtard) and `bpt`
- (which stands for [Bash Pure Templates](https://github.com/husixu1/bpt). The
- engine used is defined through the file's extension. If no extension is set,
- it will default to `satpl`.
## [1.0.0] - 2022-05-06
diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt
deleted file mode 100644
index da4c7e6..0000000
--- a/LICENSES/MIT.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-
- The MIT License (MIT)
- Copyright (c) 2023 Hu Sixu
-
- 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.
-
diff --git a/lib/util.bash b/lib/util.bash
index bae620b..c2429a1 100644
--- a/lib/util.bash
+++ b/lib/util.bash
@@ -10,8 +10,6 @@
. "$BASHTARD_LIBDIR/util/pkg.bash"
# shellcheck source=lib/util/svc.bash
. "$BASHTARD_LIBDIR/util/svc.bash"
-# shellcheck source=lib/vendor/bpt.bash
-. "$BASHTARD_LIBDIR/vendor/bpt.bash"
# Change the working directory. In usage, this is the same as using cd,
# however, it will make additional checks to ensure everything is going fine.
@@ -144,44 +142,17 @@ file_hash_md5() {
file_template()
{
local file
- local system
-
- file="$1" ; shift
-
- ext="${file##*.}"
- path="$(playbook_path "base")/share/$file"
- system="bashtard/file_template"
-
- if [[ -z "$ext" || "$ext" == "$file" ]]
- then
- debug "$system" "Missing extension for template $file, assuming satpl"
- ext="satpl"
- fi
+ local sedfile
- if [[ ! -f "$path" ]]
- then
- crit "$system" "No template found at $path"
- return 1
- fi
+ file="$(playbook_path "base")/share/$1" ; shift
+ sedfile="$(tmpfile)"
- if [[ "$(type -t "file_template_$ext")" != "function" ]]
+ if [[ ! -f $file ]]
then
- crit "$system" "Invalid extension for template $file ($ext)"
- return 1
+ crit "bashtard/template" "Tried to render template from $file, but it doesn't exist"
+ return
fi
- "file_template_$ext" "$path" "$@"
-}
-
-file_template_satpl()
-{
- local file
- local sedfile
-
- file="$1" ; shift
-
- sedfile="$(tmpfile)"
-
for kv in "$@"
do
debug "bashtard/template" "Adding $kv to sedfile at $sedfile"
@@ -207,16 +178,6 @@ file_template_satpl()
sed -f "$sedfile" "$file"
}
-file_template_bpt()
-{
- local file
-
- file="$1" ; shift
-
- eval "$* bpt.main ge \"$file\""
- printf "\n"
-}
-
# Check if the first argument given appears in the list of all following
# arguments.
in_args() {
diff --git a/lib/vendor/bpt.bash b/lib/vendor/bpt.bash
deleted file mode 100644
index cda1030..0000000
--- a/lib/vendor/bpt.bash
+++ /dev/null
@@ -1,1244 +0,0 @@
-#!/usr/bin/env bash
-
-# SPDX-FileCopyrightText: 2023 Sixu Hu <husixu1@hotmail.com>
-# SPDX-FileCopyrightText: 2023 Patrick Spek <p.spek@tyil.nl>
-#
-# SPDX-License-Identifier: MIT
-
-# shellcheck disable=SC2317
-
-# Import once
-if [[ -n $__BPT_VERSION ]]; then return; fi
-readonly __BPT_VERSION="v0.1"
-
-# Add multiple traps for EXIT
-# See https://stackoverflow.com/questions/3338030
-bpt.__add_exit_trap() {
- trap_add_cmd=${1:?${FUNCNAME[0]} usage error}
- trap -- "$(
- extract_trap_cmd() { printf '%s\n' "$3"; }
- eval "extract_trap_cmd $(trap -p EXIT)"
- printf '%s\n' "${trap_add_cmd}"
- )" EXIT || echo "Unable to add to trap" >&2
-}
-
-# The shift-reduce LR(1) parser.
-# $1: Parse table name.
-# The parse table should be an associative array where the key is
-# <state>,<token> and the value actions (s <k>/r <rule>/a/<k>).
-# $2: Reduce function hook
-# This function can access `rule=(LHS RHS1 RHS2 ...)`.
-# This function can access the RHS(i+1)'s content': `${contents[$((s + i))]}`.
-# This function should store the reduce result to `contents[$s]`.
-# $3: Error handler function hook
-# Args passed to this function:
-# $1: Line
-# $2: Column
-# $3: Default error message
-# $4: (optional) If set, enable debug.
-# shellcheck disable=SC2030 # Modification to `contents` and `rule` are local.
-bpt.__lr_parse() (
- local -rn table="$1"
- local -r reduce_fn="${2:-echo}"
- local -r error_fn="${3:-__error}"
- if [[ -n $4 ]]; then local -r NDEBUG=false; else local -r NDEBUG=true; fi
-
- # 20 should be enough ...
- # I assume no one's writing a BNF with more than 20 RHSs ...
- local -a STATE_PTRN=('')
- for i in {1..20}; do STATE_PTRN[i]="${STATE_PTRN[i - 1]}:*"; done
-
- # Parse stack
- # Using string manipulation for states is faster than using an array.
- local states=':0' stack_size=1
- # Contents stack associatied wit the parse stack
- # Large dict indexing is significantly faster than a regular one.
- # Thus we use stack_size + associative array to emulate a regular array.
- local -A contents=([0]='')
-
- # Current reduction rule
- local -a rule=()
- # Current look-ahead token and its content
- local token='' content='' action=''
- # Location tracking variables
- local num_lines=0 num_bytes=0
- # Temporary variables
- local i=0 str_lines=0 buffer=''
-
- # $1: Goto state after shift
- __shift() {
- states+=":$1"
- contents["$stack_size"]="$content"
- ((++stack_size))
- token='' content=''
- }
-
- # $1: Rule
- __reduce() {
- # Although not robust, word splitting is faster than `read`
- # shellcheck disable=SC2206
- local num_rhs=$((${#rule[@]} - 1))
-
- # Reduce and goto state
- # shellcheck disable=SC2295
- states="${states%${STATE_PTRN[$num_rhs]}}"
- states+=":${table["${states##*:},${rule[0]}"]}"
-
- # Reduction start location (on the contents stack)
- local s=$((stack_size - num_rhs))
-
- # Run reduce hook (which saves the reduce result to `contents[$s]`)
- $reduce_fn || exit 1
- stack_size=$((s + 1))
- }
-
- # Simply print the result
- __accept() {
- printf '%s' "${contents[1]}"
- }
-
- # Default error handler
- __error() {
- echo "Error: Line $(($1 + 1)) Column $(($2 + 1))"
- echo "$3"
- } >&2
-
- # Debugging support
- $NDEBUG || {
- eval __orig"$(declare -f __shift)"
- eval __orig"$(declare -f __reduce)"
- eval __orig"$(declare -f __accept)"
- __shift() {
- echo "[DBG] ${states##*:} Shift $1 \`$content\`" >&2
- __orig__shift "$@"
- }
- __reduce() {
- echo "[DBG] ${states##*:} Reduce ${rule[*]}" >&2
- __orig__reduce
- }
- __accept() {
- $NDEBUG || echo "[DBG] Result accepted" >&2
- __orig__accept
- }
- }
-
- while true; do
- [[ -n $token ]] || {
- read -r token str_lines num_lines num_bytes
- IFS= read -r buffer || return 1
- content="$buffer"
- for ((i = 1; i < str_lines; ++i)); do
- IFS= read -r buffer || return 1
- content+=$'\n'"$buffer"
- done
- }
-
- action="${table["${states##*:},$token"]}"
- case "$action" in
- # Shift
- s*) __shift "${action#s }" ;;
- # Reduce
- r*) # shellcheck disable=SC2206
- rule=(${action#r })
- __reduce
- ;;
- # Accept
- a) __accept && break ;;
- # Error
- '')
- local expects='' rule_key=''
- for rule_key in "${!table[@]}"; do
- [[ $rule_key != "${states##*:},"* ||
- -z "${table["$rule_key"]}" ||
- "${table["$rule_key"]}" =~ ^[[:digit:]]+$ ]] ||
- expects+="${expects:+,}${BPT_PP_TOKEN_TABLE["${rule_key##*,}"]:-${rule_key##*,}}"
- done
- $error_fn "$num_lines" "$num_bytes" \
- "Expects one of \`${expects[*]}\` but got \`${token}\` ($content)."
- $NDEBUG || echo "[DBG] PARSER STATES ${states} TOKEN ${token} CONTENT ${content}." >&2
- exit 1
- ;;
- *) # Parse table error (internal error)
- echo "Internal error: STATES ${states} TOKEN ${token} CONTENT ${content}. " >&2
- echo "Internal error: action '$action' not recognized." >&2
- exit 1
- ;;
- esac
- done
-)
-
-# The tokenizer for bpt
-# $1: Left deilmiter
-# $2: Right delimiter
-# $3: Error handler function hook
-# Args passed to this function:
-# $1: Line
-# $2: Column
-# $3: Default error message
-#
-# Terminal token name to content mappings:
-# str: Anything outside the toplevel `ld ... rd` or
-# Anything inside `"..."` or `'...'` within any `ld ... rd`
-# Note1: `"` inside `"..."` needs to be escaped using `\"`,
-# and the same for `'` inside `'...'`.
-#
-# ld: ${ldelim} rd: ${rdelim} lp: ( rp: )
-# cl: : ex: ! eq: -eq ne: -ne
-# lt: -lt gt: -gt le: -le ge: -ge
-# streq: == strne: != strlt: < strgt: >
-# and|or|if|elif|else|for|in|include: <as is>
-# id: [[:alpha:]_][[:alnum:]_]*
-bpt.scan() (
- # shellcheck disable=SC2030
- local -r ld="$1" rd="$2" error_fn="${3:-__error}"
- bpt.__test_delims "$ld" "$rd" || return 1
-
- # Default error handler
- __error() {
- echo "Error: Line $(($1 + 1)) Column $(($2 + 1))"
- echo "$3"
- } >&2
-
- # See man regex.7. We need to escape the meta characters of POSIX regex.
- local -rA ESC=(
- ['^']=\\ ['.']=\\ ['[']=\\ ['$']=\\ ['(']=\\ [')']=\\
- ['|']=\\ ['*']=\\ ['+']=\\ ['?']=\\ ['{']=\\ [\\]=\\
- )
- local e_ld='' e_rd='' i=0
- for ((i = 0; i < ${#ld}; ++i)); do e_ld+="${ESC["${ld:i:1}"]}${ld:i:1}"; done
- for ((i = 0; i < ${#rd}; ++i)); do e_rd+="${ESC["${rd:i:1}"]}${rd:i:1}"; done
-
- # Keywords
- local -ra KW=(
- "${e_ld}" "${e_rd}"
- '-eq' '-ne' '-gt' '-lt' '-ge' '-le'
- '==' '!=' '>' '<' ':' '\!' '"' "'" '\(' '\)'
- 'and' 'or' 'if' 'elif' 'else' 'for' 'in' 'include'
- )
- local -r KW_RE="$(IFS='|' && echo -n "${KW[*]}")"
- local -r ID_RE='[[:alpha:]_][[:alnum:]_]*'
-
- # Scanner states
- local num_ld=0
- local quote=''
-
- # Location trackers
- # shellcheck disable=SC2030
- local num_lines=0
- # shellcheck disable=SC2030
- local num_bytes=0
-
- # String processing tracker & buffer.
- # `str_lines=''` means currently outside the scope of string
- local string='' str_lines='' str_bytes=''
- # Start scannign string
- __start_string() {
- str_lines="${str_lines:-1}"
- str_bytes="${str_bytes:-$num_bytes}"
- }
- # Commit (possibly multiline) string buffer
- # shellcheck disable=SC2031
- __commit_string() {
- ((str_lines > 0)) || return
- echo "str $str_lines $((num_lines + 1 - str_lines)) $str_bytes"
- # `$content` can be a literal `-ne`. Thus printf is needed.
- printf '%s\n' "$string"
- string='' str_lines='' str_bytes=''
- }
-
- # Tokenizer
- local line='' content=''
- while IFS= read -r line || [[ $line ]]; do
- # Decide whether currently scanning a string
- # Only count newlines in strings (outside `ld ... rd` and inside quotes).
- [[ $num_ld -gt 0 && -z "$quote" ]] || {
- __start_string
- [[ $num_lines -eq 0 ]] || { string+=$'\n' && ((++str_lines)); }
- }
-
- # Scan the line
- while [[ -n "$line" ]]; do
- content='' # The consumed content (to be removed from `line`)
- if [[ $num_ld -eq 0 ]]; then
- # Outside `ld ... rd`
- if [[ $line =~ ^(${e_ld}) ]]; then
- # If met `ld`, enter `ld ... rd`
- __commit_string
- ((++num_ld))
- content="${BASH_REMATCH[1]}"
- echo "ld 1 $num_lines $num_bytes"
- printf '%s\n' "$content"
- elif [[ $line =~ (${e_ld}) ]]; then
- content="${line%%"${BASH_REMATCH[1]}"*}"
- string+="$content"
- else
- content="$line"
- string+="$line"
- fi
- elif [[ -n "$quote" ]]; then
- # Inside quotes in `ld ... rd`
- # Scan for `str` until we find a non-escaped quote.
- local line_copy="$line"
- while [[ $line_copy =~ ^[^${quote}]*\\${quote} ]]; do
- # Escape quote inside string
- string+="${line_copy%%"\\${quote}"*}${quote}"
- content+="${line_copy%%"\\${quote}"*}\\${quote}"
- line_copy="${line_copy#"${BASH_REMATCH[0]}"}"
- done
-
- if [[ $line_copy =~ ${quote} ]]; then
- # Remove the closing quote from line
- content+="${line_copy%%"${quote}"*}${quote}"
- string+="${line_copy%%"${quote}"*}"
- quote=''
- __commit_string
- else
- content="$line_copy"
- string+="$line_copy"
- fi
- else
- # Non-strings. Commit string first.
- __commit_string
- if [[ $line =~ ^(${KW_RE}) ]]; then
- # Inside `ld ... rd` and matches a keyword at front
- content="${BASH_REMATCH[1]}"
- case "$content" in
- '-eq') echo -n eq ;; '-ne') echo -n ne ;;
- '-lt') echo -n lt ;; '-gt') echo -n gt ;;
- '-le') echo -n le ;; '-ge') echo -n ge ;;
- '==') echo -n streq ;; '!=') echo -n strne ;;
- '>') echo -n strgt ;; '<') echo -n strlt ;;
- '!') echo -n ex ;; ':') echo -n cl ;;
- '(') echo -n lp ;; ')') echo -n rp ;;
- '"' | "'")
- quote="$content"
- __start_string
- ;;
- "$ld")
- ((++num_ld))
- echo -n ld
- ;;
- "$rd")
- ((num_ld-- > 0)) || {
- $error_fn "$num_lines" "$num_bytes" "Extra '$rd'."
- return 1
- }
- ((num_ld != 0)) || __start_string
- echo -n rd
- ;;
- and | or | if | elif | else) ;&
- for | in | include) echo -n "$content" ;;
- *)
- $error_fn "$num_lines" "$num_bytes" \
- "Internal error: Unrecognized token ${content}"
- return 1
- ;;
- esac
- [[ -n $quote ]] || {
- echo " 1 $num_lines $num_bytes"
- printf '%s\n' "$content"
- }
- else # Inside `ld ... rd` but outside quotes
- # Ignore spaces inside `ld ... rd`
- [[ $line =~ ^([[:space:]]+)(.*) ]] && {
- line="${BASH_REMATCH[2]}"
- ((num_bytes += ${#BASH_REMATCH[1]}))
- continue
- }
- content="$line"
-
- # Contents are either keywords or identifiers
- if [[ $content =~ (${KW_RE}) ]]; then
- content="${content%%"${BASH_REMATCH[1]}"*}"
- fi
- if [[ ! $content =~ ^(${ID_RE}) ]]; then
- $error_fn "$num_lines" "$num_bytes" \
- "'$content' is not a valid identifier"
- return 1
- fi
- content="${BASH_REMATCH[1]}"
- echo "id 1 $num_lines $num_bytes"
- printf '%s\n' "$content"
- fi
- fi
-
- # Post-processing only counts the last line read.
- line="${line#"$content"}"
- ((num_bytes += ${#content}))
- done
- ((++num_lines))
- num_bytes=0 content=''
- done
- __commit_string
- echo "$ 1 $num_lines 0" # The EOF token
- echo '' # The EOF content (empty)
-)
-
-bpt.__test_delims() {
- [[ $1 != *' '* && $2 != *' '* ]] || {
- echo "Left and right delimiters must not contain spaces." >&2
- return 1
- }
- [[ "$1" != "$2" ]] || {
- echo "Left and right delimiters must be different." >&2
- return 1
- }
-}
-
-# The reduce function to collect all variables
-# shellcheck disable=SC2031 # Direct access of `rule` and `contents` for speed.
-bpt.__reduce_collect_vars() {
- # For all `id` token, allow only the path via the VAR rule.
- # For all `str` token, allow only the path to the INCLUDE rule.
- case "${rule[0]}" in
- ID | STR) ;;
- STMT) [[ "${rule[1]}" != STR ]] || contents[$s]='' ;;
- VAR)
- contents[$s]="${contents[$((s + 1))]}"$'\n'
- [[ ${#rule[@]} -eq 4 || ${rule[4]} != VAR ]] ||
- contents[$s]+="${contents[$((s + 3))]}"
- ;;
- BUILTIN) contents[$s]="${contents[$((s + 3))]}" ;;
- INCLUDE) contents[$s]="$(__recursive_process "${contents[$((s + 3))]}")"$'\n' ;;
- FORIN) # Filter tokens defined by the FORIN rule
- contents[$s]="${contents[$((s + 4))]}"
- local var
- while read -r var; do
- [[ -z $var || $var == "${contents[$((s + 2))]}" ]] || contents[$s]+="$var"$'\n'
- done <<<"${contents[$((s + 6))]}"
- ;;
- *) # Prevent the propagation of all other non-terminals
- [[ "${#rule[@]}" -ne 1 ]] || { contents[$s]='' && return; }
- [[ "${rule[1]^^}" == "${rule[1]}" ]] || contents[$s]=''
- local i=1
- for (( ; i < ${#rule[@]}; ++i)); do
- [[ "${rule[i + 1],,}" == "${rule[i + 1]}" ]] ||
- contents[$s]+="${contents[$((s + i))]}"
- done
- ;;
- esac
-}
-
-# The reduce function to collect all includes
-# shellcheck disable=SC2031
-bpt.__reduce_collect_includes() {
- # For all `str` token, allow only the path via the INCLUDE rule.
- case "${rule[0]}" in
- STR) ;; # Allow the propagation of str
- STMT) [[ "${rule[1]}" != STR ]] || contents[$s]='' ;;
- VAR) contents[$s]='' ;;
- INCLUDE)
- contents[$s]="${contents[$((s + 3))]}"$'\n'
- contents[$s]+="$(__recursive_process "${contents[$((s + 3))]}")"
- ;;
- *) # Prevent the propagation of all other non-terminals
- [[ "${#rule[@]}" -ne 1 ]] || { contents[$s]='' && return; }
- [[ "${rule[1]^^}" == "${rule[1]}" ]] || contents[$s]=''
- local i=1
- for (( ; i < ${#rule[@]}; ++i)); do
- [[ "${rule[i + 1],,}" == "${rule[i + 1]}" ]] ||
- contents[$s]+="${contents[$((s + i))]}"
- done
- ;;
- esac
-}
-
-# The reduce function to generate the template
-# shellcheck disable=SC2031
-bpt.__reduce_generate() {
- case "${rule[0]}" in
- # Note: Since `contents[$s]` is exactly the first RHS, the
- # `${contents[$s]}="${contents[$s]}"` assignment is unnecessary here.
- STR | UOP | BOP) ;;
- # Tag location for BUILTIN error reporting
- ID) contents[$s]+=":$num_lines:$num_bytes" ;;
- VAR)
- case "${rule[3]}" in
- rd) contents[$s]="\${${contents[$((s + 1))]%:*:*}}" ;;
- or) contents[$s]="\${${contents[$((s + 1))]%:*:*}:-\$(e " ;;&
- and) contents[$s]="\${${contents[$((s + 1))]%:*:*}:+\$(e " ;;&
- *) case "${rule[4]}" in
- VAR) contents[$s]+="\"${contents[$((s + 3))]}\")}" ;;
- STR) contents[$s]+="${contents[$((s + 3))]@Q})}" ;;
- esac ;;
- esac
- ;;
- ARGS)
- # Strip the tag from STMT
- local stmt_type='' stmt=
- case "${#rule[@]}" in
- 2)
- stmt_type="${contents[$s]%%:*}"
- stmt="${contents[$s]#*:}"
- contents[$s]=''
- ;;
- 3)
- stmt_type="${contents[$((s + 1))]%%:*}"
- stmt="${contents[$((s + 1))]#*:}"
- ;;
- esac
-
- # Note: `${stmt@Q}` is faster than `printf '%q' ${stmt}`
- case "$stmt_type" in
- STR) contents[$s]+=" ${stmt@Q} " ;;
- VAR | BUILTIN) contents[$s]+=" $stmt " ;;
- INCLUDE | FORIN | IF) contents[$s]+=" \"\$($stmt)\" " ;;
- esac
- ;;
- BUILTIN)
- # Filter allowed builtints
- local builtin_name=${contents[$((s + 1))]%:*:*}
- case "$builtin_name" in
- len | seq) contents[$s]="\$($builtin_name ${contents[$((s + 3))]})" ;;
- quote) contents[$s]="\"\$(e ${contents[$((s + 3))]})\"" ;;
- *) # Extract and compute correct error location from ID
- local line_col="${contents[$((s + 1))]#"$builtin_name"}"
- local err_line=${line_col%:*} && err_line="${err_line:1}"
- local err_byte=$((${line_col##*:} - ${#builtin_name}))
- $error_fn "$err_line" "$err_byte" \
- "Error Unrecognized builtin function $builtin_name" >&2
- exit 1
- ;;
- esac
- ;;
- INCLUDE) contents[$s]="$(__recursive_process "${contents[$((s + 3))]}")" ;;
- FORIN) contents[$s]="for ${contents[$((s + 2))]%:*:*} in ${contents[$((s + 4))]}; do ${contents[$((s + 6))]} done" ;;
- BOOL)
- case "${#rule[@]}" in
- 2) contents[$s]="\"\$(e ${contents[$s]})\"" ;;
- 4) contents[$s]+=" ${contents[$((s + 1))]} \"\$(e ${contents[$((s + 2))]})\"" ;;
- esac
- ;;
- BOOLA)
- case "${#rule[@]}" in
- 4) case "${rule[1]}" in
- BOOLA) contents[$s]="${contents[$s]} && ${contents[$((s + 2))]}" ;;
- lp) contents[$s]="( ${contents[$((s + 1))]} )" ;;
- esac ;;
- 5) contents[$s]="${contents[$s]} && ${contents[$((s + 2))]} ${contents[$((s + 3))]}" ;;
- 6) contents[$s]="${contents[$s]} && ( ${contents[$((s + 3))]} )" ;;
- 7) contents[$s]="${contents[$s]} && ${contents[$((s + 2))]} ( ${contents[$((s + 4))]} )" ;;
- esac
- ;;
- BOOLO)
- case "${#rule[@]}" in
- 4) contents[$s]="${contents[$s]} || ${contents[$((s + 2))]}" ;;
- 5) contents[$s]="${contents[$s]} || ${contents[$((s + 2))]} ${contents[$((s + 3))]}" ;;
- esac
- ;;
- BOOLS) [[ ${#rule[@]} -eq 2 ]] || contents[$s]="${contents[$s]} ${contents[$((s + 1))]}" ;;
- ELSE)
- case "${#rule[@]}" in
- 1) contents[$s]='' ;;
- *) contents[$s]="else ${contents[$((s + 2))]}" ;;
- esac
- ;;
- ELIF)
- case "${#rule[@]}" in
- 1) contents[$s]='' ;;
- *) contents[$s]="${contents[$s]} elif [[ ${contents[$((s + 2))]} ]]; then ${contents[$((s + 4))]}" ;;
- esac
- ;;
- IF) contents[$s]="if [[ ${contents[$((s + 2))]} ]]; then ${contents[$((s + 4))]}${contents[$((s + 5))]}${contents[$((s + 6))]} fi" ;;
- STMT)
- # Tag the sub-type to the reduce result
- # (Need to strip the tag wherever STMT is used)
- contents[$s]="${rule[1]}:${contents[$s]}"
- ;;
- DOC) # Similar to ARGS but produces commands instead of strings
- # Return when document is empty
- [[ "${#rule[@]}" -ne 1 ]] || { contents[$s]='' && return; }
-
- # Strip the tag from STMT
- local stmt_type="${contents[$((s + 1))]%%:*}"
- local stmt="${contents[$((s + 1))]#*:}"
-
- # Reduce the document
- case "$stmt_type" in
- STR) contents[$s]+="{ e ${stmt@Q}; };" ;;
- BUILTIN | VAR) contents[$s]+="{ e \"$stmt\"; };" ;;
- INCLUDE) contents[$s]+="$stmt" ;;
- FORIN | IF) contents[$s]+="{ $stmt; };" ;;
- esac
- ;;
- *) echo "Internal error: Rule ${rule[*]} not recognized" >&2 ;;
- esac
-}
-
-# Process the template
-#
-# $1: Left deilmiter
-# $2: Right delimiter
-# $3: The reduce function hook to pass to the parser.
-# Defaults to bpt.__reduce_collect_vars
-# $4: File to process
-# $5: (optional) If set, enable debug.
-#
-# Input: Template from stdin
-#
-# Grammar:
-# DOC -> DOC STMT
-# | .
-# STMT -> IF | FORIN | INCLUDE | BUILTIN | VAR | STR .
-# IF -> ld if BOOLS cl DOC ELIF ELSE rd .
-# ELIF -> ELIF elif BOOLS cl DOC
-# | .
-# ELSE -> else cl DOC
-# | .
-# BOOLS -> BOOLO
-# | UOP BOOLS .
-# BOOLO -> BOOLO or BOOLA
-# | BOOLO or UOP BOOLA
-# | BOOLA .
-# BOOLA -> BOOLA and BOOL
-# | BOOLA and UOP BOOL
-# | BOOLA and lp BOOLS rp
-# | BOOLA and UOP lp BOOLS rp
-# | lp BOOLS rp
-# | BOOL .
-# BOOL -> ARGS BOP ARGS
-# | ARGS .
-# FORIN -> ld for ID in ARGS cl DOC rd .
-# INCLUDE -> ld include cl STR rd .
-# BUILTIN -> ld ID cl ARGS rd .
-# ARGS -> ARGS STMT
-# | STMT .
-# VAR -> ld ID rd
-# | ld ID or VAR rd
-# | ld ID or STR rd
-# | ld ID and VAR rd
-# | ld ID and STR rd .
-# BOP -> ne | eq | gt | lt | ge | le | strgt | strlt | streq | strne .
-# UOP -> ex .
-# ID -> id .
-# STR -> str .
-#
-# Note1: the combination of BOOLO and BOOLA is equivalent to the expression
-# grammar `BOOLS -> BOOL or BOOL | BOOL and BOOL | lp BOOL rp | BOOL .`
-# with left associativity for `and` and `or` meanwhile `and` having higher
-# precidence than `or`. (Solves shift-reduce conflict with subclassing).
-# See: https://ece.uwaterloo.ca/~vganesh/TEACHING/W2014/lectures/lecture08.pdf
-#
-# Note2: the `ID -> id` and `STR -> str` rules are not redundant.
-# They are for better controls when hooking the reduce function.
-bpt.process() (
- local -r ld="$1" rd="$2" file="$4" debug="$5"
- local -r reduce_fn="${3:-bpt.__reduce_generate}"
- local -a file_stack=("${file_stack[@]}")
-
- [[ -f $file ]] || {
- echo "Error: file '$file' does not exist" >&2
- return 1
- }
- file_stack+=("$file")
-
- # Curry this function so that it can be called by the reducer recursively
- __recursive_process() {
- local file
- # Detect recursive includes
- for file in "${file_stack[@]}"; do
- [[ $file -ef $1 ]] && {
- printf "Error: cyclic include detected:\n"
- printf ' In: %s\n' "${file_stack[0]}"
- printf ' --> %s\n' "${file_stack[@]:1}"
- printf ' --> %s\n' "${file}"
- return 1
- } >&2
- done
- bpt.process "$ld" "$rd" "$reduce_fn" "$1" "$debug"
- }
-
- # Pretty-print parse errors
- __error_handler() {
- echo "Error: File '$file' Line $(($1 + 1)) Column $(($2 + 1))"
- echo "$3"
- echo
- # Pretty-print the error location
- local -a line=()
- mapfile -t -s "$1" -n 1 line <"$file"
- echo "${line[0]}"
- printf "%$2s^--- \033[1mHERE\033[0m\n"
- } >&2
-
- # Prase with the provided reduce function
- bpt.__lr_parse BPT_PARSE_TABLE "$reduce_fn" __error_handler "$debug" \
- < <(bpt.scan "$ld" "$rd" __error_handler <"$file")
-)
-
-# $1: Left deilmiter
-# $2: Right delimiter
-# $3: File to process
-# $4: (optional) If set, enable debug.
-# shellcheck disable=SC2207
-bpt.fingerprint() {
- local -r ld="$1" rd="$2" file="$3" debug="$4"
-
- # Collect vars and includes
- local -a vars=() incs=()
- mapfile -t vars < <(bpt.__dedup "$(bpt.process "$ld" "$rd" bpt.__reduce_collect_vars "$infile" "$debug")")
- mapfile -t incs < <(bpt.__dedup "$(bpt.process "$ld" "$rd" bpt.__reduce_collect_includes "$infile" "$debug")")
- local fingerprint=''
- local -a md5=()
- local util
-
- case "${BASHTARD_PLATFORM[key]}" in
- freebsd) util=md5 ;;
- linux-*) util=md5sum ;;
- *)
- debug "bpt/fingerprint" "Falling back to md5sum for hashing"
- util=md5sum
- ;;
- esac
-
- # Hash this script (the generator)
- md5=($("$util" "${BASH_SOURCE[0]}")) && fingerprint+="M:${md5[0]}"
-
- # Hash the file itself
- md5=($("$util" "$file")) && fingerprint+=":S:${md5[0]}"
-
- # Digest the includes
- for inc in "${incs[@]}"; do
- md5=($("$util" "$inc")) && fingerprint+=":I:${md5[0]}"
- done
- # Digest and check for missing vars
- for var in "${vars[@]}"; do
- if [[ -z ${!var+.} ]]; then
- echo "Error: variable '$var' is required but not set" >&2
- return 1
- fi
- md5=($(echo -n "${var}${!var}" | "$util")) && fingerprint+=":V:${md5[0]}"
- done
-
- # Digest the digests
- [[ $debug ]] && echo "[DBG] Raw fingerprint: $fingerprint"
- md5=($(echo -n "${fingerprint}" | "$util")) && fingerprint="${md5[0]}"
- echo "$fingerprint"
-}
-
-bpt.print_help() {
- echo -e "\033[1mbpt - A command-line tool for processing simple templates\033[0m"
- echo
- echo -e "\033[1mSYNOPSIS\033[0m"
- echo " bpt <command> [-l <LEFT_DELIMITER>] [-r <RIGHT_DELIMITER>] [-d] [<FILENAME>]"
- echo
- echo -e "\033[1mCOMMANDS\033[0m"
- echo " scan, s:"
- echo " Call the scanner (lexer)."
- echo
- echo " generate, g:"
- echo " Generate a shell script based on the input file. Output is sent to stdout."
- echo
- echo " generate-eval, ge:"
- echo " Same as generate, but the output is evaluated. Output is sent to stdout."
- echo
- echo " collect-vars, cv:"
- echo " Collect variable used in the input file recursively and output them to stdout."
- echo
- echo " collect-includes, ci:"
- echo " Collect all files included in the input file recursively and output them to stdout."
- echo
- echo " fingerprint, f:"
- echo " Generate a unique identifier based on all factors affecting the evaluation output."
- echo
- echo " -h, --help:"
- echo " Print this help."
- echo
- echo " -v, --version:"
- echo " Print version number."
- echo
- echo -e "\033[1mOPTIONS\033[0m"
- echo " -l <LEFT_DELIMITER>, --left-delimiter <LEFT_DELIMITER>:"
- echo " Set the left delimiter to use for placeholders (default \`{{\`)."
- echo
- echo " -r <RIGHT_DELIMITER>, --right-delimiter <RIGHT_DELIMITER>:"
- echo " Set the right delimiter to use for placeholders (default \`}}\`)."
- echo
- echo " -d, --debug:"
- echo " Enable debug mode."
- echo
- echo -e "\033[1mARGUMENTS\033[0m"
- echo " bpt takes an optional input file path as its argument. If no input file is specified, bpt will read from stdin."
- echo
- echo -e "\033[1mEXAMPLES\033[0m"
- echo " Generate script from a single input file using default delimiters:"
- echo " bpt g input.tpl > output.sh"
- echo
- echo " Render the input file:"
- echo " var1=VAR1 var2=VAR2 ... bpt ge input.tpl"
- echo
- echo " Collect variable names and values from an input file:"
- echo " bpt cv input.tpl"
- echo
- echo " Collect include file paths from an input file:"
- echo " bpt ci input.tpl"
- echo
- echo " Generate a fingerprint for an input"
- echo " var1=VAR1 var2=VAR2 ... bpt f input.tpl"
- echo
- echo " Using custom delimiters:"
- echo " bpt -l \"<<\" -r \">>\" g input.tpl > output.sh"
- echo
- echo -e "\033[1mTEMPLATE GRAMMAR EXAMPLES\033[0m"
- echo " Variable replacements"
- echo ' {{ var }}'
- echo ' {{ var or "abc" }}'
- echo ' {{ var or {{var2}} }}'
- echo
- echo " Branching"
- echo ' {{ if {{x}}: {{var1}} else : {{var2}} }}'
- echo ' {{ if {{x}} -gt "5": {{var1}} elif: {{var2}} else: {{var3}} }}'
- echo ' {{ if ({{var1}} > "abc" and {{var2}} < "def") or {{var3}} == "hello" : {{ include : "input2.tpl" }} }}'
- echo
- echo " Available operators are: "
- echo " compare numbers: -ne, -eq, -gt, -lt, -ge, -le "
- echo " compare strings: >, <, ==, !="
- echo " logical operators: and, or, !"
- echo " grouping: ()"
- echo
- echo " Looping"
- echo ' {{ for {{i}} in "a" "b" "c": "abc"{{i}}"def" }}'
- echo ' {{ for {{i}} in {{seq: "5"}}: "abc"{{i}}"def" }}'
- echo
- echo " Include another template"
- echo ' {{ include : "input2.tpl" }}'
- echo
- echo " Builtin functions"
- echo ' {{ seq: "5" }}'
- echo ' {{ len: "abc" }}'
- echo ' {{ quote: {{seq: "1" "2" "5"}} }}'
- echo
- echo " Note: bpt doesn't distinguish between strings and numbers."
- echo " All non-keywords should be treated as strings."
- echo " All strings inside {{...}} need to be quoted. e.g. 'abc', \"abc\", '123'."
- echo
- echo -e "\033[1mCOPYRIGHT\033[0m"
- echo " MIT License."
- echo " Copyright (c) 2023 Hu Sixu."
- echo " https://github.com/husixu1/bpt"
-}
-
-bpt.main() (
- # Clean the environment to avoid builtin overrides
- # See https://unix.stackexchange.com/questions/188327
- POSIXLY_CORRECT=1
- \unset -f help read unset
- \unset POSIXLY_CORRECT
- while \read -r cmd; do
- [[ "$cmd" =~ ^([a-z:.\[]+): ]] && \unset -f "${BASH_REMATCH[1]}"
- done < <(\help -s "*")
-
- local ld='{{' rd='}}'
- local infile=''
- local cmd='' reduce_fn=bpt.__reduce_generate post_process=eval
- local debug=''
-
- # Parse command
- case "$1" in
- scan | s) cmd=scan ;;
- generate | g)
- cmd=generate
- reduce_fn=bpt.__reduce_generate
- post_process='echo'
- ;;
- generate-eval | ge)
- cmd=generate-eval
- reduce_fn=bpt.__reduce_generate
- post_process='eval'
- ;;
- collect-vars | cv)
- cmd=collect-vars
- reduce_fn=bpt.__reduce_collect_vars
- post_process=bpt.__dedup
- ;;
- collect-includes | ci)
- cmd=collect-includes
- reduce_fn=bpt.__reduce_collect_includes
- post_process=bpt.__dedup
- ;;
- fingerprint | f)
- cmd=fingerprint
- ;;
- -v | --version) echo "$__BPT_VERSION" && exit 0 ;;
- -h | --help | '') bpt.print_help && exit 0 ;;
- *)
- echo "Unrecognized command '$1'" >&2
- bpt.print_help
- exit 1
- ;;
- esac
- shift
-
- # Parse arguments
- while [[ $# -gt 0 ]]; do
- case "$1" in
- -l | --left-delimiter) shift && ld="$1" ;;
- -r | --right-delimiter) shift && rd="$1" ;;
- -d | --debug) debug=1 ;;
- -h | --help)
- bpt.print_help
- exit 0
- ;;
- *)
- [[ -z $infile ]] || {
- echo "Error: Option '$1' not recognized." >&2
- bpt.print_help
- return 1
- }
- infile="$1"
- ;;
- esac
- shift
- done
-
- # If file not provided, read into a temporary file and use that file.
- [[ -n $infile ]] || {
- infile="$(mktemp)" || { echo "Error: mktemp failed." >&2 && exit 1; }
- bpt.__add_exit_trap "rm -f \"${infile:?}\""
- cat >"${infile:?}"
- }
-
- # Global constants for pretty-printing
- local -rA BPT_PP_TOKEN_TABLE=(
- [ld]="$ld" [rd]="$rd"
- [eq]='-eq' [ne]='-ne' [gt]='-gt' [lt]='-lt' [ge]='-ge' [le]='-le'
- [streq]='==' [strne]='!=' [strgt]='>' [strlt]='<'
- [cl]=':' [ex]='!' [lp]='(' [rp]=')')
-
- # shellcheck disable=SC2034
- # >>> BPT_PARSE_TABLE_S >>>
- local -rA BPT_PARSE_TABLE=( # {{{
- ["0,ld"]="r DOC" ["0,str"]="r DOC" ["0,$"]="r DOC" ["0,DOC"]="1" ["1,ld"]="s 9"
- ["1,str"]="s 10" ["1,$"]="a" ["1,STMT"]="2" ["1,IF"]="3" ["1,FORIN"]="4"
- ["1,INCLUDE"]="5" ["1,BUILTIN"]="6" ["1,VAR"]="7" ["1,STR"]="8"
- ["2,ld"]="r DOC DOC STMT" ["2,rd"]="r DOC DOC STMT" ["2,elif"]="r DOC DOC STMT"
- ["2,else"]="r DOC DOC STMT" ["2,str"]="r DOC DOC STMT" ["2,$"]="r DOC DOC STMT"
- ["3,ld"]="r STMT IF" ["3,cl"]="r STMT IF" ["3,rd"]="r STMT IF"
- ["3,elif"]="r STMT IF" ["3,else"]="r STMT IF" ["3,or"]="r STMT IF"
- ["3,and"]="r STMT IF" ["3,rp"]="r STMT IF" ["3,ne"]="r STMT IF"
- ["3,eq"]="r STMT IF" ["3,gt"]="r STMT IF" ["3,lt"]="r STMT IF"
- ["3,ge"]="r STMT IF" ["3,le"]="r STMT IF" ["3,strgt"]="r STMT IF"
- ["3,strlt"]="r STMT IF" ["3,streq"]="r STMT IF" ["3,strne"]="r STMT IF"
- ["3,str"]="r STMT IF" ["3,$"]="r STMT IF" ["4,ld"]="r STMT FORIN"
- ["4,cl"]="r STMT FORIN" ["4,rd"]="r STMT FORIN" ["4,elif"]="r STMT FORIN"
- ["4,else"]="r STMT FORIN" ["4,or"]="r STMT FORIN" ["4,and"]="r STMT FORIN"
- ["4,rp"]="r STMT FORIN" ["4,ne"]="r STMT FORIN" ["4,eq"]="r STMT FORIN"
- ["4,gt"]="r STMT FORIN" ["4,lt"]="r STMT FORIN" ["4,ge"]="r STMT FORIN"
- ["4,le"]="r STMT FORIN" ["4,strgt"]="r STMT FORIN" ["4,strlt"]="r STMT FORIN"
- ["4,streq"]="r STMT FORIN" ["4,strne"]="r STMT FORIN" ["4,str"]="r STMT FORIN"
- ["4,$"]="r STMT FORIN" ["5,ld"]="r STMT INCLUDE" ["5,cl"]="r STMT INCLUDE"
- ["5,rd"]="r STMT INCLUDE" ["5,elif"]="r STMT INCLUDE"
- ["5,else"]="r STMT INCLUDE" ["5,or"]="r STMT INCLUDE" ["5,and"]="r STMT INCLUDE"
- ["5,rp"]="r STMT INCLUDE" ["5,ne"]="r STMT INCLUDE" ["5,eq"]="r STMT INCLUDE"
- ["5,gt"]="r STMT INCLUDE" ["5,lt"]="r STMT INCLUDE" ["5,ge"]="r STMT INCLUDE"
- ["5,le"]="r STMT INCLUDE" ["5,strgt"]="r STMT INCLUDE"
- ["5,strlt"]="r STMT INCLUDE" ["5,streq"]="r STMT INCLUDE"
- ["5,strne"]="r STMT INCLUDE" ["5,str"]="r STMT INCLUDE" ["5,$"]="r STMT INCLUDE"
- ["6,ld"]="r STMT BUILTIN" ["6,cl"]="r STMT BUILTIN" ["6,rd"]="r STMT BUILTIN"
- ["6,elif"]="r STMT BUILTIN" ["6,else"]="r STMT BUILTIN"
- ["6,or"]="r STMT BUILTIN" ["6,and"]="r STMT BUILTIN" ["6,rp"]="r STMT BUILTIN"
- ["6,ne"]="r STMT BUILTIN" ["6,eq"]="r STMT BUILTIN" ["6,gt"]="r STMT BUILTIN"
- ["6,lt"]="r STMT BUILTIN" ["6,ge"]="r STMT BUILTIN" ["6,le"]="r STMT BUILTIN"
- ["6,strgt"]="r STMT BUILTIN" ["6,strlt"]="r STMT BUILTIN"
- ["6,streq"]="r STMT BUILTIN" ["6,strne"]="r STMT BUILTIN"
- ["6,str"]="r STMT BUILTIN" ["6,$"]="r STMT BUILTIN" ["7,ld"]="r STMT VAR"
- ["7,cl"]="r STMT VAR" ["7,rd"]="r STMT VAR" ["7,elif"]="r STMT VAR"
- ["7,else"]="r STMT VAR" ["7,or"]="r STMT VAR" ["7,and"]="r STMT VAR"
- ["7,rp"]="r STMT VAR" ["7,ne"]="r STMT VAR" ["7,eq"]="r STMT VAR"
- ["7,gt"]="r STMT VAR" ["7,lt"]="r STMT VAR" ["7,ge"]="r STMT VAR"
- ["7,le"]="r STMT VAR" ["7,strgt"]="r STMT VAR" ["7,strlt"]="r STMT VAR"
- ["7,streq"]="r STMT VAR" ["7,strne"]="r STMT VAR" ["7,str"]="r STMT VAR"
- ["7,$"]="r STMT VAR" ["8,ld"]="r STMT STR" ["8,cl"]="r STMT STR"
- ["8,rd"]="r STMT STR" ["8,elif"]="r STMT STR" ["8,else"]="r STMT STR"
- ["8,or"]="r STMT STR" ["8,and"]="r STMT STR" ["8,rp"]="r STMT STR"
- ["8,ne"]="r STMT STR" ["8,eq"]="r STMT STR" ["8,gt"]="r STMT STR"
- ["8,lt"]="r STMT STR" ["8,ge"]="r STMT STR" ["8,le"]="r STMT STR"
- ["8,strgt"]="r STMT STR" ["8,strlt"]="r STMT STR" ["8,streq"]="r STMT STR"
- ["8,strne"]="r STMT STR" ["8,str"]="r STMT STR" ["8,$"]="r STMT STR"
- ["9,if"]="s 11" ["9,for"]="s 12" ["9,include"]="s 13" ["9,id"]="s 15"
- ["9,ID"]="14" ["10,ld"]="r STR str" ["10,cl"]="r STR str" ["10,rd"]="r STR str"
- ["10,elif"]="r STR str" ["10,else"]="r STR str" ["10,or"]="r STR str"
- ["10,and"]="r STR str" ["10,rp"]="r STR str" ["10,ne"]="r STR str"
- ["10,eq"]="r STR str" ["10,gt"]="r STR str" ["10,lt"]="r STR str"
- ["10,ge"]="r STR str" ["10,le"]="r STR str" ["10,strgt"]="r STR str"
- ["10,strlt"]="r STR str" ["10,streq"]="r STR str" ["10,strne"]="r STR str"
- ["10,str"]="r STR str" ["10,$"]="r STR str" ["11,ld"]="s 9" ["11,lp"]="s 21"
- ["11,ex"]="s 20" ["11,str"]="s 10" ["11,STMT"]="24" ["11,IF"]="3"
- ["11,FORIN"]="4" ["11,INCLUDE"]="5" ["11,BUILTIN"]="6" ["11,VAR"]="7"
- ["11,STR"]="8" ["11,BOOLS"]="16" ["11,BOOLO"]="17" ["11,UOP"]="18"
- ["11,BOOLA"]="19" ["11,BOOL"]="22" ["11,ARGS"]="23" ["12,id"]="s 15"
- ["12,ID"]="25" ["13,cl"]="s 26" ["14,cl"]="s 27" ["14,rd"]="s 28"
- ["14,or"]="s 29" ["14,and"]="s 30" ["15,cl"]="r ID id" ["15,rd"]="r ID id"
- ["15,or"]="r ID id" ["15,and"]="r ID id" ["15,in"]="r ID id" ["16,cl"]="s 31"
- ["17,cl"]="r BOOLS BOOLO" ["17,or"]="s 32" ["17,rp"]="r BOOLS BOOLO"
- ["18,ld"]="s 9" ["18,lp"]="s 21" ["18,ex"]="s 20" ["18,str"]="s 10"
- ["18,STMT"]="24" ["18,IF"]="3" ["18,FORIN"]="4" ["18,INCLUDE"]="5"
- ["18,BUILTIN"]="6" ["18,VAR"]="7" ["18,STR"]="8" ["18,BOOLS"]="33"
- ["18,BOOLO"]="17" ["18,UOP"]="18" ["18,BOOLA"]="19" ["18,BOOL"]="22"
- ["18,ARGS"]="23" ["19,cl"]="r BOOLO BOOLA" ["19,or"]="r BOOLO BOOLA"
- ["19,and"]="s 34" ["19,rp"]="r BOOLO BOOLA" ["20,ld"]="r UOP ex"
- ["20,lp"]="r UOP ex" ["20,ex"]="r UOP ex" ["20,str"]="r UOP ex" ["21,ld"]="s 9"
- ["21,lp"]="s 21" ["21,ex"]="s 20" ["21,str"]="s 10" ["21,STMT"]="24"
- ["21,IF"]="3" ["21,FORIN"]="4" ["21,INCLUDE"]="5" ["21,BUILTIN"]="6"
- ["21,VAR"]="7" ["21,STR"]="8" ["21,BOOLS"]="35" ["21,BOOLO"]="17"
- ["21,UOP"]="18" ["21,BOOLA"]="19" ["21,BOOL"]="22" ["21,ARGS"]="23"
- ["22,cl"]="r BOOLA BOOL" ["22,or"]="r BOOLA BOOL" ["22,and"]="r BOOLA BOOL"
- ["22,rp"]="r BOOLA BOOL" ["23,ld"]="s 9" ["23,cl"]="r BOOL ARGS"
- ["23,or"]="r BOOL ARGS" ["23,and"]="r BOOL ARGS" ["23,rp"]="r BOOL ARGS"
- ["23,ne"]="s 38" ["23,eq"]="s 39" ["23,gt"]="s 40" ["23,lt"]="s 41"
- ["23,ge"]="s 42" ["23,le"]="s 43" ["23,strgt"]="s 44" ["23,strlt"]="s 45"
- ["23,streq"]="s 46" ["23,strne"]="s 47" ["23,str"]="s 10" ["23,STMT"]="37"
- ["23,IF"]="3" ["23,FORIN"]="4" ["23,INCLUDE"]="5" ["23,BUILTIN"]="6"
- ["23,VAR"]="7" ["23,STR"]="8" ["23,BOP"]="36" ["24,ld"]="r ARGS STMT"
- ["24,cl"]="r ARGS STMT" ["24,rd"]="r ARGS STMT" ["24,or"]="r ARGS STMT"
- ["24,and"]="r ARGS STMT" ["24,rp"]="r ARGS STMT" ["24,ne"]="r ARGS STMT"
- ["24,eq"]="r ARGS STMT" ["24,gt"]="r ARGS STMT" ["24,lt"]="r ARGS STMT"
- ["24,ge"]="r ARGS STMT" ["24,le"]="r ARGS STMT" ["24,strgt"]="r ARGS STMT"
- ["24,strlt"]="r ARGS STMT" ["24,streq"]="r ARGS STMT" ["24,strne"]="r ARGS STMT"
- ["24,str"]="r ARGS STMT" ["25,in"]="s 48" ["26,str"]="s 10" ["26,STR"]="49"
- ["27,ld"]="s 9" ["27,str"]="s 10" ["27,STMT"]="24" ["27,IF"]="3"
- ["27,FORIN"]="4" ["27,INCLUDE"]="5" ["27,BUILTIN"]="6" ["27,VAR"]="7"
- ["27,STR"]="8" ["27,ARGS"]="50" ["28,ld"]="r VAR ld ID rd"
- ["28,cl"]="r VAR ld ID rd" ["28,rd"]="r VAR ld ID rd"
- ["28,elif"]="r VAR ld ID rd" ["28,else"]="r VAR ld ID rd"
- ["28,or"]="r VAR ld ID rd" ["28,and"]="r VAR ld ID rd"
- ["28,rp"]="r VAR ld ID rd" ["28,ne"]="r VAR ld ID rd" ["28,eq"]="r VAR ld ID rd"
- ["28,gt"]="r VAR ld ID rd" ["28,lt"]="r VAR ld ID rd" ["28,ge"]="r VAR ld ID rd"
- ["28,le"]="r VAR ld ID rd" ["28,strgt"]="r VAR ld ID rd"
- ["28,strlt"]="r VAR ld ID rd" ["28,streq"]="r VAR ld ID rd"
- ["28,strne"]="r VAR ld ID rd" ["28,str"]="r VAR ld ID rd"
- ["28,$"]="r VAR ld ID rd" ["29,ld"]="s 53" ["29,str"]="s 10" ["29,VAR"]="51"
- ["29,STR"]="52" ["30,ld"]="s 53" ["30,str"]="s 10" ["30,VAR"]="54"
- ["30,STR"]="55" ["31,ld"]="r DOC" ["31,rd"]="r DOC" ["31,elif"]="r DOC"
- ["31,else"]="r DOC" ["31,str"]="r DOC" ["31,DOC"]="56" ["32,ld"]="s 9"
- ["32,lp"]="s 21" ["32,ex"]="s 20" ["32,str"]="s 10" ["32,STMT"]="24"
- ["32,IF"]="3" ["32,FORIN"]="4" ["32,INCLUDE"]="5" ["32,BUILTIN"]="6"
- ["32,VAR"]="7" ["32,STR"]="8" ["32,UOP"]="58" ["32,BOOLA"]="57" ["32,BOOL"]="22"
- ["32,ARGS"]="23" ["33,cl"]="r BOOLS UOP BOOLS" ["33,rp"]="r BOOLS UOP BOOLS"
- ["34,ld"]="s 9" ["34,lp"]="s 61" ["34,ex"]="s 20" ["34,str"]="s 10"
- ["34,STMT"]="24" ["34,IF"]="3" ["34,FORIN"]="4" ["34,INCLUDE"]="5"
- ["34,BUILTIN"]="6" ["34,VAR"]="7" ["34,STR"]="8" ["34,UOP"]="60"
- ["34,BOOL"]="59" ["34,ARGS"]="23" ["35,rp"]="s 62" ["36,ld"]="s 9"
- ["36,str"]="s 10" ["36,STMT"]="24" ["36,IF"]="3" ["36,FORIN"]="4"
- ["36,INCLUDE"]="5" ["36,BUILTIN"]="6" ["36,VAR"]="7" ["36,STR"]="8"
- ["36,ARGS"]="63" ["37,ld"]="r ARGS ARGS STMT" ["37,cl"]="r ARGS ARGS STMT"
- ["37,rd"]="r ARGS ARGS STMT" ["37,or"]="r ARGS ARGS STMT"
- ["37,and"]="r ARGS ARGS STMT" ["37,rp"]="r ARGS ARGS STMT"
- ["37,ne"]="r ARGS ARGS STMT" ["37,eq"]="r ARGS ARGS STMT"
- ["37,gt"]="r ARGS ARGS STMT" ["37,lt"]="r ARGS ARGS STMT"
- ["37,ge"]="r ARGS ARGS STMT" ["37,le"]="r ARGS ARGS STMT"
- ["37,strgt"]="r ARGS ARGS STMT" ["37,strlt"]="r ARGS ARGS STMT"
- ["37,streq"]="r ARGS ARGS STMT" ["37,strne"]="r ARGS ARGS STMT"
- ["37,str"]="r ARGS ARGS STMT" ["38,ld"]="r BOP ne" ["38,str"]="r BOP ne"
- ["39,ld"]="r BOP eq" ["39,str"]="r BOP eq" ["40,ld"]="r BOP gt"
- ["40,str"]="r BOP gt" ["41,ld"]="r BOP lt" ["41,str"]="r BOP lt"
- ["42,ld"]="r BOP ge" ["42,str"]="r BOP ge" ["43,ld"]="r BOP le"
- ["43,str"]="r BOP le" ["44,ld"]="r BOP strgt" ["44,str"]="r BOP strgt"
- ["45,ld"]="r BOP strlt" ["45,str"]="r BOP strlt" ["46,ld"]="r BOP streq"
- ["46,str"]="r BOP streq" ["47,ld"]="r BOP strne" ["47,str"]="r BOP strne"
- ["48,ld"]="s 9" ["48,str"]="s 10" ["48,STMT"]="24" ["48,IF"]="3"
- ["48,FORIN"]="4" ["48,INCLUDE"]="5" ["48,BUILTIN"]="6" ["48,VAR"]="7"
- ["48,STR"]="8" ["48,ARGS"]="64" ["49,rd"]="s 65" ["50,ld"]="s 9"
- ["50,rd"]="s 66" ["50,str"]="s 10" ["50,STMT"]="37" ["50,IF"]="3"
- ["50,FORIN"]="4" ["50,INCLUDE"]="5" ["50,BUILTIN"]="6" ["50,VAR"]="7"
- ["50,STR"]="8" ["51,rd"]="s 67" ["52,rd"]="s 68" ["53,id"]="s 15" ["53,ID"]="69"
- ["54,rd"]="s 70" ["55,rd"]="s 71" ["56,ld"]="s 9" ["56,rd"]="r ELIF"
- ["56,elif"]="r ELIF" ["56,else"]="r ELIF" ["56,str"]="s 10" ["56,STMT"]="2"
- ["56,IF"]="3" ["56,FORIN"]="4" ["56,INCLUDE"]="5" ["56,BUILTIN"]="6"
- ["56,VAR"]="7" ["56,STR"]="8" ["56,ELIF"]="72"
- ["57,cl"]="r BOOLO BOOLO or BOOLA" ["57,or"]="r BOOLO BOOLO or BOOLA"
- ["57,and"]="s 34" ["57,rp"]="r BOOLO BOOLO or BOOLA" ["58,ld"]="s 9"
- ["58,lp"]="s 21" ["58,str"]="s 10" ["58,STMT"]="24" ["58,IF"]="3"
- ["58,FORIN"]="4" ["58,INCLUDE"]="5" ["58,BUILTIN"]="6" ["58,VAR"]="7"
- ["58,STR"]="8" ["58,BOOLA"]="73" ["58,BOOL"]="22" ["58,ARGS"]="23"
- ["59,cl"]="r BOOLA BOOLA and BOOL" ["59,or"]="r BOOLA BOOLA and BOOL"
- ["59,and"]="r BOOLA BOOLA and BOOL" ["59,rp"]="r BOOLA BOOLA and BOOL"
- ["60,ld"]="s 9" ["60,lp"]="s 75" ["60,str"]="s 10" ["60,STMT"]="24"
- ["60,IF"]="3" ["60,FORIN"]="4" ["60,INCLUDE"]="5" ["60,BUILTIN"]="6"
- ["60,VAR"]="7" ["60,STR"]="8" ["60,BOOL"]="74" ["60,ARGS"]="23" ["61,ld"]="s 9"
- ["61,lp"]="s 21" ["61,ex"]="s 20" ["61,str"]="s 10" ["61,STMT"]="24"
- ["61,IF"]="3" ["61,FORIN"]="4" ["61,INCLUDE"]="5" ["61,BUILTIN"]="6"
- ["61,VAR"]="7" ["61,STR"]="8" ["61,BOOLS"]="76" ["61,BOOLO"]="17"
- ["61,UOP"]="18" ["61,BOOLA"]="19" ["61,BOOL"]="22" ["61,ARGS"]="23"
- ["62,cl"]="r BOOLA lp BOOLS rp" ["62,or"]="r BOOLA lp BOOLS rp"
- ["62,and"]="r BOOLA lp BOOLS rp" ["62,rp"]="r BOOLA lp BOOLS rp" ["63,ld"]="s 9"
- ["63,cl"]="r BOOL ARGS BOP ARGS" ["63,or"]="r BOOL ARGS BOP ARGS"
- ["63,and"]="r BOOL ARGS BOP ARGS" ["63,rp"]="r BOOL ARGS BOP ARGS"
- ["63,str"]="s 10" ["63,STMT"]="37" ["63,IF"]="3" ["63,FORIN"]="4"
- ["63,INCLUDE"]="5" ["63,BUILTIN"]="6" ["63,VAR"]="7" ["63,STR"]="8"
- ["64,ld"]="s 9" ["64,cl"]="s 77" ["64,str"]="s 10" ["64,STMT"]="37"
- ["64,IF"]="3" ["64,FORIN"]="4" ["64,INCLUDE"]="5" ["64,BUILTIN"]="6"
- ["64,VAR"]="7" ["64,STR"]="8" ["65,ld"]="r INCLUDE ld include cl STR rd"
- ["65,cl"]="r INCLUDE ld include cl STR rd"
- ["65,rd"]="r INCLUDE ld include cl STR rd"
- ["65,elif"]="r INCLUDE ld include cl STR rd"
- ["65,else"]="r INCLUDE ld include cl STR rd"
- ["65,or"]="r INCLUDE ld include cl STR rd"
- ["65,and"]="r INCLUDE ld include cl STR rd"
- ["65,rp"]="r INCLUDE ld include cl STR rd"
- ["65,ne"]="r INCLUDE ld include cl STR rd"
- ["65,eq"]="r INCLUDE ld include cl STR rd"
- ["65,gt"]="r INCLUDE ld include cl STR rd"
- ["65,lt"]="r INCLUDE ld include cl STR rd"
- ["65,ge"]="r INCLUDE ld include cl STR rd"
- ["65,le"]="r INCLUDE ld include cl STR rd"
- ["65,strgt"]="r INCLUDE ld include cl STR rd"
- ["65,strlt"]="r INCLUDE ld include cl STR rd"
- ["65,streq"]="r INCLUDE ld include cl STR rd"
- ["65,strne"]="r INCLUDE ld include cl STR rd"
- ["65,str"]="r INCLUDE ld include cl STR rd"
- ["65,$"]="r INCLUDE ld include cl STR rd" ["66,ld"]="r BUILTIN ld ID cl ARGS rd"
- ["66,cl"]="r BUILTIN ld ID cl ARGS rd" ["66,rd"]="r BUILTIN ld ID cl ARGS rd"
- ["66,elif"]="r BUILTIN ld ID cl ARGS rd"
- ["66,else"]="r BUILTIN ld ID cl ARGS rd" ["66,or"]="r BUILTIN ld ID cl ARGS rd"
- ["66,and"]="r BUILTIN ld ID cl ARGS rd" ["66,rp"]="r BUILTIN ld ID cl ARGS rd"
- ["66,ne"]="r BUILTIN ld ID cl ARGS rd" ["66,eq"]="r BUILTIN ld ID cl ARGS rd"
- ["66,gt"]="r BUILTIN ld ID cl ARGS rd" ["66,lt"]="r BUILTIN ld ID cl ARGS rd"
- ["66,ge"]="r BUILTIN ld ID cl ARGS rd" ["66,le"]="r BUILTIN ld ID cl ARGS rd"
- ["66,strgt"]="r BUILTIN ld ID cl ARGS rd"
- ["66,strlt"]="r BUILTIN ld ID cl ARGS rd"
- ["66,streq"]="r BUILTIN ld ID cl ARGS rd"
- ["66,strne"]="r BUILTIN ld ID cl ARGS rd"
- ["66,str"]="r BUILTIN ld ID cl ARGS rd" ["66,$"]="r BUILTIN ld ID cl ARGS rd"
- ["67,ld"]="r VAR ld ID or VAR rd" ["67,cl"]="r VAR ld ID or VAR rd"
- ["67,rd"]="r VAR ld ID or VAR rd" ["67,elif"]="r VAR ld ID or VAR rd"
- ["67,else"]="r VAR ld ID or VAR rd" ["67,or"]="r VAR ld ID or VAR rd"
- ["67,and"]="r VAR ld ID or VAR rd" ["67,rp"]="r VAR ld ID or VAR rd"
- ["67,ne"]="r VAR ld ID or VAR rd" ["67,eq"]="r VAR ld ID or VAR rd"
- ["67,gt"]="r VAR ld ID or VAR rd" ["67,lt"]="r VAR ld ID or VAR rd"
- ["67,ge"]="r VAR ld ID or VAR rd" ["67,le"]="r VAR ld ID or VAR rd"
- ["67,strgt"]="r VAR ld ID or VAR rd" ["67,strlt"]="r VAR ld ID or VAR rd"
- ["67,streq"]="r VAR ld ID or VAR rd" ["67,strne"]="r VAR ld ID or VAR rd"
- ["67,str"]="r VAR ld ID or VAR rd" ["67,$"]="r VAR ld ID or VAR rd"
- ["68,ld"]="r VAR ld ID or STR rd" ["68,cl"]="r VAR ld ID or STR rd"
- ["68,rd"]="r VAR ld ID or STR rd" ["68,elif"]="r VAR ld ID or STR rd"
- ["68,else"]="r VAR ld ID or STR rd" ["68,or"]="r VAR ld ID or STR rd"
- ["68,and"]="r VAR ld ID or STR rd" ["68,rp"]="r VAR ld ID or STR rd"
- ["68,ne"]="r VAR ld ID or STR rd" ["68,eq"]="r VAR ld ID or STR rd"
- ["68,gt"]="r VAR ld ID or STR rd" ["68,lt"]="r VAR ld ID or STR rd"
- ["68,ge"]="r VAR ld ID or STR rd" ["68,le"]="r VAR ld ID or STR rd"
- ["68,strgt"]="r VAR ld ID or STR rd" ["68,strlt"]="r VAR ld ID or STR rd"
- ["68,streq"]="r VAR ld ID or STR rd" ["68,strne"]="r VAR ld ID or STR rd"
- ["68,str"]="r VAR ld ID or STR rd" ["68,$"]="r VAR ld ID or STR rd"
- ["69,rd"]="s 28" ["69,or"]="s 29" ["69,and"]="s 30"
- ["70,ld"]="r VAR ld ID and VAR rd" ["70,cl"]="r VAR ld ID and VAR rd"
- ["70,rd"]="r VAR ld ID and VAR rd" ["70,elif"]="r VAR ld ID and VAR rd"
- ["70,else"]="r VAR ld ID and VAR rd" ["70,or"]="r VAR ld ID and VAR rd"
- ["70,and"]="r VAR ld ID and VAR rd" ["70,rp"]="r VAR ld ID and VAR rd"
- ["70,ne"]="r VAR ld ID and VAR rd" ["70,eq"]="r VAR ld ID and VAR rd"
- ["70,gt"]="r VAR ld ID and VAR rd" ["70,lt"]="r VAR ld ID and VAR rd"
- ["70,ge"]="r VAR ld ID and VAR rd" ["70,le"]="r VAR ld ID and VAR rd"
- ["70,strgt"]="r VAR ld ID and VAR rd" ["70,strlt"]="r VAR ld ID and VAR rd"
- ["70,streq"]="r VAR ld ID and VAR rd" ["70,strne"]="r VAR ld ID and VAR rd"
- ["70,str"]="r VAR ld ID and VAR rd" ["70,$"]="r VAR ld ID and VAR rd"
- ["71,ld"]="r VAR ld ID and STR rd" ["71,cl"]="r VAR ld ID and STR rd"
- ["71,rd"]="r VAR ld ID and STR rd" ["71,elif"]="r VAR ld ID and STR rd"
- ["71,else"]="r VAR ld ID and STR rd" ["71,or"]="r VAR ld ID and STR rd"
- ["71,and"]="r VAR ld ID and STR rd" ["71,rp"]="r VAR ld ID and STR rd"
- ["71,ne"]="r VAR ld ID and STR rd" ["71,eq"]="r VAR ld ID and STR rd"
- ["71,gt"]="r VAR ld ID and STR rd" ["71,lt"]="r VAR ld ID and STR rd"
- ["71,ge"]="r VAR ld ID and STR rd" ["71,le"]="r VAR ld ID and STR rd"
- ["71,strgt"]="r VAR ld ID and STR rd" ["71,strlt"]="r VAR ld ID and STR rd"
- ["71,streq"]="r VAR ld ID and STR rd" ["71,strne"]="r VAR ld ID and STR rd"
- ["71,str"]="r VAR ld ID and STR rd" ["71,$"]="r VAR ld ID and STR rd"
- ["72,rd"]="r ELSE" ["72,elif"]="s 79" ["72,else"]="s 80" ["72,ELSE"]="78"
- ["73,cl"]="r BOOLO BOOLO or UOP BOOLA" ["73,or"]="r BOOLO BOOLO or UOP BOOLA"
- ["73,and"]="s 34" ["73,rp"]="r BOOLO BOOLO or UOP BOOLA"
- ["74,cl"]="r BOOLA BOOLA and UOP BOOL" ["74,or"]="r BOOLA BOOLA and UOP BOOL"
- ["74,and"]="r BOOLA BOOLA and UOP BOOL" ["74,rp"]="r BOOLA BOOLA and UOP BOOL"
- ["75,ld"]="s 9" ["75,lp"]="s 21" ["75,ex"]="s 20" ["75,str"]="s 10"
- ["75,STMT"]="24" ["75,IF"]="3" ["75,FORIN"]="4" ["75,INCLUDE"]="5"
- ["75,BUILTIN"]="6" ["75,VAR"]="7" ["75,STR"]="8" ["75,BOOLS"]="81"
- ["75,BOOLO"]="17" ["75,UOP"]="18" ["75,BOOLA"]="19" ["75,BOOL"]="22"
- ["75,ARGS"]="23" ["76,rp"]="s 82" ["77,ld"]="r DOC" ["77,rd"]="r DOC"
- ["77,str"]="r DOC" ["77,DOC"]="83" ["78,rd"]="s 84" ["79,ld"]="s 9"
- ["79,lp"]="s 21" ["79,ex"]="s 20" ["79,str"]="s 10" ["79,STMT"]="24"
- ["79,IF"]="3" ["79,FORIN"]="4" ["79,INCLUDE"]="5" ["79,BUILTIN"]="6"
- ["79,VAR"]="7" ["79,STR"]="8" ["79,BOOLS"]="85" ["79,BOOLO"]="17"
- ["79,UOP"]="18" ["79,BOOLA"]="19" ["79,BOOL"]="22" ["79,ARGS"]="23"
- ["80,cl"]="s 86" ["81,rp"]="s 87" ["82,cl"]="r BOOLA BOOLA and lp BOOLS rp"
- ["82,or"]="r BOOLA BOOLA and lp BOOLS rp"
- ["82,and"]="r BOOLA BOOLA and lp BOOLS rp"
- ["82,rp"]="r BOOLA BOOLA and lp BOOLS rp" ["83,ld"]="s 9" ["83,rd"]="s 88"
- ["83,str"]="s 10" ["83,STMT"]="2" ["83,IF"]="3" ["83,FORIN"]="4"
- ["83,INCLUDE"]="5" ["83,BUILTIN"]="6" ["83,VAR"]="7" ["83,STR"]="8"
- ["84,ld"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,cl"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,rd"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,elif"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,else"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,or"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,and"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,rp"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,ne"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,eq"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,gt"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,lt"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,ge"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,le"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,strgt"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,strlt"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,streq"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,strne"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,str"]="r IF ld if BOOLS cl DOC ELIF ELSE rd"
- ["84,$"]="r IF ld if BOOLS cl DOC ELIF ELSE rd" ["85,cl"]="s 89"
- ["86,ld"]="r DOC" ["86,rd"]="r DOC" ["86,str"]="r DOC" ["86,DOC"]="90"
- ["87,cl"]="r BOOLA BOOLA and UOP lp BOOLS rp"
- ["87,or"]="r BOOLA BOOLA and UOP lp BOOLS rp"
- ["87,and"]="r BOOLA BOOLA and UOP lp BOOLS rp"
- ["87,rp"]="r BOOLA BOOLA and UOP lp BOOLS rp"
- ["88,ld"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,cl"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,rd"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,elif"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,else"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,or"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,and"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,rp"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,ne"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,eq"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,gt"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,lt"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,ge"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,le"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,strgt"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,strlt"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,streq"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,strne"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,str"]="r FORIN ld for ID in ARGS cl DOC rd"
- ["88,$"]="r FORIN ld for ID in ARGS cl DOC rd" ["89,ld"]="r DOC"
- ["89,rd"]="r DOC" ["89,elif"]="r DOC" ["89,else"]="r DOC" ["89,str"]="r DOC"
- ["89,DOC"]="91" ["90,ld"]="s 9" ["90,rd"]="r ELSE else cl DOC" ["90,str"]="s 10"
- ["90,STMT"]="2" ["90,IF"]="3" ["90,FORIN"]="4" ["90,INCLUDE"]="5"
- ["90,BUILTIN"]="6" ["90,VAR"]="7" ["90,STR"]="8" ["91,ld"]="s 9"
- ["91,rd"]="r ELIF ELIF elif BOOLS cl DOC"
- ["91,elif"]="r ELIF ELIF elif BOOLS cl DOC"
- ["91,else"]="r ELIF ELIF elif BOOLS cl DOC" ["91,str"]="s 10" ["91,STMT"]="2"
- ["91,IF"]="3" ["91,FORIN"]="4" ["91,INCLUDE"]="5" ["91,BUILTIN"]="6"
- ["91,VAR"]="7" ["91,STR"]="8"
- ) # }}}
- # <<< BPT_PARSE_TABLE_E <<<
-
- # Deduplication function for collect-{var,include}
- bpt.__dedup() { echo "$1" | sort | uniq; }
-
- # Append this if reducer is bpt.__reduce_generate
- local HEADER=''
- [[ $reduce_fn != bpt.__reduce_generate ]] || {
- read -r -d '' HEADER <<-'EOF'
-#!/bin/bash
-e(){ local OIFS="$IFS"; IFS=; echo -n "$*"; IFS="$OIFS"; };
-len(){ echo -n "${#1}"; };
-seq(){ command seq -s ' ' -- "$@"; };
-EOF
- }
-
- # Execute command
- case "$cmd" in
- scan) bpt.scan "$ld" "$rd" <"$infile" ;;
- fingerprint) bpt.fingerprint "$ld" "$rd" "$infile" "$debug" ;;
- *) result="$(bpt.process "$ld" "$rd" "$reduce_fn" "$infile" "$debug")" &&
- $post_process "$HEADER$result" ;;
- esac
-)
-
-(return 0 2>/dev/null) || bpt.main "$@"