| 1 | from __future__ import print_function
|
| 2 |
|
| 3 | from _devbuild.gen.runtime_asdl import cmd_value
|
| 4 | from _devbuild.gen.value_asdl import value, value_e
|
| 5 | from core import dev
|
| 6 | from core import error
|
| 7 | from core import state
|
| 8 | from core import vm
|
| 9 | from display import ui
|
| 10 | from frontend import args
|
| 11 | from frontend import flag_util
|
| 12 | from mycpp.mylib import log
|
| 13 |
|
| 14 | from typing import cast, Dict, TYPE_CHECKING
|
| 15 | if TYPE_CHECKING:
|
| 16 | from core import optview
|
| 17 | from osh import cmd_eval
|
| 18 |
|
| 19 | _ = log
|
| 20 |
|
| 21 |
|
| 22 | class IsMain(vm._Builtin):
|
| 23 | """
|
| 24 | if is-main { echo hi }
|
| 25 | """
|
| 26 |
|
| 27 | def __init__(self, mem):
|
| 28 | # type: (state.Mem) -> None
|
| 29 | self.mem = mem
|
| 30 |
|
| 31 | def Run(self, cmd_val):
|
| 32 | # type: (cmd_value.Argv) -> int
|
| 33 | return 0 if self.mem.is_main else 1
|
| 34 |
|
| 35 |
|
| 36 | class SourceGuard(vm._Builtin):
|
| 37 | """
|
| 38 | source-guard main || return
|
| 39 | """
|
| 40 |
|
| 41 | def __init__(self, guards, exec_opts, errfmt):
|
| 42 | # type: (Dict[str, bool], optview.Exec, ui.ErrorFormatter) -> None
|
| 43 | self.guards = guards
|
| 44 | self.exec_opts = exec_opts
|
| 45 | self.errfmt = errfmt
|
| 46 |
|
| 47 | def Run(self, cmd_val):
|
| 48 | # type: (cmd_value.Argv) -> int
|
| 49 | _, arg_r = flag_util.ParseCmdVal('source-guard', cmd_val)
|
| 50 | name, _ = arg_r.ReadRequired2('requires a name')
|
| 51 | #log('guards %s', self.guards)
|
| 52 | if name in self.guards:
|
| 53 | # already defined
|
| 54 | if self.exec_opts.redefine_source():
|
| 55 | self.errfmt.PrintMessage(
|
| 56 | '(interactive) Reloading source file %r' % name)
|
| 57 | return 0
|
| 58 | else:
|
| 59 | return 1
|
| 60 | self.guards[name] = True
|
| 61 | return 0
|
| 62 |
|
| 63 |
|
| 64 | class ModuleInvoke(vm._Builtin):
|
| 65 | """
|
| 66 | This is a builtin for the __invoke__ method of Obj my-module
|
| 67 |
|
| 68 | use my-module.ysh
|
| 69 | my-module my-proc
|
| 70 | """
|
| 71 |
|
| 72 | def __init__(self, cmd_ev, tracer, errfmt):
|
| 73 | # type: (cmd_eval.CommandEvaluator, dev.Tracer, ui.ErrorFormatter) -> None
|
| 74 | self.cmd_ev = cmd_ev
|
| 75 | self.tracer = tracer
|
| 76 | self.errfmt = errfmt
|
| 77 |
|
| 78 | def Run(self, cmd_val):
|
| 79 | # type: (cmd_value.Argv) -> int
|
| 80 |
|
| 81 | arg_r = args.Reader(cmd_val.argv, locs=cmd_val.arg_locs)
|
| 82 | arg_r.Next() # move past the module name
|
| 83 |
|
| 84 | invokable_name, invokable_loc = arg_r.Peek2()
|
| 85 | if invokable_name is None:
|
| 86 | raise error.Usage(
|
| 87 | 'module must be invoked with a proc name argument',
|
| 88 | cmd_val.arg_locs[0])
|
| 89 |
|
| 90 | argv, locs = arg_r.Rest2() # include proc name
|
| 91 |
|
| 92 | self_obj = cmd_val.self_obj
|
| 93 | assert self_obj is not None # wouldn't have been called
|
| 94 |
|
| 95 | val = self_obj.d.get(invokable_name)
|
| 96 |
|
| 97 | #log('invokable_name %r', invokable_name)
|
| 98 | #log('argv %r', argv)
|
| 99 |
|
| 100 | # Similar to Procs::GetInvokable() - Proc or Obj
|
| 101 |
|
| 102 | if val is not None:
|
| 103 | # OK this is a proc 'log', so we found self, so now just invoke it
|
| 104 | # with the args. No self obj!
|
| 105 | cmd_val2 = cmd_value.Argv(argv, locs, cmd_val.is_last_cmd, None,
|
| 106 | cmd_val.proc_args)
|
| 107 |
|
| 108 | if val.tag() == value_e.Proc:
|
| 109 | proc = cast(value.Proc, val)
|
| 110 | #log('proc %r', proc.name)
|
| 111 |
|
| 112 | with dev.ctx_Tracer(self.tracer, 'module-invoke',
|
| 113 | cmd_val.argv):
|
| 114 | status = self.cmd_ev.RunProc(proc, cmd_val2)
|
| 115 | return status
|
| 116 |
|
| 117 | # The module itself is an invokable Obj, but it also CONTAINS an
|
| 118 | # invokable Obj
|
| 119 | proc_val, self_obj2 = state.ValueIsInvokableObj(val)
|
| 120 | cmd_val2.self_obj = self_obj2
|
| 121 | if proc_val:
|
| 122 | if proc_val.tag() != value_e.Proc:
|
| 123 | # Technically we can run it like this, but I don't see a
|
| 124 | # use case. It seems confusing.
|
| 125 | #return self.cmd_ev.shell_ex.RunBuiltinProc(proc_val.builtin, cmd_val2)
|
| 126 |
|
| 127 | raise error.TypeErr(
|
| 128 | proc_val,
|
| 129 | "__invoke__ on %r should be a user-defined Proc" %
|
| 130 | invokable_name, invokable_loc)
|
| 131 | proc = cast(value.Proc, proc_val)
|
| 132 |
|
| 133 | with dev.ctx_Tracer(self.tracer, 'module-invoke',
|
| 134 | cmd_val.argv):
|
| 135 | status = self.cmd_ev.RunProc(proc, cmd_val2)
|
| 136 | return status
|
| 137 |
|
| 138 | # Any other type of value
|
| 139 | raise error.Usage(
|
| 140 | "module doesn't contain invokable %r" % invokable_name,
|
| 141 | invokable_loc)
|