Beispiel #1
0
Datei: opy_.py Projekt: vck/oil
def AppBundleMain(argv):
  b = os.path.basename(argv[0])
  main_name, ext = os.path.splitext(b)

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

    # TODO: We don't have this
    if first_arg in ('-h', '--help'):
      #builtin.Help(['bundle-usage'], util.GetResourceLoader())
      raise NotImplementedError('OPy help not implemented')
      sys.exit(0)

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

    main_name = first_arg
    argv0 = argv[1]
    main_argv = argv[2:]
  else:
    argv0 = argv[0]
    main_argv = argv[1:]

  if main_name == 'opy':
    status = OpyMain(argv0, main_argv)
    return status
  elif main_name == 'opyc':
    return opy_main.OpyCommandMain(main_argv)

  else:
    raise args.UsageError('Invalid applet name %r.' % main_name)
Beispiel #2
0
def Export(argv, mem):
    arg, i = EXPORT_SPEC.Parse(argv)
    if arg.n:
        for name in argv[i:]:
            m = match.IsValidVarName(name)
            if not m:
                raise args.UsageError('export: Invalid variable name %r' %
                                      name)

            # NOTE: bash doesn't care if it wasn't found.
            mem.ClearFlag(name, var_flags_e.Exported, scope_e.Dynamic)
    else:
        for arg in argv[i:]:
            parts = arg.split('=', 1)
            if len(parts) == 1:
                name = parts[0]
                val = None  # Creates an empty variable
            else:
                name, s = parts
                val = runtime.Str(s)

            m = match.IsValidVarName(name)
            if not m:
                raise args.UsageError('export: Invalid variable name %r' %
                                      name)

            #log('%s %s', name, val)
            mem.SetVar(runtime.LhsName(name), val, (var_flags_e.Exported, ),
                       scope_e.Dynamic)

    return 0
Beispiel #3
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 = OshMain(argv0, main_argv, login_shell)
        _tlog('done osh main')
        return status
    elif main_name == 'oshc':
        return OshCommandMain(main_argv)

    elif main_name == 'oil':
        return OilMain(main_argv)
    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)
Beispiel #4
0
 def _SetOption(self, opt_name, b):
   """Private version for synchronizing from SHELLOPTS."""
   assert '_' not in opt_name
   if opt_name not in _SET_OPTION_NAMES:
     raise args.UsageError('Invalid option %r' % opt_name)
   if opt_name == 'errexit':
     self.errexit.Set(b)
   else:
     # strict-control-flow -> strict_control_flow
     opt_name = opt_name.replace('-', '_')
     setattr(self, opt_name, b)
Beispiel #5
0
def UnAlias(argv, aliases):
    if not argv:
        raise args.UsageError('unalias NAME...')

    status = 0
    for name in argv:
        try:
            del aliases[name]
        except KeyError:
            util.error('alias %r is not defined', name)
            status = 1
    return status
Beispiel #6
0
 def _SetOption(self, opt_name, b):
     """Private version for synchronizing from SHELLOPTS."""
     assert '_' not in opt_name
     if opt_name not in _SET_OPTION_NAMES:
         raise args.UsageError('Invalid option %r' % opt_name)
     if opt_name == 'errexit':
         self.errexit.Set(b)
     elif opt_name in ('vi', 'emacs'):
         if self.readline:
             self.readline.parse_and_bind("set editing-mode " + opt_name)
         else:
             # TODO error message copied from 'cmd_exec.py'; refactor?
             util.error('Oil was not built with readline/completion.')
     else:
         # strict-control-flow -> strict_control_flow
         opt_name = opt_name.replace('-', '_')
         setattr(self, opt_name, b)
Beispiel #7
0
def Shopt(argv, exec_opts):
    arg, i = SHOPT_SPEC.Parse(argv)
    #log('%s', arg)

    b = None
    if arg.s:
        b = True
    elif arg.u:
        b = False

    if b is None:
        raise NotImplementedError  # Display options

    for opt_name in argv[i:]:
        if opt_name not in ('nullglob', 'failglob'):
            raise args.UsageError('shopt: Invalid option %r' % opt_name)
        setattr(exec_opts, opt_name, b)

    return 0
