M core/state.py => core/state.py +13 -0
@@ 1276,6 1276,16 @@ class Mem(object):
definition and mutation will help translate the Oil subset of OSH to static
languages.
"""
+ if cell is not None and keyword_id in (Id.KW_Var, Id.KW_Const):
+ # This dynamic check is for 'local' before 'var', or 'readonly before
+ # 'const', etc.
+ #
+ # Another option: REMOVE assignment builtins from 'proc'. You can only
+ # use keywords.
+
+ # TODO: location
+ e_die('%r has already been declared', name)
+
# TODO: Also do this at parse time. We have some name resolution in
# ctx_Declarations.
if cell is None and keyword_id in (Id.KW_Set, Id.KW_SetLocal,
@@ 1372,6 1382,9 @@ class Mem(object):
cell.nameref = False
if val is not None: # e.g. declare -rx existing
+ # TODO: Maybe DON'T enforce this for 'const', so we can have const
+ # in a loop. It's checked statically. But that would change
+ # 'readonly x=1; const x=2'. Disallow assign builtins?
if cell.readonly:
# TODO: error context
e_die("Can't assign to readonly value %r", lval.name)
M spec/oil-assign.test.sh => spec/oil-assign.test.sh +28 -1
@@ 60,7 60,7 @@ x = 'foo'
echo x=$x
const x = 'bar'
echo x=$x
-## status: 1
+## status: 2
## STDOUT:
x=foo
## END
@@ 257,6 257,31 @@ var x = "redeclaration is an error"
x=local
## END
+#### mixing assignment builtins and Oil assignment
+shopt -s oil:all
+
+proc local-var {
+ local x=1
+ var x = 2
+ echo x=$x
+}
+
+proc readonly-const {
+ readonly x=1
+ x = 2
+ echo x=$x
+}
+
+run --assign-status :st eval 'local-var'
+echo status=$st
+run --assign-status :st eval 'readonly-const' || true
+echo status=$st
+
+## STDOUT:
+status=1
+status=1
+## END
+
#### setvar modified local or global scope
modify_with_shell_assignment() {
f=shell
@@ 334,3 359,5 @@ setvar L[0] = L
## END
+
+