Example #1
0
def AppBundleMain(argv):
    login_shell = False

    b = os_path.basename(argv[0])
    main_name, ext = os_path.splitext(b)
    if main_name.startswith('-'):
        login_shell = True
        main_name = main_name[1:]

    if main_name == 'oil' and ext:  # oil.py or oil.ovm
        try:
            first_arg = argv[1]
        except IndexError:
            raise args.UsageError('Missing required applet name.')

        if first_arg in ('-h', '--help'):
            builtin.Help(['bundle-usage'], util.GetResourceLoader())
            sys.exit(0)

        if first_arg in ('-V', '--version'):
            _ShowVersion()
            sys.exit(0)

        main_name = first_arg
        if main_name.startswith('-'):  # TODO: Remove duplication above
            login_shell = True
            main_name = main_name[1:]
        argv0 = argv[1]
        main_argv = argv[2:]
    else:
        argv0 = argv[0]
        main_argv = argv[1:]

    if main_name in ('osh', 'sh'):
        status = ShellMain('osh', argv0, main_argv, login_shell)
        _tlog('done osh main')
        return status
    elif main_name == 'oshc':
        return OshCommandMain(main_argv)

    elif main_name == 'oil':
        return ShellMain('oil', argv0, main_argv, login_shell)
    elif main_name == 'wok':
        return WokMain(main_argv)
    elif main_name == 'boil':
        return BoilMain(main_argv)

    # For testing latency
    elif main_name == 'true':
        return 0
    elif main_name == 'false':
        return 1
    elif main_name == 'readlink':
        return readlink.main(main_argv)
    else:
        raise args.UsageError('Invalid applet name %r.' % main_name)
Example #2
0
def main(argv):
    try:
        sys.exit(OilMain(argv))
    except NotImplementedError as e:
        raise
    except OilUsageError as e:
        builtin.Help(['oil-usage'], util.GetResourceLoader())
        print(str(e), file=sys.stderr)
        sys.exit(2)
    except RuntimeError as e:
        print('FATAL: %s' % e, file=sys.stderr)
        sys.exit(1)
Example #3
0
def main(argv):
    # Localization: Optionally  use GNU gettext()?  For help only.  Might be
    # useful in parser error messages too.  Good thing both kinds of code are
    # generated?  Because I don't want to deal with a C toolchain for it.

    loader = util.GetResourceLoader()
    Help([], loader)

    for name, spec in BUILTIN_DEF.arg_specs.iteritems():
        print(name)
        spec.PrintHelp(sys.stdout)
        print()
Example #4
0
File: oil.py Project: xydinesh/oil
def main(argv):
  try:
    sys.exit(OilMain(argv))
  except NotImplementedError as e:
    raise
  except OilUsageError as e:
    builtin.Help(['oil-usage'], util.GetResourceLoader())
    print(str(e), file=sys.stderr)
    sys.exit(2)
  except RuntimeError as e:
    print('FATAL: %s' % e, file=sys.stderr)
    sys.exit(1)
  finally:
    _tlog('Exiting main()')
    if _trace_path:
      _tracer.Stop(_trace_path)
Example #5
0
def OilMain(argv):
    login_shell = False

    b = os.path.basename(argv[0])
    main_name, _ = os.path.splitext(b)
    if main_name.startswith("-"):
        login_shell = True
        main_name = main_name[1:]

    if main_name in ('oil', 'oil_main'):
        try:
            first_arg = argv[1]
        except IndexError:
            raise OilUsageError('Missing name of main()')

        if first_arg in ('-h', '--help'):
            builtin.Help(['oil-usage'], util.GetResourceLoader())
            sys.exit(0)

        if first_arg in ('-V', '--version'):
            _ShowVersion()
            sys.exit(0)

        main_name = first_arg
        if main_name.startswith("-"):
            login_shell = True
            main_name = main_name[1:]
        main_argv = argv[2:]
    else:
        main_argv = argv[1:]

    if main_name in ('osh', 'sh'):
        status = OshMain(main_argv, login_shell)
        tlog('done osh main')
        return status
    elif main_name == 'wok':
        return WokMain(main_argv)
    elif main_name == 'boil':
        return BoilMain(main_argv)
    elif main_name == 'true':
        return 0
    elif main_name == 'false':
        return 1
    else:
        raise OilUsageError('Invalid main %r' % main_name)
