Skip to content

Commit 9ccf959

Browse files
author
Andy C
committed
[core] Use structured _error for purity errors
So users can catch the error
1 parent 59479a5 commit 9ccf959

File tree

3 files changed

+61
-22
lines changed

3 files changed

+61
-22
lines changed

builtin/func_misc.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,10 @@ def Call(self, rd):
544544
return value.List(l)
545545

546546

547+
# status code 4 is special, for encode/decode errors.
548+
_CODEC_STATUS = 4
549+
550+
547551
class ToJson8(vm._Callable):
548552

549553
def __init__(self, is_j8):
@@ -571,8 +575,8 @@ def Call(self, rd):
571575
else:
572576
j8.PrintJsonMessage(val, buf, indent, type_errors)
573577
except error.Encode as e:
574-
# status code 4 is special, for encode/decode errors.
575-
raise error.Structured(4, e.Message(), rd.LeftParenToken())
578+
raise error.Structured(_CODEC_STATUS, e.Message(),
579+
rd.LeftParenToken())
576580

577581
return value.Str(buf.getvalue())
578582

@@ -601,7 +605,7 @@ def Call(self, rd):
601605
'start_pos': num.ToBig(e.start_pos),
602606
'end_pos': num.ToBig(e.end_pos),
603607
} # type: Dict[str, value_t]
604-
# status code 4 is special, for encode/decode errors.
605-
raise error.Structured(4, e.Message(), rd.LeftParenToken(), props)
608+
raise error.Structured(_CODEC_STATUS, e.Message(),
609+
rd.LeftParenToken(), props)
606610

607611
return val

core/executor.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ def MaybeWaitOnProcessSubs(self, waiter, status_array):
208208
'/bin'
209209
]
210210

211+
_PURITY_STATUS = 5
212+
211213

212214
class PureExecutor(vm._Executor):
213215

@@ -226,9 +228,14 @@ def __init__(
226228

227229
def RunBuiltin(self, builtin_id, cmd_val):
228230
# type: (int, cmd_value.Argv) -> int
229-
"""Called by the 'builtin' builtin in osh/builtin_meta.py."""
230-
e_die("Can't run builtin in pure mode", cmd_val.arg_locs[0])
231-
return 1
231+
"""Called by the 'builtin' builtin in builtin/meta_oils.py."""
232+
233+
# TODO: RunSimpleCommand will allow 'true false'
234+
#
235+
# Then this function should allow
236+
# builtin true
237+
# builtin false
238+
raise AssertionError()
232239

233240
def RunSimpleCommand(self, cmd_val, cmd_st, run_flags):
234241
# type: (cmd_value.Argv, CommandStatus, int) -> int
@@ -241,8 +248,10 @@ def RunBackgroundJob(self, node):
241248

242249
def RunPipeline(self, node, status_out):
243250
# type: (command.Pipeline, CommandStatus) -> None
244-
e_die("Pipelines aren't allowed in pure mode (OILS-ERR-204)",
245-
loc.Command(node))
251+
raise error.Structured(
252+
_PURITY_STATUS,
253+
"Pipelines aren't allowed in pure mode (OILS-ERR-204)",
254+
loc.Command(node))
246255

247256
def RunSubshell(self, node):
248257
# type: (command_t) -> int
@@ -257,9 +266,10 @@ def CaptureStdout(self, node):
257266

258267
def RunCommandSub(self, cs_part):
259268
# type: (CommandSub) -> str
260-
e_die("Command subs aren't allowed in pure mode (OILS-ERR-204)",
261-
loc.WordPart(cs_part))
262-
return ''
269+
raise error.Structured(
270+
_PURITY_STATUS,
271+
"Command subs aren't allowed in pure mode (OILS-ERR-204)",
272+
loc.WordPart(cs_part))
263273

264274
def RunProcessSub(self, cs_part):
265275
# type: (CommandSub) -> str

spec/ysh-purity.test.sh

+35-10
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,41 @@ pp test_ (d)
1616

1717
var impure = ^(seq 3 | wc -l)
1818

19-
call eval(impure)
19+
try {
20+
call eval(impure)
21+
}
22+
#= _error
23+
echo impure code=$[_error.code]
24+
25+
# Can run impure code after pure code
26+
call io->eval(impure)
2027

21-
## status: 1
2228
## STDOUT:
2329
(Dict) {"a":1,"b":2}
30+
impure code=5
31+
3
2432
## END
2533

2634
#### evalExpr() is a pure function
35+
shopt --set ysh:upgrade
2736

2837
var x = 42
2938
var pure = ^[x + 1]
3039
echo pure=$[evalExpr(pure)]
3140

32-
var impure = ^[x + $(echo 1)]
33-
echo impure=$[evalExpr(impure)]
41+
var impure = ^[x + $(echo 3)]
42+
try {
43+
echo impure code=$[evalExpr(impure)]
44+
}
45+
echo impure code=$[_error.code]
46+
47+
# Can run impure code after pure code
48+
echo impure=$[io->evalExpr(impure)]
3449

35-
## status: 1
3650
## STDOUT:
3751
pure=43
52+
impure code=5
53+
impure=45
3854
## END
3955

4056
#### Idiom to handle purity errors from untrusted config files
@@ -118,20 +134,29 @@ $SH --eval-pure pipeline.sh -c 'echo pipeline.sh=$?'
118134
## status: 0
119135
## STDOUT:
120136
command sub
121-
command-sub.sh=1
122-
command-sub.ysh=1
137+
command-sub.sh=5
138+
command-sub.ysh=5
123139

124140
3
125141
eval
126-
pipeline.sh=1
142+
pipeline.sh=5
127143
## END
128144

129145
#### Executor: Builtins not allowed
130146

131-
mapfile lines < <(seq 3)
132-
echo "${lines[@]}"
147+
var cmd = ^(
148+
mapfile lines < <(seq 3)
149+
echo "${lines[@]}"
150+
)
151+
152+
var cmd = ^(
153+
builtin echo hi
154+
)
155+
156+
call eval(cmd)
133157

134158
## STDOUT:
159+
what
135160
## END
136161

137162
#### Are source or use builtins allowed?

0 commit comments

Comments
 (0)