OILS / bin / osh_parse.py View on Github | oilshell.org

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