Ejemplo n.º 1
0
def InitOilParser(code_str, arena=None):
    # NOTE: aliases don't exist in the Oil parser?
    arena = arena or MakeArena('<cmd_exec_test.py>')
    parse_ctx = parse_lib.ParseContext(arena, {})
    line_reader, _ = InitLexer(code_str, arena)
    c_parser = parse_ctx.MakeOilParser(line_reader)
    return arena, c_parser
Ejemplo n.º 2
0
def InitExecutor(parse_ctx=None, comp_lookup=None, arena=None, mem=None):
    if parse_ctx:
        arena = parse_ctx.arena
    else:
        arena or MakeArena('<InitExecutor>')
        parse_ctx = parse_lib.ParseContext(arena, {})

    mem = mem or state.Mem('', [], {}, arena)
    fd_state = process.FdState()
    funcs = {}

    comp_state = completion.State()
    comp_lookup = comp_lookup or completion.Lookup()

    readline = None  # simulate not having it
    builtins = {  # Lookup
        builtin_e.HISTORY: builtin.History(readline),

        builtin_e.COMPOPT: builtin_comp.CompOpt(comp_state),
        builtin_e.COMPADJUST: builtin_comp.CompAdjust(mem),
    }

    # For the tests, we do not use 'readline'.
    exec_opts = state.ExecOpts(mem, None)

    debug_f = util.DebugFile(sys.stderr)
    exec_deps = cmd_exec.Deps()
    exec_deps.dumper = dev.CrashDumper('')
    exec_deps.debug_f = debug_f
    exec_deps.trace_f = debug_f

    splitter = split.SplitContext(mem)
    exec_deps.splitter = splitter

    word_ev = word_eval.NormalWordEvaluator(mem, exec_opts, exec_deps, arena)
    exec_deps.word_ev = word_ev

    arith_ev = expr_eval.ArithEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.arith_ev = arith_ev

    word_ev.arith_ev = arith_ev  # Circular

    bool_ev = expr_eval.BoolEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.bool_ev = bool_ev

    tracer = cmd_exec.Tracer(parse_ctx, exec_opts, mem, word_ev, debug_f)
    exec_deps.tracer = tracer

    ex = cmd_exec.Executor(mem, fd_state, funcs, builtins, exec_opts,
                           parse_ctx, exec_deps)

    spec_builder = builtin_comp.SpecBuilder(ex, parse_ctx, word_ev, splitter,
                                            comp_lookup)
    # Add some builtins that depend on the executor!
    complete_builtin = builtin_comp.Complete(spec_builder,
                                             comp_lookup)  # used later
    builtins[builtin_e.COMPLETE] = complete_builtin
    builtins[builtin_e.COMPGEN] = builtin_comp.CompGen(spec_builder)

    return ex
Ejemplo n.º 3
0
def InitWordParser(code_str, arena=None):
    arena = arena or MakeArena('<test_lib>')
    parse_ctx = parse_lib.ParseContext(arena, {})
    line_reader, _ = InitLexer(code_str, arena)
    c_parser = parse_ctx.MakeOshParser(line_reader)
    # Hack
    return c_parser.w_parser
Ejemplo n.º 4
0
def InitCommandParser(code_str, arena=None):
    arena = arena or MakeArena('<test_lib>')
    parse_opts = parse_lib.OilParseOptions()
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, None)
    line_reader, _ = InitLexer(code_str, arena)
    c_parser = parse_ctx.MakeOshParser(line_reader)
    return c_parser
Ejemplo n.º 5
0
def main(argv):
  # type: (List[str]) -> int
  arena = alloc.Arena()
  arena.PushSource(source.Stdin(''))

  parse_opts = parse_lib.OilParseOptions()
  # Dummy value; not respecting aliases!
  aliases = {}  # type: Dict[str, Any]
  # parse `` and a[x+1]=bar differently

  loader = pyutil.GetResourceLoader()
  oil_grammar = meta.LoadOilGrammar(loader)

  parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, oil_grammar,
                                     one_pass_parse=True)

  line_reader = reader.FileLineReader(mylib.Stdin(), arena)
  c_parser = parse_ctx.MakeOshParser(line_reader)

  try:
    node = main_loop.ParseWholeFile(c_parser)
  except util.ParseError as e:
    ui.PrettyPrintError(e, arena)
    return 2
  assert node is not None

  tree = node.AbbreviatedTree()
  #tree = node.PrettyTree()

  ast_f = fmt.DetectConsoleOutput(mylib.Stdout())
  fmt.PrintTree(tree, ast_f)
  ast_f.write('\n')

  return 0
Ejemplo n.º 6
0
def main(argv):
    # type: (List[str]) -> int
    pool = alloc.Pool()
    arena = pool.NewArena()
    arena.PushSource('<stdin>')

    line_reader = reader.FileLineReader(sys.stdin, arena)
    # Dummy value; not respecting aliases!
    aliases = {}  # type: Dict[str, Any]
    # parse `` and a[x+1]=bar differently
    parse_ctx = parse_lib.ParseContext(arena, aliases, one_pass_parse=True)
    c_parser = parse_ctx.MakeOshParser(line_reader)

    try:
        node = main_loop.ParseWholeFile(c_parser)
    except util.ParseError as e:
        ui.PrettyPrintError(e, arena)
        return 2
    assert node is not None

    tree = node.AbbreviatedTree()
    #tree = node.PrettyTree()

    ast_f = fmt.DetectConsoleOutput(sys.stdout)
    fmt.PrintTree(tree, ast_f)
    ast_f.write('\n')

    return 0
Ejemplo n.º 7
0
    def testNoInfiniteLoop(self):
        # This was ONE place where we got an infinite loop.

        with open('testdata/completion/return-124.bash') as f:
            code_str = f.read()
        trail = parse_lib.Trail()
        arena = test_lib.MakeArena('<completion_test.py>')
        parse_opts = parse_lib.OilParseOptions()
        parse_ctx = parse_lib.ParseContext(arena,
                                           parse_opts, {},
                                           None,
                                           trail=trail)

        comp_lookup = completion.Lookup()
        ex = test_lib.EvalCode(code_str, parse_ctx, comp_lookup=comp_lookup)

        r = _MakeRootCompleter(parse_ctx=parse_ctx, comp_lookup=comp_lookup)

        m = list(r.Matches(MockApi('bad ')))
        self.assertEqual([], sorted(m))

        # Error: spec not changed
        m = list(r.Matches(MockApi('both ')))
        self.assertEqual([], sorted(m))

        # Redefines completions
        m = list(r.Matches(MockApi('both2 ')))
        self.assertEqual(['both2 b1 ', 'both2 b2 '], sorted(m))
Ejemplo n.º 8
0
def _MakeHistoryEvaluator(history_items):
    arena = test_lib.MakeArena('<reader_test.py>')
    trail = parse_lib.Trail()
    parse_ctx = parse_lib.ParseContext(arena, {}, trail=trail)
    debug_f = util.DebugFile(sys.stdout)
    readline = _MockReadlineHistory(history_items)
    return reader.HistoryEvaluator(readline, parse_ctx, debug_f)
