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

150 lines, 84 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
69 def Call(self, rd):
70 # type: (typed_args.Reader) -> value_t
71
72 string = rd.PosStr()
73 rd.Done()
74 return self._Call(string)
75
76
77class EvalHay(vm._Callable):
78 """evalHay()"""
79
80 def __init__(
81 self,
82 hay_state, # type: hay_ysh.HayState
83 mutable_opts, # type: state.MutableOpts
84 mem, # type: state.Mem
85 cmd_ev, #type: cmd_eval.CommandEvaluator
86 ):
87 # type: (...) -> None
88 self.hay_state = hay_state
89 self.mutable_opts = mutable_opts
90 self.mem = mem
91 self.cmd_ev = cmd_ev
92
93 def _Call(self, cmd):
94 # type: (command_t) -> Dict[str, value_t]
95
96 with hay_ysh.ctx_HayEval(self.hay_state, self.mutable_opts, self.mem):
97 unused = self.cmd_ev.EvalCommandFrag(cmd)
98
99 return self.hay_state.Result()
100
101 # Note: we should discourage the unvalidated top namespace for files? It
102 # needs more validation.
103
104 def Call(self, rd):
105 # type: (typed_args.Reader) -> value_t
106
107 cmd = rd.PosCommandFrag()
108 rd.Done()
109 return value.Dict(self._Call(cmd))
110
111
112class BlockAsStr(vm._Callable):
113 """block_as_str
114
115 TODO:
116 - I think this should be cmd->exportAsJson() or something
117 - maybe not toJson(), because that's a bit cavalier?
118 """
119
120 def __init__(self, arena):
121 # type: (alloc.Arena) -> None
122 self.arena = arena
123
124 def _Call(self, block):
125 # type: (value_t) -> value_t
126 return block
127
128 def Call(self, rd):
129 # type: (typed_args.Reader) -> value_t
130 val = rd.PosValue()
131 rd.Done()
132 return self._Call(val)
133
134
135class HayFunc(vm._Callable):
136 """_hay() register"""
137
138 def __init__(self, hay_state):
139 # type: (hay_ysh.HayState) -> None
140 self.hay_state = hay_state
141
142 def _Call(self):
143 # type: () -> Dict[str, value_t]
144 return self.hay_state.HayRegister()
145
146 def Call(self, rd):
147 # type: (typed_args.Reader) -> value_t
148
149 # TODO: check args
150 return value.Dict(self._Call())