1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#
5# Copyright 2017, Data61
6# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
7# ABN 41 687 119 230.
8#
9# This software may be distributed and modified according to the terms of
10# the BSD 2-Clause license. Note that NO WARRANTY is provided.
11# See "LICENSE_BSD2.txt" for details.
12#
13# @TAG(DATA61_BSD)
14#
15
16'''
17Stage 1 parser. The following parser is designed to accept a stage 0 parser,
18whose output it consumes. A stage 1 parser makes the following transformation:
19
20    augmented_input ��� raw_ast
21'''
22
23from __future__ import absolute_import, division, print_function, \
24    unicode_literals
25from camkes.internal.seven import cmp, filter, map, zip
26
27import os, plyplus, re
28from .base import Parser
29from camkes.ast import SourceLocation
30from .exception import ParseError
31
32GRAMMAR = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'camkes.g')
33
34_parser = None
35def _parse(string):
36    # Construct the parser lazily.
37    global _parser
38    if _parser is None:
39        with open(GRAMMAR, 'rt') as f:
40            _parser = plyplus.Grammar(f.read())
41
42    # Parse `string` into a plyplus STree.
43    return _parser.parse(string)
44
45class Parse1(Parser):
46    def __init__(self, parse0):
47        self.parse0 = parse0
48
49    def parse_file(self, filename):
50        processed, read = self.parse0.parse_file(filename)
51        try:
52            ast_raw = _parse(processed)
53        except plyplus.ParseError as e:
54            location = SourceLocation(filename, e, processed)
55            e = augment_exception(e)
56            raise ParseError(e, location)
57        return processed, ast_raw, read
58
59    def parse_string(self, string):
60        processed, read = self.parse0.parse_string(string)
61        try:
62            ast_raw = _parse(processed)
63        except plyplus.ParseError as e:
64            location = SourceLocation(None, e, processed)
65            e = augment_exception(e)
66            raise ParseError(e, location)
67        return processed, ast_raw, read
68
69def augment_exception(exc):
70    '''
71    Bolt on some extra, potentially helpful information to a PlyPlus exception.
72    There are certain common typos that manifest in inscrutable PlyPlus
73    exceptions. This function recognises these and adds a note about the
74    possible root cause.
75    '''
76    assert isinstance(exc, plyplus.ParseError)
77    if str(exc) == 'Syntax error in input (details unknown): None\nCould ' \
78            'not create parse tree!':
79        exc = plyplus.ParseError('%s (missing closing brace?)' % str(exc))
80    return exc
81