Example #6
0
File: oil.py Project: gnprice/oil
def OilMain(argv):
    arg_r = args.Reader(argv)
    try:
        opts = OIL_SPEC.Parse(arg_r)
    except args.UsageError as e:
        ui.usage('oil usage error: %s', e)
        return 2

    if opts.help:
        loader = util.GetResourceLoader()
        builtin.Help(['oil-usage'], 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

    raise NotImplementedError('oil')
    return 0
Example #7
0
def _ShowVersion():
    loader = util.GetResourceLoader()
    f = loader.open('oil-version.txt')
    version = f.readline().strip()
    f.close()

    try:
        f = loader.open('release-date.txt')
    except IOError:
        release_date = '-'  # in dev tree
    else:
        release_date = f.readline().strip()
    finally:
        f.close()

    # What C functions do these come from?
    print('Oil version %s' % version)
    print('Release Date: %s' % release_date)
    print('Arch: %s' % platform.machine())
    print('OS: %s' % platform.system())
    print('Platform: %s' % platform.version())
Example #8
0
def OilMain(argv):
    spec = args.FlagsAndOptions()
    # TODO: -h too
    spec.LongFlag('--help')
    spec.LongFlag('--version')
    #builtin.AddOptionsToArgSpec(spec)

    try:
        opts, opt_index = spec.Parse(argv)
    except args.UsageError as e:
        util.usage(str(e))
        return 2

    if opts.help:
        loader = util.GetResourceLoader()
        builtin.Help(['oil-usage'], 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

    raise NotImplementedError('oil')
    return 0
Example #9
0
  def _RunBuiltin(self, builtin_id, argv):
    restore_fd_state = True

    # NOTE: Builtins don't need to know their own name.
    argv = argv[1:]

    # TODO: figure out a quicker dispatch mechanism.  Just make a table of
    # builtins I guess.
    if builtin_id == EBuiltin.EXEC:
      status = self._Exec(argv)  # may never return
      # But if it returns, then we want to permanently apply the redirects
      # associated with it.
      self.fd_state.MakePermanent()

    elif builtin_id == EBuiltin.READ:
      status = builtin.Read(argv, self.mem)

    elif builtin_id == EBuiltin.ECHO:
      status = builtin.Echo(argv)

    elif builtin_id == EBuiltin.SHIFT:
      status = builtin.Shift(argv, self.mem)

    elif builtin_id == EBuiltin.CD:
      status = builtin.Cd(argv, self.mem)

    elif builtin_id == EBuiltin.SET:
      status = builtin.Set(argv, self.exec_opts, self.mem)

    elif builtin_id == EBuiltin.SHOPT:
      status = builtin.Shopt(argv, self.exec_opts)

    elif builtin_id == EBuiltin.UNSET:
      status = builtin.Unset(argv, self.mem, self.funcs)

    elif builtin_id == EBuiltin.EXPORT:
      status = builtin.Export(argv, self.mem)

    elif builtin_id == EBuiltin.EXIT:
      status = builtin.Exit(argv)

    elif builtin_id == EBuiltin.WAIT:
      status = builtin.Wait(argv, self.waiter, self.job_state, self.mem)

    elif builtin_id == EBuiltin.JOBS:
      status = builtin.Jobs(argv, self.job_state)

    elif builtin_id == EBuiltin.PUSHD:
      status = builtin.Pushd(argv, self.dir_stack)

    elif builtin_id == EBuiltin.POPD:
      status = builtin.Popd(argv, self.dir_stack)

    elif builtin_id == EBuiltin.DIRS:
      status = builtin.Dirs(argv, self.dir_stack)

    elif builtin_id in (EBuiltin.SOURCE, EBuiltin.DOT):
      status = self._Source(argv)

    elif builtin_id == EBuiltin.TRAP:
      status = builtin.Trap(argv, self.traps)

    elif builtin_id == EBuiltin.UMASK:
      status = builtin.Umask(argv)

    elif builtin_id == EBuiltin.EVAL:
      status = self._Eval(argv)

    elif builtin_id == EBuiltin.COMPLETE:
      status = self._Complete(argv)

    elif builtin_id == EBuiltin.COMPGEN:
      status = self._CompGen(argv)

    elif builtin_id == EBuiltin.COLON:  # special builtin like 'true'
      status = 0

    elif builtin_id == EBuiltin.TRUE:
      status = 0

    elif builtin_id == EBuiltin.FALSE:
      status = 1

    elif builtin_id == EBuiltin.HELP:
      loader = util.GetResourceLoader()
      status = builtin.Help(argv, loader)

    elif builtin_id == EBuiltin.DEBUG_LINE:
      status = builtin.DebugLine(argv, self.status_lines)

    else:
      raise AssertionError('Unhandled builtin: %d' % builtin_id)

    assert isinstance(status, int)
    return status
Example #10
0
  def _RunBuiltin(self, builtin_id, argv, span_id):
    # NOTE: Builtins don't need to know their own name.
    argv = argv[1:]

    # TODO: figure out a quicker dispatch mechanism.  Just make a table of
    # builtins I guess.
    if builtin_id == builtin_e.EXEC:
      status = self._Exec(argv)  # may never return
      # But if it returns, then we want to permanently apply the redirects
      # associated with it.
      self.fd_state.MakePermanent()

    elif builtin_id == builtin_e.READ:
      status = builtin.Read(argv, self.splitter, self.mem)

    elif builtin_id == builtin_e.ECHO:
      status = builtin.Echo(argv)

    elif builtin_id == builtin_e.SHIFT:
      status = builtin.Shift(argv, self.mem)

    elif builtin_id == builtin_e.CD:
      status = builtin.Cd(argv, self.mem, self.dir_stack)

    elif builtin_id == builtin_e.SET:
      status = builtin.Set(argv, self.exec_opts, self.mem)

    elif builtin_id == builtin_e.SHOPT:
      status = builtin.Shopt(argv, self.exec_opts)

    elif builtin_id == builtin_e.UNSET:
      status = builtin.Unset(argv, self.mem, self.funcs)

    elif builtin_id == builtin_e.EXPORT:
      status = builtin.Export(argv, self.mem)

    elif builtin_id == builtin_e.WAIT:
      status = builtin.Wait(argv, self.waiter, self.job_state, self.mem)

    elif builtin_id == builtin_e.JOBS:
      status = builtin.Jobs(argv, self.job_state)

    elif builtin_id == builtin_e.PUSHD:
      status = builtin.Pushd(argv, self.mem.GetVar('HOME'), self.dir_stack)

    elif builtin_id == builtin_e.POPD:
      status = builtin.Popd(argv, self.mem.GetVar('HOME'), self.dir_stack)

    elif builtin_id == builtin_e.DIRS:
      status = builtin.Dirs(argv, self.mem.GetVar('HOME'), self.dir_stack)

    elif builtin_id == builtin_e.PWD:
      status = builtin.Pwd(argv, self.mem)

    elif builtin_id in (builtin_e.SOURCE, builtin_e.DOT):
      status = self._Source(argv)

    elif builtin_id == builtin_e.TRAP:
      status = builtin.Trap(argv, self.traps, self.nodes_to_run, self)

    elif builtin_id == builtin_e.UMASK:
      status = builtin.Umask(argv)

    elif builtin_id == builtin_e.EVAL:
      status = self._Eval(argv, span_id)

    elif builtin_id == builtin_e.COMPLETE:
      status = comp_builtins.Complete(argv, self, self.comp_lookup)

    elif builtin_id == builtin_e.COMPGEN:
      status = comp_builtins.CompGen(argv, self)

    elif builtin_id == builtin_e.COMPOPT:
      status = comp_builtins.CompOpt(argv)

    elif builtin_id == builtin_e.COLON:  # special builtin like 'true'
      status = 0

    elif builtin_id == builtin_e.TRUE:
      status = 0

    elif builtin_id == builtin_e.FALSE:
      status = 1

    elif builtin_id == builtin_e.TEST:
      status = test_builtin.Test(argv, False)

    elif builtin_id == builtin_e.BRACKET:
      status = test_builtin.Test(argv, True)  # need_right_bracket

    elif builtin_id == builtin_e.GETOPTS:
      status = builtin.GetOpts(argv, self.mem)

    elif builtin_id == builtin_e.COMMAND:
      path = self.mem.GetVar('PATH')
      status = builtin.Command(argv, self.funcs, path)

    elif builtin_id == builtin_e.TYPE:
      path = self.mem.GetVar('PATH')
      status = builtin.Type(argv, self.funcs, path)

    elif builtin_id in (builtin_e.DECLARE, builtin_e.TYPESET):
      # These are synonyms
      status = builtin.DeclareTypeset(argv, self.mem, self.funcs)

    elif builtin_id == builtin_e.ALIAS:
      status = builtin.Alias(argv, self.aliases)

    elif builtin_id == builtin_e.UNALIAS:
      status = builtin.UnAlias(argv, self.aliases)

    elif builtin_id == builtin_e.HELP:
      loader = util.GetResourceLoader()
      status = builtin.Help(argv, loader)

    elif builtin_id == builtin_e.REPR:
      status = builtin.Repr(argv, self.mem)

    else:
      raise AssertionError('Unhandled builtin: %s' % builtin_id)

    assert isinstance(status, int)
    return status
Example #11
0
def OshMain(argv0, argv, login_shell):
    spec = args.FlagsAndOptions()
    spec.ShortFlag('-c', args.Str, quit_parsing_flags=True)  # command string
    spec.ShortFlag('-i')  # interactive

    # TODO: -h too
    spec.LongFlag('--help')
    spec.LongFlag('--version')
    spec.LongFlag(
        '--ast-format',
        ['text', 'abbrev-text', 'html', 'abbrev-html', 'oheap', 'none'],
        default='abbrev-text')
    spec.LongFlag('--show-ast')  # execute and show
    spec.LongFlag('--fix')
    spec.LongFlag('--debug-spans')  # For oshc translate
    spec.LongFlag('--print-status')
    spec.LongFlag(
        '--trace',
        ['cmd-parse', 'word-parse', 'lexer'])  # NOTE: can only trace one now
    spec.LongFlag('--hijack-shebang')

    # For benchmarks/*.sh
    spec.LongFlag('--parser-mem-dump', args.Str)
    spec.LongFlag('--runtime-mem-dump', args.Str)

    builtin.AddOptionsToArgSpec(spec)

    try:
        opts, opt_index = spec.Parse(argv)
    except args.UsageError as e:
        util.usage(str(e))
        return 2

    if opts.help:
        loader = util.GetResourceLoader()
        builtin.Help(['osh-usage'], 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

    trace_state = util.TraceState()
    if 'cmd-parse' == opts.trace:
        util.WrapMethods(cmd_parse.CommandParser, trace_state)
    if 'word-parse' == opts.trace:
        util.WrapMethods(word_parse.WordParser, trace_state)
    if 'lexer' == opts.trace:
        util.WrapMethods(lexer.Lexer, trace_state)

    if opt_index == len(argv):
        dollar0 = argv0
    else:
        dollar0 = argv[opt_index]  # the script name, or the arg after -c

    # TODO: Create a --parse action or 'osh parse' or 'oil osh-parse'
    # osh-fix
    # It uses a different memory-management model.  It's a batch program and not
    # an interactive program.

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

    # TODO: Maybe wrap this initialization sequence up in an oil_State, like
    # lua_State.
    status_lines = ui.MakeStatusLines()
    mem = state.Mem(dollar0, argv[opt_index + 1:], os.environ, arena)
    funcs = {}

    # Passed to Executor for 'complete', and passed to completion.Init
    if completion:
        comp_lookup = completion.CompletionLookup()
    else:
        # TODO: NullLookup?
        comp_lookup = None

    exec_opts = state.ExecOpts(mem)
    builtin.SetExecOpts(exec_opts, opts.opt_changes)

    fd_state = process.FdState()
    ex = cmd_exec.Executor(mem, fd_state, status_lines, funcs, readline,
                           completion, comp_lookup, exec_opts, arena)

    # NOTE: The rc file can contain both commands and functions... ideally we
    # would only want to save nodes/lines for the functions.
    try:
        rc_path = 'oilrc'
        arena.PushSource(rc_path)
        with open(rc_path) as f:
            rc_line_reader = reader.FileLineReader(f, arena)
            _, rc_c_parser = parse_lib.MakeParser(rc_line_reader, arena)
            try:
                rc_node = rc_c_parser.ParseWholeFile()
                if not rc_node:
                    err = rc_c_parser.Error()
                    ui.PrintErrorStack(err, arena, sys.stderr)
                    return 2  # parse error is code 2
            finally:
                arena.PopSource()

        status = ex.Execute(rc_node)
        #print('oilrc:', status, cflow, file=sys.stderr)
        # Ignore bad status?
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise

    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>')
        line_reader = reader.InteractiveLineReader(OSH_PS1, arena)
        exec_opts.interactive = True
    else:
        try:
            script_name = argv[opt_index]
        except IndexError:
            if sys.stdin.isatty():
                arena.PushSource('<interactive>')
                line_reader = reader.InteractiveLineReader(OSH_PS1, arena)
                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,
                           os.strerror(e.errno))
                return 1
            line_reader = reader.FileLineReader(f, arena)

    # TODO: assert arena.NumSourcePaths() == 1
    # TODO: .rc file needs its own arena.
    w_parser, c_parser = parse_lib.MakeParser(line_reader, arena)

    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 HAVE_READLINE:
            splitter = legacy.SplitContext(mem)
            ev = word_eval.CompletionWordEvaluator(mem, exec_opts, splitter)
            status_out = completion.StatusOutput(status_lines, exec_opts)
            completion.Init(pool, builtin.BUILTIN_DEF, mem, funcs, comp_lookup,
                            status_out, ev)

        return InteractiveLoop(opts, ex, c_parser, w_parser, line_reader)
    else:
        # Parse the whole thing up front
        #print('Parsing file')

        _tlog('ParseWholeFile')
        # TODO: Do I need ParseAndEvalLoop?  How is it different than
        # InteractiveLoop?
        try:
            node = c_parser.ParseWholeFile()
        except util.ParseError as e:
            ui.PrettyPrintError(e, arena, sys.stderr)
            print('parse error: %s' % e.UserErrorString(), file=sys.stderr)
            return 2
        else:
            # TODO: Remove this older form of error handling.
            if not node:
                err = c_parser.Error()
                assert err, err  # can't be empty
                ui.PrintErrorStack(err, arena, sys.stderr)
                return 2  # parse error is code 2

        do_exec = True
        if opts.fix:
            #log('SPANS: %s', arena.spans)
            osh2oil.PrintAsOil(arena, node, opts.debug_spans)
            do_exec = False
        if exec_opts.noexec:
            do_exec = False

        # Do this after parsing the entire file.  There could be another option to
        # do it before exiting runtime?
        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' % os.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)

        # -n prints AST, --show-ast prints and executes
        if exec_opts.noexec or opts.show_ast:
            if opts.ast_format == 'none':
                print('AST not printed.', file=sys.stderr)
            elif opts.ast_format == 'oheap':
                # TODO: Make this a separate flag?
                if sys.stdout.isatty():
                    raise RuntimeError(
                        'ERROR: Not dumping binary data to a TTY.')
                f = sys.stdout

                enc = encode.Params()
                out = encode.BinOutput(f)
                encode.EncodeRoot(node, enc, out)

            else:  # text output
                f = sys.stdout

                if opts.ast_format in ('text', 'abbrev-text'):
                    ast_f = fmt.DetectConsoleOutput(f)
                elif opts.ast_format in ('html', 'abbrev-html'):
                    ast_f = fmt.HtmlOutput(f)
                else:
                    raise AssertionError
                abbrev_hook = (ast_lib.AbbreviateNodes
                               if 'abbrev-' in opts.ast_format else None)
                tree = fmt.MakeTree(node, abbrev_hook=abbrev_hook)
                ast_f.FileHeader()
                fmt.PrintTree(tree, ast_f)
                ast_f.FileFooter()
                ast_f.write('\n')

            #util.log("Execution skipped because 'noexec' is on ")
            status = 0

        if do_exec:
            _tlog('Execute(node)')
            status = ex.ExecuteAndRunExitTrap(node)
            # 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' % os.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)

        else:
            status = 0

    return status
Example #12
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
Example #13
0
File: oil.py Project: gnprice/oil
def OshMain(argv0, argv, login_shell):

    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(['osh-usage'], 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 = {}

    comp_lookup = completion.CompletionLookup()

    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)

    if opts.debug_file:
        debug_f = util.DebugFile(fd_state.Open(opts.debug_file, mode='w'))
    else:
        debug_f = util.NullDebugFile()
    debug_f.log('Debug file is %s', opts.debug_file)

    # Controlled by env variable, flag, or hook?
    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)
    devtools = dev.DevTools(dumper, debug_f, trace_f)

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

    # NOTE: The rc file can contain both commands and functions... ideally we
    # would only want to save nodes/lines for the functions.
    try:
        rc_path = 'oilrc'
        arena.PushSource(rc_path)
        with open(rc_path) as f:
            rc_line_reader = reader.FileLineReader(f, arena)
            _, rc_c_parser = parse_ctx.MakeParser(rc_line_reader)
            try:
                status = main_loop.Batch(ex, rc_c_parser, arena)
            finally:
                arena.PopSource()
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise

    # Needed in non-interactive shells for @P
    prompt = ui.Prompt(arena, parse_ctx, ex)
    ui.PROMPT = prompt

    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>')
        line_reader = reader.InteractiveLineReader(arena, prompt)
        exec_opts.interactive = True
    else:
        try:
            script_name = arg_r.Peek()
        except IndexError:
            if sys.stdin.isatty():
                arena.PushSource('<interactive>')
                line_reader = reader.InteractiveLineReader(arena, prompt)
                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.
    w_parser, c_parser = parse_ctx.MakeParser(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 HAVE_READLINE:
            splitter = legacy.SplitContext(mem)  # TODO: share with executor.
            ev = word_eval.CompletionWordEvaluator(mem, exec_opts, splitter,
                                                   arena)
            progress_f = ui.StatusLine()
            var_action = completion.VariablesActionInternal(ex.mem)
            root_comp = completion.RootCompleter(ev, comp_lookup, var_action,
                                                 parse_ctx, progress_f,
                                                 debug_f)
            completion.Init(readline, root_comp, debug_f)
            _InitDefaultCompletions(ex, comp_lookup)

        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)

    if nodes_out is not None:
        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
Example #14
0
File: opy_main.py Project: vck/oil
def OpyCommandMain(argv):
    """Dispatch to the right action."""

    # TODO: Use core/args.
    #opts, argv = Options().parse_args(argv)

    try:
        action = argv[0]
    except IndexError:
        raise args.UsageError('opy: Missing required subcommand.')

    if action in ('parse', 'compile', 'eval', 'repl', 'run'):
        loader = util.GetResourceLoader()
        f = loader.open(PICKLE_REL_PATH)
        gr = grammar.Grammar()
        gr.load(f)
        f.close()

        # In Python 2 code, always use from __future__ import print_function.
        try:
            del gr.keywords["print"]
        except KeyError:
            pass

        symbols = Symbols(gr)
        pytree.Init(symbols)  # for type_repr() pretty printing
        transformer.Init(symbols)  # for _names and other dicts
        tr = transformer.Transformer()
    else:
        # e.g. pgen2 doesn't use any of these.  Maybe we should make a different
        # tool.
        gr = None
        symbols = None
        tr = None

    #
    # Actions
    #

    if action == 'pgen2':
        grammar_path = argv[1]
        pickle_path = argv[2]
        WriteGrammar(grammar_path, pickle_path)

    elif action == 'stdlib-parse':
        # This is what the compiler/ package was written against.
        import parser

        py_path = argv[1]
        with open(py_path) as f:
            st = parser.suite(f.read())

        tree = st.totuple()

        printer = TupleTreePrinter(HostStdlibNames())
        printer.Print(tree)
        n = CountTupleTree(tree)
        log('COUNT %d', n)

    elif action == 'lex':
        py_path = argv[1]
        with open(py_path) as f:
            tokens = tokenize.generate_tokens(f.readline)
            for typ, val, start, end, unused_line in tokens:
                print('%10s %10s %-10s %r' %
                      (start, end, token.tok_name[typ], val))

    elif action == 'parse':
        py_path = argv[1]
        with open(py_path) as f:
            tokens = tokenize.generate_tokens(f.readline)
            p = parse.Parser(gr, convert=skeleton.py2st)
            parse_tree = driver.PushTokens(p, tokens,
                                           gr.symbol2number['file_input'])

        if isinstance(parse_tree, tuple):
            n = CountTupleTree(parse_tree)
            log('COUNT %d', n)

            printer = TupleTreePrinter(transformer._names)
            printer.Print(parse_tree)
        else:
            tree.PrettyPrint(sys.stdout)
            log('\tChildren: %d' % len(tree.children), file=sys.stderr)

    elif action == 'compile':  # 'opyc compile' is pgen2 + compiler2
        py_path = argv[1]
        out_path = argv[2]

        with open(py_path) as f:
            co = skeleton.Compile(f, py_path, gr, 'file_input', 'exec')

        log("Compiled to %d bytes of bytecode", len(co.co_code))

        # Write the .pyc file
        with open(out_path, 'wb') as out_f:
            h = misc.getPycHeader(py_path)
            out_f.write(h)
            marshal.dump(co, out_f)

    elif action == 'eval':  # Like compile, but parses to a code object and prints it
        py_expr = argv[1]
        f = cStringIO.StringIO(py_expr)
        co = skeleton.Compile(f, '<eval input>', gr, 'eval_input', 'eval')

        v = dis_tool.Visitor()
        v.show_code(co)
        print()
        print('RESULT:')
        print(eval(co))

    elif action == 'repl':  # Like eval in a loop
        while True:
            py_expr = raw_input('opy> ')
            f = cStringIO.StringIO(py_expr)

            # TODO: change this to 'single input'?  Why doesn't this work?
            co = skeleton.Compile(f, '<REPL input>', gr, 'eval_input', 'eval')

            v = dis_tool.Visitor()
            v.show_code(co)
            print(eval(co))

    elif action == 'dis':
        pyc_path = argv[1]
        try:
            report_path = argv[2]
            report_f = open(report_path, 'w')
        except IndexError:
            report_f = sys.stdout

        with open(pyc_path, 'rb') as f:
            # TODO: Make this a flag.
            #v = dis_tool.Visitor(dis_bytecode=False)
            v = dis_tool.Visitor()
            #v = dis_tool.Visitor(co_name='_parse')
            v.Visit(f)

        v.Report(report_f)

    elif action == 'dis-md5':
        pyc_paths = argv[1:]
        if not pyc_paths:
            raise args.UsageError(
                'dis-md5: At least one .pyc path is required.')

        for path in pyc_paths:
            h = hashlib.md5()
            with open(path) as f:
                magic = f.read(4)
                h.update(magic)
                ignored_timestamp = f.read(4)
                while True:
                    b = f.read(64 * 1024)
                    if not b:
                        break
                    h.update(b)
            print('%6d %s %s' % (os.path.getsize(path), h.hexdigest(), path))

    elif action == 'run':
        # TODO: Add an option like -v in __main__

        #level = logging.DEBUG if args.verbose else logging.WARNING
        #logging.basicConfig(level=level)
        #logging.basicConfig(level=logging.DEBUG)

        # Compile and run, without writing pyc file
        py_path = argv[1]
        opy_argv = argv[1:]

        if py_path.endswith('.py'):
            with open(py_path) as f:
                co = skeleton.Compile(f, py_path, gr, 'file_input', 'exec')
            execfile.run_code_object(co, opy_argv)

        elif py_path.endswith('.pyc') or py_path.endswith('.opyc'):
            with open(py_path) as f:
                f.seek(8)  # past header.  TODO: validate it!
                co = marshal.load(f)
            execfile.run_code_object(co, opy_argv)

        else:
            raise args.UsageError('Invalid path %r' % py_path)

    else:
        raise args.UsageError('Invalid action %r' % action)
Example #15
0
#!/usr/bin/env python
"""
arith_ast.py
"""

import sys

from asdl import front_end
from asdl import py_meta
from core import util

f = util.GetResourceLoader().open('asdl/arith.asdl')
_asdl_module, _type_lookup = front_end.LoadSchema(f, {})  # no app_types
f.close()

root = sys.modules[__name__]
py_meta.MakeTypes(_asdl_module, root, _type_lookup)
Example #16
0
def OpyCommandMain(argv):
    """Dispatch to the right action."""

    # TODO: Use core/args.
    opts, argv = Options().parse_args(argv)

    try:
        action = argv[0]
    except IndexError:
        raise args.UsageError('opy: Missing required subcommand.')

    if action in ('parse', 'compile'):
        loader = util.GetResourceLoader()
        f = loader.open(PICKLE_REL_PATH)
        gr = grammar.Grammar()
        gr.load(f)
        f.close()

        # In Python 2 code, always use from __future__ import print_function.
        try:
            del gr.keywords["print"]
        except KeyError:
            pass

        FILE_INPUT = gr.symbol2number['file_input']

        symbols = Symbols(gr)
        pytree.Init(symbols)  # for type_repr() pretty printing
        transformer.Init(symbols)  # for _names and other dicts
    else:
        # e.g. pgen2 doesn't use any of these.  Maybe we should make a different
        # tool.
        gr = None
        FILE_INPUT = None
        symbols = None

    #do_glue = False
    do_glue = True

    if do_glue:  # Make it a flag
        # Emulating parser.st structures from parsermodule.c.
        # They have a totuple() method, which outputs tuples like this.
        def py2st(gr, raw_node):
            type, value, context, children = raw_node
            # See pytree.Leaf
            if context:
                _, (lineno, column) = context
            else:
                lineno = 0  # default in Leaf
                column = 0

            if children:
                return (type, ) + tuple(children)
            else:
                return (type, value, lineno, column)

        convert = py2st
    else:
        convert = pytree.convert

    dr = driver.Driver(gr, convert=convert)

    if action == 'pgen2':
        grammar_path = argv[1]
        pickle_path = argv[2]
        WriteGrammar(grammar_path, pickle_path)

    elif action == 'stdlib-parse':
        # This is what the compiler/ package was written against.
        import parser

        py_path = argv[1]
        with open(py_path) as f:
            st = parser.suite(f.read())

        tree = st.totuple()

        n = CountTupleTree(tree)
        log('COUNT %d', n)
        printer = TupleTreePrinter(HostStdlibNames())
        printer.Print(tree)

    elif action == 'parse':
        py_path = argv[1]
        with open(py_path) as f:
            tokens = tokenize.generate_tokens(f.readline)
            tree = dr.parse_tokens(tokens, start_symbol=FILE_INPUT)

        if isinstance(tree, tuple):
            n = CountTupleTree(tree)
            log('COUNT %d', n)

            printer = TupleTreePrinter(transformer._names)
            printer.Print(tree)
        else:
            tree.PrettyPrint(sys.stdout)
            log('\tChildren: %d' % len(tree.children), file=sys.stderr)

    elif action == 'compile':
        # 'opy compile' is pgen2 + compiler2

        py_path = argv[1]
        out_path = argv[2]

        if do_glue:
            py_parser = Pgen2PythonParser(dr, FILE_INPUT)
            printer = TupleTreePrinter(transformer._names)
            tr = transformer.Pgen2Transformer(py_parser, printer)
        else:
            tr = transformer.Transformer()

        with open(py_path) as f:
            contents = f.read()
        co = pycodegen.compile(contents, py_path, 'exec', transformer=tr)
        log("Code length: %d", len(co.co_code))

        # Write the .pyc file
        with open(out_path, 'wb') as out_f:
            h = pycodegen.getPycHeader(py_path)
            out_f.write(h)
            marshal.dump(co, out_f)

    elif action == 'dis':
        pyc_path = argv[1]
        try:
            report_path = argv[2]
            report_f = open(report_path, 'w')
        except IndexError:
            report_f = sys.stdout

        with open(pyc_path, 'rb') as f:
            # TODO: Make this a flag.
            #v = inspect_pyc.Visitor(dis_bytecode=False)
            v = inspect_pyc.Visitor()
            v.Visit(f)

        v.Report(report_f)

    elif action == 'dis-md5':
        pyc_paths = argv[1:]
        if not pyc_paths:
            raise args.UsageError(
                'dis-md5: At least one .pyc path is required.')

        for path in pyc_paths:
            h = hashlib.md5()
            with open(path) as f:
                magic = f.read(4)
                h.update(magic)
                ignored_timestamp = f.read(4)
                while True:
                    b = f.read(64 * 1024)
                    if not b:
                        break
                    h.update(b)
            print('%6d %s %s' % (os.path.getsize(path), h.hexdigest(), path))

    # NOTE: Unused
    elif action == 'old-compile':
        py_path = argv[1]
        out_path = argv[2]

        if do_glue:
            py_parser = Pgen2PythonParser(dr, FILE_INPUT)
            printer = TupleTreePrinter(transformer._names)
            tr = transformer.Pgen2Transformer(py_parser, printer)
        else:
            tr = transformer.Transformer()

        f = open(py_path)
        contents = f.read()
        co = pycodegen.compile(contents, py_path, 'exec', transformer=tr)
        log("Code length: %d", len(co.co_code))

        # Write the .pyc file
        with open(out_path, 'wb') as out_f:
            h = pycodegen.getPycHeader(py_path)
            out_f.write(h)
            marshal.dump(co, out_f)

    # TODO: Not used
    elif action == 'compile2':
        in_path = argv[1]
        out_path = argv[2]

        from compiler2 import pycodegen as pycodegen2
        from misc import stdlib_compile

        stdlib_compile.compileAndWrite(in_path, out_path, pycodegen2.compile)

    elif action == 'run':
        # TODO: Add an option like -v in __main__

        #level = logging.DEBUG if args.verbose else logging.WARNING
        #logging.basicConfig(level=level)
        #logging.basicConfig(level=logging.DEBUG)

        # Compile and run, without writing pyc file
        py_path = argv[1]
        opy_argv = argv[1:]

        if py_path.endswith('.py'):
            py_parser = Pgen2PythonParser(dr, FILE_INPUT)
            printer = TupleTreePrinter(transformer._names)
            tr = transformer.Pgen2Transformer(py_parser, printer)
            with open(py_path) as f:
                contents = f.read()
            co = pycodegen.compile(contents, py_path, 'exec', transformer=tr)
            #execfile.run_code_object(co, opy_argv)

        elif py_path.endswith('.pyc') or py_path.endswith('.opyc'):
            with open(py_path) as f:
                f.seek(8)  # past header.  TODO: validate it!
                co = marshal.load(f)
            #execfile.run_code_object(co, opy_argv)

        else:
            raise args.UsageError('Invalid path %r' % py_path)

    else:
        raise args.UsageError('Invalid action %r' % action)
Example #17
0
def OshMain(argv, login_shell):
    spec = args.FlagsAndOptions()
    spec.ShortFlag('-c', args.Str, quit_parsing_flags=True)  # command string
    spec.ShortFlag('-i')  # interactive

    # TODO: -h too
    spec.LongFlag('--help')
    spec.LongFlag('--version')
    spec.LongFlag('--ast-format',
                  ['text', 'abbrev-text', 'html', 'abbrev-html', 'oheap'],
                  default='abbrev-text')
    spec.LongFlag('--show-ast')  # execute and show
    spec.LongFlag('--fix')
    spec.LongFlag('--debug-spans')
    spec.LongFlag('--print-status')
    spec.LongFlag(
        '--trace',
        ['cmd-parse', 'word-parse', 'lexer'])  # NOTE: can only trace one now
    spec.LongFlag('--hijack-shebang')

    builtin.AddOptionsToArgSpec(spec)

    try:
        opts, opt_index = spec.Parse(argv)
    except args.UsageError as e:
        util.usage(str(e))
        return 2

    if opts.help:
        loader = util.GetResourceLoader()  # TOOD: Use Global
        builtin.Help(['osh-usage'], 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

    trace_state = util.TraceState()
    if 'cmd-parse' == opts.trace:
        util.WrapMethods(cmd_parse.CommandParser, trace_state)
    if 'word-parse' == opts.trace:
        util.WrapMethods(word_parse.WordParser, trace_state)
    if 'lexer' == opts.trace:
        util.WrapMethods(lexer.Lexer, trace_state)

    if opt_index == len(argv):
        dollar0 = sys.argv[0]  # e.g. bin/osh
    else:
        dollar0 = argv[opt_index]  # the script name, or the arg after -c

    # TODO: Create a --parse action or 'osh parse' or 'oil osh-parse'
    # osh-fix
    # It uses a different memory-management model.  It's a batch program and not
    # an interactive program.

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

    # TODO: Maybe wrap this initialization sequence up in an oil_State, like
    # lua_State.
    status_lines = ui.MakeStatusLines()
    mem = state.Mem(dollar0, argv[opt_index + 1:], os.environ)
    funcs = {}

    # Passed to Executor for 'complete', and passed to completion.Init
    if completion:
        comp_lookup = completion.CompletionLookup()
    else:
        # TODO: NullLookup?
        comp_lookup = None
    exec_opts = state.ExecOpts()
    builtin.SetExecOpts(exec_opts, opts.opt_changes)

    # TODO: How to get a handle to initialized builtins here?
    # tokens.py has it.  I think you just make a separate table, with
    # metaprogramming.
    ex = cmd_exec.Executor(mem, status_lines, funcs, completion, comp_lookup,
                           exec_opts, arena)

    # NOTE: The rc file can contain both commands and functions... ideally we
    # would only want to save nodes/lines for the functions.
    try:
        rc_path = 'oilrc'
        arena.PushSource(rc_path)
        with open(rc_path) as f:
            rc_line_reader = reader.FileLineReader(f, arena=arena)
            _, rc_c_parser = parse_lib.MakeParser(rc_line_reader, arena)
            try:
                rc_node = rc_c_parser.ParseWholeFile()
                if not rc_node:
                    # TODO: Error should return a token, and then the token should have a
                    # arena index, and then look that up in the arena.
                    err = rc_c_parser.Error()
                    ui.PrintErrorStack(err, arena, sys.stderr)
                    return 2  # parse error is code 2
            finally:
                arena.PopSource()

        status = ex.Execute(rc_node)
        #print('oilrc:', status, cflow, file=sys.stderr)
        # Ignore bad status?
    except IOError as e:
        if e.errno != errno.ENOENT:
            raise

    if opts.c is not None:
        arena.PushSource('<command string>')
        line_reader = reader.StringLineReader(opts.c, arena=arena)
        interactive = False
    elif opts.i:  # force interactive
        arena.PushSource('<stdin -i>')
        line_reader = reader.InteractiveLineReader(OSH_PS1, arena=arena)
        interactive = True
    else:
        try:
            script_name = argv[opt_index]
        except IndexError:
            if sys.stdin.isatty():
                arena.PushSource('<interactive>')
                line_reader = reader.InteractiveLineReader(OSH_PS1,
                                                           arena=arena)
                interactive = True
            else:
                arena.PushSource('<stdin>')
                line_reader = reader.FileLineReader(sys.stdin, arena=arena)
                interactive = False
        else:
            arena.PushSource(script_name)
            # TODO: Does this open file descriptor need to be moved beyond 3..9 ?
            # Yes!  See dash input.c setinputfile.  It calls savefd().
            # TODO: It also needs to be closed later.
            try:
                f = open(script_name)
            except IOError as e:
                util.error("Couldn't open %r: %s", script_name,
                           os.strerror(e.errno))
                return 1
            line_reader = reader.FileLineReader(f, arena=arena)
            interactive = False

    # TODO: assert arena.NumSourcePaths() == 1
    # TODO: .rc file needs its own arena.
    w_parser, c_parser = parse_lib.MakeParser(line_reader, arena)

    if interactive:
        # NOTE: We're using a different evaluator here.  The completion system can
        # also run functions... it gets the Executor through Executor._Complete.
        if HAVE_READLINE:
            ev = word_eval.CompletionWordEvaluator(mem, exec_opts)
            status_out = completion.StatusOutput(status_lines, exec_opts)
            completion.Init(builtin.BUILTIN_DEF, mem, funcs, comp_lookup,
                            status_out, ev)

        # TODO: Could instantiate "printer" instead of showing ops
        InteractiveLoop(opts, ex, c_parser, w_parser, line_reader)
        status = 0  # TODO: set code
    else:
        # Parse the whole thing up front
        #print('Parsing file')

        tlog('ParseWholeFile')
        # TODO: Do I need ParseAndEvalLoop?  How is it different than
        # InteractiveLoop?
        try:
            node = c_parser.ParseWholeFile()
        except util.ParseError as e:
            ui.PrettyPrintError(e, arena, sys.stderr)
            print('parse error: %s' % e.UserErrorString(), file=sys.stderr)
            return 2
        else:
            # TODO: Remove this older form of error handling.
            if not node:
                err = c_parser.Error()
                ui.PrintErrorStack(err, arena, sys.stderr)
                return 2  # parse error is code 2

        do_exec = True
        if opts.fix:
            osh2oil.PrintAsOil(arena, node, opts.debug_spans)
            do_exec = False
        if exec_opts.noexec:
            do_exec = False

        if exec_opts.noexec or opts.show_ast:  # -n shows the AST
            if opts.ast_format == 'oheap':
                # TODO: Make this a separate flag?
                if sys.stdout.isatty():
                    raise RuntimeError(
                        'ERROR: Not dumping binary data to a TTY.')
                f = sys.stdout

                enc = encode.Params()
                out = encode.BinOutput(f)
                encode.EncodeRoot(node, enc, out)

            else:  # text output
                f = sys.stdout

                if opts.ast_format in ('text', 'abbrev-text'):
                    ast_f = fmt.DetectConsoleOutput(f)
                elif opts.ast_format in ('html', 'abbrev-html'):
                    ast_f = fmt.HtmlOutput(f)
                else:
                    raise AssertionError
                abbrev_hook = (ast.AbbreviateNodes
                               if 'abbrev-' in opts.ast_format else None)
                tree = fmt.MakeTree(node, abbrev_hook=abbrev_hook)
                ast_f.FileHeader()
                fmt.PrintTree(tree, ast_f)
                ast_f.FileFooter()
                ast_f.write('\n')

            #util.log("Execution skipped because 'noexec' is on ")
            status = 0

        if do_exec:
            tlog('Execute(node)')
            status = ex.Execute(node)
        else:
            status = 0

    return status
Example #18
0
from core.id_kind import Id


def _LoadSchema(f):
    module = asdl.parse(f)

    app_types = {'id': asdl.UserType(Id)}
    type_lookup = asdl.ResolveTypes(module, app_types)

    # Check for type errors
    if not asdl.check(module, app_types):
        raise AssertionError('ASDL file is invalid')
    return module, type_lookup


f = util.GetResourceLoader().open('core/runtime.asdl')
root = sys.modules[__name__]
module, type_lookup = _LoadSchema(f)

if 0:
    py_meta.MakeTypes(module, root, type_lookup)
else:
    # Exported for the generated code to use
    TYPE_LOOKUP = type_lookup

    # Get the types from elsewhere
    from _devbuild.gen import runtime_asdl
    py_meta.AssignTypes(runtime_asdl, root)

f.close()
Example #19
0
File: oil.py Project: tyxieblub/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 = util.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

    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, 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 = pool.NewArena()
    comp_arena.PushSource('<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 = 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()

    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 = 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,
                                            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, 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 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 = 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,
                                                   line_input, prompt_state)
        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, line_input, prompt_state)
                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)

    # 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)
            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)

    # TODO: This doesn't do anything interesting.
    # - Remove the column from osh-runtime, since it doesn't work with main_loop.
    # - http://www.oilshell.org/release/0.6.pre6/benchmarks.wwz/osh-runtime/
    # - Move it to right before ui.PrintAst(), so we can use it in -n mode.
    # This benchmark has been broken since 0.6.pre4.
    # http://www.oilshell.org/release/0.6.pre3/benchmarks.wwz/osh-parser/
    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: We haven't closed the file opened with fd_state.Open
    return status
