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

157 lines, 91 significant
1#!/usr/bin/env python2
2from __future__ import print_function
3
4from _devbuild.gen.syntax_asdl import source, loc, command_t
5from _devbuild.gen.value_asdl import value, cmd_frag
6from builtin import hay_ysh
7from core import alloc
8from core import error
9from core import main_loop
10from core import state
11from display import ui
12from core import vm
13from frontend import reader
14from frontend import typed_args
15
16import posix_ as posix
17
18from typing import TYPE_CHECKING, Dict
19
20if TYPE_CHECKING:
21 from _devbuild.gen.value_asdl import value_t
22 from core import process
23 from frontend import parse_lib
24 from osh import cmd_eval
25
26
27class ParseHay(vm._Callable):
28 """parseHay()"""
29
30 def __init__(
31 self,
32 fd_state, # type:process.FdState
33 parse_ctx, # type: parse_lib.ParseContext
34 mem, # type: state.Mem
35 errfmt, # type: ui.ErrorFormatter
36 ):
37 # type: (...) -> None
38 self.fd_state = fd_state
39 self.parse_ctx = parse_ctx
40 self.mem = mem
41 self.errfmt = errfmt
42
43 def _Call(self, path):
44 # type: (str) -> value_t
45
46 call_loc = loc.Missing # TODO: location info
47
48 # TODO: need to close the file!
49 try:
50 f = self.fd_state.Open(path)
51 except (IOError, OSError) as e:
52 msg = posix.strerror(e.errno)
53 raise error.Expr("Couldn't open %r: %s" % (path, msg), call_loc)
54
55 arena = self.parse_ctx.arena
56 line_reader = reader.FileLineReader(f, arena)
57
58 parse_opts = state.MakeYshParseOpts()
59 # Note: runtime needs these options and totally different memory
60
61 # TODO: CommandParser needs parse_opts
62 c_parser = self.parse_ctx.MakeConfigParser(line_reader)
63
64 # TODO: Should there be a separate config file source?
65 src = source.OtherFile(path, call_loc)
66 try:
67 with alloc.ctx_SourceCode(arena, src):
68 node = main_loop.ParseWholeFile(c_parser)
69 except error.Parse as e:
70 self.errfmt.PrettyPrintError(e)
71 return None
72
73 return value.Command(cmd_frag.Expr(node), self.mem.CurrentFrame(),
74 self.mem.GlobalFrame())
75
76 def Call(self, rd):
77 # type: (typed_args.Reader) -> value_t
78
79 string = rd.PosStr()
80 rd.Done()
81 return self._Call(string)
82
83
84class EvalHay(vm._Callable):
85 """evalHay()"""
86
87 def __init__(
88 self,
89 hay_state, # type: hay_ysh.HayState
90 mutable_opts, # type: state.MutableOpts
91 mem, # type: state.Mem
92 cmd_ev, #type: cmd_eval.CommandEvaluator
93 ):
94 # type: (...) -> None
95 self.hay_state = hay_state
96 self.mutable_opts = mutable_opts
97 self.mem = mem
98 self.cmd_ev = cmd_ev
99
100 def _Call(self, cmd):
101 # type: (command_t) -> Dict[str, value_t]
102
103 with hay_ysh.ctx_HayEval(self.hay_state, self.mutable_opts, self.mem):
104 unused = self.cmd_ev.EvalCommandFrag(cmd)
105
106 return self.hay_state.Result()
107
108 # Note: we should discourage the unvalidated top namespace for files? It
109 # needs more validation.
110
111 def Call(self, rd):
112 # type: (typed_args.Reader) -> value_t
113
114 cmd = rd.PosCommandFrag()
115 rd.Done()
116 return value.Dict(self._Call(cmd))
117
118
119class BlockAsStr(vm._Callable):
120 """block_as_str
121
122 TODO:
123 - I think this should be cmd->exportAsJson() or something
124 - maybe not toJson(), because that's a bit cavalier?
125 """
126
127 def __init__(self, arena):
128 # type: (alloc.Arena) -> None
129 self.arena = arena
130
131 def _Call(self, block):
132 # type: (value_t) -> value_t
133 return block
134
135 def Call(self, rd):
136 # type: (typed_args.Reader) -> value_t
137 val = rd.PosValue()
138 rd.Done()
139 return self._Call(val)
140
141
142class HayFunc(vm._Callable):
143 """_hay() register"""
144
145 def __init__(self, hay_state):
146 # type: (hay_ysh.HayState) -> None
147 self.hay_state = hay_state
148
149 def _Call(self):
150 # type: () -> Dict[str, value_t]
151 return self.hay_state.HayRegister()
152
153 def Call(self, rd):
154 # type: (typed_args.Reader) -> value_t
155
156 # TODO: check args
157 return value.Dict(self._Call())