def _TestGetCompletionType(buf): ev = test_lib.MakeTestEvaluator() arena = test_lib.MakeArena('<completion_test.py>') parse_ctx = parse_lib.ParseContext(arena, {}) w_parser, c_parser = parse_ctx.MakeParserForCompletion(buf, arena) print('---', buf) return completion._GetCompletionType(w_parser, c_parser, ev, debug_f)
def _MakeParser(code_str): # NOTE: We need the extra ]] token arena = test_lib.MakeArena('<bool_parse_test.py>') parse_ctx = parse_lib.ParseContext(arena, {}) w_parser, _ = parse_ctx.MakeParserForCompletion(code_str + ' ]]', arena) w_parser._Next(lex_mode_e.DBRACKET) # for tests only p = bool_parse.BoolParser(w_parser) p._Next() return p
def InitExecutor(arena=None): arena = arena or MakeArena('<InitExecutor>') mem = state.Mem('', [], {}, arena) fd_state = process.FdState() funcs = {} comp_funcs = {} # For the tests, we do not use 'readline'. exec_opts = state.ExecOpts(mem, None) parse_ctx = parse_lib.ParseContext(arena, {}) debug_f = util.DebugFile(sys.stderr) devtools = dev.DevTools(dev.CrashDumper(''), debug_f, debug_f) return cmd_exec.Executor(mem, fd_state, funcs, comp_funcs, exec_opts, parse_ctx, devtools)
def ParseAndEval(code_str): arena = test_lib.MakeArena('<arith_parse_test.py>') parse_ctx = parse_lib.ParseContext(arena, {}) w_parser, _ = parse_ctx.MakeParserForCompletion(code_str, arena) w_parser._Next(lex_mode_e.ARITH) # Calling private method anode = w_parser._ReadArithExpr() # need the right lex state? print('node:', anode) mem = state.Mem('', [], {}, arena) exec_opts = state.ExecOpts(mem, None) splitter = legacy.SplitContext(mem) ev = word_eval.CompletionWordEvaluator(mem, exec_opts, splitter, arena) arith_ev = expr_eval.ArithEvaluator(mem, exec_opts, ev, arena) value = arith_ev.Eval(anode) return value
def _Detect(test, word_str, expected): # TODO: This function could be moved to test_lib. log('-' * 80) arena, w = word_parse_test._assertReadWordWithArena(test, word_str) actual = word.DetectAssignment(w) left_token, close_token, part_offset = actual expected_left, expected_close, expected_part_offset = expected print(left_token, close_token, part_offset) print() if expected_left is None: test.assertEqual(None, left_token) else: test.assertEqual(expected_left, left_token.id) if expected_close is None: test.assertEqual(None, close_token) else: test.assertEqual(expected_left, left_token.id) test.assertEqual(expected_part_offset, part_offset) parse_ctx = parse_lib.ParseContext(arena, {}) if left_token and left_token.id in (Id.Lit_VarLike, Id.Lit_ArrayLhsOpen): more_env = [] preparsed = (left_token, close_token, part_offset, w) try: cmd_parse._AppendMoreEnv([preparsed], more_env) except Exception as e: log('Error: %s', e) else: log('more_env: %s', more_env) try: assign_pair = cmd_parse._MakeAssignPair(parse_ctx, preparsed) except Exception as e: log('Error: %s', e) else: log('assign_pair: %s', assign_pair)
def testRootCompleter(self): comp_lookup = completion.CompletionLookup() comp_lookup.RegisterName('grep', C1) comp_lookup.RegisterName('__first', FIRST) ev = test_lib.MakeTestEvaluator() pool = alloc.Pool() arena = pool.NewArena() parse_ctx = parse_lib.ParseContext(arena, {}) var_comp = V1 r = completion.RootCompleter(ev, comp_lookup, var_comp, parse_ctx, progress_f, debug_f) comp = completion.CompletionApi(line='grep f') m = list(r.Matches(comp)) self.assertEqual(['foo.py', 'foo'], m) comp = completion.CompletionApi(line='grep g') m = list(r.Matches(comp)) self.assertEqual([], m) m = list(r.Matches(completion.CompletionApi(line='ls $v'))) self.assertEqual(['$var1', '$var2'], m) m = list(r.Matches(completion.CompletionApi(line='g'))) self.assertEqual(['grep'], m) # Empty completer m = list(r.Matches(completion.CompletionApi(''))) self.assertEqual(['grep', 'sed', 'test'], m) # Test compound commands. These PARSE m = list(r.Matches(completion.CompletionApi('echo hi || grep f'))) m = list(r.Matches(completion.CompletionApi('echo hi; grep f'))) # Brace -- does NOT parse m = list(r.Matches(completion.CompletionApi('{ echo hi; grep f'))) # TODO: Test if/for/while/case/etc. m = list(r.Matches(completion.CompletionApi('var=$v'))) m = list(r.Matches(completion.CompletionApi('local var=$v')))
def InitCommandParser(code_str): arena = test_lib.MakeArena('<cmd_parse_test.py>') parse_ctx = parse_lib.ParseContext(arena, {}) line_reader, lexer = parse_lib.InitLexer(code_str, arena) _, c_parser = parse_ctx.MakeParser(line_reader) return arena, c_parser # arena is returned for printing errors
def InitCommandParser(code_str, arena=None): arena = arena or test_lib.MakeArena('<cmd_exec_test.py>') parse_ctx = parse_lib.ParseContext(arena, {}) line_reader, lexer = parse_lib.InitLexer(code_str, arena) _, c_parser = parse_ctx.MakeParser(line_reader) return c_parser
def _InitWordParserWithArena(s): arena = alloc.SideArena('word_parse_test.py') parse_ctx = parse_lib.ParseContext(arena, {}) line_reader, lexer = parse_lib.InitLexer(s, arena) w_parser, _ = parse_ctx.MakeParser(line_reader) return arena, w_parser
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
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