1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Markdown AST representation
21 # Node location in original markdown
22 var location
: MdLocation
25 var parent
: nullable MdNode = null is writable
28 var first_child
: nullable MdNode = null is writable
31 var last_child
: nullable MdNode = null is writable
34 var prev
: nullable MdNode = null is writable
37 var next
: nullable MdNode = null is writable
39 # Children nodes of `self`
40 fun children
: Array[MdNode] do
41 var nodes
= new Array[MdNode]
43 var node
= first_child
52 # Append a child to `self`
53 fun append_child
(child
: MdNode) do
56 if last_child
!= null then
57 last_child
.as(not null).next
= child
58 child
.prev
= last_child
66 # Prepend a child to `self`
67 fun prepend_child
(child
: MdNode) do
70 if first_child
!= null then
71 first_child
.as(not null).prev
= child
72 child
.next
= first_child
80 # Unlink `self` from its `parent`
83 prev
.as(not null).next
= next
84 else if parent
!= null then
85 parent
.as(not null).first_child
= next
88 next
.as(not null).prev
= prev
89 else if parent
!= null then
90 parent
.as(not null).last_child
= prev
97 # Insert `sibling` after `self`.
98 fun insert_after
(sibling
: MdNode) do
101 if sibling
.next
!= null then
102 sibling
.next
.as(not null).prev
= sibling
106 sibling
.parent
= parent
107 if sibling
.next
== null then
108 sibling
.parent
.as(not null).last_child
= sibling
112 # Insert `sibling` before `self`.
113 fun insert_before
(sibling
: MdNode) do
116 if sibling
.prev
!= null then
117 sibling
.prev
.as(not null).next
= sibling
121 sibling
.parent
= parent
122 if sibling
.prev
== null then
123 sibling
.parent
.as(not null).first_child
= sibling
127 # Visit all children or `self`
128 fun visit_all
(v
: MdVisitor) do
129 var node
= first_child
130 while node
!= null do
137 redef fun to_s
do return "{super}\{{to_s_attrs}\}"
139 # Returns `self` attributes as a String
141 # Mainly used for debug purposes.
142 fun to_s_attrs
: String do return "loc: {location}"
146 var v
= new MdASTPrinter
151 # A visitor for Markdown AST
154 # Start visiting `node`
155 fun enter_visit
(node
: MdNode) do visit
(node
)
159 # Method to define in specific visitor.
160 # It should not be called directly but used by `enter_visit`.
161 protected fun visit
(node
: MdNode) is abstract
164 # Print the AST content
168 # Current indent level
171 # Visit `self` to print the AST content
172 fun print_ast
(node
: MdNode) do
173 print
"{" " * indent}{node}"
179 redef fun visit
(node
) do print_ast
(node
)
184 # An abstract markdown block
185 abstract class MdBlock
188 redef fun parent
do return super
190 # Can this block contain other blocks?
191 var is_container
= false
193 # Can this block contain `block`?
194 fun can_contain
(block
: MdBlock): Bool do return false
196 # Parents of blocks can only be blocks
197 redef fun parent
=(node
) do
198 assert parent
== null or parent
isa MdBlock else
199 print
"Parent of block must also be block."
205 # A Markdown document
209 redef var is_container
= true
211 redef fun can_contain
(block
) do return true
218 redef var is_container
= true
220 redef fun can_contain
(block
) do return true
223 # A block of code (indented or fenced)
224 abstract class MdCodeBlock
228 var literal
: nullable String = null is writable
231 var info
: nullable String = null is writable
233 redef fun to_s_attrs
do return "{super}, info={info or else "null"}, literal={literal or else "null"}"
236 # A block code that starts with an indent
237 class MdIndentedCodeBlock
240 # Does this block use tabs instead of spaces?
243 redef fun to_s_attrs
do return "{super}, use_tabs={use_tabs}"
246 # A code block that starts with a fence
247 class MdFencedCodeBlock
254 var fence_length
: Int
256 # Fence indentation level
257 var fence_indent
: Int
259 redef fun to_s_attrs
do return "{super}, fence_char={fence_char}, fence_length={fence_length}, fence_indent={fence_indent}"
266 # Heading level (from 1 to 6)
269 # Is this heading in the setext format in the original source?
270 var is_setext
= false is optional
272 # Does this heading has an atx trailing in the original source?
273 var has_atx_trailing
= false is optional
275 redef fun to_s_attrs
do return "{super}, level={level}"
283 var literal
: nullable String = null is writable
285 redef fun to_s_attrs
do return "{super}, literal={literal or else "null"}"
288 # An ordered or unordered list block
289 abstract class MdListBlock
292 # Does this list contains line breaks?
293 var is_tight
: Bool = false is writable
295 redef var is_container
= true
297 redef fun can_contain
(block
) do return block
isa MdListItem
299 redef fun to_s_attrs
do return "{super}, is_tight={is_tight}"
302 # An ordered or unordered list item block
306 redef var is_container
= true
308 redef fun can_contain
(block
) do return true
311 # An ordered list block
315 # List starting number
316 var start_number
: Int
318 # List number delimiter
321 redef fun to_s_attrs
do return "{super}, start_number={start_number}, delimiter={delimiter}"
325 class MdUnorderedList
329 var bullet_marker
: Char
331 redef fun to_s_attrs
do return "{super}, bullet_marker={bullet_marker}"
338 # Is this paragraph in a list?
339 fun is_in_list
: Bool do
340 var parent
= self.parent
341 return parent
!= null and parent
.parent
isa MdListBlock
344 # Is this paragraph in a tight list?
345 fun is_in_tight_list
: Bool do
346 var parent
= self.parent
347 if parent
== null then return false
348 var gramps
= parent
.parent
349 return gramps
isa MdListBlock and gramps
.is_tight
354 class MdThematicBreak
357 # Thematic break pattern used in markdown source
358 var original_pattern
: String
363 # A line break (soft or hard)
364 abstract class MdLineBreak
368 # A hardline break (`\\n` or ` \n`)
369 class MdHardLineBreak
372 # Does this line break used a backslash in the original source?
373 var has_backslash
: Bool
376 # A soft line breack (`\r` or `\n`)
377 class MdSoftLineBreak
381 # An inline code string
386 var delimiter
: String
389 var literal
: String is writable
391 redef fun to_s_attrs
do return "{super}, literal={literal}"
394 # A node that users delimiters in the Markdown form
396 # For example the emphasis: `*bold*`.
397 abstract class MdDelimited
401 var delimiter
: String
404 fun opening_delimiter
: String do return delimiter
407 fun closing_delimiter
: String do return delimiter
409 redef fun to_s_attrs
do return "{super}, delimiter={delimiter}"
417 # A strong emphasis token
418 class MdStrongEmphasis
422 # An inlined html string
427 var literal
: String is writable
429 redef fun to_s_attrs
do return "{super}, literal={literal}"
433 abstract class MdLinkOrImage
437 var destination
: String is writable
440 var title
: nullable String is writable
442 # Is the `destination` between pointy brackets `<dest>`
443 var has_brackets
= false is writable
445 redef fun to_s_attrs
do return "{super}, destination={destination}, title={title or else "null"}"
457 # Is this link an autolink?
458 var is_autolink
= false is optional
, writable
466 var literal
: String is writable
468 redef fun to_s_attrs
do return "{super}, literal={literal}"
471 # MdNode location in the Markdown input
474 # Starting line number (starting from 1).
475 var line_start
: Int is writable
477 # Starting column number (starting from 1).
478 var column_start
: Int is writable
480 # Stopping line number (starting from 1).
481 var line_end
: Int is writable
483 # Stopping column number (starting from 1).
484 var column_end
: Int is writable
486 redef fun to_s
do return "{line_start},{column_start}--{line_end},{column_end}"