OILS / builtin / method_io.py View on Github | oilshell.org

183 lines, 99 significant
1"""Methods on IO type"""
2from __future__ import print_function
3
4from _devbuild.gen.syntax_asdl import command_t
5from _devbuild.gen.value_asdl import value, value_e, value_t
6
7from core import error
8from core import num
9from core import state
10from core import vm
11from mycpp.mylib import log, NewDict
12from osh import prompt
13
14from typing import Dict, List, cast, TYPE_CHECKING
15if TYPE_CHECKING:
16 from frontend import typed_args
17 from osh import cmd_eval
18
19_ = log
20
21EVAL_NULL = 1
22EVAL_DICT = 2
23
24
25class Eval(vm._Callable):
26 """
27 These are similar:
28
29 var cmd = ^(echo hi)
30 call io->eval(cmd)
31
32 Also give the top namespace
33
34 call io->evalToDict(cmd)
35
36 TODO: remove eval (c)
37
38 The CALLER must handle errors.
39 """
40
41 def __init__(self, cmd_ev, which):
42 # type: (cmd_eval.CommandEvaluator, int) -> None
43 self.cmd_ev = cmd_ev
44 self.which = which
45
46 def Call(self, rd):
47 # type: (typed_args.Reader) -> value_t
48 unused = rd.PosValue()
49
50 val = rd.PosValue()
51 if val.tag() == value_e.Block:
52 block = cast(value.Block, val)
53 cmd = block.block.brace_group # type: command_t
54 frame = block.frame
55 elif val.tag() == value_e.Command:
56 cmd = cast(value.Command, val).c
57 frame = None
58 else:
59 assert False
60
61 dollar0 = rd.NamedStr("dollar0", None)
62 pos_args_raw = rd.NamedList("pos_args", None)
63 vars_ = rd.NamedDict("vars", None)
64 rd.Done()
65
66 pos_args = None # type: List[str]
67 if pos_args_raw is not None:
68 pos_args = []
69 for arg in pos_args_raw:
70 if arg.tag() != value_e.Str:
71 raise error.TypeErr(
72 arg, "Expected pos_args to be a List of Strs",
73 rd.LeftParenToken())
74
75 pos_args.append(cast(value.Str, arg).s)
76
77 if self.which == EVAL_NULL:
78 with state.ctx_Eval(self.cmd_ev.mem, frame, dollar0, pos_args, vars_):
79 unused_status = self.cmd_ev.EvalCommand(cmd)
80 return value.Null
81
82 elif self.which == EVAL_DICT:
83 # TODO: dollar0, pos_args, vars_ not supposed
84 # Does ctx_FrontFrame has different scoping rules? For "vars"?
85
86 bindings = NewDict() # type: Dict[str, value_t]
87 with state.ctx_FrontFrame(self.cmd_ev.mem, bindings):
88 unused_status = self.cmd_ev.EvalCommand(cmd)
89 return value.Dict(bindings)
90
91 else:
92 raise AssertionError()
93
94
95class CaptureStdout(vm._Callable):
96
97 def __init__(self, shell_ex):
98 # type: (vm._Executor) -> None
99 self.shell_ex = shell_ex
100
101 def Call(self, rd):
102 # type: (typed_args.Reader) -> value_t
103
104 unused = rd.PosValue()
105 cmd = rd.PosCommand()
106 rd.Done() # no more args
107
108 status, stdout_str = self.shell_ex.CaptureStdout(cmd)
109 if status != 0:
110 # Note that $() raises error.ErrExit with the status.
111 # But I think that results in a more confusing error message, so we
112 # "wrap" the errors.
113 properties = {
114 'status': num.ToBig(status)
115 } # type: Dict[str, value_t]
116 raise error.Structured(
117 4, 'captureStdout(): command failed with status %d' % status,
118 rd.LeftParenToken(), properties)
119
120 return value.Str(stdout_str)
121
122
123class PromptVal(vm._Callable):
124 """
125 _io->promptVal('$') is like \$
126 It expands to $ or # when root
127 """
128
129 def __init__(self, prompt_ev):
130 # type: (prompt.Evaluator) -> None
131 self.prompt_ev = prompt_ev
132
133 def Call(self, rd):
134 # type: (typed_args.Reader) -> value_t
135
136 # "self" param is guaranteed to succeed
137 unused = rd.PosValue()
138 what = rd.PosStr()
139 rd.Done() # no more args
140
141 # Bug fix: protect against crash later in PromptVal()
142 if len(what) != 1:
143 raise error.Expr(
144 'promptVal() expected a single char, got %r' % what,
145 rd.LeftParenToken())
146
147 return value.Str(self.prompt_ev.PromptVal(what))
148
149
150# TODO: Implement these
151
152
153class Time(vm._Callable):
154
155 def __init__(self):
156 # type: () -> None
157 pass
158
159 def Call(self, rd):
160 # type: (typed_args.Reader) -> value_t
161 return value.Null
162
163
164class Strftime(vm._Callable):
165
166 def __init__(self):
167 # type: () -> None
168 pass
169
170 def Call(self, rd):
171 # type: (typed_args.Reader) -> value_t
172 return value.Null
173
174
175class Glob(vm._Callable):
176
177 def __init__(self):
178 # type: () -> None
179 pass
180
181 def Call(self, rd):
182 # type: (typed_args.Reader) -> value_t
183 return value.Null