mirror of
https://github.com/tonydamage/nux-env.git
synced 2025-12-11 13:24:28 +01:00
nuxsh: Added custom syntax to bash.
Signed-off-by: Tony Tkacik <tonydamage@gmail.com>
This commit is contained in:
parent
acefb64cdc
commit
eef3628269
3 changed files with 352 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
cache
|
||||
142
inc/nux/dsl.inc.sh
Normal file
142
inc/nux/dsl.inc.sh
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## nulang - NUX Custom DSL Support Library
|
||||
##
|
||||
## # Language Definition
|
||||
##
|
||||
## Language is defined in terms of BASH REGEX matches and functions that process
|
||||
## or execute particular match.
|
||||
|
||||
NUDSL_CACHE_SUFFIX=".nux.dsl.sh"
|
||||
|
||||
nux.dsl.eval() {
|
||||
$nudsl_eval "$@"
|
||||
}
|
||||
|
||||
nux.dsl.env() {
|
||||
.process.highlight() {
|
||||
echo "$line";
|
||||
}
|
||||
.match._unmatched.highlight() {
|
||||
echo "${_gen_highlight_unmatched}$line${nc_end}"
|
||||
}
|
||||
|
||||
.gen.parser._unmatched.process() {
|
||||
nux.exec.or .match._unmatched.$action .process.$action
|
||||
}
|
||||
|
||||
.highlight() {
|
||||
nux.dsl.eval _gen_highlight_$1='$nc_'$2
|
||||
}
|
||||
.match() {
|
||||
local type=$1;
|
||||
local pattern=$2;
|
||||
shift; shift;
|
||||
i=0;
|
||||
local parse_body="";
|
||||
nux.dsl.eval _gen_parser_types='"$_gen_parser_types '$type'"'
|
||||
nux.dsl.eval _gen_parser_pattern_$type="'"$pattern"'"
|
||||
nux.dsl.eval """.gen.parser.$type.process() {
|
||||
$(
|
||||
for group in "$@"; do
|
||||
let i=$i+1;
|
||||
if [ "$group" != "-" ]; then
|
||||
echo local ${group}='${BASH_REMATCH['$i']}'
|
||||
fi
|
||||
done
|
||||
)
|
||||
nux.exec.or .match.$type.\$action .process.\$action
|
||||
}
|
||||
"""
|
||||
|
||||
nux.dsl.eval """.match.$type.highlight() {
|
||||
$(
|
||||
for group in "$@"; do
|
||||
let i=$i+1;
|
||||
if [ "$group" != "-" ]; then
|
||||
echo ' echo -n "${_gen_highlight_'$group'}$'$group'${nc_end}"'
|
||||
fi
|
||||
done
|
||||
)
|
||||
echo;
|
||||
}
|
||||
"""
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
nudsl_eval=eval
|
||||
|
||||
nux.dsl.process() {
|
||||
local action=$1;
|
||||
local language=$2;
|
||||
local file=$3;
|
||||
(
|
||||
nux.dsl.env
|
||||
$language
|
||||
cat "$file" | nux.dsl.process0 $action)
|
||||
|
||||
}
|
||||
|
||||
nux.dsl.exec() {
|
||||
local language="$1";
|
||||
local file="$2";
|
||||
local cached="${3:-$file${NUDSL_CACHE_SUFFIX}}";
|
||||
if nux.dsl.plan "$language" "$file" "$cached"; then
|
||||
source "$cached";
|
||||
fi
|
||||
}
|
||||
|
||||
nux.dsl.plan.file() {
|
||||
local language="$1"
|
||||
local file="$2";
|
||||
echo "$file${NUDSL_CACHE_SUFFIX}";
|
||||
}
|
||||
|
||||
nux.dsl.plan() {
|
||||
local language="$1";
|
||||
local file="$2";
|
||||
local cached="${3:-$file${NUDSL_CACHE_SUFFIX}}";
|
||||
if [ "$file" -ot "$cached" ]; then
|
||||
nux.log debug No need to recompile.
|
||||
return;
|
||||
fi
|
||||
|
||||
nux.log debug Needs regeneration, creating new version.
|
||||
|
||||
local dirname=$(dirname "$cached")
|
||||
mkdir -p "$dirname";
|
||||
local execution_plan=$(mktemp "$dirname/.nux.dsl.XXXX")
|
||||
if (nux.dsl.process plan "$language" "$file" > "$execution_plan") ; then
|
||||
mv -f "$execution_plan" "$cached";
|
||||
else
|
||||
echo "Plan could not be generated. See errors."
|
||||
rm "$execution_plan"
|
||||
return -1;
|
||||
fi
|
||||
}
|
||||
|
||||
nux.dsl.process.fail() {
|
||||
process_failed=true
|
||||
echo "$linenum:$@" >&2
|
||||
}
|
||||
|
||||
nux.dsl.process0() {
|
||||
local _gen_parser_pattern__unmatched='(.*)';
|
||||
local patterns="$_gen_parser_types _unmatched";
|
||||
local linenum=0;
|
||||
while IFS= read -r line ;
|
||||
do
|
||||
let linenum=$linenum+1
|
||||
for t in $patterns; do
|
||||
local pattern=_gen_parser_pattern_$t
|
||||
if [[ "$line" =~ ${!pattern} ]]; then
|
||||
.gen.parser.$t.process
|
||||
break;
|
||||
fi
|
||||
done
|
||||
if [ -n "$process_failed" ]; then
|
||||
return -1;
|
||||
fi
|
||||
done;
|
||||
}
|
||||
209
inc/nux/nuxsh.inc.sh
Normal file
209
inc/nux/nuxsh.inc.sh
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
nux.use nux/dsl
|
||||
|
||||
nux.nuxsh.language.def() {
|
||||
local identifier='[^ ;{}=()$]+'
|
||||
local comment='(( *)(#.*))?'
|
||||
local whitespace="([ ]*)"
|
||||
local uarg="([^ #\{\}\"'\"'\"';]+)";
|
||||
local sarg="('\"'\"'[^'\"'\"']+'\"'\"')";
|
||||
local darg='("[^"]*")';
|
||||
|
||||
local args="((($uarg|$darg|$sarg) *)*)";
|
||||
|
||||
local prefixed_id="([^ :]*:)?($identifier)"
|
||||
|
||||
.match.line() {
|
||||
local type="$1";
|
||||
local match="^( *)$2$comment$";
|
||||
shift;shift;
|
||||
.match "$type" "$match" indent "$@" - indent_comment comment;
|
||||
}
|
||||
|
||||
.match.line comment ''
|
||||
.match.line rule "(@)([^ ]+)( +)$args?( *);?"\
|
||||
syntaxM rule indent2 args - - - - - indent3 syntax2
|
||||
|
||||
.match.line namespace_block_start "(@)(namespace)(( +)$uarg)( *)(\{)" \
|
||||
syntaxM keyword - indent2 identifier indent3 syntax3
|
||||
#.match.line namespace_start "@(namespace)( +)$uarg( *)(\{)" \
|
||||
# namespace indent2 args indent3 syntax
|
||||
.match.line block_end '(\})' \
|
||||
syntax
|
||||
|
||||
|
||||
.match.line if_start "(if)( +)$prefixed_id( +)$args?( *)(\{)" \
|
||||
keyword indent2 prefix identifier indent3 args - - - - - indent4 syntax3
|
||||
|
||||
.match.line function_start "((function)( +))($identifier)((\()|( *))(($identifier,? *)*)(\))?( *)(\{)" \
|
||||
- keyword indent2 identifier - syntax indent3 args - syntax2 indent4 syntax3
|
||||
|
||||
.match.line block_start "($identifier)(( +)$args)?( *)(\{)" \
|
||||
identifier - indent2 args - - - - - indent3 syntax3
|
||||
|
||||
.match.line statement "$prefixed_id(( +)$args)?( *)(;?)"\
|
||||
prefix identifier - indent2 args - - - - - indent3 syntax2
|
||||
|
||||
#.match.line variable "([^ ]+=)$args( *)(;?)"\
|
||||
# variable args - - - - - indent3 syntax
|
||||
|
||||
.highlight rule cyan
|
||||
.highlight syntaxM cyan
|
||||
|
||||
.highlight prefix cyan
|
||||
.highlight identifier green
|
||||
.highlight keyword blue
|
||||
.highlight args yellow
|
||||
|
||||
.highlight comment magenta
|
||||
|
||||
.highlight unmatched red
|
||||
|
||||
.highlight syntax white
|
||||
.highlight syntax2 white
|
||||
.highlight syntax3 white
|
||||
|
||||
blocktrac_root="#blocktrac_root"
|
||||
_block_type[${#_block_type[@]}]="$blocktrac_root"
|
||||
|
||||
function .block.get {
|
||||
echo ${_block_type[${#_block_type[@]}-1]}
|
||||
}
|
||||
|
||||
function .block.pop {
|
||||
unset _block_type[${#_block_type[@]}-1]
|
||||
}
|
||||
|
||||
function .block.push {
|
||||
_block_type[${#_block_type[@]}]="$1"
|
||||
}
|
||||
|
||||
.match.block_start.plan() {
|
||||
.block.push $identifier;
|
||||
nux.exec.or .block.$identifier.start.plan .block.start.plan
|
||||
}
|
||||
|
||||
.match.block_end.plan() {
|
||||
local identifier=$(.block.get)
|
||||
if [ "$identifier" == "$blocktrac_root" ]; then
|
||||
nux.dsl.process.fail "unnecessary block end '$line' "
|
||||
return -1;
|
||||
fi
|
||||
nux.exec.or .block.$identifier.end.plan .block.end.plan
|
||||
.block.pop;
|
||||
}
|
||||
|
||||
.action.alias() {
|
||||
local alias=$1; shift;
|
||||
echo "# alias: $alias $@";
|
||||
eval "_alias_$alias='$@'";
|
||||
}
|
||||
|
||||
.action.prefix() {
|
||||
echo "# prefix: $1 $2"
|
||||
eval "_import_prefix_$1='$2'";
|
||||
}
|
||||
|
||||
|
||||
.identifier() {
|
||||
if [ -n "$prefix" ]; then
|
||||
local var=_import_prefix_${prefix%:}
|
||||
local prepend=${!var};
|
||||
if [ -z "$prepend" ] ; then
|
||||
nudsl.process.fail "undefined prefix: $prefix";
|
||||
fi
|
||||
echo "$prepend$identifier"
|
||||
else
|
||||
echo "$identifier"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
.match.statement.plan() {
|
||||
echo "${indent}$(.identifier) ${args}"
|
||||
}
|
||||
|
||||
.match.rule.plan() {
|
||||
eval ".action.${rule//:/.} $args";
|
||||
}
|
||||
|
||||
.process.plan() {
|
||||
echo "$line";
|
||||
}
|
||||
|
||||
|
||||
.match.if_start.plan() {
|
||||
.block.push lang.if;
|
||||
echo "${indent}${keyword} $(.identifier) ${args} ; then"
|
||||
}
|
||||
|
||||
.block.lang.if.end.plan() {
|
||||
echo "${indent}fi";
|
||||
}
|
||||
|
||||
.match.namespace_block_start.plan() {
|
||||
.block.push rule.namespace;
|
||||
echo "# namespace $identifier"
|
||||
_namespace="$identifier"
|
||||
_import_prefix_="$identifier"
|
||||
}
|
||||
|
||||
.block.rule.namespace.end.plan() {
|
||||
_namespace=""
|
||||
_import_prefix_=""
|
||||
echo "#namespace end"
|
||||
}
|
||||
|
||||
.match.function_start.plan() {
|
||||
.block.push function
|
||||
case $identifier in
|
||||
.*) ;;
|
||||
:*) identifier="$_namespace${identifier#:}"
|
||||
esac;
|
||||
echo "${indent}$identifier() {";
|
||||
for arg in ${args//,/ }; do
|
||||
echo "${indent} local $arg="'"$1"'";shift;"
|
||||
done
|
||||
}
|
||||
|
||||
.block.start.plan() {
|
||||
case $identifier in
|
||||
function) echo "$line";;
|
||||
*"()") echo "$line";;
|
||||
*) nudsl.process.fail Invalid block syntax: "'$identifier' '$line'";
|
||||
esac;
|
||||
}
|
||||
|
||||
.block.end.plan() {
|
||||
.process.plan;
|
||||
}
|
||||
|
||||
.do.function.prefix() {
|
||||
echo "${indent}function $1$args {"
|
||||
}
|
||||
|
||||
.action.block.rewrite.function.prefix() {
|
||||
echo "# block:rewrite:function:prefix $@"
|
||||
eval """.block.$1.start.plan() {
|
||||
.do.function.prefix "$2"
|
||||
}
|
||||
"""
|
||||
}
|
||||
|
||||
.action.block.rewrite.call() {
|
||||
echo "# block:rewrite:block:call $@"
|
||||
eval """.block.$1.start.plan() {
|
||||
echo \"\${indent}\"'${2}'\" \$args\"'${3}'
|
||||
}
|
||||
|
||||
.block.$1.end.plan() {
|
||||
echo \"\${indent}\"'${4}'
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
function nux.nuxsh.use {
|
||||
local file="$1";
|
||||
local cached="$2";
|
||||
nux.dsl.exec nux.nuxsh.language.def "$file" "$cached"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue