///|
#warnings("-unused_constructor")
priv enum ArgType {
ColorArg
SizeArg
UrlArg
RawArg
OriginalArg
HboxArg
PrimitiveArg
MathArg
TextArg
}
///|
priv struct FunctionContext {
func_name : String
mode : Mode
token : Token?
break_on_token_text : String?
set_macro : (String, MacroDefinition?) -> Unit
report_nonstrict : (String, String) -> Unit raise ParseFailure
is_trusted : (TrustContext) -> Bool
parse_optional_size : () -> Measurement? raise ParseFailure
display_mode : Bool
use_strict_behavior : (String, String) -> Bool
current_color : () -> String? raise ParseFailure
in_left_right : () -> Bool
parse_expression : (Bool, String?) -> Array[ParseNode] raise ParseFailure
parse_math_mode : (String) -> Array[ParseNode] raise ParseFailure
parse_left_right : (String) -> ParseNode raise ParseFailure
pop_token : () -> Token raise ParseFailure
future_token : () -> Token raise ParseFailure
push_token : (Token) -> Unit
consume_spaces : () -> Unit raise ParseFailure
consume_macro_arg : () -> Array[Token] raise ParseFailure
expand_tokens : (Array[Token]) -> Array[Token] raise ParseFailure
get_macro : (String) -> MacroDefinition?
set_macro_definition : (String, MacroDefinition, Bool) -> Unit
is_expandable : (String) -> Bool
parse_prefixed_function : (String) -> ParseNode raise ParseFailure
parse_environment : (String) -> ParseNode raise ParseFailure
}
///|
type FunctionHandler = (FunctionContext, Array[ParseNode], Array[ParseNode?]) -> ParseNode raise ParseFailure
///|
#warnings("-unused_field")
priv struct FunctionSpec {
names : Array[String]
num_args : Int
num_optional_args : Int
arg_types : Array[ArgType]
allowed_in_argument : Bool
allowed_in_text : Bool
allowed_in_math : Bool
infix : Bool
primitive : Bool
primitive_after_missing_optional : Int?
handler : FunctionHandler?
}
///|
fn FunctionSpec::make(
names : Array[String],
num_args : Int,
num_optional_args? : Int = 0,
arg_types? : Array[ArgType] = [],
allowed_in_argument? : Bool = false,
allowed_in_text? : Bool = false,
allowed_in_math? : Bool = true,
infix? : Bool = false,
primitive? : Bool = false,
primitive_after_missing_optional? : Int,
handler? : FunctionHandler,
) -> FunctionSpec {
{
names,
num_args,
num_optional_args,
arg_types,
allowed_in_argument,
allowed_in_text,
allowed_in_math,
infix,
primitive,
primitive_after_missing_optional,
handler,
}
}
///|
fn FunctionSpec::is_expandable(self : FunctionSpec) -> Bool {
!self.primitive
}
///|
priv struct FunctionRegistry {
entries : Map[String, FunctionSpec]
}
///|
fn FunctionRegistry::make() -> FunctionRegistry {
{ entries: Map([]) }
}
///|
fn FunctionRegistry::register(
self : FunctionRegistry,
spec : FunctionSpec,
) -> Unit {
for name in spec.names {
self.entries[name] = spec
}
}
///|
fn FunctionRegistry::get(
self : FunctionRegistry,
name : String,
) -> FunctionSpec? {
self.entries.get(name)
}
///|
fn verb_spec() -> FunctionSpec {
FunctionSpec::make(["\\verb"], 0, allowed_in_text=true, handler=verb_handler)
}
///|
fn verb_handler(
context : FunctionContext,
_args : Array[ParseNode],
_opt_args : Array[ParseNode?],
) -> ParseNode raise ParseFailure {
let loc = token_location(context.token)
raise InvalidArgument(
message="\\verb ended by end of line instead of matching delimiter",
loc~,
)
}
///|
fn relax_spec() -> FunctionSpec {
FunctionSpec::make(
["\\relax"],
0,
allowed_in_argument=true,
allowed_in_text=true,
handler=relax_handler,
)
}
///|
#warnings("-unused_error_type")
fn relax_handler(
_context : FunctionContext,
_args : Array[ParseNode],
_opt_args : Array[ParseNode?],
) -> ParseNode raise ParseFailure {
Internal(mode=_context.mode)
}
///|
let builtin_function_specs : Array[FunctionSpec] = [
verb_spec(),
relax_spec(),
sqrt_spec(),
standard_genfrac_spec(),
infix_genfrac_spec(),
general_genfrac_spec(),
above_spec(),
abovefrac_spec(),
text_spec(),
textcolor_spec(),
color_spec(),
styling_spec(),
font_spec(),
boldsymbol_spec(),
old_font_spec(),
mclass_spec(),
binrel_spec(),
stackrel_spec(),
big_operator_spec(),
mathop_spec(),
named_operator_spec(),
limited_named_operator_spec(),
integral_operator_spec(),
operatorname_spec(),
overline_spec(),
underline_spec(),
smash_spec(),
phantom_spec(),
vphantom_spec(),
pmb_spec(),
vcenter_spec(),
rule_spec(),
raisebox_spec(),
hbox_spec(),
lap_spec(),
mathchoice_spec(),
sizing_spec(),
char_spec(),
horiz_brace_spec(),
x_arrow_spec(),
accent_under_spec(),
accent_spec(),
text_accent_spec(),
kern_spec(),
colorbox_spec(),
fcolorbox_spec(),
fbox_spec(),
cancel_spec(),
sout_spec(),
angl_spec(),
href_spec(),
url_spec(),
html_spec(),
cr_spec(),
macro_prefix_spec(),
definition_spec(),
let_spec(),
futurelet_spec(),
includegraphics_spec(),
begin_end_spec(),
hline_spec(),
cd_internal_spec(),
cd_parent_spec(),
html_mathml_spec(),
math_mode_spec(),
math_closing_spec(),
delim_sizing_spec(),
left_right_closing_spec(),
left_right_spec(),
middle_spec(),
]
///|
fn build_builtin_function_registry() -> FunctionRegistry {
let registry = FunctionRegistry::make()
for spec in builtin_function_specs {
registry.register(spec)
}
registry
}
///|
let builtin_function_registry : FunctionRegistry = build_builtin_function_registry()
///|
fn lookup_function(name : String) -> FunctionSpec? {
builtin_function_registry.get(name)
}