///|
fn tokens_to_text(tokens : Array[Token]) -> String {
let builder = StringBuilder()
for token in tokens.rev() {
builder.write_string(token.text)
}
builder.to_string()
}
///|
fn message_macro(
context : MacroExpander,
) -> MacroReplacement raise ParseFailure {
let args = context.consume_args(1, None)
(context.macro_reporter)(MacroMessage(tokens_to_text(args[0])))
ReplacementText("")
}
///|
fn error_message_macro(
context : MacroExpander,
) -> MacroReplacement raise ParseFailure {
let args = context.consume_args(1, None)
(context.macro_reporter)(MacroErrorMessage(tokens_to_text(args[0])))
ReplacementText("")
}
///|
fn show_macro(context : MacroExpander) -> MacroReplacement raise ParseFailure {
let token = context.pop_token()
let status = if context.is_defined(token.text) {
"defined"
} else {
"undefined"
}
(context.macro_reporter)(MacroShow("\{token.text}: \{status}"))
ReplacementText("")
}
///|
fn tag_literal_macro(
context : MacroExpander,
) -> MacroReplacement raise ParseFailure {
guard !context.macros.has("\\df@tag") else {
raise InvalidArgument(message="Multiple \\tag", loc=None)
}
ReplacementText("\\gdef\\df@tag{\\text{#1}}")
}
///|
fn restore_dynamic_macro(
context : MacroExpander,
name : String,
old_value : MacroHandler?,
) -> Unit {
context.dynamic_macros.set(name, old_value)
}
///|
fn braket_separator_handler(
one : Bool,
doubled : Bool,
middle : Array[Token],
middle_double : Array[Token],
old_middle : MacroHandler?,
old_middle_double : MacroHandler?,
) -> MacroHandler {
context => {
if one {
restore_dynamic_macro(context, "|", old_middle)
if !middle_double.is_empty() {
restore_dynamic_macro(context, "\\|", old_middle_double)
}
}
let mut use_double = doubled
if !doubled && !middle_double.is_empty() {
let next = context.future()
if next.text == "|" {
let _ = context.pop_token()
use_double = true
}
}
if use_double {
token_expansion(middle_double)
} else {
token_expansion(middle)
}
}
}
///|
fn braket_helper(
context : MacroExpander,
one : Bool,
) -> MacroReplacement raise ParseFailure {
let parts = context.consume_args(4, None)
let left = parts[0]
let middle = parts[1]
let middle_double = parts[2]
let right = parts[3]
let old_middle = context.dynamic_macros.get_current("|")
let old_middle_double = context.dynamic_macros.get_current("\\|")
context.begin_group()
context.dynamic_macros.set(
"|",
Some(
braket_separator_handler(
one, false, middle, middle_double, old_middle, old_middle_double,
),
),
)
if !middle_double.is_empty() {
context.dynamic_macros.set(
"\\|",
Some(
braket_separator_handler(
one, true, middle, middle_double, old_middle, old_middle_double,
),
),
)
}
let expanded : Result[Array[Token], ParseFailure] = capture_parse_result(() => {
let argument = context.consume_arg(None).tokens
let input = right.copy()
input.append(argument)
input.append(left)
context.expand_tokens(input)
})
let close_result : Result[Unit, ParseFailure] = capture_parse_result(() => {
context.end_group()
})
match (expanded, close_result) {
(Err(err), _) => raise err
(Ok(_), Err(err)) => raise err
(Ok(tokens), Ok(_)) => {
tokens.rev_in_place()
token_expansion(tokens)
}
}
}
///|
fn braket_macro(context : MacroExpander) -> MacroReplacement raise ParseFailure {
braket_helper(context, false)
}
///|
fn set_macro(context : MacroExpander) -> MacroReplacement raise ParseFailure {
braket_helper(context, true)
}