Example #20
0
# Do NOT create any any more instances of them!  Always used IdInstance().

# TODO: Fold Id into ASDL, which will enforce uniqueness?

_ID_INSTANCES = {}  # int -> Id


def IdInstance(i):
    return _ID_INSTANCES[i]


#
# Instantiate osh/types.asdl
#

f = util.GetResourceLoader().open('osh/types.asdl')
_asdl_module, _type_lookup = asdl.LoadSchema(f, {})  # no app_types

types = _AsdlModule()
if 0:
    py_meta.MakeTypes(_asdl_module, types, _type_lookup)
else:
    # Exported for the generated code to use
    TYPES_TYPE_LOOKUP = _type_lookup

    # Get the types from elsewhere
    from _devbuild.gen import types_asdl
    py_meta.AssignTypes(types_asdl, types)

f.close()
Example #21
0
def OpyCommandMain(argv):
    """Dispatch to the right action."""

    # TODO: Use core/args.
    #opts, argv = Options().parse_args(argv)

    try:
        action = argv[0]
    except IndexError:
        raise args.UsageError('opy: Missing required subcommand.')

    argv = argv[1:]  # TODO: Should I do input.ReadRequiredArg()?
    # That will shift the input.

    if action in ('parse', 'compile', 'dis', 'cfg', 'compile-ovm', 'eval',
                  'repl', 'run', 'run-ovm'):
        loader = util.GetResourceLoader()
        f = loader.open(PICKLE_REL_PATH)
        gr = grammar.Grammar()
        gr.load(f)
        f.close()

        # In Python 2 code, always use from __future__ import print_function.
        try:
            del gr.keywords["print"]
        except KeyError:
            pass

        symbols = Symbols(gr)
        pytree.Init(symbols)  # for type_repr() pretty printing
        transformer.Init(symbols)  # for _names and other dicts

        compiler = skeleton.Compiler(gr)
    else:
        # e.g. pgen2 doesn't use any of these.  Maybe we should make a different
        # tool.
        compiler = None

    # TODO: Also have a run_spec for 'opyc run'.
    compile_spec = args.OilFlags()
    compile_spec.Flag('-emit-docstring',
                      args.Bool,
                      default=True,
                      help='Whether to emit docstrings')
    compile_spec.Flag('-fast-ops',
                      args.Bool,
                      default=True,
                      help='Whether to emit LOAD_FAST, STORE_FAST, etc.')
    compile_spec.Flag('-oil-subset',
                      args.Bool,
                      default=False,
                      help='Only allow the constructs necessary to implement'
                      'Oil. Example: using multiple inheritance will abort '
                      'compilation.')

    #
    # Actions
    #

    if action == 'pgen2':
        grammar_path = argv[0]
        pickle_path = argv[1]
        WriteGrammar(grammar_path, pickle_path)

    elif action == 'stdlib-parse':
        # This is what the compiler/ package was written against.
        import parser

        py_path = argv[1]
        with open(py_path) as f:
            st = parser.suite(f.read())

        tree = st.totuple()

        printer = TupleTreePrinter(HostStdlibNames())
        printer.Print(tree)
        n = CountTupleTree(tree)
        log('COUNT %d', n)

    elif action == 'lex':
        py_path = argv[0]
        with open(py_path) as f:
            tokens = tokenize.generate_tokens(f.readline)
            for typ, val, start, end, unused_line in tokens:
                print('%10s %10s %-10s %r' %
                      (start, end, token.tok_name[typ], val))

    elif action == 'parse':
        py_path = argv[0]
        with open(py_path) as f:
            tokens = tokenize.generate_tokens(f.readline)
            p = parse.Parser(gr, convert=skeleton.py2st)
            parse_tree = driver.PushTokens(p, tokens,
                                           gr.symbol2number['file_input'])

        if isinstance(parse_tree, tuple):
            n = CountTupleTree(parse_tree)
            log('COUNT %d', n)

            printer = TupleTreePrinter(transformer._names)
            printer.Print(parse_tree)
        else:
            tree.PrettyPrint(sys.stdout)
            log('\tChildren: %d' % len(tree.children), file=sys.stderr)

    elif action == 'cfg':  # output Control Flow Graph
        opt, i = compile_spec.Parse(argv)
        py_path = argv[i]
        with open(py_path) as f:
            graph = compiler.Compile(f, opt, 'exec', return_cfg=True)

        print(graph)

    elif action == 'compile':  # 'opyc compile' is pgen2 + compiler2
        # spec.Arg('action', ['foo', 'bar'])
        # But that leads to some duplication.

        opt, i = compile_spec.Parse(argv)

        py_path = argv[i]
        out_path = argv[i + 1]

        with open(py_path) as f:
            co = compiler.Compile(f, opt, 'exec')

        log("Compiled to %d bytes of top-level bytecode", len(co.co_code))

        # Write the .pyc file
        with open(out_path, 'wb') as out_f:
            h = misc.getPycHeader(py_path)
            out_f.write(h)
            marshal.dump(co, out_f)

    elif action == 'compile-ovm':
        opt, i = compile_spec.Parse(argv)
        py_path = argv[i]
        out_path = argv[i + 1]

        # Compile to OVM bytecode
        with open(py_path) as f:
            co = compiler.Compile(f, opt, 'ovm')

        log("Compiled to %d bytes of top-level bytecode", len(co.co_code))
        # Write the .pyc file
        with open(out_path, 'wb') as out_f:
            if 1:
                out_f.write(co.co_code)
            else:
                h = misc.getPycHeader(py_path)
                out_f.write(h)
                marshal.dump(co, out_f)
        log('Wrote only the bytecode to %r', out_path)

    elif action == 'eval':  # Like compile, but parses to a code object and prints it
        opt, i = compile_spec.Parse(argv)
        py_expr = argv[i]
        f = skeleton.StringInput(py_expr, '<eval input>')
        co = compiler.Compile(f, opt, 'eval')

        v = dis_tool.Visitor()
        v.show_code(co)
        print()
        print('RESULT:')
        print(eval(co))

    elif action == 'repl':  # Like eval in a loop
        while True:
            py_expr = raw_input('opy> ')
            f = skeleton.StringInput(py_expr, '<REPL input>')

            # TODO: change this to 'single input'?  Why doesn't this work?
            co = compiler.Compile(f, opt, 'eval')

            v = dis_tool.Visitor()
            v.show_code(co)
            print(eval(co))

    elif action == 'dis-tables':
        out_dir = argv[0]
        pyc_paths = argv[1:]

        out = TableOutput(out_dir)

        for pyc_path in pyc_paths:
            with open(pyc_path) as f:
                magic, unixtime, timestamp, code = dis_tool.unpack_pyc(f)
                WriteDisTables(pyc_path, code, out)

        out.Close()

    elif action == 'dis':
        opt, i = compile_spec.Parse(argv)
        path = argv[i]
        v = dis_tool.Visitor()

        if path.endswith('.py'):
            with open(path) as f:
                co = compiler.Compile(f, opt, 'exec')

            log("Compiled to %d bytes of top-level bytecode", len(co.co_code))
            v.show_code(co)

        else:  # assume pyc_path
            with open(path, 'rb') as f:
                v.Visit(f)

    elif action == 'dis-md5':
        pyc_paths = argv
        if not pyc_paths:
            raise args.UsageError(
                'dis-md5: At least one .pyc path is required.')

        for path in pyc_paths:
            h = hashlib.md5()
            with open(path) as f:
                magic = f.read(4)
                h.update(magic)
                ignored_timestamp = f.read(4)
                while True:
                    b = f.read(64 * 1024)
                    if not b:
                        break
                    h.update(b)
            print('%6d %s %s' % (os.path.getsize(path), h.hexdigest(), path))

    elif action == 'run':  # Compile and run, without writing pyc file
        # TODO: Add an option like -v in __main__

        #level = logging.DEBUG if args.verbose else logging.WARNING
        #logging.basicConfig(level=level)
        #logging.basicConfig(level=logging.DEBUG)

        opt, i = compile_spec.Parse(argv)

        py_path = argv[i]
        opy_argv = argv[i:]

        if py_path.endswith('.py'):
            with open(py_path) as f:
                co = compiler.Compile(f, opt, 'exec')
            num_ticks = execfile.run_code_object(co, opy_argv)

        elif py_path.endswith('.pyc') or py_path.endswith('.opyc'):
            with open(py_path) as f:
                f.seek(8)  # past header.  TODO: validate it!
                co = marshal.load(f)
            num_ticks = execfile.run_code_object(co, opy_argv)

        else:
            raise args.UsageError('Invalid path %r' % py_path)

    elif action == 'run-ovm':  # Compile and run, without writing pyc file
        opt, i = compile_spec.Parse(argv)
        py_path = argv[1]
        opy_argv = argv[1:]

        if py_path.endswith('.py'):
            #mode = 'exec'
            mode = 'ovm'  # OVM bytecode is different!
            with open(py_path) as f:
                co = compiler.Compile(f, opt, mode)
            log('Compiled to %d bytes of OVM code', len(co.co_code))
            num_ticks = ovm.run_code_object(co, opy_argv)

        elif py_path.endswith('.pyc') or py_path.endswith('.opyc'):
            with open(py_path) as f:
                f.seek(8)  # past header.  TODO: validate it!
                co = marshal.load(f)
            num_ticks = ovm.run_code_object(co, opy_argv)

        else:
            raise args.UsageError('Invalid path %r' % py_path)

    else:
        raise args.UsageError('Invalid action %r' % action)
Example #22
0
        node.unnamed_fields.append(out_val)


def PrettyPrint(node, f=sys.stdout):
  ast_f = fmt.DetectConsoleOutput(f)
  tree = fmt.MakeTree(node, AbbreviateNodes)
  fmt.PrintTree(tree, ast_f)
  f.write('\n')


def _ParseAndMakeTypes(f, root):
  # TODO: A better syntax for this might be:
  #
  #     id = external
  #
  # in osh.asdl.  Then we can show an error if it's not provided.
  app_types = {'id': asdl.UserType(Id)}

  module = asdl.parse(f)

  # Check for type errors
  if not asdl.check(module, app_types):
    raise AssertionError('ASDL file is invalid')
  py_meta.MakeTypes(module, root, app_types)


f = util.GetResourceLoader().open('osh/osh.asdl')
root = sys.modules[__name__]
_ParseAndMakeTypes(f, root)
f.close()