Ejemplo n.º 9
0
def InitExecutor(comp_state=None, arena=None, mem=None):
  arena = arena or MakeArena('<InitExecutor>')

  mem = mem or state.Mem('', [], {}, arena)
  fd_state = process.FdState()
  funcs = {}

  comp_state = comp_state or completion.State()
  readline = None  # simulate not having it
  builtins = {  # Lookup
      builtin_e.HISTORY: builtin.History(readline),

      builtin_e.COMPOPT: builtin_comp.CompOpt(comp_state),
      builtin_e.COMPADJUST: builtin_comp.CompAdjust(mem),
  }

  # For the tests, we do not use 'readline'.
  exec_opts = state.ExecOpts(mem, None)
  parse_ctx = parse_lib.ParseContext(arena, {})

  debug_f = util.DebugFile(sys.stderr)
  devtools = dev.DevTools(dev.CrashDumper(''), debug_f, debug_f)

  ex = cmd_exec.Executor(mem, fd_state, funcs, builtins, exec_opts,
                         parse_ctx, devtools)

  # Add some builtins that depend on the executor!
  complete_builtin = builtin_comp.Complete(ex, comp_state)  # used later
  builtins[builtin_e.COMPLETE] = complete_builtin
  builtins[builtin_e.COMPGEN] = builtin_comp.CompGen(ex)

  return ex
Ejemplo n.º 10
0
    def testCompletesAliases(self):
        # I put some aliases in this file.
        with open('testdata/completion/osh-unit.bash') as f:
            code_str = f.read()
        trail = parse_lib.Trail()
        arena = alloc.SideArena('<completion_test.py>')
        parse_ctx = parse_lib.ParseContext(arena, {}, trail=trail)
        comp_lookup = completion.Lookup()

        ex = test_lib.EvalCode(code_str, parse_ctx, comp_lookup=comp_lookup)

        r = _MakeRootCompleter(parse_ctx=parse_ctx, comp_lookup=comp_lookup)

        # The original command
        m = list(r.Matches(MockApi('ls ')))
        self.assertEqual(['ls one ', 'ls two '], sorted(m))

        # Alias for the command
        m = list(r.Matches(MockApi('ll ')))
        self.assertEqual(['ll one ', 'll two '], sorted(m))

        # DOUBLE alias expansion goes back to original
        m = list(r.Matches(MockApi('ll_classify ')))
        self.assertEqual(['ll_classify one ', 'll_classify two '], sorted(m))

        # Trailing space
        m = list(r.Matches(MockApi('ll_trailing ')))
        self.assertEqual(['ll_trailing one ', 'll_trailing two '], sorted(m))

        # It should NOT clobber completio registered for aliases
        m = list(r.Matches(MockApi('ll_own_completion ')))
        self.assertEqual(
            ['ll_own_completion own ', 'll_own_completion words '], sorted(m))
Ejemplo n.º 11
0
    def testRunsUserDefinedFunctions(self):
        # This is here because it's hard to test readline with the spec tests.
        with open('testdata/completion/osh-unit.bash') as f:
            code_str = f.read()
        trail = parse_lib.Trail()
        arena = test_lib.MakeArena('<completion_test.py>')
        parse_opts = parse_lib.OilParseOptions()
        parse_ctx = parse_lib.ParseContext(arena,
                                           parse_opts, {},
                                           None,
                                           trail=trail)
        comp_lookup = completion.Lookup()
        ex = test_lib.EvalCode(code_str, parse_ctx, comp_lookup=comp_lookup)

        r = _MakeRootCompleter(comp_lookup=comp_lookup)

        # By default, we get a space on the end.
        m = list(r.Matches(MockApi('mywords t')))
        self.assertEqual(['mywords three ', 'mywords two '], sorted(m))

        # No space
        m = list(r.Matches(MockApi('mywords_nospace t')))
        self.assertEqual(['mywords_nospace three', 'mywords_nospace two'],
                         sorted(m))

        # Filtered out two and bin
        m = list(r.Matches(MockApi('flagX ')))
        self.assertEqual(['flagX one ', 'flagX three '], sorted(m))

        # Filter out everything EXCEPT two and bin
        m = list(r.Matches(MockApi('flagX_bang ')))
        self.assertEqual(['flagX_bang bin ', 'flagX_bang two '], sorted(m))

        # -X with -P
        m = list(r.Matches(MockApi('flagX_prefix ')))
        self.assertEqual(['flagX_prefix __one ', 'flagX_prefix __three '],
                         sorted(m))

        # -P with plusdirs
        m = list(r.Matches(MockApi('prefix_plusdirs b')))
        self.assertEqual([
            'prefix_plusdirs __bin ', 'prefix_plusdirs benchmarks/',
            'prefix_plusdirs bin/', 'prefix_plusdirs build/'
        ], sorted(m))

        # -X with plusdirs.  We're filtering out bin/, and then it's added back by
        # plusdirs.  The filter doesn't kill it.
        m = list(r.Matches(MockApi('flagX_plusdirs b')))
        self.assertEqual([
            'flagX_plusdirs benchmarks/', 'flagX_plusdirs bin/',
            'flagX_plusdirs build/'
        ], sorted(m))

        # -P with dirnames.  -P is NOT respected.
        m = list(r.Matches(MockApi('prefix_dirnames b')))
        self.assertEqual([
            'prefix_dirnames benchmarks/', 'prefix_dirnames bin/',
            'prefix_dirnames build/'
        ], sorted(m))
Ejemplo n.º 12
0
def InitParseContext(arena=None, oil_grammar=None, aliases=None):
    arena = arena or MakeArena('<test_lib>')
    if aliases is None:
        aliases = {}
    opt_array = [False] * option_i.ARRAY_SIZE
    parse_opts = optview.Parse(opt_array)
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, oil_grammar)
    return parse_ctx
Ejemplo n.º 13
0
def _MakeHistoryEvaluator(history_items):
    arena = test_lib.MakeArena('<reader_test.py>')
    parse_opts = parse_lib.OilParseOptions()
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, None)
    parse_ctx.Init_Trail(parse_lib.Trail())

    debug_f = util.DebugFile(sys.stdout)
    readline = _MockReadlineHistory(history_items)
    return history.Evaluator(readline, parse_ctx, debug_f)
