Skip to content

Commit e587f90

Browse files
author
Andy C
committed
[main] Handle parse errors in --eval
And polish the error messages.
1 parent efe9ee7 commit e587f90

File tree

3 files changed

+54
-30
lines changed

3 files changed

+54
-30
lines changed

core/main_loop.py

+46-22
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212

1313
from _devbuild.gen import arg_types
1414
from _devbuild.gen.syntax_asdl import (command, command_t, parse_result,
15-
parse_result_e, loc, source)
15+
parse_result_e, source)
1616
from core import alloc
1717
from core import error
1818
from core import process
19-
from core import pyutil
2019
from core import state
2120
from core import util
2221
from display import ui
@@ -28,7 +27,7 @@
2827
import fanos
2928
import posix_ as posix
3029

31-
from typing import cast, Any, List, TYPE_CHECKING
30+
from typing import cast, Any, List, Tuple, TYPE_CHECKING
3231
if TYPE_CHECKING:
3332
from core.comp_ui import _IDisplay
3433
from core import process
@@ -324,8 +323,29 @@ def Interactive(
324323
return status
325324

326325

327-
def Batch(cmd_ev, c_parser, errfmt, cmd_flags=0):
328-
# type: (cmd_eval.CommandEvaluator, cmd_parse.CommandParser, ui.ErrorFormatter, int) -> int
326+
def Batch(
327+
cmd_ev, # type: cmd_eval.CommandEvaluator
328+
c_parser, # type: cmd_parse.CommandParser
329+
errfmt, # type: ui.ErrorFormatter
330+
cmd_flags=0, # type: int
331+
):
332+
# type: (...) -> int
333+
"""
334+
source, eval, etc. treat parse errors as error code 2. But the --eval flag does not.
335+
"""
336+
was_parsed, status = Batch2(cmd_ev, c_parser, errfmt, cmd_flags=cmd_flags)
337+
if not was_parsed:
338+
return 2
339+
return status
340+
341+
342+
def Batch2(
343+
cmd_ev, # type: cmd_eval.CommandEvaluator
344+
c_parser, # type: cmd_parse.CommandParser
345+
errfmt, # type: ui.ErrorFormatter
346+
cmd_flags=0, # type: int
347+
):
348+
# type: (...) -> Tuple[bool, int]
329349
"""Loop for batch execution.
330350
331351
Returns:
@@ -347,6 +367,7 @@ def Batch(cmd_ev, c_parser, errfmt, cmd_flags=0):
347367
- In contrast, 'trap' should parse up front?
348368
- What about $() ?
349369
"""
370+
was_parsed = True
350371
status = 0
351372
while True:
352373
probe('main_loop', 'Batch_parse_enter')
@@ -357,7 +378,8 @@ def Batch(cmd_ev, c_parser, errfmt, cmd_flags=0):
357378
break
358379
except error.Parse as e:
359380
errfmt.PrettyPrintError(e)
360-
status = 2
381+
was_parsed = False
382+
status = -1 # invalid value
361383
break
362384

363385
# After every "logical line", no lines will be referenced by the Arena.
@@ -387,7 +409,7 @@ def Batch(cmd_ev, c_parser, errfmt, cmd_flags=0):
387409
mylib.MaybeCollect() # manual GC point
388410
probe('main_loop', 'Batch_collect_exit')
389411

390-
return status
412+
return was_parsed, status
391413

392414

393415
def ParseWholeFile(c_parser):
@@ -416,8 +438,15 @@ def ParseWholeFile(c_parser):
416438
else:
417439
return command.CommandList(children)
418440

419-
def EvalFile(fs_path, fd_state, parse_ctx, cmd_ev):
420-
# type: (str, process.FdState, parse_lib.ParseContext, cmd_eval.CommandEvaluator) -> bool
441+
442+
def EvalFile(
443+
fs_path, # type: str
444+
fd_state, # type: process.FdState
445+
parse_ctx, # type: parse_lib.ParseContext
446+
cmd_ev, # type: cmd_eval.CommandEvaluator
447+
lang, # type: str
448+
):
449+
# type: (...) -> bool
421450
"""Evaluate a disk file, for --eval --eval-pure
422451
423452
Copied and adapted from the 'source' builtin in builtin/meta_oils.py.
@@ -429,32 +458,27 @@ def EvalFile(fs_path, fd_state, parse_ctx, cmd_ev):
429458
Returns:
430459
ok: whether processing should continue
431460
"""
432-
mem = cmd_ev.mem
433-
arena = cmd_ev.arena
434-
errfmt = cmd_ev.errfmt
435-
436-
# _LoadDiskFile
437-
blame_loc = loc.Missing
438461
try:
439462
f = fd_state.Open(fs_path)
440463
except (IOError, OSError) as e:
441-
errfmt.Print_(
442-
'Error reading %r: %s' % (fs_path, pyutil.strerror(e)),
443-
blame_loc=blame_loc)
464+
print_stderr("%s: Couldn't open %r for --eval: %s" %
465+
(lang, fs_path, posix.strerror(e.errno)))
444466
return False
445467

446-
line_reader = reader.FileLineReader(f, arena)
468+
line_reader = reader.FileLineReader(f, cmd_ev.arena)
447469
c_parser = parse_ctx.MakeOshParser(line_reader)
448470

449471
# TODO:
450472
# - Improve error locations
451473
# - parse error should be fatal
452474

453475
with process.ctx_FileCloser(f):
454-
with state.ctx_ThisDir(mem, fs_path):
476+
with state.ctx_ThisDir(cmd_ev.mem, fs_path):
455477
src = source.MainFile(fs_path)
456-
with alloc.ctx_SourceCode(arena, src):
478+
with alloc.ctx_SourceCode(cmd_ev.arena, src):
457479
# May raise util.UserExit
458-
unused = Batch(cmd_ev, c_parser, errfmt)
480+
was_parsed, unused = Batch2(cmd_ev, c_parser, cmd_ev.errfmt)
481+
if not was_parsed:
482+
return False
459483

460484
return True

core/shell.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -962,13 +962,12 @@ def Main(
962962
# TODO: process these in a loop, in order
963963
if flag.eval is not None:
964964
try:
965-
ok = main_loop.EvalFile(flag.eval, fd_state, parse_ctx, cmd_ev)
965+
ok = main_loop.EvalFile(flag.eval, fd_state, parse_ctx, cmd_ev,
966+
lang)
966967
except util.UserExit as e:
967-
# TODO:
968-
# do we need this?
969-
# should there be a different shopt? Could be verbose in YSH
970-
if exec_opts.verbose_errexit():
971-
errfmt.StderrLine('oils: --eval exit')
968+
# Doesn't seem like we need this, and verbose_errexit isn't the right option
969+
#if exec_opts.verbose_errexit():
970+
# print-stderr('oils: --eval exit')
972971
return e.status
973972
if not ok: # parse error or I/O error was already printed
974973
return 1

spec/ysh-usage.test.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
## our_shell: ysh
2-
## oils_failures_allowed: 2
2+
## oils_failures_allowed: 1
33

44
#### ysh --location-str --location-start-line
55

@@ -76,8 +76,9 @@ $[ENV.SH] --eval nonexistent.ysh -c 'echo flag -c'
7676

7777
echo 'echo zz; ( echo' >bad.ysh
7878

79-
$[ENV.SH] --eval bad.ysh -c 'echo hi'
79+
$[ENV.SH] --eval bad.ysh -c 'echo flag -c'
8080

81+
## status: 1
8182
## STDOUT:
8283
## END
8384

0 commit comments

Comments
 (0)