Merge: No old style accessors
[nit.git] / contrib / nitcc / src / nitcc_semantic.nit
index 9854075..b723c1a 100644 (file)
@@ -62,21 +62,23 @@ class CollectNameVisitor
 
                # Build the NFA automaton
                for t in gram.tokens do
-                       var nexpr = t.nexpr
-                       var nfa2
-                       if nexpr == null then
-                               nfa2 = new Automaton.epsilon
-                               for c in t.text.as(not null) do
-                                       nfa2.concat(new Automaton.atom(c.ascii))
-                               end
-                       else
-                               nfa2 = nexpr.build_nfa
+                       var nfa2 = t.build_nfa
+                       nfa2.tag_accept(t)
+                       nfa.absorb(nfa2)
+               end
+
+               if not v2.ignoreds.is_empty then
+                       var ign = new Token("Ignored")
+                       var nfa2 = new Automaton.empty
+                       for t in v2.ignoreds do
+                               assert t isa Token
+                               var nfa3 = t.build_nfa
+                               nfa2.alternate(nfa3)
                        end
-                       nfa.states.add_all nfa2.states
-                       nfa.start.add_trans(nfa2.start, null)
-                       for s in nfa2.accept do nfa.add_tag(s, t)
-                       nfa.accept.add_all nfa2.accept
+                       nfa2.tag_accept(ign)
+                       nfa.absorb(nfa2)
                end
+
        end
 
        redef fun visit(n) do n.accept_collect_prod(self)
@@ -100,8 +102,11 @@ private class CheckNameVisitor
        # Is the alternative transformed, for the alternative
        var trans = false
 
+       # Known ignored tokens
+       var ignoreds = new Array[Element]
+
        # Known rejected tokens
-       var rejecteds = new Array[Token]
+       var rejecteds = new Array[Element]
 
        # Pool of elements that are modified with + (reuse them!)
        private var plusizes = new HashMap[Element, Production]
@@ -170,6 +175,10 @@ redef class Nexpr
        redef fun accept_collect_prod(v) do
                var id = children.first.as(Nid)
                var name = id.text
+               if v.names.has_key(name) then
+                       print "{id.position.to_s} Error {name} already defined."
+                       exit(1)
+               end
                v.names[name] = self
                self.name = name
        end
@@ -216,13 +225,13 @@ redef class Nre_id
                var id = children.first.as(Nid)
                var name = id.text
                if not v.v1.names.has_key(name) then
-                       print "{id.position} Error: unknown name {name}"
+                       print "{id.position.to_s} Error: unknown name {name}"
                        exit(1)
                        abort
                end
                var node = v.v1.names[name]
                if node isa Nprod then
-                       print "{id.position} Error: cannot use production {name} in a regular expression"
+                       print "{id.position.to_s} Error: cannot use production {name} in a regular expression"
                        exit(1)
                        abort
                else if not node isa Nexpr then
@@ -239,41 +248,30 @@ redef class Nre_id
 end
 
 redef class Nign
-       # The named element
-       var elem: nullable Element
-
        redef fun accept_check_name_visitor(v) do
-               var id = children[1].as(Nid)
-               var name = id.text
-               if not v.v1.names.has_key(name) then
-                       print "{id.position} Error: unknown name {name}"
-                       exit(1)
-                       abort
-               end
-               var node = v.v1.names[name]
-               var elem: nullable Element
-               if node isa Nprod then
-                       print "{id.position} Error: cannot ignore a production"
-                       exit(1)
-                       abort
-               else if node isa Nexpr then
-                       elem = node.token
-                       if elem == null then
-                               elem = new Token("Ignored")
-                               elem.nexpr = node
-                               v.v1.gram.tokens.add(elem)
-                               node.token = elem
+               # Add elements to the ignored list
+               v.elems = v.ignoreds
+               super
+               for e in v.elems do
+                       if e isa Production then
+                               print "Error: cannot ignore {e}, it is a production"
+                               exit(1)
+                               abort
+                       else if e isa Token then
+                               # The token was build and registered during the visit
+                               # So, unregister then, the bit Ignred token will be build later
+                               v.v1.gram.tokens.remove(e)
+                       else
+                               abort
                        end
-               else
-                       abort
                end
-               self.elem = elem
        end
 end
 
 redef class Nrej
        redef fun accept_check_name_visitor(v) do
-               v.elems = new Array[Element]
+               # Add elements to the rejected list
+               v.elems = v.rejecteds
                super
                for e in v.elems do
                        if e isa Production then
@@ -282,8 +280,6 @@ redef class Nrej
                                abort
                        else if e isa Token then
                                # The token was build and registered during the visit