Ejemplo n.º 14
0
    def __init__(self, script_path=None):

        # generally, defer work until we know the script loaded
        with (open(script_path) if script_path else sys.stdin) as script:
            arena = alloc.Arena()
            parse_ctx = parse_lib.ParseContext(
                arena=arena,
                parse_opts=optview.Parse(NO_OPTIONS),
                aliases={},  # dummy
                oil_grammar=None,
            )
            parse_ctx.Init_OnePassParse(True)

            if script_path:
                # TODO: is there a real difference between using mainfile and
                # sourcedfile? (this gets re-used for sourced scripts)
                arena.PushSource(source.MainFile(script_path))
            else:
                arena.PushSource(source.Stdin())

            try:
                node = main_loop.ParseWholeFile(
                    self._make_parser(parse_ctx, script, arena))
            except error.Parse as e:
                ui.PrettyPrintError(e, arena)
                raise

        assert node is not None

        # actually initialize
        self.arena = arena
        # TODO: not certain we don't want more, but minimize for now
        self.aliases = set()
        self.builtins = defaultdict(list)
        self.commands = defaultdict(list)
        self.sources = defaultdict(list)
        self.funcs_defined = set()
        self.resolved_commands = dict()
        self.resolved_functions = dict()
        self.resolved_aliases = dict()
        self.resolved_source = dict()
        self.parsed_source = dict()
        self.unresolved_commands = set()
        # unresolved functions doesn't make sense because we can't disambiguate an unresolved function from an unresolved external command...
        self.unresolved_source = set()
        self.word_obs = dict()

        # "resolve"
        try:
            self.Visit(node)
            self.resolve_records()
        except ResolutionError as e:
            e.print_if_needed()
            raise
Ejemplo n.º 15
0
def InitWordParser(word_str, oil_at=False, arena=None):
    arena = arena or MakeArena('<test_lib>')
    parse_opts = parse_lib.OilParseOptions()
    parse_opts.parse_at = oil_at
    loader = pyutil.GetResourceLoader()
    oil_grammar = meta.LoadOilGrammar(loader)
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, oil_grammar)
    line_reader, _ = InitLexer(word_str, arena)
    c_parser = parse_ctx.MakeOshParser(line_reader)
    # Hack
    return c_parser.w_parser
Ejemplo n.º 16
0
  def setUp(self):
    """Done on every test."""
    self.arena = alloc.Arena()
    self.arena.PushSource(source.Unused(''))
    parse_opts = parse_lib.OilParseOptions()

    loader = pyutil.GetResourceLoader()
    oil_grammar = meta.LoadOilGrammar(loader)

    self.parse_ctx = parse_lib.ParseContext(self.arena, parse_opts, {},
                                            oil_grammar, one_pass_parse=True)
Ejemplo n.º 17
0
def InitWordParser(word_str, oil_at=False, arena=None):
    arena = arena or MakeArena('<test_lib>')
    opt_array = [False] * option_i.ARRAY_SIZE
    parse_opts = optview.Parse(opt_array)
    opt_array[option_i.parse_at] = oil_at
    loader = pyutil.GetResourceLoader()
    oil_grammar = meta.LoadOilGrammar(loader)
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, oil_grammar)
    line_reader, _ = InitLexer(word_str, arena)
    c_parser = parse_ctx.MakeOshParser(line_reader)
    # Hack
    return c_parser.w_parser
Ejemplo n.º 18
0
def InitParseContext(arena=None, oil_grammar=None, aliases=None,
                     parse_opts=None):
  arena = arena or MakeArena('<test_lib>')

  if aliases is None:
    aliases = {}

  mem = state.Mem('', [], arena, [])
  if parse_opts is None:
    parse_opts, exec_opts, mutable_opts = state.MakeOpts(mem, None)

  parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, oil_grammar)
  return parse_ctx
Ejemplo n.º 19
0
def main(argv):
    init_code = ' echo hi >&2 '

    arena = test_lib.MakeArena('<InitCompletionTest>')
    parse_ctx = parse_lib.ParseContext(arena, {})
    mem = state.Mem('', [], {}, arena)

    comp_lookup = completion.Lookup()
    ex = test_lib.EvalCode(init_code,
                           parse_ctx,
                           comp_lookup=comp_lookup,
                           mem=mem)

    print('hi')
Ejemplo n.º 20
0
def InitWordParser(word_str, oil_at=False, arena=None):
  arena = arena or MakeArena('<test_lib>')

  mem = state.Mem('', [], arena, [])
  parse_opts, exec_opts, mutable_opts = state.MakeOpts(mem, None)

  # CUSTOM SETTING
  mutable_opts.opt0_array[option_i.parse_at] = oil_at

  loader = pyutil.GetResourceLoader()
  oil_grammar = pyutil.LoadOilGrammar(loader)
  parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, oil_grammar)
  line_reader, _ = InitLexer(word_str, arena)
  c_parser = parse_ctx.MakeOshParser(line_reader)
  # Hack
  return c_parser.w_parser
Ejemplo n.º 21
0
def _MakeRootCompleter(comp_state=None):
    comp_state = comp_state or completion.State()
    ev = test_lib.MakeTestEvaluator()

    pool = alloc.Pool()
    arena = pool.NewArena()
    arena.PushSource('<_MakeRootCompleter>')
    trail = parse_lib.Trail()
    parse_ctx = parse_lib.ParseContext(arena, {}, trail=trail)
    if 0:  # enable for details
        debug_f = util.DebugFile(sys.stdout)
    else:
        debug_f = util.NullDebugFile()
    progress_f = ui.TestStatusLine()
    return completion.RootCompleter(ev, comp_state, mem, parse_ctx, progress_f,
                                    debug_f)
Ejemplo n.º 22
0
def _Detect(test, word_str, expected):
  # TODO: This function could be moved to test_lib.
  log('-'*80)
  w = word_parse_test._assertReadWord(test, word_str)

  actual = word_.DetectShAssignment(w)
  left_token, close_token, part_offset = actual

  expected_left, expected_close, expected_part_offset = expected

  print(left_token, close_token, part_offset)
  print()

  if expected_left is None:
    test.assertEqual(None, left_token)
  else:
    test.assertEqual(expected_left, left_token.id)

  if expected_close is None:
    test.assertEqual(None, close_token)
  else:
    test.assertEqual(expected_left, left_token.id)

  test.assertEqual(expected_part_offset, part_offset)

  arena = test_lib.MakeArena('word_test.py')
  parse_opts = parse_lib.OilParseOptions()
  parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, None)

  if left_token and left_token.id in (Id.Lit_VarLike, Id.Lit_ArrayLhsOpen):
    more_env = []
    preparsed = (left_token, close_token, part_offset, w)
    try:
      cmd_parse._AppendMoreEnv([preparsed], more_env)
    except Exception as e:
      log('Error: %s', e)
    else:
      log('more_env: %s', more_env)

    try:
      assign_pair = cmd_parse._MakeAssignPair(parse_ctx, preparsed)
    except Exception as e:
      log('Error: %s', e)
    else:
      log('assign_pair: %s', assign_pair)
Ejemplo n.º 23
0
def _MakeRootCompleter(parse_ctx=None, comp_lookup=None):
    #comp_state = comp_state or completion.State()
    compopt_state = completion.OptionState()
    comp_ui_state = comp_ui.State()
    comp_lookup = comp_lookup or completion.Lookup()
    ev = test_lib.MakeTestEvaluator()

    if not parse_ctx:
        arena = alloc.Arena()
        arena.PushSource(source.MainFile('<_MakeRootCompleter>'))
        parse_opts = parse_lib.OilParseOptions()
        parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, None)
        parse_ctx.Init_Trail(parse_lib.Trail())
        parse_ctx.Init_OnePassParse(True)

    if 1:  # enable for details
        debug_f = util.DebugFile(sys.stdout)
    else:
        debug_f = util.NullDebugFile()
    return completion.RootCompleter(ev, mem, comp_lookup, compopt_state,
                                    comp_ui_state, parse_ctx, debug_f)
