assert node1 isa AModule
var node = new Start(node1, node2)
node2.parent = node
- (new ComputeProdLocationVisitor).enter_visit(node)
+ (new ComputeProdLocationVisitor(lexer.file.first_token)).enter_visit(node)
return node
else if action_type == 3 then # ERROR
# skip injected tokens
# Uses existing token locations to infer location of productions.
private class ComputeProdLocationVisitor
super Visitor
+
+ # The current (or starting) cursor on the token sequence used to collect loose tokens
+ var token: nullable Token
+
# Currently visited productions that need a first token
var need_first_prods = new Array[Prod]
redef fun visit(n: ANode)
do
if n isa Token then
+ # Skip injected tokens
if not isset n._location then return
+
+ # Collect loose tokens (not in the AST) and attach them to token in the AST
+ var cursor = token
+ if n != cursor then
+ var lt = last_token
+ # In order, we have the tokens:
+ # * `lt` the previous visited token in the AST (if any)
+ # * then `cursor` the loose tokens to attach
+ # * then `n` the current visited token in the AST
+
+ # In the following, we advance `cursor` to add them to `lt.next_looses` or to `n.prev_looses`.
+ if lt != null then
+ var ltl = lt.location.line_end
+ # floating tokens on the same line of a AST-token follows it
+ while cursor != null and cursor != n and ltl == cursor.location.line_start do
+ cursor.is_loose = true
+ lt.next_looses.add cursor
+ cursor = cursor.next_token
+ end
+ end
+ # other loose tokens precede the next AST-token
+ while cursor != null and cursor != n do
+ cursor.is_loose = true
+ n.prev_looses.add cursor
+ cursor = cursor.next_token
+ end
+ end
+ token = n.next_token
+
var loc = n._location
_last_token = n
end
var goto: Int
end
+
+redef class AExpr
+
+ # Get `self` as a single identifier.
+ # Return null if not a single identifier.
+ fun as_id: nullable String
+ do
+ if self isa AMethidExpr then
+ return self.collect_text
+ end
+ if not self isa ACallExpr then return null
+ if not self.n_expr isa AImplicitSelfExpr then return null
+ if not self.n_args.n_exprs.is_empty then return null
+ return self.n_qid.n_id.text
+ end
+end