import location
import ordered_tree
+private import console
# Root of the AST class-hierarchy
abstract class ANode
- # Location is set during AST building. Once built, location cannon be null.
+ # Location is set during AST building. Once built, location can not be null.
# However, manual instantiated nodes may need more care.
var location: Location is writable, noinit
sys.stderr.write "{hot_location} {self.class_name}: {message}\n{hot_location.colored_line("0;32")}\n"
end
+ # Is `self` a token or a pure-structural production like `AQId`?
+ fun is_structural: Bool do return false
+
# Write the subtree on stdout.
- # See `ASTDump`
- fun dump_tree
+ #
+ # Visit the subtree and display it with additional and useful information.
+ #
+ # By default, this displays all kind of nodes and the corresponding lines of codes.
+ #
+ # See `ASTDump` for details.
+ fun dump_tree(display_structural, display_line: nullable Bool)
do
- var d = new ASTDump
+ var d = new ASTDump(display_structural or else true, display_line or else true)
d.enter_visit(self)
d.write_to(sys.stdout)
end
+ # Information to display on a node
+ #
+ # Refine this method to add additional information on each node type.
+ fun dump_info(v: ASTDump): String do return ""
+
# Parent of the node in the AST
var parent: nullable ANode = null
# Is used to handle the initial node parent and workaround possible inconsistent `ANode::parent`
private var last_parent: nullable ANode = null
+ # Display tokens and structural production?
+ #
+ # Should tokens (and structural production like AQId) be displayed?
+ var display_structural: Bool
+
+ # Display lines?
+ #
+ # Should each new line be displayed (numbered and in gray)?
+ var display_line: Bool
+
+ # Current line number (when printing lines)
+ private var line = 0
+
redef fun visit(n)
do
+ if not display_structural and n.is_structural then return
var p = last_parent
add(p, n)
last_parent = n
last_parent = p
end
- redef fun display(n)
+ redef fun write_line(o, n, p)
do
- if n isa Token then
- return "{n.class_name} \"{n.text.escape_to_c}\" @{n.location}"
- else
- return "{n.class_name} @{n.location}"
+ if display_line then
+ var ls = n.location.line_start
+ var file = n.location.file
+ var line = self.line
+ if ls > line and file != null then
+ if line == 0 then line = ls - 1
+ while line < ls do
+ line += 1
+ o.write "{line}\t{file.get_line(line)}\n".light_gray
+ end
+ self.line = ls
+ end
end
+
+ super
end
+
+ redef fun display(n)
+ do
+ return "{n.class_name} {n.dump_info(self)} @{n.location}"
+ end
+
+ # `s` as yellow
+ fun yellow(s: String): String do return s.yellow
+
+ # `s` as red
+ fun red(s: String): String do return s.red
end
# A sequence of nodes
private var parent: ANode
private var items = new Array[E]
redef fun iterator do return items.iterator
+ redef fun reverse_iterator do return items.reverse_iterator
redef fun length do return items.length
redef fun is_empty do return items.is_empty
redef fun push(e)
# May have disappeared in the AST
var next_token: nullable Token = null
+ # Is `self` a token discarded from the AST?
+ #
+ # Loose tokens are not present in the AST.
+ # It means they were identified by the lexer but were discarded by the parser.
+ # It also means that they are not visited or manipulated by AST-related functions.
+ #
+ # Each loose token is attached to the non-loose token that precedes or follows it.
+ # The rules are the following:
+ #
+ # * tokens that follow a non-loose token on a same line are attached to it.
+ # See `next_looses`.
+ # * other tokens, thus that precede a non-loose token on the same line or the next one,
+ # are attached to this one. See `prev_looses`.
+ #
+ # Loose tokens are mostly end of lines (`TEol`) and comments (`TComment`).
+ # Whitespace are ignored by the lexer, so they are not even considered as loose tokens.
+ # See `blank_before` to get the whitespace that separate tokens.
+ var is_loose = false
+
+ redef fun is_structural do return true
+
+ redef fun dump_info(v) do return " {text.escape_to_c}"
+
+ # Loose tokens that precede `self`.
+ #
+ # These tokens start the line or belong to a line with only loose tokens.
+ var prev_looses = new Array[Token] is lazy
+
+ # Loose tokens that follow `self`
+ #
+ # These tokens are on the same line than `self`.
+ var next_looses = new Array[Token] is lazy
+
# The verbatim blank text between `prev_token` and `self`
fun blank_before: String
do
super TokenKeyword
end
-# The keywords `enum` ane `universal`
+# The keywords `enum` and `universal`
class TKwenum
super TokenKeyword
end
+# The keyword `subset`
+class TKwsubset
+ super TokenKeyword
+end
+
# The keyword `end`
class TKwend
super TokenKeyword
super TokenKeyword
end
+# The keyword `catch`
+class TKwcatch
+ super TokenKeyword
+end
+
# The keyword `var`
class TKwvar
super TokenKeyword
super TokenKeyword
end
+# The keyword `yield`
+class TKwyield
+ super TokenKeyword
+end
+
# The special keyword `__DEBUG__`
class TKwdebug
super Token
end
end
-# A literal decimal integer
-class TNumber
- super TokenLiteral
-end
-
-# A literal hexadecimal integer
-class THexNumber
+# A literal integer
+class TInteger
super TokenLiteral
end
class APublicVisibility
super AVisibility
# The `public` keyword, if any
- var n_kwpublic: nullable TKwpublic is writable
+ var n_kwpublic: nullable TKwpublic = null is writable
end
# An explicit private visibility modifier
class APrivateVisibility
end
# A class definition
-# While most definition are `AStdClassdef`
-# There is tow special case of class definition
+#
+# While most definitions are `AStdClassdef`s,
+# there are 2 special cases of class definitions.
abstract class AClassdef
super Prod
# All the declared properties (including the main method)
var n_classkind: AClasskind is writable, noinit
# The name of the class
- var n_id: nullable TClassid = null is writable
+ var n_qid: nullable AQclassid = null is writable
# The `[` symbol
var n_obra: nullable TObra = null is writable
return [for d in n_propdefs do if d isa ASuperPropdef then d]
end
- redef fun hot_location do return n_id.location
+ redef fun hot_location do return n_qid.location
end
# The implicit class definition of the implicit main method
var n_kwclass: nullable TKwclass = null is writable
end
+class ASubsetClasskind
+ super AClasskind
+
+ # The `subset` keyword.
+ var n_kwsubset: TKwsubset is writable, noinit
+
+ redef fun visit_all(v) do
+ # TODO: Remove this redefinition once generated from the grammar.
+ v.enter_visit(n_kwsubset)
+ end
+end
+
# The definition of a formal generic parameter type. eg `X: Y`
class AFormaldef
super Prod
var n_kwtype: TKwtype is writable, noinit
# The name of the virtual type
- var n_id: TClassid is writable, noinit
+ var n_qid: AQclassid is writable, noinit
# The bound of the virtual type
var n_type: AType is writable, noinit
var n_assign: TAssign is writable, noinit
end
+# A potentially qualified simple identifier `foo::bar::baz`
+class AQid
+ super Prod
+ # The qualifier, if any
+ var n_qualified: nullable AQualified = null is writable
+
+ # The final identifier
+ var n_id: TId is writable, noinit
+
+ redef fun is_structural do return true
+end
+
+# A potentially qualified class identifier `foo::bar::Baz`
+class AQclassid
+ super Prod
+ # The qualifier, if any
+ var n_qualified: nullable AQualified = null is writable
+
+ # The final identifier
+ var n_id: TClassid is writable, noinit
+
+ redef fun is_structural do return true
+end
+
# A signature in a method definition. eg `(x,y:X,z:Z):T`
class ASignature
super Prod
var n_kwnullable: nullable TKwnullable = null is writable
# The name of the class or of the formal type
- var n_id: TClassid is writable, noinit
+ var n_qid: AQclassid is writable, noinit
# The opening bracket
var n_obra: nullable TObra = null is writable
# A `return` statement. eg `return x`
class AReturnExpr
- super AExpr
+ super AEscapeExpr
# The `return` keyword
var n_kwreturn: nullable TKwreturn = null is writable
+end
+
+# A `yield` statement. eg `yield x`
+class AYieldExpr
+ super AExpr
+
+ # The `yield` keyword
+ var n_kwyield: nullable TKwyield = null is writable
# The return value, if any
var n_expr: nullable AExpr = null is writable
# The list of statements of the `do`.
var n_block: nullable AExpr = null is writable
+
+ # The `catch` keyword
+ var n_kwcatch: nullable TKwcatch = null is writable
+
+ # The do catch block
+ var n_catch: nullable AExpr = null is writable
end
# A `if` statement
# The `for` keyword
var n_kwfor: TKwfor is writable, noinit
+ # The list of groups to iterate
+ var n_groups = new ANodes[AForGroup](self)
+
+ # The `do` keyword
+ var n_kwdo: TKwdo is writable, noinit
+
+ # The body of the loop
+ var n_block: nullable AExpr = null is writable
+end
+
+# A collection iterated by a for, its automatic variables and its implicit iterator.
+#
+# Standard `for` iterate on a single collection.
+# Multiple `for` can iterate on more than one collection at once.
+class AForGroup
+ super Prod
+
# The list of name of the automatic variables
var n_ids = new ANodes[TId](self)
# The expression used as the collection to iterate on
var n_expr: AExpr is writable, noinit
-
- # The `do` keyword
- var n_kwdo: TKwdo is writable, noinit
-
- # The body of the loop
- var n_block: nullable AExpr = null is writable
end
# A `with` statement
var n_expr: AExpr is writable, noinit
end
+# A `==` or a `!=` expression
+#
+# Both have a similar effect on adaptive typing, so this class factorizes the common behavior.
+class AEqFormExpr
+ super ABinopExpr
+end
+
# A `==` expression
class AEqExpr
- super ABinopExpr
+ super AEqFormExpr
redef fun operator do return "=="
end
# A `!=` expression
class ANeExpr
- super ABinopExpr
+ super AEqFormExpr
redef fun operator do return "!="
end
end
# A unary operation on a method
-class AUnaryopExpr
+abstract class AUnaryopExpr
super ASendExpr
# The operator
var n_type: AType is writable, noinit
# The name of the named-constructor, if any
- var n_id: nullable TId = null is writable
+ var n_qid: nullable AQid = null is writable
# The arguments of the `new`
var n_args: AExprs is writable, noinit
super ASendExpr
# The name of the method
- var n_id: TId is writable, noinit
+ var n_qid: AQid is writable, noinit
# The arguments of the call
var n_args: AExprs is writable, noinit
end
# An integer literal
-class AIntExpr
+class AIntegerExpr
super AExpr
-end
-
-# An integer literal in decimal format
-class ADecIntExpr
- super AIntExpr
-
- # The decimal token
- var n_number: TNumber is writable, noinit
-end
-
-# An integer literal in hexadecimal format
-class AHexIntExpr
- super AIntExpr
- # The hexadecimal token
- var n_hex_number: THexNumber is writable, noinit
+ # The integer token
+ var n_integer: TInteger is writable, noinit
end
# A float literal
# The starting quad (`::`)
var n_quad: nullable TQuad = null is writable
- # The list of quad-separated project/group identifiers
+ # The list of quad-separated package/group identifiers
var n_path = new ANodes[TId](self)
# The final module identifier
# The starting quad (`::`)
var n_quad: nullable TQuad = null is writable
- # The list of quad-separated project/group/module identifiers
+ # The list of quad-separated package/group/module identifiers
var n_id = new ANodes[TId](self)
# A class identifier
super Prod
# The identifier of the annotation.
- # Can be a TId of a keyword
+ #
+ # Can be a TId or a keyword.
var n_id: Token is writable, noinit
end