def _ResolveNames(names, funcs, aliases, search_path): results = [] for name in names: if name in funcs: kind = ('function', name) elif name in aliases: kind = ('alias', name) # TODO: Use match instead? elif consts.LookupNormalBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupSpecialBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupAssignBuiltin(name) != 0: kind = ('builtin', name) elif lexer_def.IsOtherBuiltin(name): # continue, etc. kind = ('builtin', name) elif lexer_def.IsKeyword(name): kind = ('keyword', name) else: resolved = search_path.Lookup(name) if resolved is None: kind = (None, None) else: kind = ('file', resolved) results.append(kind) return results
def ResolveNames(names, funcs, aliases, search_path): # type: (List[str], Dict[str, command__ShFunction], Dict[str, str], SearchPath) -> Tuple[str, str] results = [] for name in names: if name in funcs: kind = ('function', name) elif name in aliases: kind = ('alias', name) # TODO: Use match instead? elif consts.LookupNormalBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupSpecialBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupAssignBuiltin(name) != 0: kind = ('builtin', name) elif lexer_def.IsControlFlow(name): # continue, etc. kind = ('keyword', name) elif lexer_def.IsKeyword(name): kind = ('keyword', name) else: resolved = search_path.Lookup(name) if resolved is None: kind = (None, None) else: kind = ('file', resolved) results.append(kind) return results
def Run(self, cmd_val): # type: (cmd_value__Argv) -> int if len(cmd_val.argv) == 1: return 0 # this could be an error in strict mode? name = cmd_val.argv[1] # Run regular builtin or special builtin to_run = consts.LookupNormalBuiltin(name) if to_run == consts.NO_INDEX: to_run = consts.LookupSpecialBuiltin(name) if to_run == consts.NO_INDEX: span_id = cmd_val.arg_spids[1] if consts.LookupAssignBuiltin(name) != consts.NO_INDEX: # NOTE: There's a similar restriction for 'command' self.errfmt.Print("Can't run assignment builtin recursively", span_id=span_id) else: self.errfmt.Print("%r isn't a shell builtin", name, span_id=span_id) return 1 cmd_val2 = cmd_value.Argv(cmd_val.argv[1:], cmd_val.arg_spids[1:], cmd_val.block) return self.shell_ex.RunBuiltin(to_run, cmd_val2)
def _ResolveNames(names, funcs, aliases, search_path): # type: (List[str], Dict[str, Proc], Dict[str, str], state.SearchPath) -> List[Tuple[str, str]] results = [] # type: List[Tuple[str, str]] for name in names: if name in funcs: kind = ('function', name) elif name in aliases: kind = ('alias', name) # TODO: Use match instead? elif consts.LookupNormalBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupSpecialBuiltin(name) != 0: kind = ('builtin', name) elif consts.LookupAssignBuiltin(name) != 0: kind = ('builtin', name) elif consts.IsControlFlow(name): # continue, etc. kind = ('keyword', name) elif consts.IsKeyword(name): kind = ('keyword', name) else: resolved = search_path.Lookup(name) if resolved is None: no_str = None # type: Optional[str] kind = (no_str, name) else: kind = ('file', resolved) results.append(kind) return results
def _Visit(self, node): """ """ #log('VISIT %s', node.__class__.__name__) # NOTE: The tags are not unique!!! We would need this: # if isinstance(node, ast.command) and node.tag == command_e.Simple: # But it's easier to check the __class__ attribute. cls = node.__class__ if cls is command.Simple: #log('SimpleCommand %s', node.words) #log('--') #node.PrettyPrint() # Things to consider: # - source and . # - DONE builtins: get a list from builtin.py # - DONE functions: have to enter function definitions into a dictionary # - Commands that call others: sudo, su, find, xargs, etc. # - builtins that call others: exec, command # - except not command -v! if not node.words: return w = node.words[0] ok, argv0, _ = word_.StaticEval(w) if not ok: log("Couldn't statically evaluate %r", w) return if (consts.LookupSpecialBuiltin(argv0) == consts.NO_INDEX and consts.LookupAssignBuiltin(argv0) == consts.NO_INDEX and consts.LookupNormalBuiltin(argv0) == consts.NO_INDEX): self.progs_used[argv0] = True # NOTE: If argv1 is $0, then we do NOT print a warning! if argv0 == 'sudo': if len(node.words) < 2: return w1 = node.words[1] ok, argv1, _ = word_.StaticEval(w1) if not ok: log("Couldn't statically evaluate %r", w) return # Should we mark them behind 'sudo'? e.g. "sudo apt install"? self.progs_used[argv1] = True elif cls is command.ShFunction: self.funcs_defined[node.name] = True
def record_word(self, word_ob, text): pos = word_.LeftMostSpanForWord(word_ob) self.word_obs[text] = word_ob if (consts.LookupSpecialBuiltin(text) == consts.NO_INDEX and consts.LookupAssignBuiltin(text) == consts.NO_INDEX and consts.LookupNormalBuiltin(text) == consts.NO_INDEX): logger.info("Recording command: %r", text) logger.debug(" position: %d, word object: %r", pos, word_ob) self.commands[text].append(pos) else: # TODO: no immediate use since I'm no longer patching builtins # but there may still be utility in recording builtins a script # depends on. This would support spotting function/alias # clashes and such. self.builtins[text].append(pos)
def RunSimpleCommand(self, cmd_val, do_fork, call_procs=True): # type: (cmd_value__Argv, bool, bool) -> int """ Run builtins, functions, external commands Oil and other languages might have different, simpler rules. No special builtins, etc. Oil might have OIL_PATH = @( ... ) or something. Interpreters might want to define all their own builtins. Args: procs: whether to look up procs. """ argv = cmd_val.argv span_id = cmd_val.arg_spids[0] if len(cmd_val.arg_spids) else runtime.NO_SPID # This happens when you write "$@" but have no arguments. if len(argv) == 0: if self.exec_opts.strict_argv(): e_die("Command evaluated to an empty argv array", span_id=span_id) else: return 0 # status 0, or skip it? arg0 = argv[0] builtin_id = consts.LookupAssignBuiltin(arg0) if builtin_id != consts.NO_INDEX: # command readonly is disallowed, for technical reasons. Could relax it # later. self.errfmt.Print_("Can't run assignment builtin recursively", span_id=span_id) return 1 builtin_id = consts.LookupSpecialBuiltin(arg0) if builtin_id != consts.NO_INDEX: status = self.RunBuiltin(builtin_id, cmd_val) # TODO: Enable this and fix spec test failures. # Also update _SPECIAL_BUILTINS in osh/builtin.py. #if status != 0: # e_die('special builtin failed', status=status) return status # TODO: if shopt -s namespaces, then look up in current namespace FIRST. # # Then fallback on self.procs, which should be renamed self.procs? # # honestly there is no real chance of colllision because # foo-bar() {} can't be accessed anyway # functions can have hyphens, but variables can't # Builtins like 'true' can be redefined as functions. if call_procs: proc_node = self.procs.get(arg0) if proc_node is not None: if (self.exec_opts.strict_errexit() and self.mutable_opts.ErrExitIsDisabled()): self.errfmt.Print_('errexit was disabled for this construct', span_id=self.mutable_opts.ErrExitSpanId()) self.errfmt.StderrLine('') e_die("Can't run a proc while errexit is disabled. " "Use 'run' or wrap it in a process with $0 myproc", span_id=span_id) # NOTE: Functions could call 'exit 42' directly, etc. status = self.cmd_ev.RunProc(proc_node, argv[1:]) return status # TODO: # look up arg0 in global namespace? And see if the type is value.Obj # And it's a proc? # isinstance(val.obj, objects.Proc) UP_val = self.mem.GetVar(arg0) if mylib.PYTHON: # Not reusing CPython objects if UP_val.tag_() == value_e.Obj: val = cast(value__Obj, UP_val) if isinstance(val.obj, objects.Proc): status = self.cmd_ev.RunOilProc(val.obj, argv[1:]) return status builtin_id = consts.LookupNormalBuiltin(arg0) if builtin_id != consts.NO_INDEX: return self.RunBuiltin(builtin_id, cmd_val) environ = self.mem.GetExported() # Include temporary variables if cmd_val.block: e_die('Unexpected block passed to external command %r', arg0, span_id=cmd_val.block.spids[0]) # Resolve argv[0] BEFORE forking. argv0_path = self.search_path.CachedLookup(arg0) if argv0_path is None: self.errfmt.Print_('%r not found' % arg0, span_id=span_id) return 127 # Normal case: ls / if do_fork: thunk = process.ExternalThunk(self.ext_prog, argv0_path, cmd_val, environ) p = process.Process(thunk, self.job_state) status = p.Run(self.waiter) return status # Already forked for pipeline: ls / | wc -l # TODO: count subshell? ( ls / ) vs. ( ls /; ls / ) self.ext_prog.Exec(argv0_path, cmd_val, environ) # NEVER RETURNS assert False, "This line should never be reached" # makes mypy happy