#!/usr/bin/env python

""" Toy Parser Generator - A Python parser generator

Toy Parser Generator: A Python parser generator
Copyright (C) 2001-2013 Christophe Delord

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

For further information about TPG you can visit
http://cdsoft.fr/tpg
"""

import re
import sys
import tpg

def say(msg, file=sys.stdout):
    file.write(msg)
    file.write("\n")

class ArgError(Exception): pass

def getargs(args):
    def check(cond):
        if not cond: raise ArgError
    i, o, v = None, None, 0
    while args:
        arg = args.pop(0)
        if arg == '-o':
            check(o is None and args)
            o = args.pop(0)
            check(o.endswith('.py'))
        elif re.match('-v+$', arg):
            v += len(arg)-1
        else:
            check(i is None and arg.endswith('.pyg'))
            i = arg
    check(i is not None)
    if o is None: o = i[:-4] + '.py'
    return i, o, v

say("TPG v%s (c) %s"%(tpg.__version__, tpg.__author__))
try: (grammar_file, output_file, v) = getargs(sys.argv[1:])
except ArgError: say("Syntax: %s [-v|-vv] grammar_file.pyg [-o output_file.py]"%sys.argv[0], file=sys.stderr)
else:
    try:

        say("TPG: translating %s to %s"%(grammar_file,output_file))
        f = open(grammar_file, 'r')
        source = f.read()
        f.close()

        TPG = tpg.TPGParser()

        parser_re = re.compile(r"""
            [ \t]* class [ \t]+ (?P<class_name>\w+) (?P<base_name> \( .* \b tpg\.Parser \b .* \) ) \s* : \s* \n
            (?P<indent>     [ \t]*
            )
            (?P<grammar>    r"{3} (?: "{0,2} [^"]+ )* "{3}
            |               r'{3} (?: '{0,2} [^']+ )* '{3}
            )
            """, re.VERBOSE)

        for class_name, base_name, indent, grammar in parser_re.findall(source):
            code = []
            if v >= 1: say("Parser %s"%class_name)
            for attribute, attribute_source, attribute_code in TPG(grammar[4:-3]):
                if v>=2:
                    if attribute_code.__doc__ is not None:
                        say("    %s"%(attribute_code.__doc__.strip()))
                indented_code = "".join([indent+line+"\n" for line in attribute_source.splitlines()])
                code.append(indented_code)
            code = "__grammar__ = %s\n\n%s"%(grammar, "\n".join(code))
            source = source.replace(grammar, code)

        g = open(output_file, 'w')
        g.write(source)
        g.close()

        say("Translation OK")
        sys.exit(0)

    except IOError:
        say("IOError: %s"%tpg.exc(), file=sys.stderr)
    except tpg.Error:
        say(tpg.exc(), file=sys.stderr)
sys.exit(1)