-                               # Just add it to the rejected list
-                               v.rejecteds.add(e)
                        else
                                abort
                        end
@@ -298,6 +294,10 @@ redef class Nprod
        redef fun accept_collect_prod(v) do
                var id = children.first.as(Nid)
                var name = id.text
+               if v.names.has_key(name) then
+                       print "{id.position.to_s} Error {name} already defined."
+                       exit(1)
+               end
                v.names[name] = self
                v.nprods.add(self)
                prod = new Production(name)
@@ -333,13 +333,14 @@ end
 
 redef class Natrans
        redef fun accept_check_name_visitor(v) do
-               var id = children[2].as(Nid)
-               var name = id.text
-
                v.trans = true
        end
 end
 
+redef class Alternative
+       var short_name: nullable String
+end
+
 redef class Nalt
        # The associated alternative
        var alt: nullable Alternative
@@ -376,6 +377,7 @@ redef class Nalt
                        name = prodabs.name + "_" + name
                end
                var alt = prod.new_alt2(name, v.elems)
+               alt.short_name = v.altname
                alt.elems_names.add_all(v.elems_names)
                self.alt = alt
                if v.trans then
@@ -391,6 +393,15 @@ redef class Naltid
                var id = children[1].as(Nid)
                var name = id.text
                v.altname = name
+               var prod = v.prod.as(not null)
+               var prodabs = prod.spe
+               if prodabs == null then prodabs = prod
+               for x in prodabs.alts do
+                       if x.short_name == name then
+                               print "{id.position.to_s} Error: already an alternative named {name}"
+                               exit(1)
+                       end
+               end
        end
 end
 
@@ -399,22 +410,30 @@ redef class Nelem
        var elem: nullable Element
 
        # Set the element and check things
-       fun set_elem(v: CheckNameVisitor, pos: nullable Position, elem: Element)
+       private fun set_elem(v: CheckNameVisitor, pos: nullable Position, elem: Element)
        do
                assert self.elem == null
                self.elem = elem
-               v.elems.push(elem)
-               if elem isa Token and v.rejecteds.has(elem) then
-                       if pos != null then
-                               print "{pos} Error: {elem.name} is already a rejected token."
-                       else
-                               print "Error: {elem.name} is already a rejected token."
+               if elem isa Token then
+                       if v.ignoreds.has(elem) then
+                               if pos != null then
+                                       print "{pos} Error: {elem.name} is already an ignored token."
+                               else
+                                       print "Error: {elem.name} is already an ignored token."
+                               end
+                               exit(1)
+                       end
+                       if v.rejecteds.has(elem) then
+                               if pos != null then
+                                       print "{pos} Error: {elem.name} is already a rejected token."
+                               else
+                                       print "Error: {elem.name} is already a rejected token."
+                               end
+                               exit(1)
                        end
-                       exit(1)
                end
-
+               v.elems.push(elem)
        end
-
 end
 
 redef class Token
@@ -422,6 +441,26 @@ redef class Token
        var nexpr: nullable Nexpr
        # The associated text (if any, ie defined in the parser part)
        var text: nullable String
+
+       # Build a NFA according to nexpr or text
+       # Does not tag it!
+       fun build_nfa: Automaton
+       do
+               var nexpr = self.nexpr
+               if nexpr != null then
+                       assert self.text == null
+                       return nexpr.build_nfa
+               end
+               var text = self.text
+               if text != null then
+                       var nfa = new Automaton.epsilon
+                       for c in text.chars do
+                               nfa.concat(new Automaton.atom(c.ascii))
+                       end
+                       return nfa
+               end
+               abort
+       end
 end
 
 redef class Nnelem
@@ -444,6 +483,12 @@ redef class Nelemid
        do
                var id = children[1].as(Nid)
                var name = id.text
+               for n2 in v.elems_names do
+                       if name == n2 then
+                               print "{id.position.to_s} Error: already an element named {name}."
+                               exit(1)
+                       end
+               end
                v.elemname = name
        end
 end
@@ -453,7 +498,7 @@ redef class Nelem_id
                var id = children.first.as(Nid)
                var name = id.text
                if not v.v1.names.has_key(name) then
-                       print "{id.position} Error: unknown name {name}"
+                       print "{id.position.to_s} Error: unknown name {name}"
                        exit(1)
                        abort
                end
@@ -480,7 +525,7 @@ end
 
 redef class Nelem_str
        redef fun accept_check_name_visitor(v) do
-               var str = children.first.as(Nstr)
+               var str = children.first.children.first.as(NToken)
                var text = str.value
                var name = str.text
                var elem: nullable Element