Skip to content

Commit

Permalink
[builtin/read refactor] Prepare for read --line (&x), i.e. value.Place
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy C committed Oct 30, 2023
1 parent f075946 commit e35e925
Showing 1 changed file with 57 additions and 55 deletions.
112 changes: 57 additions & 55 deletions builtin/read_osh.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,60 +286,34 @@ def __init__(
self.errfmt = errfmt
self.stdin_ = mylib.Stdin()

def _Line(self, arg, var_name):
# type: (arg_types.read, str) -> int
"""For read --line."""

# Use an optimized C implementation rather than ReadLineSlowly, which
# calls ReadByte() over and over.
line = pyos.ReadLine()
if len(line) == 0: # EOF
return 1

if not arg.with_eol:
if line.endswith('\r\n'):
line = line[:-2]
elif line.endswith('\n'):
line = line[:-1]

# Lines that don't start with a single quote aren't QSN. They may contain
# a single quote internally, like:
def _MaybeDecodeLine(self, line):
# type: (str) -> str
"""Raises error.Parse if line isn't valid."""

# Lines that don't start with a single quote aren't QSN. They may
# contain a single quote internally, like:
#
# Fool's Gold
if arg.q and line.startswith("'"):
arena = self.parse_ctx.arena
line_reader = reader.StringLineReader(line, arena)
lexer = self.parse_ctx.MakeLexer(line_reader)

# The parser only yields valid tokens:
# Char_Literals, Char_OneChar, Char_Hex, Char_UBraced
# So we can use word_compile.EvalCStringToken, which is also used for
# $''.
# Important: we don't generate Id.Unknown_Backslash because that is valid
# in echo -e. We just make it Id.Unknown_Tok?
try:
# TODO: read should know about stdin, and redirects, and pipelines?
with alloc.ctx_SourceCode(arena, source.Stdin('')):
tokens = qsn_native.Parse(lexer)
except error.Parse as e:
self.errfmt.PrettyPrintError(e)
return 1
tmp = [word_compile.EvalCStringToken(t) for t in tokens]
line = ''.join(tmp)

lhs = location.LName(var_name)
self.mem.SetNamed(lhs, value.Str(line), scope_e.LocalOnly)
return 0

def _All(self, var_name):
# type: (str) -> int
contents = ReadAll()

# No error conditions?

lhs = location.LName(var_name)
self.mem.SetNamed(lhs, value.Str(contents), scope_e.LocalOnly)
return 0
if not line.startswith("'"):
return line

arena = self.parse_ctx.arena
line_reader = reader.StringLineReader(line, arena)
lexer = self.parse_ctx.MakeLexer(line_reader)

# The parser only yields valid tokens:
# Char_Literals, Char_OneChar, Char_Hex, Char_UBraced
# So we can use word_compile.EvalCStringToken, which is also used for
# $''.
# Important: we don't generate Id.Unknown_Backslash because that is valid
# in echo -e. We just make it Id.Unknown_Tok?

# TODO: read location info should know about stdin, and redirects, and
# pipelines?
with alloc.ctx_SourceCode(arena, source.Stdin('')):
tokens = qsn_native.Parse(lexer)
tmp = [word_compile.EvalCStringToken(t) for t in tokens]
return ''.join(tmp)

def Run(self, cmd_val):
# type: (cmd_value.Argv) -> int
Expand Down Expand Up @@ -392,7 +366,10 @@ def _Run(self, cmd_val):
place = rd.PosPlace()
rd.Done()

#log('p %s', place)
# TODO: need to respect --line and --all
# And maybe make read (&x) the same as read --all (&x)

log('p %s', place)

# Don't respect any of the other options here? This is buffered I/O.
if arg.line: # read --line
Expand All @@ -408,7 +385,29 @@ def _Run(self, cmd_val):
if next_arg is not None:
raise error.Usage('got extra argument', next_loc)

return self._Line(arg, var_name)
# Use an optimized C implementation rather than ReadLineSlowly, which
# calls ReadByte() over and over.
line = pyos.ReadLine()
if len(line) == 0: # EOF
return 1 # 'while read --line' loop

if not arg.with_eol:
if line.endswith('\r\n'):
line = line[:-2]
elif line.endswith('\n'):
line = line[:-1]

# TODO: This should be --j8 or --json
if arg.q:
try:
line = self._MaybeDecodeLine(line)
except error.Parse as e:
self.errfmt.PrettyPrintError(e)
return 1

lhs = location.LName(var_name)
self.mem.SetNamed(lhs, value.Str(line), scope_e.LocalOnly)
return 0

if arg.q:
e_usage('--qsn can only be used with --line', loc.Missing)
Expand All @@ -426,7 +425,10 @@ def _Run(self, cmd_val):
if next_arg is not None:
raise error.Usage('got extra argument', next_loc)

return self._All(var_name)
contents = ReadAll()
lhs = location.LName(var_name)
self.mem.SetNamed(lhs, value.Str(contents), scope_e.LocalOnly)
return 0

if arg.q:
e_usage('--qsn not implemented yet', loc.Missing)
Expand Down

0 comments on commit e35e925

Please sign in to comment.