Beispiel #8
0
def GetOpts(argv, mem):
    """
  Vars to set:
    OPTIND - initialized to 1 at startup
    OPTARG - argument
  Vars used:
    OPTERR: disable printing of error messages
  """
    # TODO: need to handle explicit args.

    try:
        # NOTE: If first char is a colon, error reporting is different.  Alpine
        # might not use that?
        spec_str = argv[0]
        var_name = argv[1]
    except IndexError:
        raise args.UsageError('getopts optstring name [arg]')

    try:
        spec = _GETOPTS_CACHE[spec_str]
    except KeyError:
        spec = _ParseOptSpec(spec_str)
        _GETOPTS_CACHE[spec_str] = spec

    # These errors are fatal errors, not like the builtin exiting with code 1.
    # Because the invariants of the shell have been violated!
    v = mem.GetVar('OPTIND')
    if v.tag != value_e.Str:
        e_die('OPTIND should be a string, got %r', v)
    try:
        optind = int(v.s)
    except ValueError:
        e_die("OPTIND doesn't look like an integer, got %r", v.s)

    user_argv = argv[2:] or mem.GetArgv()
    status, opt_char, optarg, optind = _GetOpts(spec, user_argv, optind)

    # Bug fix: bash-completion uses a *local* OPTIND !  Not global.
    state.SetStringDynamic(mem, var_name, opt_char)
    state.SetStringDynamic(mem, 'OPTARG', optarg)
    state.SetStringDynamic(mem, 'OPTIND', str(optind))
    return status
Beispiel #9
0
def Umask(argv):
    if len(argv) == 0:
        # umask() has a dumb API: you can't get it without modifying it first!
        # NOTE: dash disables interrupts around the two umask() calls, but that
        # shouldn't be a concern for us.  Signal handlers won't call umask().
        mask = posix.umask(0)
        posix.umask(mask)  #
        print('0%03o' % mask)  # octal format
        return 0

    if len(argv) == 1:
        a = argv[0]
        try:
            new_mask = int(a, 8)
        except ValueError:
            # NOTE: This happens if we have '8' or '9' in the input too.

            util.warn('*** umask with symbolic input not implemented ***')
            return 1
        else:
            posix.umask(new_mask)
            return 0

    raise args.UsageError('umask: unexpected arguments')
Beispiel #10
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,
                       os.strerror(e.errno))
            return 2

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

    line_reader = reader.FileLineReader(f, arena)
    _, c_parser = parse_lib.MakeParser(line_reader, arena)

    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

    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':
        # TODO: FIx this invocation up.
        #debug_spans = opt.debug_spans
        debug_spans = False
        osh2oil.PrintAsOil(arena, node, debug_spans)

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

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

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

    else:
        raise AssertionError  # Checked above

    return 0