Ejemplo n.º 24
0
def _MakeRootCompleter(parse_ctx=None, comp_lookup=None):
    #comp_state = comp_state or completion.State()
    compopt_state = completion.OptionState()
    comp_ui_state = comp_ui.State()
    comp_lookup = comp_lookup or completion.Lookup()
    ev = test_lib.MakeTestEvaluator()

    if not parse_ctx:
        pool = alloc.Pool()
        arena = pool.NewArena()
        arena.PushSource('<_MakeRootCompleter>')
        trail = parse_lib.Trail()
        parse_ctx = parse_lib.ParseContext(arena, {},
                                           trail=trail,
                                           one_pass_parse=True)

    if 1:  # enable for details
        debug_f = util.DebugFile(sys.stdout)
    else:
        debug_f = util.NullDebugFile()
    return completion.RootCompleter(ev, mem, comp_lookup, compopt_state,
                                    comp_ui_state, parse_ctx, debug_f)
Ejemplo n.º 25
0
def TeaMain(argv):
    # type: (str, List[str]) -> int
    arena = alloc.Arena()
    try:
        script_name = argv[1]
        arena.PushSource(source.MainFile(script_name))
    except IndexError:
        arena.PushSource(source.Stdin())
        f = sys.stdin
    else:
        try:
            f = open(script_name)
        except IOError as e:
            stderr_line("tea: Couldn't open %r: %s", script_name,
                        posix.strerror(e.errno))
            return 2

    aliases = {}  # Dummy value; not respecting aliases!

    loader = pyutil.GetResourceLoader()
    oil_grammar = pyutil.LoadOilGrammar(loader)

    # Not used in tea, but OK...
    opt0_array = state.InitOpts()
    parse_opts = optview.Parse(opt0_array)

    # parse `` and a[x+1]=bar differently
    parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, oil_grammar)

    line_reader = reader.FileLineReader(f, arena)

    try:
        parse_ctx.ParseTeaModule(line_reader)
        status = 0
    except error.Parse as e:
        ui.PrettyPrintError(e, arena)
        status = 2

    return status
Ejemplo n.º 26
0
def main(argv):
    # type: (List[str]) -> int
    arena = alloc.Arena()

    opt_array = [False] * option_i.ARRAY_SIZE
    parse_opts = optview.Parse(opt_array)
    # Dummy value; not respecting aliases!
    aliases = {}  # type: Dict[str, str]
    # parse `` and a[x+1]=bar differently

    oil_grammar = None  # type: Grammar
    if mylib.PYTHON:
        loader = pyutil.GetResourceLoader()
        oil_grammar = pyutil.LoadOilGrammar(loader)

    parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, oil_grammar)

    pretty_print = True

    if len(argv) == 1:
        line_reader = reader.FileLineReader(mylib.Stdin(), arena)
        src = source.Stdin('')  # type: source_t

    elif len(argv) == 2:
        path = argv[1]
        f = mylib.open(path)
        line_reader = reader.FileLineReader(f, arena)
        src = source.MainFile(path)

    elif len(argv) == 3:
        if argv[1] == '-c':
            # This path is easier to run through GDB
            line_reader = reader.StringLineReader(argv[2], arena)
            src = source.CFlag()

        elif argv[1] == '-n':  # For benchmarking, allow osh_parse -n file.txt
            path = argv[2]
            f = mylib.open(path)
            line_reader = reader.FileLineReader(f, arena)
            src = source.MainFile(path)
            # This is like --ast-format none, which benchmarks/osh-helper.sh passes.
            pretty_print = False

        else:
            raise AssertionError()

    else:
        raise AssertionError()

    arena.PushSource(src)

    c_parser = parse_ctx.MakeOshParser(line_reader)

    try:
        #node = main_loop.ParseWholeFile(c_parser)
        node = ParseWholeFile(c_parser)
    except error.Parse as e:
        ui.PrettyPrintError(e, arena)
        return 2
    assert node is not None

    # C++ doesn't have the abbreviations yet (though there are some differences
    # like omitting spids)
    #tree = node.AbbreviatedTree()
    if pretty_print:
        tree = node.PrettyTree()

        ast_f = fmt.DetectConsoleOutput(mylib.Stdout())
        fmt.PrintTree(tree, ast_f)
        ast_f.write('\n')

    return 0
Ejemplo n.º 27
0
def OshCommandMain(argv):
    """Run an 'oshc' tool.

  'osh' is short for "osh compiler" or "osh command".

  TODO:
  - oshc --help

  oshc deps
    --path: the $PATH to use to find executables.  What about libraries?

    NOTE: we're leaving out su -c, find, xargs, etc.?  Those should generally
    run functions using the $0 pattern.
    --chained-command sudo
  """
    try:
        action = argv[0]
    except IndexError:
        raise args.UsageError('oshc: Missing required subcommand.')

    if action not in SUBCOMMANDS:
        raise args.UsageError('oshc: Invalid subcommand %r.' % action)

    try:
        script_name = argv[1]
    except IndexError:
        script_name = '<stdin>'
        f = sys.stdin
    else:
        try:
            f = open(script_name)
        except IOError as e:
            util.error("Couldn't open %r: %s", script_name,
                       posix.strerror(e.errno))
            return 2

    pool = alloc.Pool()
    arena = pool.NewArena()
    arena.PushSource(script_name)

    line_reader = reader.FileLineReader(f, arena)
    aliases = {}  # Dummy value; not respecting aliases!
    parse_ctx = parse_lib.ParseContext(arena, aliases)
    c_parser = parse_ctx.MakeOshParser(line_reader)

    try:
        node = main_loop.ParseWholeFile(c_parser)
    except util.ParseError as e:
        ui.PrettyPrintError(e, arena, sys.stderr)
        return 2
    assert node is not None

    f.close()

    # Columns for list-*
    # path line name
    # where name is the binary path, variable name, or library path.

    # bin-deps and lib-deps can be used to make an app bundle.
    # Maybe I should list them together?  'deps' can show 4 columns?
    #
    # path, line, type, name
    #
    # --pretty can show the LST location.

    # stderr: show how we're following imports?

    if action == 'translate':
        osh2oil.PrintAsOil(arena, node)

    elif action == 'arena':  # for debugging
        osh2oil.PrintArena(arena)

    elif action == 'spans':  # for debugging
        osh2oil.PrintSpans(arena)

    elif action == 'format':
        # TODO: autoformat code
        raise NotImplementedError(action)

    elif action == 'deps':
        deps.Deps(node)

    elif action == 'undefined-vars':  # could be environment variables
        raise NotImplementedError

    else:
        raise AssertionError  # Checked above

    return 0
