Skip to content

Commit 7f3c044

Browse files
author
Andy C
committed
[spec/builtin-meta] Failing test cases for builtin local s=42, etc.
Also refactor detection of assignment builtins.
1 parent 2bfd36e commit 7f3c044

File tree

2 files changed

+224
-24
lines changed

2 files changed

+224
-24
lines changed

osh/word_eval.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,8 @@ def _PerformSlice(
377377
# NOTE: This error is ALWAYS fatal in bash. It's inconsistent with
378378
# strings.
379379
if has_length and length < 0:
380-
e_die(
381-
"Array slice can't have negative length: %d" %
382-
length, loc.WordPart(part))
380+
e_die("Array slice can't have negative length: %d" % length,
381+
loc.WordPart(part))
383382

384383
# Quirk: "begin" for positional arguments ($@ and $*) counts $0.
385384
if arg0_val is not None:
@@ -2151,7 +2150,7 @@ def SimpleEvalWordSequence2(self, words, allow_assign):
21512150
for i, w in enumerate(words):
21522151
# No globbing in the first arg for command.Simple.
21532152
if i == 0 and allow_assign:
2154-
strs0 = self._EvalWordToArgv(w) # respects strict-array
2153+
strs0 = self._EvalWordToArgv(w)
21552154
if len(strs0) == 1:
21562155
arg0 = strs0[0]
21572156
builtin_id = consts.LookupAssignBuiltin(arg0)
@@ -2202,17 +2201,30 @@ def SimpleEvalWordSequence2(self, words, allow_assign):
22022201

22032202
return cmd_value.Argv(strs, locs, None, None, None, None)
22042203

2204+
def _DetectAssignBuiltinStr(self, arg0, words):
2205+
# type: (str, List[CompoundWord]) -> Optional[cmd_value.Assign]
2206+
builtin_id = consts.LookupAssignBuiltin(arg0)
2207+
if builtin_id != consts.NO_INDEX:
2208+
return self._EvalAssignBuiltin(builtin_id, arg0, words)
2209+
return None
2210+
2211+
def _DetectAssignBuiltin(self, val0, words):
2212+
# type: (part_value_t, List[CompoundWord]) -> Optional[cmd_value.Assign]
2213+
UP_val0 = val0
2214+
if val0.tag() == part_value_e.String:
2215+
val0 = cast(Piece, UP_val0)
2216+
if not val0.quoted:
2217+
return self._DetectAssignBuiltinStr(val0.s, words)
2218+
return None
2219+
22052220
def EvalWordSequence2(self, words, allow_assign=False):
22062221
# type: (List[CompoundWord], bool) -> cmd_value_t
22072222
"""Turns a list of Words into a list of strings.
22082223
22092224
Unlike the EvalWord*() methods, it does globbing.
22102225
22112226
Args:
2212-
words: list of Word instances
2213-
2214-
Returns:
2215-
argv: list of string arguments, or None if there was an eval error
2227+
allow_assign: True for command.Simple, False for BashArray a=(1 2 3)
22162228
"""
22172229
if self.exec_opts.simple_word_eval():
22182230
return self.SimpleEvalWordSequence2(words, allow_assign)
@@ -2242,10 +2254,9 @@ def EvalWordSequence2(self, words, allow_assign=False):
22422254

22432255
# e.g. the 'local' in 'local a=b c=d' will be here
22442256
if allow_assign and i == 0:
2245-
builtin_id = consts.LookupAssignBuiltin(fast_str)
2246-
if builtin_id != consts.NO_INDEX:
2247-
return self._EvalAssignBuiltin(builtin_id, fast_str,
2248-
words)
2257+
cmd_val = self._DetectAssignBuiltinStr(fast_str, words)
2258+
if cmd_val:
2259+
return cmd_val
22492260
continue
22502261

22512262
part_vals = [] # type: List[part_value_t]
@@ -2261,15 +2272,9 @@ def EvalWordSequence2(self, words, allow_assign=False):
22612272
# But we don't want to evaluate the first word twice in the case of:
22622273
# $(some-command) --flag
22632274
if allow_assign and i == 0 and len(part_vals) == 1:
2264-
val0 = part_vals[0]
2265-
UP_val0 = val0
2266-
if val0.tag() == part_value_e.String:
2267-
val0 = cast(Piece, UP_val0)
2268-
if not val0.quoted:
2269-
builtin_id = consts.LookupAssignBuiltin(val0.s)
2270-
if builtin_id != consts.NO_INDEX:
2271-
return self._EvalAssignBuiltin(
2272-
builtin_id, val0.s, words)
2275+
cmd_val = self._DetectAssignBuiltin(part_vals[0], words)
2276+
if cmd_val:
2277+
return cmd_val
22732278

22742279
if 0:
22752280
log('')

spec/builtin-meta.test.sh

Lines changed: 198 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
## oils_failures_allowed: 0
1+
## oils_failures_allowed: 6
22
## compare_shells: dash bash mksh zsh
33

4-
5-
64
#### command -v
75
myfunc() { echo x; }
86
command -v echo
@@ -320,3 +318,200 @@ builtin command echo hi
320318
## stdout: hi
321319
## N-I dash status: 127
322320
## N-I dash stdout-json: ""
321+
322+
#### builtin typeset / export / readonly
323+
case $SH in dash) exit ;; esac
324+
325+
builtin typeset s=typeset
326+
echo s=$s
327+
328+
builtin export s=export
329+
echo s=$s
330+
331+
builtin readonly s=readonly
332+
echo s=$s
333+
334+
echo --
335+
336+
builtin builtin typeset s2=typeset
337+
echo s2=$s2
338+
339+
builtin builtin export s2=export
340+
echo s2=$s2
341+
342+
builtin builtin readonly s2=readonly
343+
echo s2=$s2
344+
345+
## STDOUT:
346+
s=typeset
347+
s=export
348+
s=readonly
349+
--
350+
s2=typeset
351+
s2=export
352+
s2=readonly
353+
## END
354+
## N-I dash STDOUT:
355+
## END
356+
357+
#### builtin declare / local
358+
case $SH in dash|mksh) exit ;; esac
359+
360+
builtin declare s=declare
361+
echo s=$s
362+
363+
f() {
364+
builtin local s=local
365+
echo s=$s
366+
}
367+
368+
f
369+
370+
## STDOUT:
371+
s=declare
372+
s=local
373+
## END
374+
## N-I dash/mksh STDOUT:
375+
## END
376+
377+
#### builtin declare etc. with array is not parsed
378+
379+
$SH -c 'builtin declare a=(x y)'
380+
test $? -ne 0 && echo 'fail'
381+
382+
$SH -c 'builtin declare -a a=(x y)'
383+
test $? -ne 0 && echo 'fail'
384+
385+
## STDOUT:
386+
fail
387+
fail
388+
## END
389+
390+
#### command export / readonly
391+
case $SH in zsh) exit ;; esac
392+
393+
# dash doesn't have declare typeset
394+
395+
command export c=export
396+
echo c=$c
397+
398+
command readonly c=readonly
399+
echo c=$c
400+
401+
echo --
402+
403+
command command export cc=export
404+
echo cc=$cc
405+
406+
command command readonly cc=readonly
407+
echo cc=$cc
408+
409+
## STDOUT:
410+
c=export
411+
c=readonly
412+
--
413+
cc=export
414+
cc=readonly
415+
## END
416+
## N-I zsh STDOUT:
417+
## END
418+
419+
#### command local
420+
421+
f() {
422+
command local s=local
423+
echo s=$s
424+
}
425+
426+
f
427+
428+
## STDOUT:
429+
s=local
430+
## END
431+
## BUG dash/mksh/zsh STDOUT:
432+
s=
433+
## END
434+
435+
436+
#### static builtin command ASSIGN, command builtin ASSIGN
437+
case $SH in dash|zsh) exit ;; esac
438+
439+
# dash doesn't have declare typeset
440+
441+
builtin command export bc=export
442+
echo bc=$bc
443+
444+
builtin command readonly bc=readonly
445+
echo bc=$bc
446+
447+
echo --
448+
449+
command builtin export cb=export
450+
echo cb=$cb
451+
452+
command builtin readonly cb=readonly
453+
echo cb=$cb
454+
455+
## STDOUT:
456+
bc=export
457+
bc=readonly
458+
--
459+
cb=export
460+
cb=readonly
461+
## END
462+
## N-I dash/zsh STDOUT:
463+
## END
464+
465+
#### dynamic builtin command ASSIGN, command builtin ASSIGN
466+
case $SH in dash|zsh) exit ;; esac
467+
468+
b=builtin
469+
c=command
470+
e=export
471+
r=readonly
472+
473+
$b $c export bc=export
474+
echo bc=$bc
475+
476+
$b $c readonly bc=readonly
477+
echo bc=$bc
478+
479+
echo --
480+
481+
$c $b export cb=export
482+
echo cb=$cb
483+
484+
$c $b readonly cb=readonly
485+
echo cb=$cb
486+
487+
echo --
488+
489+
$b $c $e bce=export
490+
echo bce=$bce
491+
492+
$b $c $r bcr=readonly
493+
echo bcr=$bcr
494+
495+
echo --
496+
497+
$c $b $e cbe=export
498+
echo cbe=$cbe
499+
500+
$c $b $r cbr=readonly
501+
echo cbr=$cbr
502+
503+
## STDOUT:
504+
bc=export
505+
bc=readonly
506+
--
507+
cb=export
508+
cb=readonly
509+
--
510+
bce=export
511+
bcr=readonly
512+
--
513+
cbe=export
514+
cbr=readonly
515+
## END
516+
## N-I dash/zsh STDOUT:
517+
## END

0 commit comments

Comments
 (0)