Beispiel #11
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.MakeParser(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
Beispiel #12
0
def Trap(argv, traps, nodes_to_run, ex):
    arg, i = TRAP_SPEC.Parse(argv)

    if arg.p:  # Print registered handlers
        for name, value in traps.iteritems():
            print(name)
            print(value)
            print()

        sys.stdout.flush()
        return 0

    if arg.l:  # List valid signals and hooks
        ordered = _SIGNAL_NAMES.items()
        ordered.sort(key=lambda x: x[1])

        for name in _HOOK_NAMES:
            print('   %s' % name)
        for name, int_val in ordered:
            print('%2d %s' % (int_val, name))

        sys.stdout.flush()
        return 0

    try:
        code_str = argv[0]
        sig_spec = argv[1]
    except IndexError:
        raise args.UsageError('trap CODE SIGNAL_SPEC')

    # NOTE: sig_spec isn't validated when removing handlers.
    if code_str == '-':
        if sig_spec in _HOOK_NAMES:
            try:
                del traps[sig_spec]
            except KeyError:
                pass
            return 0

        sig_val = _GetSignalValue(sig_spec)
        if sig_val is not None:
            try:
                del traps[sig_spec]
            except KeyError:
                pass

            # Restore default
            if sig_val == signal.SIGINT:
                RegisterSigIntHandler()
            else:
                signal.signal(sig_val, signal.SIG_DFL)
            return 0

        util.error("Can't remove invalid trap %r" % sig_spec)
        return 1

    # Try parsing the code first.
    node = ex.ParseTrapCode(code_str)
    if node is None:
        return 1  # ParseTrapCode() prints an error for us.

    # Register a hook.
    if sig_spec in _HOOK_NAMES:
        if sig_spec in ('ERR', 'RETURN', 'DEBUG'):
            util.warn("*** The %r isn't yet implemented in OSH ***", sig_spec)
        traps[sig_spec] = _TrapHandler(node, nodes_to_run)
        return 0

    # Register a signal.
    sig_val = _GetSignalValue(sig_spec)
    if sig_val is not None:
        handler = _TrapHandler(node, nodes_to_run)
        # For signal handlers, the traps dictionary is used only for debugging.
        traps[sig_spec] = handler

        signal.signal(sig_val, handler)
        return 0

    util.error('Invalid trap %r' % sig_spec)
    return 1
Beispiel #13
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', '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)
Beispiel #14
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)
Beispiel #15
0
 def SetShoptOption(self, opt_name, b):
     """ For shopt -s/-u. """
     if opt_name not in self.SHOPT_OPTIONS:
         raise args.UsageError('Invalid option %r' % opt_name)
     setattr(self, opt_name, b)
Beispiel #16
0
def _BuildCompletionChain(argv, arg, ex):
  """Given flags to complete/compgen, built a ChainedCompleter."""
  actions = []

  # NOTE: bash doesn't actually check the name until completion time, but
  # obviously it's better to check here.
  if arg.F:
    func_name = arg.F
    func = ex.funcs.get(func_name)
    if func is None:
      raise args.UsageError('Function %r not found' % func_name)
    actions.append(completion.ShellFuncAction(ex, func))

  # NOTE: We need completion for -A action itself!!!  bash seems to have it.
  for name in arg.actions:
    if name == 'alias':
      a = _SortedWordsAction(ex.aliases)

    elif name == 'binding':
      # TODO: Where do we get this from?
      a = _SortedWordsAction(['vi-delete'])

    elif name == 'command':
      # TODO: This needs keywords too
      actions.append(_SortedWordsAction(builtin.BUILTIN_NAMES))

      a = completion.ExternalCommandAction(ex.mem)

    elif name == 'directory':
      a = completion.FileSystemAction(dirs_only=True)

    elif name == 'file':
      a = completion.FileSystemAction()

    elif name == 'function':
      a = _SortedWordsAction(ex.funcs)

    elif name == 'job':
      a = _SortedWordsAction(['jobs-not-implemented'])

    elif name == 'user':
      a = _UsersAction()

    elif name == 'variable':
      a = completion.VariablesAction(ex.mem)

    elif name == 'helptopic':
      a = _SortedWordsAction(osh_help.TOPIC_LOOKUP)

    elif name == 'setopt':
      a = _SortedWordsAction(state.SET_OPTION_NAMES)

    elif name == 'shopt':
      a = _SortedWordsAction(state.SHOPT_OPTION_NAMES)

    elif name == 'signal':
      a = _SortedWordsAction(['TODO:signals'])

    elif name == 'stopped':
      a = _SortedWordsAction(['jobs-not-implemented'])

    else:
      raise NotImplementedError(name)

    actions.append(a)

  # e.g. -W comes after -A directory
  if arg.W:
    # TODO: Split with IFS.  Is that done at registration time or completion
    # time?
    actions.append(completion.WordsAction(arg.W.split()))

  if not actions:
    raise args.UsageError('No actions defined in completion: %s' % argv)

  chain = completion.ChainedCompleter(
      actions,
      prefix=arg.P or '',
      suffix=arg.S or '')

  return chain
Beispiel #17
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)