| 1 | #!/usr/bin/env python2
|
| 2 | from __future__ import print_function
|
| 3 |
|
| 4 | from _devbuild.gen.syntax_asdl import source, loc, command_t
|
| 5 | from _devbuild.gen.value_asdl import value, cmd_frag
|
| 6 | from builtin import hay_ysh
|
| 7 | from core import alloc
|
| 8 | from core import error
|
| 9 | from core import main_loop
|
| 10 | from core import state
|
| 11 | from display import ui
|
| 12 | from core import vm
|
| 13 | from frontend import reader
|
| 14 | from frontend import typed_args
|
| 15 |
|
| 16 | import posix_ as posix
|
| 17 |
|
| 18 | from typing import TYPE_CHECKING, Dict
|
| 19 |
|
| 20 | if 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 |
|
| 27 | class 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 |
|
| 84 | class 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 |
|
| 119 | class 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 |
|
| 142 | class 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())
|