Skip to content

Commit daa1d56

Browse files
authored
Merge pull request #19 from iamgio/numbered-fix
Fix `.numbered` errors
2 parents 70f2fd3 + fd04413 commit daa1d56

File tree

24 files changed

+334
-56
lines changed

24 files changed

+334
-56
lines changed

quarkdown-core/src/main/kotlin/com/quarkdown/core/ast/attributes/location/LocationLabelProperty.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import com.quarkdown.core.property.Property
1111
* Examples of these nodes are figures and tables. For instance, depending on the document's [NumberingFormat],
1212
* an element may be labeled as `1.1`, `1.2`, `1.3`, `2.1`, etc.
1313
* @param value the formatted label
14-
* @see com.quarkdown.core.context.hooks.LocationAwareLabelStorerHook for the storing stage
14+
* @see com.quarkdown.core.context.hooks.location.LocationAwareLabelStorerHook for the storing stage
1515
*/
1616
data class LocationLabelProperty(
1717
override val value: String,

quarkdown-core/src/main/kotlin/com/quarkdown/core/ast/attributes/location/LocationTrackableNode.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fun LocationTrackableNode.getLocation(context: Context): SectionLocation? = cont
3030
* Registers the location of this node within the document handled by [context].
3131
* @param context context where location data is stored
3232
* @param location location to set
33-
* @see com.quarkdown.core.context.hooks.LocationAwarenessHook
33+
* @see com.quarkdown.core.context.hooks.location.LocationAwarenessHook
3434
*/
3535
fun LocationTrackableNode.setLocation(
3636
context: MutableContext,
@@ -52,7 +52,7 @@ fun LocationTrackableNode.getLocationLabel(context: Context): String? = context.
5252
* according to [this] node's [NumberingFormat].
5353
* @param context context where location data is stored
5454
* @param label formatted location to set
55-
* @see com.quarkdown.core.context.hooks.LocationAwareLabelStorerHook
55+
* @see com.quarkdown.core.context.hooks.location.LocationAwareLabelStorerHook
5656
*/
5757
fun LocationTrackableNode.setLocationLabel(
5858
context: MutableContext,

quarkdown-core/src/main/kotlin/com/quarkdown/core/ast/attributes/location/SectionLocationProperty.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import com.quarkdown.core.property.Property
66
* [Property] that is assigned to each node that requests its location to be tracked ([LocationTrackableNode]).
77
* It contains the node's location in the document, in terms of section indices.
88
* @see SectionLocation
9-
* @see com.quarkdown.core.context.hooks.LocationAwarenessHook for the storing stage
9+
* @see com.quarkdown.core.context.hooks.location.LocationAwarenessHook for the storing stage
1010
*/
1111
data class SectionLocationProperty(
1212
override val value: SectionLocation,
Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.quarkdown.core.ast.quarkdown.block
22

3+
import com.quarkdown.core.ast.NestableNode
34
import com.quarkdown.core.ast.Node
45
import com.quarkdown.core.ast.attributes.location.LocationTrackableNode
56
import com.quarkdown.core.ast.attributes.location.SectionLocation
@@ -9,14 +10,31 @@ import com.quarkdown.core.visitor.node.NodeVisitor
910
/**
1011
* Node that can be numbered depending on its location in the document
1112
* and the amount of occurrences according to its [key].
13+
*
14+
* This node is peculiar, as it's the only node whose children are not evaluated directly during the function call expansion stage,
15+
* but rather during the AST traversal.
16+
*
17+
* This is because in order to evaluate the children, we need to know the location of the node in the document,
18+
* which is not known until the AST is fully traversed by [com.quarkdown.core.context.hooks.location.LocationAwareLabelStorerHook].
19+
*
20+
* After the traversal, the [com.quarkdown.core.context.hooks.location.NumberedEvaluatorHook] will evaluate and assign the [children] of this node, ready to be rendered.
21+
*
22+
* Since the evaluation does not happen within [com.quarkdown.core.function.call.FunctionCallNodeExpander],
23+
* errors thrown during the evaluation will have to be caught externally. This is handled by the hook itself,
24+
* which appends an error box (the same produced from the expander) to [children].
25+
* From the user's perspective, this does not have any effect.
1226
* @param key name to group (and count) numbered nodes
13-
* @param children supplier of the node content given the evaluated [SectionLocation], formatted according to the active [DocumentNumbering]
14-
* @see com.quarkdown.core.context.hooks.LocationAwareLabelStorerHook for storing locations
27+
* @param childrenSupplier supplier of the node content given the evaluated [SectionLocation], formatted according to the active [DocumentNumbering]
28+
* @see com.quarkdown.core.context.hooks.location.LocationAwareLabelStorerHook for storing locations
29+
* @see com.quarkdown.core.context.hooks.location.NumberedEvaluatorHook for evaluating [childrenSupplier]
1530
* @see com.quarkdown.core.document.numbering.NumberingFormat
1631
*/
1732
class Numbered(
1833
val key: String,
19-
val children: (location: String) -> List<Node>,
20-
) : LocationTrackableNode {
34+
internal val childrenSupplier: (location: String) -> List<Node>,
35+
) : NestableNode,
36+
LocationTrackableNode {
37+
override var children: List<Node> = emptyList()
38+
2139
override fun <T> accept(visitor: NodeVisitor<T>): T = visitor.visit(this)
2240
}

quarkdown-core/src/main/kotlin/com/quarkdown/core/context/hooks/LocationAwareLabelStorerHook.kt renamed to quarkdown-core/src/main/kotlin/com/quarkdown/core/context/hooks/location/LocationAwareLabelStorerHook.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.quarkdown.core.context.hooks
1+
package com.quarkdown.core.context.hooks.location
22

33
import com.quarkdown.core.ast.attributes.location.LocationTrackableNode
44
import com.quarkdown.core.ast.attributes.location.SectionLocation

quarkdown-core/src/main/kotlin/com/quarkdown/core/context/hooks/LocationAwarenessHook.kt renamed to quarkdown-core/src/main/kotlin/com/quarkdown/core/context/hooks/location/LocationAwarenessHook.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.quarkdown.core.context.hooks
1+
package com.quarkdown.core.context.hooks.location
22

33
import com.quarkdown.core.ast.attributes.location.LocationTrackableNode
44
import com.quarkdown.core.ast.attributes.location.SectionLocation
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.quarkdown.core.context.hooks.location
2+
3+
import com.quarkdown.core.ast.attributes.location.getLocationLabel
4+
import com.quarkdown.core.ast.iterator.AstIteratorHook
5+
import com.quarkdown.core.ast.iterator.ObservableAstIterator
6+
import com.quarkdown.core.ast.quarkdown.block.Numbered
7+
import com.quarkdown.core.context.Context
8+
import com.quarkdown.core.pipeline.error.PipelineException
9+
import com.quarkdown.core.pipeline.error.asNode
10+
11+
/**
12+
* Hook that evaluates the [Numbered] nodes in the document.
13+
* If the evaluation fails, it attaches an error box, as in a regular function call expansion.
14+
* This needs to be attached **after** the [LocationAwareLabelStorerHook] has populated the location labels.
15+
* @param context context to retrieve the location label from
16+
* @see Numbered to understand why it needs evaluation
17+
*/
18+
class NumberedEvaluatorHook(
19+
private val context: Context,
20+
) : AstIteratorHook {
21+
override fun attach(iterator: ObservableAstIterator) {
22+
iterator.on<Numbered> { node ->
23+
val label = node.getLocationLabel(context) ?: ""
24+
node.children =
25+
try {
26+
node.childrenSupplier(label)
27+
} catch (e: PipelineException) {
28+
// Set an error box as the node's child if the evaluation fails.
29+
listOf(e.asNode(context))
30+
}
31+
}
32+
}
33+
}

quarkdown-core/src/main/kotlin/com/quarkdown/core/flavor/quarkdown/QuarkdownTreeIteratorFactory.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package com.quarkdown.core.flavor.quarkdown
22

33
import com.quarkdown.core.ast.iterator.ObservableAstIterator
44
import com.quarkdown.core.context.MutableContext
5-
import com.quarkdown.core.context.hooks.LocationAwareLabelStorerHook
6-
import com.quarkdown.core.context.hooks.LocationAwarenessHook
75
import com.quarkdown.core.context.hooks.MediaStorerHook
86
import com.quarkdown.core.context.hooks.TableOfContentsGeneratorHook
7+
import com.quarkdown.core.context.hooks.location.LocationAwareLabelStorerHook
8+
import com.quarkdown.core.context.hooks.location.LocationAwarenessHook
9+
import com.quarkdown.core.context.hooks.location.NumberedEvaluatorHook
910
import com.quarkdown.core.flavor.TreeIteratorFactory
1011
import com.quarkdown.core.flavor.base.BaseMarkdownTreeIteratorFactory
1112

@@ -18,6 +19,7 @@ class QuarkdownTreeIteratorFactory : TreeIteratorFactory {
1819
.default(context)
1920
.attach(LocationAwarenessHook(context))
2021
.attach(LocationAwareLabelStorerHook(context))
22+
.attach(NumberedEvaluatorHook(context))
2123
.attach(TableOfContentsGeneratorHook(context))
2224
.apply {
2325
if (context.attachedPipeline?.options?.enableMediaStorage == true) {

quarkdown-core/src/main/kotlin/com/quarkdown/core/function/call/FunctionCallNodeExpander.kt

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@ package com.quarkdown.core.function.call
22

33
import com.quarkdown.core.ast.Node
44
import com.quarkdown.core.ast.quarkdown.FunctionCallNode
5-
import com.quarkdown.core.ast.quarkdown.block.Box
65
import com.quarkdown.core.context.MutableContext
7-
import com.quarkdown.core.function.error.FunctionException
86
import com.quarkdown.core.function.value.output.OutputValueVisitorFactory
97
import com.quarkdown.core.function.value.output.node.NodeOutputValueVisitorFactory
108
import com.quarkdown.core.pipeline.error.PipelineErrorHandler
119
import com.quarkdown.core.pipeline.error.PipelineException
10+
import com.quarkdown.core.pipeline.error.asNode
1211

1312
/**
1413
* Given a [FunctionCallNode] from the AST, this expander resolves its referenced function, executes it
@@ -48,18 +47,8 @@ class FunctionCallNodeExpander(
4847
val outputNode = call.execute().accept(mapper)
4948
appendOutput(node, outputNode)
5049
} catch (e: PipelineException) {
51-
// If the function call is invalid.
52-
53-
// The function that the error originated from.
54-
// Note that sourceFunction might be different from call.function if the error comes from a nested function call down the stack.
55-
val sourceFunction = (e as? FunctionException)?.function
56-
57-
// The error is handled by the error handler strategy.
58-
errorHandler.handle(e, sourceFunction) {
59-
// Shows an error message box in the final document.
60-
// If the exception is linked to a function, its name appears in the error title.
61-
appendOutput(node, Box.error(e.richMessage, title = sourceFunction?.name))
62-
}
50+
// If the function call is invalid, shows an error box.
51+
appendOutput(node, e.asNode(errorHandler))
6352
}
6453
}
6554

quarkdown-core/src/main/kotlin/com/quarkdown/core/function/value/AdaptableValue.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ package com.quarkdown.core.function.value
44
* If a [Value] subclass is adaptable, it can be converted to another [Value]
55
* in case the parameter of the function it is passed to expects a different type.
66
*
7-
* For example, a [DictionaryValue] can be adapted to an [IterableValue].
7+
* For example, a [DictionaryValue] can be adapted to an [IterableValue],
8+
* and a [MarkdownContentValue] can be adapted to a [NodeValue].
89
*
910
* @param T type of the value to adapt to
1011
*/

0 commit comments

Comments
 (0)