| 1 | #!/usr/bin/env python2
 | 
| 2 | """Osh_parse.py."""
 | 
| 3 | from __future__ import print_function
 | 
| 4 | 
 | 
| 5 | import sys
 | 
| 6 | 
 | 
| 7 | from _devbuild.gen.option_asdl import option_i
 | 
| 8 | from _devbuild.gen.syntax_asdl import source, source_t, command, command_t
 | 
| 9 | from asdl import format as fmt
 | 
| 10 | from core import alloc
 | 
| 11 | from core import error
 | 
| 12 | from core import optview
 | 
| 13 | #from core import main_loop
 | 
| 14 | from core import pyutil
 | 
| 15 | from core import state
 | 
| 16 | from core import ui
 | 
| 17 | from frontend import parse_lib
 | 
| 18 | from frontend import reader
 | 
| 19 | from mycpp import mylib
 | 
| 20 | from mycpp.mylib import log
 | 
| 21 | 
 | 
| 22 | _ = log
 | 
| 23 | 
 | 
| 24 | from typing import List, Dict, TYPE_CHECKING
 | 
| 25 | if 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
 | 
| 31 | def 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 | 
 | 
| 51 | def 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 | 
 | 
| 127 | if __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)
 |