OILS / bin / osh_parse.py View on Github | oils.pub

126 lines, 86 significant
1#!/usr/bin/env python2
2from __future__ import print_function
3
4import sys
5
6from _devbuild.gen.option_asdl import option_i
7from _devbuild.gen.syntax_asdl import source, source_t, command, command_t
8from asdl import format as fmt
9from core import alloc
10from core import error
11from core import optview
12#from core import main_loop
13from core import pyutil
14from core import state
15from display import ui
16from frontend import parse_lib
17from frontend import reader
18from mycpp import mylib
19from mycpp.mylib import log
20
21_ = log
22
23from typing import List, Dict, TYPE_CHECKING
24if TYPE_CHECKING:
25 from osh.cmd_parse import CommandParser
26 from pgen2.grammar import Grammar
27
28
29# TEMP: Copied from core/main_loop.py
30def ParseWholeFile(c_parser):
31 # type: (CommandParser) -> command_t
32 """Parse an entire shell script.
33
34 This uses the same logic as Batch().
35 """
36 children = [] # type: List[command_t]
37 while True:
38 node = c_parser.ParseLogicalLine() # can raise ParseError
39 if node is None: # EOF
40 c_parser.CheckForPendingHereDocs() # can raise ParseError
41 break
42 children.append(node)
43
44 if len(children) == 1:
45 return children[0]
46 else:
47 return command.CommandList(children)
48
49
50def main(argv):
51 # type: (List[str]) -> int
52 arena = alloc.Arena()
53 errfmt = ui.ErrorFormatter()
54
55 opt0_array = state.InitOpts()
56 no_stack = None # type: List[bool] # for mycpp
57 opt_stacks = [no_stack] * option_i.ARRAY_SIZE # type: List[List[bool]]
58 parse_opts = optview.Parse(opt0_array, opt_stacks)
59 # Dummy value; not respecting aliases!
60 aliases = {} # type: Dict[str, str]
61 # parse `` and a[x+1]=bar differently
62
63 ysh_grammar = None # type: Grammar
64 if mylib.PYTHON:
65 loader = pyutil.GetResourceLoader()
66 ysh_grammar = pyutil.LoadYshGrammar(loader)
67
68 parse_ctx = parse_lib.ParseContext(arena, parse_opts, aliases, ysh_grammar)
69
70 pretty_print = True
71
72 if len(argv) == 1:
73 line_reader = reader.FileLineReader(mylib.Stdin(), arena)
74 src = source.Stdin('') # type: source_t
75
76 elif len(argv) == 2:
77 path = argv[1]
78 f = mylib.open(path)
79 line_reader = reader.FileLineReader(f, arena)
80 src = source.MainFile(path)
81
82 elif len(argv) == 3:
83 if argv[1] == '-c':
84 # This path is easier to run through GDB
85 line_reader = reader.StringLineReader(argv[2], arena)
86 src = source.CFlag
87
88 elif argv[1] == '-n': # For benchmarking, allow osh_parse -n file.txt
89 path = argv[2]
90 f = mylib.open(path)
91 line_reader = reader.FileLineReader(f, arena)
92 src = source.MainFile(path)
93 # This is like --ast-format none, which benchmarks/osh-helper.sh passes.
94 pretty_print = False
95
96 else:
97 raise AssertionError()
98
99 else:
100 raise AssertionError()
101
102 arena.PushSource(src)
103
104 c_parser = parse_ctx.MakeOshParser(line_reader)
105
106 try:
107 #node = main_loop.ParseWholeFile(c_parser)
108 node = ParseWholeFile(c_parser)
109 except error.Parse as e:
110 errfmt.PrettyPrintError(e)
111 return 2
112 assert node is not None
113
114 if pretty_print:
115 tree = node.PrettyTree(True)
116 fmt.HNodePrettyPrint(tree, mylib.Stdout())
117
118 return 0
119
120
121if __name__ == '__main__':
122 try:
123 main(sys.argv)
124 except RuntimeError as e:
125 print('FATAL: %s' % e, file=sys.stderr)
126 sys.exit(1)