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

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