Permalink
Browse files

Respect flags like -r and -x to assignment keywords.

declare/typeset, local, and readonly all take the same flags.

NOTE: We still don't do anything with -a.  'local -a foo' in bash
creates a cell for a variable that is STILL undefined.  That is,
evaluating it will fail in 'set -o nounset' mode.

Addresses issue #59.
  • Loading branch information...
Andy Chu
Andy Chu committed Jan 20, 2018
1 parent f782759 commit 7ffbfde27c8f78e5f79342adf48af6fa5ace9755
Showing with 146 additions and 6 deletions.
  1. +8 −6 core/cmd_exec.py
  2. +32 −0 core/word_compile.py
  3. +21 −0 spec/array.test.sh
  4. +85 −0 spec/assign.test.sh
View
@@ -39,6 +39,7 @@
from core import process
from core import runtime
from core import state
from core import word_compile
from osh import ast_ as ast
from osh import parse_lib
@@ -738,25 +739,23 @@ def _Dispatch(self, node, fork_external):
elif node.tag == command_e.Assignment:
pairs = []
flags = word_compile.ParseAssignFlags(node.flags)
if node.keyword == Id.Assign_Local:
lookup_mode = scope_e.LocalOnly
flags = ()
# typeset and declare are synonyms? I see typeset -a a=() the most.
elif node.keyword in (Id.Assign_Declare, Id.Assign_Typeset):
# declare is like local, except it can also be used outside functions?
lookup_mode = scope_e.LocalOnly
# TODO: Respect flags. -r and -x matter, but -a and -A might be
# implicit in the RHS?
flags = ()
elif node.keyword == Id.Assign_Readonly:
lookup_mode = scope_e.Dynamic
flags = (var_flags_e.ReadOnly,)
flags.append(var_flags_e.ReadOnly)
elif node.keyword == Id.Assign_None: # mutate existing local or global
lookup_mode = scope_e.Dynamic
flags = ()
else:
# TODO: typeset, declare, etc. Those are dynamic though.
raise NotImplementedError(node.keyword)
raise AssertionError(node.keyword)
for pair in node.pairs:
if pair.op == assign_op_e.PlusEqual:
@@ -790,6 +789,9 @@ def _Dispatch(self, node, fork_external):
# e.g. 'readonly x' or 'local x'
val = None # only changing flags
# NOTE: In bash and mksh, declare -a myarray makes an empty cell with
# Undef value, but the 'array' attribute.
self.mem.SetVar(lval, val, flags, lookup_mode)
# Assignment always appears to have a spid.
View
@@ -7,6 +7,10 @@
"""
from core.id_kind import Id
from core import runtime
var_flags_e = runtime.var_flags_e
_ONE_CHAR = {
'0': '\0',
@@ -75,3 +79,31 @@ def EvalCStringToken(id_, value):
else:
raise AssertionError
#
# Assignment
#
def ParseAssignFlags(flag_args):
"""
Args:
flag_args looks like ['-r', '-x'] or ['-rx'], etc.
Returns:
A list of var_flags_e
NOTE: Any errors should be caught at PARSE TIME, not compile time.
"""
flags = []
for arg in flag_args:
assert arg[0] == '-', arg
for char in arg[1:]:
if char == 'x':
flags.append(var_flags_e.Exported)
elif char == 'r':
flags.append(var_flags_e.ReadOnly)
else:
# -a is ignored right now?
pass
return flags
View
@@ -369,3 +369,24 @@ echo ${#a[@]} ${#b[@]} ${#c[@]} ${#d[@]}
4 4 4 4
1 1 1 1
## END
### declare -a / local -a is empty array
declare -a myarray
argv.py "${myarray[@]}"
myarray+=('x')
argv.py "${myarray[@]}"
f() {
local -a myarray
argv.py "${myarray[@]}"
myarray+=('x')
argv.py "${myarray[@]}"
}
f
## STDOUT:
[]
['x']
[]
['x']
## END
View
@@ -290,3 +290,88 @@ echo $?
127
127
## END
### typeset -r makes a string readonly
typeset -r s1='12'
typeset -r s2='34'
s1='c'
echo status=$?
s2='d'
echo status=$?
s1+='e'
echo status=$?
s2+='f'
echo status=$?
unset s1
echo status=$?
unset s2
echo status=$?
## status: 1
## stdout-json: ""
## OK mksh status: 2
## OK bash status: 0
## OK bash STDOUT:
status=1
status=1
status=1
status=1
status=1
status=1
## END
## OK dash status: 0
## N-I dash STDOUT:
status=0
status=0
status=127
status=127
status=0
status=0
## END
### typeset -ar makes it readonly
typeset -a -r array1=(1 2)
typeset -ar array2=(3 4)
array1=('c')
echo status=$?
array2=('d')
echo status=$?
array1+=('e')
echo status=$?
array2+=('f')
echo status=$?
unset array1
echo status=$?
unset array2
echo status=$?
## status: 1
## stdout-json: ""
## OK bash status: 0
## OK bash STDOUT:
status=1
status=1
status=1
status=1
status=1
status=1
## END
# N-I dash status: 2
# N-I dash stdout-json: ""
# N-I mksh status: 1
# N-I mksh stdout-json: ""
### typeset -x makes it exported
typeset -rx PYTHONPATH=lib/
printenv.py PYTHONPATH
## STDOUT:
lib/
## END
# N-I dash stdout: None

0 comments on commit 7ffbfde

Please sign in to comment.