From 64b55b7683f110a42579ef9e6e93510e96da7246 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Tue, 16 Feb 2021 08:35:33 +0900 Subject: [PATCH] syntax: properly support case patterns --- lib/core-syntax-ctx.def | 6 +- lib/core-syntax.sh | 83 ++++++++++-- memo/ChangeLog.md | 5 +- note.txt | 279 +++++++++++++++++++++++++++++++++++----- 4 files changed, 322 insertions(+), 51 deletions(-) diff --git a/lib/core-syntax-ctx.def b/lib/core-syntax-ctx.def index d190dfa1..3a45fde5 100644 --- a/lib/core-syntax-ctx.def +++ b/lib/core-syntax-ctx.def @@ -55,7 +55,11 @@ CTX_ARGVR 62 # (コマンド) declare の引数の右辺 CTX_CONDX 32 CTX_CONDI 33 CTX_CONDQ 67 -CTX_CASE 34 # case パターン待ち +CTX_CASE 34 # case パターン 開始待ち ("(" を特別扱い) +CTX_CPATX 76 # case パターン 単語待ち ("(" の後) +CTX_CPATI 77 # case パターン 単語内部 +CTX_CPATQ 79 # case パターン 変数代入形式(チルダ展開の為に区別) +CTX_CPATX0 78 # case パターン 単語終了後。"|" or ")" 待ち CTX_PATN 30 # glob 通常文字 ATTR_GLOB 31 # glob 特別文字 CTX_BRAX 54 # [...] (角括弧式) diff --git a/lib/core-syntax.sh b/lib/core-syntax.sh index 4d9f1960..32a56b73 100644 --- a/lib/core-syntax.sh +++ b/lib/core-syntax.sh @@ -2323,21 +2323,17 @@ function ble/syntax:bash/ctx-quot { _BLE_SYNTAX_FCTX[CTX_CASE]=ble/syntax:bash/ctx-case function ble/syntax:bash/ctx-case { if [[ $tail =~ ^$_ble_syntax_bash_RexIFSs ]]; then - ((_ble_syntax_attr[i]=ctx, - i+=${#BASH_REMATCH})) + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) return 0 elif [[ $tail == '('* ]]; then - ((ctx=CTX_CMDX)) - ble/syntax/parse/nest-push "$CTX_PATN" - ((_ble_syntax_attr[i++]=ATTR_GLOB)) + ((_ble_syntax_attr[i++]=ATTR_GLOB,ctx=CTX_CPATX)) return 0 elif [[ $tail == 'esac'$_ble_syntax_bash_RexDelimiter* || $tail == 'esac' ]]; then ((ctx=CTX_CMDX)) ble/syntax:bash/ctx-command else - ((ctx=CTX_CMDX)) - ble/syntax/parse/nest-push "$CTX_PATN" - ble/syntax:bash/ctx-globpat + ((ctx=CTX_CPATX)) + ble/syntax:bash/ctx-command-case-pattern-expect fi } @@ -3035,6 +3031,8 @@ function ble/syntax:bash/check-tilde-expansion { # 変数代入の形式の引数の右辺ではチルダ展開が有効である。 # +# 変数代入形式の時に文脈を切り替える文脈値。実際に変数代入でなくても変数代入形 +# 式によるチルダ展開が有効である時には区別する必要がある。 _ble_syntax_bash_command_CtxAssign[CTX_CMDI]=$CTX_VRHS _ble_syntax_bash_command_CtxAssign[CTX_COARGI]=$CTX_VRHS _ble_syntax_bash_command_CtxAssign[CTX_ARGVI]=$CTX_ARGVR @@ -3042,6 +3040,7 @@ _ble_syntax_bash_command_CtxAssign[CTX_ARGEI]=$CTX_ARGER _ble_syntax_bash_command_CtxAssign[CTX_ARGI]=$CTX_ARGQ _ble_syntax_bash_command_CtxAssign[CTX_FARGI3]=$CTX_FARGQ3 _ble_syntax_bash_command_CtxAssign[CTX_CARGI1]=$CTX_CARGQ1 +_ble_syntax_bash_command_CtxAssign[CTX_CPATI]=$CTX_CPATQ _ble_syntax_bash_command_CtxAssign[CTX_VALI]=$CTX_VALQ _ble_syntax_bash_command_CtxAssign[CTX_CONDI]=$CTX_CONDQ @@ -3052,6 +3051,7 @@ _ble_syntax_bash_command_IsAssign[CTX_ARGER]=$CTX_ARGEI _ble_syntax_bash_command_IsAssign[CTX_ARGQ]=$CTX_ARGI _ble_syntax_bash_command_IsAssign[CTX_FARGQ3]=$CTX_FARGI3 _ble_syntax_bash_command_IsAssign[CTX_CARGQ1]=$CTX_CARGI1 +_ble_syntax_bash_command_IsAssign[CTX_CPATQ]=$CTX_CPATI _ble_syntax_bash_command_IsAssign[CTX_VALR]=$CTX_VALI _ble_syntax_bash_command_IsAssign[CTX_VALQ]=$CTX_VALI _ble_syntax_bash_command_IsAssign[CTX_CONDQ]=$CTX_CONDI @@ -3192,12 +3192,18 @@ _BLE_SYNTAX_FEND[CTX_FARGI3]=ble/syntax:bash/ctx-command/check-word-end _BLE_SYNTAX_FEND[CTX_FARGQ3]=ble/syntax:bash/ctx-command/check-word-end _BLE_SYNTAX_FCTX[CTX_CARGX1]=ble/syntax:bash/ctx-command-compound-expect _BLE_SYNTAX_FCTX[CTX_CARGX2]=ble/syntax:bash/ctx-command-compound-expect +_BLE_SYNTAX_FCTX[CTX_CPATX]=ble/syntax:bash/ctx-command-case-pattern-expect +_BLE_SYNTAX_FCTX[CTX_CPATX0]=ble/syntax:bash/ctx-command-case-pattern-expect _BLE_SYNTAX_FCTX[CTX_CARGI1]=ble/syntax:bash/ctx-command _BLE_SYNTAX_FCTX[CTX_CARGQ1]=ble/syntax:bash/ctx-command _BLE_SYNTAX_FCTX[CTX_CARGI2]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[CTX_CPATI]=ble/syntax:bash/ctx-command +_BLE_SYNTAX_FCTX[CTX_CPATQ]=ble/syntax:bash/ctx-command _BLE_SYNTAX_FEND[CTX_CARGI1]=ble/syntax:bash/ctx-command/check-word-end _BLE_SYNTAX_FEND[CTX_CARGQ1]=ble/syntax:bash/ctx-command/check-word-end _BLE_SYNTAX_FEND[CTX_CARGI2]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[CTX_CPATI]=ble/syntax:bash/ctx-command/check-word-end +_BLE_SYNTAX_FEND[CTX_CPATQ]=ble/syntax:bash/ctx-command/check-word-end _BLE_SYNTAX_FCTX[CTX_TARGX1]=ble/syntax:bash/ctx-command-time-expect _BLE_SYNTAX_FCTX[CTX_TARGX2]=ble/syntax:bash/ctx-command-time-expect _BLE_SYNTAX_FCTX[CTX_TARGI1]=ble/syntax:bash/ctx-command @@ -3339,6 +3345,8 @@ _ble_syntax_bash_command_EndCtx[CTX_FARGQ3]=$CTX_FARGX3 _ble_syntax_bash_command_EndCtx[CTX_CARGI1]=$CTX_CARGX2 _ble_syntax_bash_command_EndCtx[CTX_CARGQ1]=$CTX_CARGX2 _ble_syntax_bash_command_EndCtx[CTX_CARGI2]=$CTX_CASE +_ble_syntax_bash_command_EndCtx[CTX_CPATI]=$CTX_CPATX0 +_ble_syntax_bash_command_EndCtx[CTX_CPATQ]=$CTX_CPATX0 _ble_syntax_bash_command_EndCtx[CTX_TARGI1]=$((_ble_bash>=40200?CTX_TARGX2:CTX_CMDXT)) #1 _ble_syntax_bash_command_EndCtx[CTX_TARGI2]=$CTX_CMDXT @@ -3363,6 +3371,8 @@ _ble_syntax_bash_command_EndWtype[CTX_FARGX2]=$CTX_FARGI2 # in _ble_syntax_bash_command_EndWtype[CTX_FARGX3]=$CTX_ARGI # in _ble_syntax_bash_command_EndWtype[CTX_CARGX1]=$CTX_ARGI _ble_syntax_bash_command_EndWtype[CTX_CARGX2]=$CTX_CARGI2 # in +_ble_syntax_bash_command_EndWtype[CTX_CPATX]=$CTX_CPATI +_ble_syntax_bash_command_EndWtype[CTX_CPATX0]=$CTX_CPATI _ble_syntax_bash_command_EndWtype[CTX_TARGX1]=$CTX_ARGI # -p _ble_syntax_bash_command_EndWtype[CTX_TARGX2]=$CTX_ARGI # -- @@ -3748,6 +3758,8 @@ _ble_syntax_bash_command_BeginCtx[CTX_FARGX2]=$CTX_FARGI2 _ble_syntax_bash_command_BeginCtx[CTX_FARGX3]=$CTX_FARGI3 _ble_syntax_bash_command_BeginCtx[CTX_CARGX1]=$CTX_CARGI1 _ble_syntax_bash_command_BeginCtx[CTX_CARGX2]=$CTX_CARGI2 +_ble_syntax_bash_command_BeginCtx[CTX_CPATX]=$CTX_CPATI +_ble_syntax_bash_command_BeginCtx[CTX_CPATX0]=$CTX_CPATI _ble_syntax_bash_command_BeginCtx[CTX_TARGX1]=$CTX_TARGI1 _ble_syntax_bash_command_BeginCtx[CTX_TARGX2]=$CTX_TARGI2 _ble_syntax_bash_command_BeginCtx[CTX_COARGX]=$CTX_COARGI @@ -3755,8 +3767,8 @@ _ble_syntax_bash_command_BeginCtx[CTX_COARGX]=$CTX_COARGI #%if !release ## @arr _ble_syntax_bash_command_isARGI[ctx] ## -## この配列要素が非空文字列のとき、 -## その文脈はシェル単語を解析中に用いられることを表す。 +## assert 用の配列。シェル単語の解析中に現れても良い文脈値を管理する。この配 +## 列要素が非空文字列のとき、その文脈はシェル単語の解析中に現れても良い。 ## _ble_syntax_bash_command_isARGI[CTX_CMDI]=1 _ble_syntax_bash_command_isARGI[CTX_VRHS]=1 @@ -3773,6 +3785,8 @@ _ble_syntax_bash_command_isARGI[CTX_FARGQ3]=1 # args... (= の後) _ble_syntax_bash_command_isARGI[CTX_CARGI1]=1 # value _ble_syntax_bash_command_isARGI[CTX_CARGQ1]=1 # value (= の後) _ble_syntax_bash_command_isARGI[CTX_CARGI2]=1 # in +_ble_syntax_bash_command_isARGI[CTX_CPATI]=1 # pattern +_ble_syntax_bash_command_isARGI[CTX_CPATQ]=1 # pattern _ble_syntax_bash_command_isARGI[CTX_TARGI1]=1 # -p _ble_syntax_bash_command_isARGI[CTX_TARGI2]=1 # -- _ble_syntax_bash_command_isARGI[CTX_COARGI]=1 # var (coproc の後) @@ -3792,7 +3806,7 @@ function ble/syntax:bash/ctx-command/.check-word-begin { # 配列 _ble_syntax_bash_command_EndWtype により変換されてから tree に登録される。 ble/syntax/parse/word-push "$wtype" "$i" - ((octx!=CTX_ARGX0)); return "$?" # return unexpectedWbegin + ((octx!=CTX_ARGX0&&octx!=CTX_CPATX0)); return "$?" # return unexpectedWbegin fi #%if !release @@ -3806,7 +3820,8 @@ function ble/syntax:bash/ctx-command { #%if !release if ble/syntax:bash/starts-with-delimiter-or-redirect; then ble/util/assert ' - ((ctx==CTX_ARGX||ctx==CTX_ARGX0||ctx==CTX_ARGVX||ctx==CTX_ARGEX||ctx==CTX_FARGX2||ctx==CTX_FARGX3||ctx==CTX_COARGX|| + ((ctx==CTX_ARGX||ctx==CTX_ARGX0||ctx==CTX_ARGVX||ctx==CTX_ARGEX|| + ctx==CTX_FARGX2||ctx==CTX_FARGX3||ctx==CTX_COARGX|| ctx==CTX_CMDX||ctx==CTX_CMDX1||ctx==CTX_CMDXT||ctx==CTX_CMDXC|| ctx==CTX_CMDXE||ctx==CTX_CMDXD||ctx==CTX_CMDXD0||ctx==CTX_CMDXV))' "invalid ctx=$ctx @ i=$i" ble/util/assert '((wbegin<0&&wtype<0))' "invalid word-context (wtype=$wtype wbegin=$wbegin) on non-word char." @@ -3963,6 +3978,38 @@ function ble/syntax:bash/ctx-command-time-expect { ble/syntax:bash/ctx-command } +function ble/syntax:bash/ctx-command-case-pattern-expect { + ble/util/assert '((ctx==CTX_CPATX||ctx==CTX_CPATX0))' + + if ble/syntax:bash/starts-with-delimiter-or-redirect; then + local delimiter=$BASH_REMATCH + if [[ $tail =~ ^$_ble_syntax_bash_RexSpaces ]]; then + ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH})) + elif [[ $tail == '|'* ]]; then + ((_ble_syntax_attr[i++]=ctx==CTX_CPATX?ATTR_ERR:ATTR_GLOB,ctx=CTX_CPATX)) + elif [[ $tail == ')'* ]]; then + ((_ble_syntax_attr[i++]=ctx==CTX_CPATX?ATTR_ERR:ATTR_GLOB,ctx=CTX_CMDX)) + elif [[ $tail == '('* ]]; then + # ctx-command と同様にエラーにして @() を始める。 + ble/syntax:bash/ctx-command/.check-delimiter-or-redirect + else + # 改行、リダイレクト、; & はエラー + ((_ble_syntax_attr[i]=ATTR_ERR,i+=${#delimiter})) + fi + return "$?" + fi + + # コメント禁止 + local i0=$i + if ble/syntax:bash/check-comment; then + ((_ble_syntax_attr[i0]=ATTR_ERR)) + return 0 + fi + + # 他は同じ + ble/syntax:bash/ctx-command +} + #------------------------------------------------------------------------------ # 文脈: 配列値リスト # @@ -5138,6 +5185,8 @@ _ble_syntax_bash_complete_check_prefix[CTX_FARGI3]='inside-argument argument' _ble_syntax_bash_complete_check_prefix[CTX_FARGQ3]='inside-argument argument' _ble_syntax_bash_complete_check_prefix[CTX_CARGI1]='inside-argument argument' _ble_syntax_bash_complete_check_prefix[CTX_CARGQ1]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[CTX_CPATI]='inside-argument argument' +_ble_syntax_bash_complete_check_prefix[CTX_CPATQ]='inside-argument argument' _ble_syntax_bash_complete_check_prefix[CTX_COARGI]='inside-argument variable command' _ble_syntax_bash_complete_check_prefix[CTX_VALI]='inside-argument file' _ble_syntax_bash_complete_check_prefix[CTX_VALQ]='inside-argument file' @@ -5203,6 +5252,7 @@ function ble/syntax/completion-context/.check-prefix/ctx:next-command { ## ARGX 系統の文脈に対する補完文脈の生成 _ble_syntax_bash_complete_check_prefix[CTX_ARGX]=next-argument _ble_syntax_bash_complete_check_prefix[CTX_CARGX1]=next-argument +_ble_syntax_bash_complete_check_prefix[CTX_CPATX]=next-argument _ble_syntax_bash_complete_check_prefix[CTX_FARGX3]=next-argument _ble_syntax_bash_complete_check_prefix[CTX_COARGX]=next-argument _ble_syntax_bash_complete_check_prefix[CTX_ARGVX]=next-argument @@ -5273,6 +5323,7 @@ function ble/syntax/completion-context/.check-prefix/ctx:next-identifier { fi } _ble_syntax_bash_complete_check_prefix[CTX_ARGX0]="next-word sabbrev" +_ble_syntax_bash_complete_check_prefix[CTX_CPATX0]="next-word sabbrev" _ble_syntax_bash_complete_check_prefix[CTX_CMDXD0]="next-word wordlist:-rs:';:{:do'" _ble_syntax_bash_complete_check_prefix[CTX_CMDXD]="next-word wordlist:-rs:'{:do'" _ble_syntax_bash_complete_check_prefix[CTX_CMDXE]="next-word wordlist:-rs:'}:fi:done:esac:then:elif:else:do'" @@ -5528,7 +5579,7 @@ function ble/syntax/completion-context/.check-here { ble/syntax/completion-context/.add wordlist:-rs:';:{:do' "$index" elif ((ctx==CTX_CMDXD)); then ble/syntax/completion-context/.add wordlist:-rs:'{:do' "$index" - elif ((ctx==CTX_ARGX0)); then + elif ((ctx==CTX_ARGX0||ctx==CTX_CPATX0)); then ble/syntax/completion-context/.add sabbrev "$index" elif ((ctx==CTX_ARGX||ctx==CTX_CARGX1||ctx==CTX_FARGX3)); then ble/syntax/completion-context/.add argument "$index" @@ -5550,7 +5601,7 @@ function ble/syntax/completion-context/.check-here { elif ((ctx==CTX_COARGX)); then ble/syntax/completion-context/.add variable:w "$index" ble/syntax/completion-context/.add command "$index" - elif ((ctx==CTX_RDRF||ctx==CTX_RDRS)); then + elif ((ctx==CTX_CPATI||ctx==CTX_RDRF||ctx==CTX_RDRS)); then ble/syntax/completion-context/.add file "$index" elif ((ctx==CTX_VRHS||ctx==CTX_ARGVR||ctx==CTX_ARGER||ctx==CTX_VALR)); then ble/syntax/completion-context/.add rhs "$index" @@ -5965,6 +6016,10 @@ function ble/syntax/faces-onload-hook { ble/syntax/attr2iface/.define CTX_CARGI1 syntax_default ble/syntax/attr2iface/.define CTX_CARGQ1 syntax_default ble/syntax/attr2iface/.define CTX_CARGI2 command_keyword + ble/syntax/attr2iface/.define CTX_CPATX syntax_default + ble/syntax/attr2iface/.define CTX_CPATI syntax_default + ble/syntax/attr2iface/.define CTX_CPATQ syntax_default + ble/syntax/attr2iface/.define CTX_CPATX0 syntax_default ble/syntax/attr2iface/.define CTX_TARGX1 syntax_default ble/syntax/attr2iface/.define CTX_TARGX2 syntax_default diff --git a/memo/ChangeLog.md b/memo/ChangeLog.md index a59c335c..74df4ea0 100644 --- a/memo/ChangeLog.md +++ b/memo/ChangeLog.md @@ -15,6 +15,7 @@ - canvas, edit: support `bleopt info_display` (suggested by 0neGuyDev) `#D1458` 69228fa - canvas (panel): always call `panel::render` to update height `#D1472` 51d2c05 - prompt: support `bleopt prompt_status_{line,align}` and `face prompt_status_line` `#D1462` cca1cbc +- syntax: properly support case patterns `#D1474` `#D1475` `#D1476` 0000000 ## Changes @@ -29,7 +30,7 @@ - complete: perform pathname expansions in subshells (motivated by 3ximus) `#D1450` d511896 - complete: support `bleopt complete_timeout_compvar` to time out pathname expansions for `COMP_WORDS` / `COMP_LINE` `#D1457` cc2881a - prompt: rename `bleopt prompt_{status_line => term_status}` `#D1462` cca1cbc -- edit (`ble/builtin/read`): cancel by C-d on an empty line `#D1473` 0000000 +- edit (`ble/builtin/read`): cancel by C-d on an empty line `#D1473` ecb8888 ## Fixes @@ -47,7 +48,7 @@ - syntax: fix broken AST with `[[` keyword `#D1454` 69658ef - benchmark (`ble-measure`): work around a locale-dependent decimal point of `EPOCHREALTIME` (reported by 3ximus) `#D1460` 1aa471b - global:work around bash-4.2 bug of `declare -gA` (reported by 0xC0ncord) `#D1470` 8856a04 - - global: fix declaration of associative arrays for `ble-reload` `#D1471` 3cae6e4 + - global: fix declaration of associative arrays for `ble-reload` (reported by 0xC0ncord) `#D1471` 3cae6e4 ## Internal changes and fixes diff --git a/note.txt b/note.txt index 6cb7c658..9344d6df 100644 --- a/note.txt +++ b/note.txt @@ -3157,40 +3157,6 @@ bash_tips 例えばシェル関数を定義した履歴項目に跳んだり、変数名から declare に移動するなど。 そういう機能でまともそうなのが定義できればそれを実装する。 -2017-10-01 - - * syntax: case $x in (a b) : ;; esac のパターン "a b" はエラー - - どうやら一個の単語までしか駄目な様子? - - 更に case aaa in ((aaa)) echo;; esac 等の様に () の入れ子もエラーになる。 - shopt -s/-u extglob に拘らずエラーになる。 - 一方で extglob の @() に関しては中で () の入れ子が可能である。 - つまり、case の中の (...) と extglob @(...) の文脈は異なる。 - - 他にも違いはある。@(<>) は許されるが、in (<>) は許されない。 - @(&&) は許されるが in (&&) は許されない。 - in (a|a|a) は許されるが in (a||a) や in (||) は許されない。 - in (&), in (|), in (;), in (<), in (>) は何れも駄目。 - in (a&b), in (a;b), in (ab) も何れも駄目。 - - どうも全然違う文脈の様に思われてきた。 - - 現在の実装では ble-syntax:bash/ctx-case から CTX_PATN に突入している。 - (他に CTX_PATN に入っている箇所を探すと、 - 関数の引数の括弧に何か変な物が入っている場合と、 - コマンドの途中で突然括弧が現れた場合である。 - これらはエラーに対する復帰としての CTX_PATN なのでそんなに気にしなくて良い) - - どうも振る舞いを観察すると ctx-conditions と ctx-globpat の中間のように思う。 - 単語を設置しなければならないという観点で言うと ctx-conditions に近い。 - 一方で対応している構文の集合という観点で言うと ctx-globpat が幾らか近いように思う。 - - 2017-11-27 追記 - どうやら () の中の単語ではチルダ展開も有効のようだ。以下で hello が出力される。 - case a=~ in (a=/home/murase) echo hello; esac # これは対応済み - case a=/home/murase in (a=~) echo hello; esac - 2017-09-18 * vi-mode: operator = [#tmp0001] @@ -3762,6 +3728,251 @@ bash_tips Done (実装ログ) ------------------------------------------------------------------------------- +2021-02-15 + + * 2017-10-01 syntax: case $x in (a b) : ;; esac のパターン "a b" はエラー [#D1476] + これも #D1474 で対応した。此処に挙げられているテストケースは有用だった。 + + どうやら一個の単語までしか駄目な様子? + + 更に case aaa in ((aaa)) echo;; esac 等の様に () の入れ子もエラーになる。 + shopt -s/-u extglob に拘らずエラーになる。 + 一方で extglob の @() に関しては中で () の入れ子が可能である。 + つまり、case の中の (...) と extglob @(...) の文脈は異なる。 + + 他にも違いはある。@(<>) は許されるが、in (<>) は許されない。 + @(&&) は許されるが in (&&) は許されない。 + in (a|a|a) は許されるが in (a||a) や in (||) は許されない。 + in (&), in (|), in (;), in (<), in (>) は何れも駄目。 + in (a&b), in (a;b), in (ab) も何れも駄目。 + + どうも全然違う文脈の様に思われてきた。 + + 現在の実装では ble-syntax:bash/ctx-case から CTX_PATN に突入している。 + (他に CTX_PATN に入っている箇所を探すと、 + 関数の引数の括弧に何か変な物が入っている場合と、 + コマンドの途中で突然括弧が現れた場合である。 + これらはエラーに対する復帰としての CTX_PATN なのでそんなに気にしなくて良い) + + どうも振る舞いを観察すると ctx-conditions と ctx-globpat の中間のように思う。 + 単語を設置しなければならないという観点で言うと ctx-conditions に近い。 + 一方で対応している構文の集合という観点で言うと ctx-globpat が幾らか近いように思う。 + + 2017-11-27 追記 + どうやら () の中の単語ではチルダ展開も有効のようだ。以下で hello が出力される。 + case a=~ in (a=/home/murase) echo hello; esac # これは対応済み + case a=/home/murase in (a=~) echo hello; esac + + * syntax: case x) とした時の ")" の着色が括弧でちゃんと囲んだ時と異なる [#D1475] + これは #D1474 における再実装で一緒に修正した。 + + * syntax: case a in @) で @() と入力すると fatal error [#D1474] + + case a in ) の状態でパターンに @() を入力しようとするとシフトエラーになる + + | もっと具体的に調べてみると case a in @) の状態で @ の直後に ( を挿入する + | となる。シフトエラーになるという事は case a in @) と入力した時点で壊れて + | いると考えられる。 + | + | | 先に ) を入力した時 + | | $ case a in @) + | | _ble_syntax_attr/tree/nest/stat? + | | 18 a 000 'c' | stat=(CMDX w=- n=- t=-:-) + | | | a 001 'a' | + | | | a 002 's' | + | | | a 003 'e' + word=CMDI:0-4/(wattr=d) + | | 39 a 004 ' ' stat=(CARGX1 w=- n=- t=$4:-) + | | 40 a 005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-) + | | 41 a 006 ' ' stat=(CARGX2 w=- n=- t=$6:-) + | | 42 a 007 'i' | stat=(CARGX2 w=- n=- t=$6:-) + | | | a 008 'n' + word=CARGI2:@5>7-9/(wattr=d) + | | 34*a 009 ' ' stat=(CASE w=- n=- t=$9:-) + | | 30*a 010 '@' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-) + | | 30*a s 011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9) + | | | s 012 ^@ stat=(CMDX w=- n=- t=$12:-) + | | + | | 先に @ を入力した時 + | | $ case a in @) + | | _ble_syntax_attr/tree/nest/stat? + | | 18 a 000 'c' | stat=(CMDX w=- n=- t=-:-) + | | | a 001 'a' | + | | | a 002 's' | + | | | a 003 'e' + word=CMDI:0-4/(wattr=d) + | | 39 a 004 ' ' stat=(CARGX1 w=- n=- t=$4:-) + | | 40 a 005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-) + | | 41 a 006 ' ' stat=(CARGX2 w=- n=- t=$6:-) + | | 42 a 007 'i' | stat=(CARGX2 w=- n=- t=$6:-) + | | | a 008 'n' + word=CARGI2:@5>7-9/(wattr=d) + | | 34 a 009 ' ' stat=(CASE w=- n=- t=$9:-) + | | 30*a 010 '@' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-) + | | 30*a 011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9) + | | | s 012 ^@ stat=(CMDX w=- n=- t=$12:-) + | + | これら二つを比較しても違いは 011 の位置の s という記号のみである。この s + | というのが何であるかは覚えていないが、実のところこの二つの両方で問題が再 + | 現するので @ を先に入力するか ) を先に入力するかは問題には関係ない。 + | + | @の代わりに X を挿入した場合にどうなるか調べる。X に引き続いて ( + | を挿入しても問題は発生しない。 + | + | | $ case a in X) + | | _ble_syntax_attr/tree/nest/stat? + | | 18 a 000 'c' | stat=(CMDX w=- n=- t=-:-) + | | | a 001 'a' | + | | | a 002 's' | + | | | a 003 'e' + word=CMDI:0-4/(wattr=d) + | | 39 a 004 ' ' stat=(CARGX1 w=- n=- t=$4:-) + | | 40 a 005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-) + | | 41 a 006 ' ' stat=(CARGX2 w=- n=- t=$6:-) + | | 42 a 007 'i' | stat=(CARGX2 w=- n=- t=$6:-) + | | | a 008 'n' + word=CARGI2:@5>7-9/(wattr=d) + | | 34 a 009 ' ' stat=(CASE w=- n=- t=$9:-) + | | 30 a 010 'X' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-) + | | 30 a 011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9) + | | | s 012 ^@ stat=(CMDX w=- n=- t=$12:-) + | + | 然し木構造を調べても X の時と @ の時で全く同じ状態になっている。な + | のにシフトでエラーが発生するというのは不思議である。 + | →改めて確認した所、一番最初に発生するエラーはシフトエラーではなかった。 + | + | | ble/syntax/tree-enumerate/.initialize/FATAL2 + | | @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:4 (ble/syntax/tree-enumerate) + | | @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:6 (ble/syntax/print-status/.dump-tree) + | | @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:8 (ble/syntax/print-status) + | | @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:74 (ble/highlight/layer:syntax/update) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:13 (ble/highlight/layer/update) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:10 (ble/textarea#update-text-buffer) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:76 (ble/textarea#render) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble-edit/bind/.tail) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:18 (ble-decode/EPILOGUE) + | | @ /home/murase/.mwg/src/ble.sh/out/ble.sh:79 (ble-decode/.hook) + | + | print-status の段階でエラーが発生している。つまり、直前の状態が問 + | 題なのではなくて ( を入力した直後の状態が壊れているのである。 + | + | | _ble_syntax_attr/tree/nest/stat? + | | 18 a e 000 'c' | stat=(CMDX w=- n=- t=-:-) + | | | a e 001 'a' | + | | | a e 002 's' | + | | | a e 003 'e' + word=CMDI:0-4/(wattr=d) + | | 39 a e 004 ' ' stat=(CARGX1 w=- n=- t=$4:-) + | | 40 a e 005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-) + | | 41 a e 006 ' ' stat=(CARGX2 w=- n=- t=$6:-) + | | 42 a e 007 'i' | stat=(CARGX2 w=- n=- t=$6:-) + | | | a e 008 'n' + word=CARGI2:@5>7-9/(wattr=d) + | | 34 a e 009 ' ' stat=(CASE w=- n=- t=$9:-) + | | 31*a e 010 '@' | nest=(PATN w=- n='none':10- t=-:$9) stat=(CASE w=- n=- t=$9:-) + | | |*a e 011 '(' | + | | 6*a es 012 ')' + word="none":10-13 stat=(PATN w=- n=@10 t=-:-) + | | | s 013 ^@ stat=(PATN w=- n=@10 t=$13:$9) + | + | というか、")" が存在しなくても普通に @( と入力しただけでエラーになってい + | る。a@( としている時には大丈夫である。これはつまり単語と nest が同じ場所 + | で始まる事によってエラーになっているという事だろうか。うーん。確かに a@( + | とすると a の位置と @ の位置の両方に nest が設定されている。という事は、 + | @( を入力した時に同時に二箇所に nest を設定しようとして状態が破壊されてい + | るのである。だとすると $( でも問題が発生する筈→発生した。" でも問題が発 + | 生した。うーん。根本的に nest を再考する必要があるのかもしれない。 + + [状況] + + 以下の何れでも問題が発生する。原因は同じ位置に2つの nest を設置しようとして + いる事にある。 + + - case a in @( + - case a in $( + - case a in " + - case a in (x);;" + + nest の位置をずらそうとしても " の場合には一文字しか無いのでずらす事ができ + ない。逆にパターンの側の nest の位置を一文字前にずらすという事も考えたが、 + 必ずしもパターンの前が空白とは限らない。例えば ;; など。この場合には結局同 + じ位置に nest を設置するしかない。或いは ;; の位置に nest を設置してしまう + という手もあるのかもしれないが、それは不自然だし色々とまた変な問題が発生し + そうである。 + + [修正] + + やはり解決策としては同じ位置に nest を設置できる様にするという事。然し、現 + 状のコードで nest が同じ位置に設置されないという前提は何処で使っていただろ + うか。場合によって単に対応するだけでは済まないかもしれない。 + + 或いはもう一つの方法として、そもそも case パターンを nest にする必要があっ + たのかという事。この方法の方が確実に簡単に修正できる気がする。然し、nest に + した理由は何だろうか。単に既存の CTX_PATN を使いたかったからというのであれ + ば簡単である。 + + コードを確認してみたがやはり nest を使わないとすると新しい文脈値が必要にな + りそうである。更に、元から case pattern の中は単語が一個だけになる様に制限 + を加える予定だった。これに対応する為には結局新しい文脈値が必要だったのだ。 + case pattern の単語数も一緒に対応してしまうのが良いだろう。 + + うーん。実はコマンド文脈で読み取った方が良い? とも思ったがそうでも + ない気もする。例えば | の取り扱いが異なる。& や ; 等他の delim の + 場合にはエラーにする必要がある。|| は一まとまりではなく一文字ずつ取る。 + | の直後は再び単語を受け付けて OK。など。 + + - done: ble/syntax:bash/ctx-command-case-pattern + + 実装したが無限ループになってしまう。調べると parse の中で同じ位置に対してずっ + と計算している。 + + parse (i=19): ctx=78 ble/syntax:bash/ctx-command-case-pattern-expect + + $ case x in @() echo ;; esac + + 問題は ;; の直前で起きている様だ。これは BASH_REMATCH が途中で書き換わって + いたのが見落としだった。修正した。OK 動いている。 + + ---------------------------------------------------------------------- + + 2021-02-19 assertion failure が出た。 + + assertion failure: ((_ble_syntax_bash_command_isARGI[ctx])) + invalid ctx=79 in words + @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:15 (ble/syntax:bash/ctx-command) + @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:86 (ble/syntax/parse) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7 (ble-edit/content/update-syntax) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:75 (ble/textarea#render) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble/textarea#panel::render) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:5 (ble/function#try) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:8 (ble/canvas/panel/render) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble-edit/bind/.tail) + @ /home/murase/.mwg/src/ble.sh/out/ble.sh:18 (ble-decode/EPILOGUE) + + [再現] + + | 以下のコマンドラインに於いて "'; の ; の前にカーソルを置いて、其処から BS + | の autorepeat で削除を行うと確率的に上記のエラーが発生する。不思議なのは + | ctx=79 は最近追加した CTX_CPATQ であり、これは case の時にしか発生しない筈 + | の物であるという事。現状では何処にも case はないので ctx が 79 になる事はな + | い様に思われる。core-syntax.sh の中を再度確認してみたが混入する事はない気が + | する。 + | + | $ debug/builtin() { unset -f builtin; IFS=" " eval 'echo "[$*]"'; builtin "$@"; local _ext=$?; echo "[$* ($_ext)]"; + | builtin() { debug/builtin "$@"; }; return "$_ext"; } + | + | $ d() { unset -f builtin; A=" " : ': "[$*]"'; : "$@"; : a=$?; : "[$* ($a)]"; } + | + | $ : helloworldhelloworld; A=" " :; : a=$?; : "[$* ($a)]" + | + | あー。成程。79 が現れたのは BS で消す途中に ;; が現れる為である。確率的に発 + | 生していたのは、丁度 ";;" の時に文法の再解析が起こるか起こらないかである。 + | 一つずつ BS を押していれば必ず発生する。 + | + | $ :; :;: a=$?;: + | + | OK. 以下が最小再現コードである。以下の状態から間の空白を削除するとエラーになる。 + | + | $ ; ;a=1 + | + | というより変な事をしなくても普通に以下で問題が発生する。 + | + | $ case x in a=1 + + 取り敢えず 79 が出るのは別にバグではないという事は確認できた。 + そして修正は簡単だった。これは fixup にする。 + 2021-02-10 * ble/builtin/read: 空文字列の時 C-d でキャンセルしない [#D1473]