Ejemplo n.º 28
0
def ShellMain(lang, argv0, argv, login_shell):
    """Used by bin/osh and bin/oil.

  Args:
    lang: 'osh' or 'oil'
    argv0, argv: So we can also invoke bin/osh as 'oil.ovm osh'.  Like busybox.
    login_shell: Was - on the front?
  """
    # Differences between osh and oil:
    # - --help?  I guess Oil has a SUPERSET of OSH options.
    # - oshrc vs oilrc
    # - the parser and executor
    # - Change the prompt in the interactive shell?

    assert lang in ('osh', 'oil'), lang

    arg_r = args.Reader(argv)
    try:
        opts = OSH_SPEC.Parse(arg_r)
    except args.UsageError as e:
        ui.usage('osh usage error: %s', e)
        return 2

    if opts.help:
        loader = util.GetResourceLoader()
        builtin.Help(['%s-usage' % lang], loader)
        return 0
    if opts.version:
        # OSH version is the only binary in Oil right now, so it's all one version.
        _ShowVersion()
        return 0

    # TODO: This should be in interactive mode only?
    builtin.RegisterSigIntHandler()

    if arg_r.AtEnd():
        dollar0 = argv0
        has_main = False
    else:
        dollar0 = arg_r.Peek()  # the script name, or the arg after -c
        has_main = True

    pool = alloc.Pool()
    arena = pool.NewArena()

    # NOTE: has_main is only for ${BASH_SOURCE[@} and family.  Could be a
    # required arg.
    mem = state.Mem(dollar0,
                    argv[arg_r.i + 1:],
                    posix.environ,
                    arena,
                    has_main=has_main)
    funcs = {}

    fd_state = process.FdState()
    exec_opts = state.ExecOpts(mem, readline)
    builtin.SetExecOpts(exec_opts, opts.opt_changes)
    aliases = {}  # feedback between runtime and parser

    parse_ctx = parse_lib.ParseContext(arena, aliases)  # For main_loop

    # Three ParseContext instances SHARE aliases.  TODO: Complete aliases.
    comp_arena = pool.NewArena()
    comp_arena.PushSource('<completion>')
    trail1 = parse_lib.Trail()
    comp_ctx = parse_lib.ParseContext(comp_arena, aliases, trail=trail1)

    hist_arena = pool.NewArena()
    hist_arena.PushSource('<history>')
    trail2 = parse_lib.Trail()
    hist_ctx = parse_lib.ParseContext(hist_arena, aliases, trail=trail2)

    # Deps helps manages dependencies.  These dependencies are circular:
    # - ex and word_ev, arith_ev -- for command sub, arith sub
    # - arith_ev and word_ev -- for $(( ${a} )) and $x$(( 1 ))
    # - ex and builtins (which execute code, like eval)
    # - prompt_ev needs word_ev for $PS1, which needs prompt_ev for @P
    exec_deps = cmd_exec.Deps()

    if opts.debug_file:
        debug_f = util.DebugFile(fd_state.Open(opts.debug_file, mode='w'))
    else:
        debug_f = util.NullDebugFile()
    exec_deps.debug_f = debug_f

    debug_f.log('Debug file is %s', opts.debug_file)

    splitter = split.SplitContext(mem)
    exec_deps.splitter = splitter

    # Controlled by env variable, flag, or hook?
    exec_deps.dumper = dev.CrashDumper(
        posix.environ.get('OSH_CRASH_DUMP_DIR', ''))

    if opts.xtrace_to_debug_file:
        trace_f = debug_f
    else:
        trace_f = util.DebugFile(sys.stderr)
    exec_deps.trace_f = trace_f

    # TODO: Separate comp_state and comp_lookup.
    comp_state = completion.State()
    comp_lookup = completion.Lookup()

    builtins = {  # Lookup
        builtin_e.HISTORY: builtin.History(readline),

        builtin_e.COMPOPT: builtin_comp.CompOpt(comp_state),
        builtin_e.COMPADJUST: builtin_comp.CompAdjust(mem),
    }
    ex = cmd_exec.Executor(mem, fd_state, funcs, builtins, exec_opts,
                           parse_ctx, exec_deps)
    exec_deps.ex = ex

    word_ev = word_eval.NormalWordEvaluator(mem, exec_opts, exec_deps, arena)
    exec_deps.word_ev = word_ev

    arith_ev = expr_eval.ArithEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.arith_ev = arith_ev
    word_ev.arith_ev = arith_ev  # Another circular dependency

    bool_ev = expr_eval.BoolEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.bool_ev = bool_ev

    tracer = cmd_exec.Tracer(parse_ctx, exec_opts, mem, word_ev, trace_f)
    exec_deps.tracer = tracer

    # HACK for circular deps
    ex.word_ev = word_ev
    ex.arith_ev = arith_ev
    ex.bool_ev = bool_ev
    ex.tracer = tracer

    spec_builder = builtin_comp.SpecBuilder(ex, parse_ctx, word_ev, splitter)
    # Add some builtins that depend on the executor!
    complete_builtin = builtin_comp.Complete(spec_builder,
                                             comp_lookup)  # used later
    builtins[builtin_e.COMPLETE] = complete_builtin
    builtins[builtin_e.COMPGEN] = builtin_comp.CompGen(spec_builder)

    if lang == 'oil':
        # The Oil executor wraps an OSH executor?  It needs to be able to source
        # it.
        ex = oil_cmd_exec.OilExecutor(ex)

    # PromptEvaluator rendering is needed in non-interactive shells for @P.
    prompt_ev = ui.PromptEvaluator(lang, arena, parse_ctx, ex, mem)
    exec_deps.prompt_ev = prompt_ev
    word_ev.prompt_ev = prompt_ev  # HACK for circular deps

    # History evaluation is a no-op if readline is None.
    hist_ev = reader.HistoryEvaluator(readline, hist_ctx, debug_f)

    # Calculate ~/.config/oil/oshrc or oilrc
    # Use ~/.config/oil to avoid cluttering the user's home directory.  Some
    # users may want to ln -s ~/.config/oil/oshrc ~/oshrc or ~/.oshrc.

    # https://unix.stackexchange.com/questions/24347/why-do-some-applications-use-config-appname-for-their-config-data-while-other
    home_dir = mem.GetVar('HOME')
    assert home_dir.tag == value_e.Str, home_dir
    rc_path = opts.rcfile or os_path.join(home_dir.s, '.config/oil',
                                          lang + 'rc')

    history_filename = os_path.join(home_dir.s, '.config/oil',
                                    'history_' + lang)

    if opts.c is not None:
        arena.PushSource('<command string>')
        line_reader = reader.StringLineReader(opts.c, arena)
        if opts.i:  # -c and -i can be combined
            exec_opts.interactive = True

    elif opts.i:  # force interactive
        arena.PushSource('<stdin -i>')
        # interactive shell only
        line_reader = reader.InteractiveLineReader(arena, prompt_ev, hist_ev)
        exec_opts.interactive = True

    else:
        try:
            script_name = arg_r.Peek()
        except IndexError:
            if sys.stdin.isatty():
                arena.PushSource('<interactive>')
                # interactive shell only
                line_reader = reader.InteractiveLineReader(
                    arena, prompt_ev, hist_ev)
                exec_opts.interactive = True
            else:
                arena.PushSource('<stdin>')
                line_reader = reader.FileLineReader(sys.stdin, arena)
        else:
            arena.PushSource(script_name)
            try:
                f = fd_state.Open(script_name)
            except OSError as e:
                util.error("Couldn't open %r: %s", script_name,
                           posix.strerror(e.errno))
                return 1
            line_reader = reader.FileLineReader(f, arena)

    # TODO: assert arena.NumSourcePaths() == 1
    # TODO: .rc file needs its own arena.
    if lang == 'osh':
        c_parser = parse_ctx.MakeOshParser(line_reader)
    else:
        c_parser = parse_ctx.MakeOilParser(line_reader)

    if exec_opts.interactive:
        # NOTE: We're using a different evaluator here.  The completion system can
        # also run functions... it gets the Executor through Executor._Complete.
        if readline:
            ev = word_eval.CompletionWordEvaluator(mem, exec_opts, exec_deps,
                                                   arena)
            progress_f = ui.StatusLine()
            root_comp = completion.RootCompleter(ev, mem, comp_lookup,
                                                 comp_state, comp_ctx,
                                                 progress_f, debug_f)
            _InitReadline(readline, history_filename, root_comp, debug_f)
            _InitDefaultCompletions(ex, complete_builtin, comp_lookup)

        # NOTE: Call this AFTER _InitDefaultCompletions.
        SourceStartupFile(rc_path, lang, parse_ctx, ex)

        return main_loop.Interactive(opts, ex, c_parser, arena)

    # TODO: Remove this after removing it from benchmarks/osh-runtime.  It's no
    # longer relevant with main_loop.
    if opts.parser_mem_dump:
        # This might be superstition, but we want to let the value stabilize
        # after parsing.  bash -c 'cat /proc/$$/status' gives different results
        # with a sleep.
        time.sleep(0.001)
        input_path = '/proc/%d/status' % posix.getpid()
        with open(input_path) as f, open(opts.parser_mem_dump, 'w') as f2:
            contents = f.read()
            f2.write(contents)
            log('Wrote %s to %s (--parser-mem-dump)', input_path,
                opts.parser_mem_dump)

    nodes_out = [] if exec_opts.noexec else None

    _tlog('Execute(node)')
    status = main_loop.Batch(ex, c_parser, arena, nodes_out=nodes_out)

    # Only print nodes if the whole parse succeeded.
    if nodes_out is not None and status == 0:
        ui.PrintAst(nodes_out, opts)

    # NOTE: 'exit 1' is ControlFlow and gets here, but subshell/commandsub
    # don't because they call sys.exit().
    if opts.runtime_mem_dump:
        # This might be superstition, but we want to let the value stabilize
        # after parsing.  bash -c 'cat /proc/$$/status' gives different results
        # with a sleep.
        time.sleep(0.001)
        input_path = '/proc/%d/status' % posix.getpid()
        with open(input_path) as f, open(opts.runtime_mem_dump, 'w') as f2:
            contents = f.read()
            f2.write(contents)
            log('Wrote %s to %s (--runtime-mem-dump)', input_path,
                opts.runtime_mem_dump)

    # NOTE: This doesn't cause any spec tests to fail, but it could.
    if posix.environ.get('ASDL_TYPE_CHECK'):
        log('NOTE: Performed %d ASDL_TYPE_CHECKs.', runtime.NUM_TYPE_CHECKS)

    # NOTE: We haven't closed the file opened with fd_state.Open
    return status
