- n.last_token = _last_token
-
- if n.first_token != null then
- var start_location = n.first_token.location
- var end_location = _last_token.location
-
- if start_location != null and end_location != null then
- var file = end_location.file
- var line_start = start_location.line_start
- var line_end = end_location.line_end
- var column_start = start_location.column_start
- var column_end = end_location.column_end
- n.location = new Location(file, line_start, line_end, column_start, column_end)
+ var endl = _last_location
+ if endl == null then _last_location = old_last
+
+ n._last_location = endl
+ var startl = n._first_location
+ if startl != null then
+ # Non-epsilon production
+ assert endl != null
+
+ n.location = new Location(startl.file, startl.line_start, endl.line_end, startl.column_start, endl.column_end)
+
+ for no in _need_before_epsilons do
+ # Epsilon production that starts the current non-epsilon production
+ #var startl = n.location
+ no.location = new Location(startl.file, startl.line_start, startl.line_start, startl.column_start, startl.column_start)
+ end
+ _need_before_epsilons.clear
+
+ for no in _need_after_epsilons do
+ # Epsilon production that finishes the current non-epsilon production
+ #var endl = n.location
+ no.location = new Location(endl.file, endl.line_end, endl.line_end, endl.column_end, endl.column_end)
+ end
+ _need_after_epsilons.clear
+ else
+ # No first token means epsilon production (or "throw all my tokens" production)
+ # So, it must be located it later
+ if endl == null then
+ # Epsilon production that starts a parent non-epsilon production
+ _need_before_epsilons.add(n)
+ else
+ # Epsilon production in the middle or that finishes a parent non-epsilon production
+ _need_after_epsilons.add(n)