# This file is part of the Coral project.
# Please read the copyright notice in the LICENSE file.

#
# Converts a Coral metamodel to BNF grammar
#
from coral import kernel as coral
from coral.lgen.bnf import bnf

def lang2grammar(L):
    class _tmp:
        def __init__(self):
            self.cache = {}

    def create(tmp, ed):
        if tmp.cache.has_key(ed):
            return tmp.cache[ed]
        if isinstance(ed, coral.EnumerationDefinition):
            # Special case when only one value
            if ed.size() == 1:
                e = bnf.Terminal(ed.getDescription(0))
                tmp.cache[ed] = e
                return e
            e = bnf.Nonterminal(ed.getName())
            tmp.cache[ed] = e
            g = bnf.Group()
            e.seq.targets.append(bnf.Target(g))
            for i in xrange(ed.size()):
                t = bnf.Terminal(ed.getDescription(i))
                seq = bnf.Sequence()
                r = bnf.Target(t)
                seq.targets.append(r)
                g.choices.append(seq)
            return e
        if isinstance(ed, coral.DatatypeDefinition):
            if ed.isSubclass(coral.UnlimitedInteger):
                e = bnf.Integer
            elif ed.isSubclass(coral.String):
                e = bnf.String
            elif ed.isSubclass(coral.UnlimitedReal):
                e = bnf.Real
            elif ed.isSubclass(coral.coralPyObj):
                assert 0
            assert e
            return e
            
        assert isinstance(ed, coral.ElementDefinition)

        e = None
        if ed.isAbstract():
            subclasses = ed.getSubclasses()
            assert subclasses
            e = bnf.Group()
            tmp.cache[ed] = e
            for sub in subclasses:
                r = create(tmp, sub)
                e.choices.append(r)
            return e
        elif ed.getSuperclasses():
            e = bnf.Sequence()
            tmp.cache[ed] = e
        else:
            e = bnf.Nonterminal(ed.getName())
            tmp.cache[ed] = e

        seq = bnf.Sequence()
        for p in ed.__properties__():
            if p.isAnonymous():
                continue
            if not p.isComposition():
                continue
            targettype = create(tmp, p.getTarget())
            ml = p.getMultLower()
            mu = p.getMultUpper()
            t = bnf.Target(targettype, ml, mu)
            seq.targets.append(t)
        if isinstance(e, bnf.Sequence):
            e.targets = seq.targets
            return e
        e.seq = seq
        return e
    
    tmp = _tmp()
    B = bnf.BNF()
    B.start_token = create(tmp, L.getRoot())
    return B
    