Ejemplo n.º 29
0
Archivo: oil.py Proyecto: rbs-pli/oil
def ShellMain(lang, argv0, argv, login_shell):
    """Used by bin/osh and bin/oil.

  Args:
    lang: 'osh' or 'oil'
    argv0, argv: So we can also invoke bin/osh as 'oil.ovm osh'.  Like busybox.
    login_shell: Was - on the front?
  """
    # Differences between osh and oil:
    # - --help?  I guess Oil has a SUPERSET of OSH options.
    # - oshrc vs oilrc
    # - the parser and executor
    # - Change the prompt in the interactive shell?

    assert lang in ('osh', 'oil'), lang

    arg_r = args.Reader(argv)
    try:
        opts = OSH_SPEC.Parse(arg_r)
    except args.UsageError as e:
        ui.usage('osh usage error: %s', e)
        return 2

    # NOTE: This has a side effect of deleting _OVM_* from the environment!
    # TODO: Thread this throughout the program, and get rid of the global
    # variable in core/util.py.  Rename to InitResourceLaoder().  It's now only
    # used for the 'help' builtin and --version.
    loader = pyutil.GetResourceLoader()

    if opts.help:
        builtin.Help(['%s-usage' % lang], loader)
        return 0
    if opts.version:
        # OSH version is the only binary in Oil right now, so it's all one version.
        _ShowVersion()
        return 0

    if arg_r.AtEnd():
        dollar0 = argv0
        has_main = False
    else:
        dollar0 = arg_r.Peek()  # the script name, or the arg after -c
        has_main = True

    arena = alloc.Arena()

    # NOTE: has_main is only for ${BASH_SOURCE[@} and family.  Could be a
    # required arg.
    mem = state.Mem(dollar0,
                    argv[arg_r.i + 1:],
                    posix.environ,
                    arena,
                    has_main=has_main)
    funcs = {}

    fd_state = process.FdState()
    exec_opts = state.ExecOpts(mem, line_input)
    builtin.SetExecOpts(exec_opts, opts.opt_changes)
    aliases = {}  # feedback between runtime and parser

    if opts.one_pass_parse and not exec_opts.noexec:
        raise args.UsageError('--one-pass-parse requires noexec (-n)')
    parse_ctx = parse_lib.ParseContext(arena,
                                       aliases,
                                       one_pass_parse=opts.one_pass_parse)

    # Three ParseContext instances SHARE aliases.
    comp_arena = alloc.Arena()
    comp_arena.PushSource(source.Unused('completion'))
    trail1 = parse_lib.Trail()
    # one_pass_parse needs to be turned on to complete inside backticks.  TODO:
    # fix the issue where ` gets erased because it's not part of
    # set_completer_delims().
    comp_ctx = parse_lib.ParseContext(comp_arena,
                                      aliases,
                                      trail=trail1,
                                      one_pass_parse=True)

    hist_arena = alloc.Arena()
    hist_arena.PushSource(source.Unused('history'))
    trail2 = parse_lib.Trail()
    hist_ctx = parse_lib.ParseContext(hist_arena, aliases, trail=trail2)

    # Deps helps manages dependencies.  These dependencies are circular:
    # - ex and word_ev, arith_ev -- for command sub, arith sub
    # - arith_ev and word_ev -- for $(( ${a} )) and $x$(( 1 ))
    # - ex and builtins (which execute code, like eval)
    # - prompt_ev needs word_ev for $PS1, which needs prompt_ev for @P
    exec_deps = cmd_exec.Deps()

    my_pid = posix.getpid()

    debug_path = ''
    debug_dir = posix.environ.get('OSH_DEBUG_DIR')
    if opts.debug_file:  # --debug-file takes precedence over OSH_DEBUG_DIR
        debug_path = opts.debug_file
    elif debug_dir:
        debug_path = os_path.join(debug_dir, '%d-osh.log' % my_pid)

    if debug_path:
        # This will be created as an empty file if it doesn't exist, or it could be
        # a pipe.
        try:
            debug_f = util.DebugFile(fd_state.Open(debug_path, mode='w'))
        except OSError as e:
            util.error("Couldn't open %r: %s", debug_path,
                       posix.strerror(e.errno))
            return 2
    else:
        debug_f = util.NullDebugFile()

    exec_deps.debug_f = debug_f

    # Not using datetime for dependency reasons.  TODO: maybe show the date at
    # the beginning of the log, and then only show time afterward?  To save
    # space, and make space for microseconds.  (datetime supports microseconds
    # but time.strftime doesn't).
    iso_stamp = time.strftime("%Y-%m-%d %H:%M:%S")
    debug_f.log('%s [%d] OSH started with argv %s', iso_stamp, my_pid, argv)
    if debug_path:
        debug_f.log('Writing logs to %r', debug_path)

    interp = posix.environ.get('OSH_HIJACK_SHEBANG', '')
    exec_deps.ext_prog = process.ExternalProgram(interp, fd_state, debug_f)

    splitter = split.SplitContext(mem)
    exec_deps.splitter = splitter

    # This could just be OSH_DEBUG_STREAMS='debug crash' ?  That might be
    # stuffing too much into one, since a .json crash dump isn't a stream.
    crash_dump_dir = posix.environ.get('OSH_CRASH_DUMP_DIR', '')
    exec_deps.dumper = dev.CrashDumper(crash_dump_dir)

    if opts.xtrace_to_debug_file:
        trace_f = debug_f
    else:
        trace_f = util.DebugFile(sys.stderr)
    exec_deps.trace_f = trace_f

    comp_lookup = completion.Lookup()

    #
    # Various Global State objects to work around readline interfaces
    #

    compopt_state = completion.OptionState()
    comp_ui_state = comp_ui.State()
    prompt_state = comp_ui.PromptState()

    builtins = {  # Lookup
        builtin_e.HISTORY: builtin.History(line_input),

        builtin_e.COMPOPT: builtin_comp.CompOpt(compopt_state),
        builtin_e.COMPADJUST: builtin_comp.CompAdjust(mem),
    }
    ex = cmd_exec.Executor(mem, fd_state, funcs, builtins, exec_opts,
                           parse_ctx, exec_deps)
    exec_deps.ex = ex

    word_ev = word_eval.NormalWordEvaluator(mem, exec_opts, exec_deps, arena)
    exec_deps.word_ev = word_ev

    arith_ev = expr_eval.ArithEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.arith_ev = arith_ev
    word_ev.arith_ev = arith_ev  # Another circular dependency

    bool_ev = expr_eval.BoolEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.bool_ev = bool_ev

    tracer = dev.Tracer(parse_ctx, exec_opts, mem, word_ev, trace_f)
    exec_deps.tracer = tracer

    # HACK for circular deps
    ex.word_ev = word_ev
    ex.arith_ev = arith_ev
    ex.bool_ev = bool_ev
    ex.tracer = tracer

    spec_builder = builtin_comp.SpecBuilder(ex, parse_ctx, word_ev, splitter,
                                            comp_lookup)

    # Add some builtins that depend on the executor!
    complete_builtin = builtin_comp.Complete(spec_builder, comp_lookup)
    builtins[builtin_e.COMPLETE] = complete_builtin
    builtins[builtin_e.COMPGEN] = builtin_comp.CompGen(spec_builder)

    if lang == 'oil':
        # The Oil executor wraps an OSH executor?  It needs to be able to source
        # it.
        ex = oil_cmd_exec.OilExecutor(ex)

    # PromptEvaluator rendering is needed in non-interactive shells for @P.
    prompt_ev = prompt.Evaluator(lang, parse_ctx, ex, mem)
    exec_deps.prompt_ev = prompt_ev
    word_ev.prompt_ev = prompt_ev  # HACK for circular deps

    # History evaluation is a no-op if line_input is None.
    hist_ev = history.Evaluator(line_input, hist_ctx, debug_f)

    # Calculate ~/.config/oil/oshrc or oilrc
    # Use ~/.config/oil to avoid cluttering the user's home directory.  Some
    # users may want to ln -s ~/.config/oil/oshrc ~/oshrc or ~/.oshrc.

    # https://unix.stackexchange.com/questions/24347/why-do-some-applications-use-config-appname-for-their-config-data-while-other
    home_dir = process.GetHomeDir()
    assert home_dir is not None
    rc_path = opts.rcfile or os_path.join(home_dir, '.config/oil', lang + 'rc')

    history_filename = os_path.join(home_dir, '.config/oil', 'history_' + lang)

    if opts.c is not None:
        arena.PushSource(source.CFlag())
        line_reader = reader.StringLineReader(opts.c, arena)
        if opts.i:  # -c and -i can be combined
            exec_opts.interactive = True

    elif opts.i:  # force interactive
        arena.PushSource(source.Stdin(' -i'))
        # interactive shell only
        line_reader = reader.InteractiveLineReader(arena, prompt_ev, hist_ev,
                                                   line_input, prompt_state)
        exec_opts.interactive = True

    else:
        try:
            script_name = arg_r.Peek()
        except IndexError:
            if sys.stdin.isatty():
                arena.PushSource(source.Interactive())
                # interactive shell only
                line_reader = reader.InteractiveLineReader(
                    arena, prompt_ev, hist_ev, line_input, prompt_state)
                exec_opts.interactive = True
            else:
                arena.PushSource(source.Stdin(''))
                line_reader = reader.FileLineReader(sys.stdin, arena)
        else:
            arena.PushSource(source.MainFile(script_name))
            try:
                f = fd_state.Open(script_name)
            except OSError as e:
                util.error("Couldn't open %r: %s", script_name,
                           posix.strerror(e.errno))
                return 1
            line_reader = reader.FileLineReader(f, arena)

    # TODO: assert arena.NumSourcePaths() == 1
    # TODO: .rc file needs its own arena.
    if lang == 'osh':
        c_parser = parse_ctx.MakeOshParser(line_reader)
    else:
        c_parser = parse_ctx.MakeOilParser(line_reader)

    # NOTE: SIGINT is temporarily enabled during readline() by
    # frontend/reader.py.
    # It's treated differently than SIGQUIT and SIGTSTP because Python handles it
    # with KeyboardInterrupt.  We don't want KeyboardInterrupt at arbitrary
    # points in a non-interactive shell.  (e.g. osh -c 'sleep 5' then Ctrl-C)
    signal.signal(signal.SIGINT, signal.SIG_IGN)

    if exec_opts.interactive:
        if line_input:
            # NOTE: We're using a different WordEvaluator here.
            ev = word_eval.CompletionWordEvaluator(mem, exec_opts, exec_deps,
                                                   arena)
            root_comp = completion.RootCompleter(ev, mem, comp_lookup,
                                                 compopt_state, comp_ui_state,
                                                 comp_ctx, debug_f)

            term_width = 0
            if opts.completion_display == 'nice':
                try:
                    term_width = libc.get_terminal_width()
                except IOError:  # stdin not a terminal
                    pass

            if term_width != 0:
                display = comp_ui.NiceDisplay(term_width, comp_ui_state,
                                              prompt_state, debug_f,
                                              line_input)
            else:
                display = comp_ui.MinimalDisplay(comp_ui_state, prompt_state,
                                                 debug_f)

            _InitReadline(line_input, history_filename, root_comp, display,
                          debug_f)
            _InitDefaultCompletions(ex, complete_builtin, comp_lookup)

        else:  # Without readline module
            display = comp_ui.MinimalDisplay(comp_ui_state, prompt_state,
                                             debug_f)

        # The shell itself should ignore Ctrl-\.
        signal.signal(signal.SIGQUIT, signal.SIG_IGN)

        # This prevents Ctrl-Z from suspending OSH in interactive mode.  But we're
        # not getting notification via wait() that the child stopped?
        signal.signal(signal.SIGTSTP, signal.SIG_IGN)

        # Register a callback to receive terminal width changes.
        signal.signal(signal.SIGWINCH, lambda x, y: display.OnWindowChange())

        # NOTE: Call this AFTER _InitDefaultCompletions.
        SourceStartupFile(rc_path, lang, parse_ctx, ex)

        line_reader.Reset()  # After sourcing startup file, render $PS1
        return main_loop.Interactive(opts, ex, c_parser, display, arena)

    nodes_out = [] if exec_opts.noexec else None

    if nodes_out is None and opts.parser_mem_dump:
        raise args.UsageError('--parser-mem-dump can only be used with -n')

    _tlog('Execute(node)')
    status = main_loop.Batch(ex, c_parser, arena, nodes_out=nodes_out)

    # Only print nodes if the whole parse succeeded.
    if nodes_out is not None and status == 0:
        if opts.parser_mem_dump:  # only valid in -n mode
            # This might be superstition, but we want to let the value stabilize
            # after parsing.  bash -c 'cat /proc/$$/status' gives different results
            # with a sleep.
            time.sleep(0.001)
            input_path = '/proc/%d/status' % posix.getpid()
            with open(input_path) as f, open(opts.parser_mem_dump, 'w') as f2:
                contents = f.read()
                f2.write(contents)
                log('Wrote %s to %s (--parser-mem-dump)', input_path,
                    opts.parser_mem_dump)

        ui.PrintAst(nodes_out, opts)

    # NOTE: 'exit 1' is ControlFlow and gets here, but subshell/commandsub
    # don't because they call sys.exit().
    if opts.runtime_mem_dump:
        # This might be superstition, but we want to let the value stabilize
        # after parsing.  bash -c 'cat /proc/$$/status' gives different results
        # with a sleep.
        time.sleep(0.001)
        input_path = '/proc/%d/status' % posix.getpid()
        with open(input_path) as f, open(opts.runtime_mem_dump, 'w') as f2:
            contents = f.read()
            f2.write(contents)
            log('Wrote %s to %s (--runtime-mem-dump)', input_path,
                opts.runtime_mem_dump)

    # NOTE: We haven't closed the file opened with fd_state.Open
    return status
