| 1 | #!/usr/bin/env python2
 | 
| 2 | """func_hay.py."""
 | 
| 3 | from __future__ import print_function
 | 
| 4 | 
 | 
| 5 | from _devbuild.gen.syntax_asdl import source, loc, command_t
 | 
| 6 | from _devbuild.gen.value_asdl import value
 | 
| 7 | from builtin import hay_ysh
 | 
| 8 | from core import alloc
 | 
| 9 | from core import error
 | 
| 10 | from core import main_loop
 | 
| 11 | from core import state
 | 
| 12 | from core import ui
 | 
| 13 | from core import vm
 | 
| 14 | from frontend import reader
 | 
| 15 | from frontend import typed_args
 | 
| 16 | 
 | 
| 17 | import posix_ as posix
 | 
| 18 | 
 | 
| 19 | from typing import TYPE_CHECKING, Dict
 | 
| 20 | 
 | 
| 21 | if TYPE_CHECKING:
 | 
| 22 |     from _devbuild.gen.value_asdl import value_t
 | 
| 23 |     from core import process
 | 
| 24 |     from frontend import parse_lib
 | 
| 25 |     from osh import cmd_eval
 | 
| 26 | 
 | 
| 27 | 
 | 
| 28 | class ParseHay(vm._Callable):
 | 
| 29 |     """parseHay()"""
 | 
| 30 | 
 | 
| 31 |     def __init__(self, fd_state, parse_ctx, errfmt):
 | 
| 32 |         # type: (process.FdState, parse_lib.ParseContext, ui.ErrorFormatter) -> None
 | 
| 33 |         self.fd_state = fd_state
 | 
| 34 |         self.parse_ctx = parse_ctx
 | 
| 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.SourcedFile(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(node)
 | 
| 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 | 
 | 
| 77 | class 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.EvalCommand(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.PosCommand()
 | 
| 108 |         rd.Done()
 | 
| 109 |         return value.Dict(self._Call(cmd))
 | 
| 110 | 
 | 
| 111 | 
 | 
| 112 | class 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 | 
 | 
| 135 | class 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())
 |