Ejemplo n.º 30
0
def InitExecutor(parse_ctx=None,
                 comp_lookup=None,
                 arena=None,
                 mem=None,
                 aliases=None,
                 ext_prog=None):
    if parse_ctx:
        arena = parse_ctx.arena
        parse_opts = parse_ctx.parse_opts
    else:
        arena or MakeArena('<InitExecutor>')
        parse_opts = parse_lib.OilParseOptions()
        parse_ctx = parse_lib.ParseContext(arena, parse_opts, {}, None)

    mem = mem or state.Mem('', [], {}, arena)
    exec_opts = state.ExecOpts(mem, parse_opts, None)
    errfmt = ui.ErrorFormatter(arena)
    job_state = process.JobState()
    fd_state = process.FdState(errfmt, job_state)
    funcs = {}
    aliases = {} if aliases is None else aliases

    compopt_state = completion.OptionState()
    comp_lookup = comp_lookup or completion.Lookup()

    readline = None  # simulate not having it
    new_var = builtin_assign.NewVar(mem, funcs, errfmt)
    builtins = {  # Lookup
        builtin_e.ECHO: builtin_pure.Echo(exec_opts),
        builtin_e.SHIFT: builtin_assign.Shift(mem),

        builtin_e.HISTORY: builtin.History(readline),

        builtin_e.COMPOPT: builtin_comp.CompOpt(compopt_state, errfmt),
        builtin_e.COMPADJUST: builtin_comp.CompAdjust(mem),

        builtin_e.ALIAS: builtin_pure.Alias(aliases, errfmt),
        builtin_e.UNALIAS: builtin_pure.UnAlias(aliases, errfmt),

        builtin_e.DECLARE: new_var,
        builtin_e.TYPESET: new_var,
        builtin_e.LOCAL: new_var,

        builtin_e.EXPORT: builtin_assign.Export(mem, errfmt),
        builtin_e.READONLY: builtin_assign.Readonly(mem, errfmt),
    }

    # For the tests, we do not use 'readline'.
    exec_opts = state.ExecOpts(mem, parse_opts, None)

    debug_f = util.DebugFile(sys.stderr)
    exec_deps = cmd_exec.Deps()
    exec_deps.search_path = state.SearchPath(mem)
    exec_deps.errfmt = errfmt
    exec_deps.trap_nodes = []
    exec_deps.job_state = job_state
    exec_deps.waiter = process.Waiter(exec_deps.job_state, exec_opts)

    exec_deps.ext_prog = \
        ext_prog or process.ExternalProgram('', fd_state,
                                            exec_deps.search_path, errfmt,
                                            debug_f)

    exec_deps.dumper = dev.CrashDumper('')
    exec_deps.debug_f = debug_f
    exec_deps.trace_f = debug_f

    splitter = split.SplitContext(mem)
    exec_deps.splitter = splitter

    word_ev = word_eval.NormalWordEvaluator(mem, exec_opts, exec_deps, arena)
    exec_deps.word_ev = word_ev

    arith_ev = expr_eval.ArithEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.arith_ev = arith_ev

    word_ev.arith_ev = arith_ev  # Circular

    bool_ev = expr_eval.BoolEvaluator(mem, exec_opts, word_ev, arena)
    exec_deps.bool_ev = bool_ev

    tracer = dev.Tracer(parse_ctx, exec_opts, mem, word_ev, debug_f)
    exec_deps.tracer = tracer

    ex = cmd_exec.Executor(mem, fd_state, funcs, builtins, exec_opts,
                           parse_ctx, exec_deps)

    spec_builder = builtin_comp.SpecBuilder(ex, parse_ctx, word_ev, splitter,
                                            comp_lookup)
    # Add some builtins that depend on the executor!
    complete_builtin = builtin_comp.Complete(spec_builder, comp_lookup)
    builtins[builtin_e.COMPLETE] = complete_builtin
    builtins[builtin_e.COMPGEN] = builtin_comp.CompGen(spec_builder)

    return ex