use crate::types::{self, BaseType, CmdArgType, MonoType, PolyType, TyVarRef};
use rustyfi_syntax::RustyfiVersion;
use std::collections::HashMap;
pub(crate) fn t_unit() -> MonoType {
MonoType::Base(BaseType::Unit)
}
pub fn t_bool() -> MonoType {
MonoType::Base(BaseType::Bool)
}
pub fn t_int() -> MonoType {
MonoType::Base(BaseType::Int)
}
pub(crate) fn t_float() -> MonoType {
MonoType::Base(BaseType::Float)
}
pub(crate) fn t_length() -> MonoType {
MonoType::Base(BaseType::Length)
}
pub fn t_string() -> MonoType {
MonoType::Base(BaseType::String)
}
pub(crate) fn t_inline_text() -> MonoType {
MonoType::Base(BaseType::InlineText)
}
pub(crate) fn t_block_text() -> MonoType {
MonoType::Base(BaseType::BlockText)
}
pub(crate) fn t_math_text() -> MonoType {
MonoType::Base(BaseType::MathText)
}
fn t_math() -> MonoType {
t_math_text()
}
pub(crate) fn t_math_boxes() -> MonoType {
MonoType::Base(BaseType::MathBoxes)
}
fn t_math_script_fn() -> MonoType {
arrow(t_context(), t_math_boxes())
}
fn t_math_class() -> MonoType {
MonoType::Variant("math-class".to_string(), Vec::new())
}
fn t_math_char_class() -> MonoType {
MonoType::Variant("math-char-class".to_string(), Vec::new())
}
pub(crate) fn t_paren(version: RustyfiVersion) -> MonoType {
if version.math_is_split() {
arrows(
vec![t_length(), t_length(), t_context()],
product(vec![t_inline_boxes(), arrow(t_length(), t_length())]),
)
} else {
arrows(
vec![t_length(), t_length(), t_length(), t_length(), t_color()],
product(vec![t_inline_boxes(), arrow(t_length(), t_length())]),
)
}
}
fn t_math_kern_func() -> MonoType {
arrows(vec![t_length(), t_length()], t_length())
}
fn t_math_variant_style() -> MonoType {
const LABELS: [&str; 9] = [
"italic",
"bold-italic",
"roman",
"bold-roman",
"script",
"bold-script",
"fraktur",
"bold-fraktur",
"double-struck",
];
let mut row = types::Row::Empty;
for label in LABELS.iter().rev() {
row = types::Row::Cons(label.to_string(), Box::new(t_string()), Box::new(row));
}
MonoType::Record(row)
}
pub(crate) fn t_image() -> MonoType {
MonoType::Base(BaseType::Image)
}
pub(crate) fn t_inline_boxes() -> MonoType {
MonoType::Base(BaseType::InlineBoxes)
}
pub(crate) fn t_block_boxes() -> MonoType {
MonoType::Base(BaseType::BlockBoxes)
}
pub(crate) fn t_context() -> MonoType {
MonoType::Base(BaseType::Context)
}
pub(crate) fn t_document() -> MonoType {
MonoType::Base(BaseType::Document)
}
fn t_color() -> MonoType {
MonoType::Variant("color".to_string(), Vec::new())
}
fn t_hyphenation() -> MonoType {
MonoType::Variant("hyphenation".to_string(), Vec::new())
}
fn t_unicode_char_database() -> MonoType {
MonoType::Variant("unicode-char-database".to_string(), Vec::new())
}
pub(crate) fn t_prepath() -> MonoType {
MonoType::Base(BaseType::PrePath)
}
pub(crate) fn t_path() -> MonoType {
MonoType::Base(BaseType::Path)
}
pub(crate) fn t_graphics() -> MonoType {
MonoType::Base(BaseType::Graphics)
}
fn t_point() -> MonoType {
product(vec![t_length(), t_length()])
}
fn t_pbinfo() -> MonoType {
MonoType::Record(types::Row::Cons(
"page-number".to_string(),
Box::new(t_int()),
Box::new(types::Row::Empty),
))
}
fn t_doc_info_dictionary() -> MonoType {
MonoType::Record(types::Row::Cons(
"title".to_string(),
Box::new(t_option(t_string())),
Box::new(types::Row::Cons(
"subject".to_string(),
Box::new(t_option(t_string())),
Box::new(types::Row::Cons(
"author".to_string(),
Box::new(t_option(t_string())),
Box::new(types::Row::Cons(
"keywords".to_string(),
Box::new(list(t_string())),
Box::new(types::Row::Empty),
)),
)),
)),
))
}
fn t_page() -> MonoType {
MonoType::Variant("page".to_string(), Vec::new())
}
fn t_page_or_geometry(version: RustyfiVersion) -> MonoType {
if version.has_page_adt() {
t_page()
} else {
product(vec![t_length(), t_length()])
}
}
fn t_page_content_scheme() -> MonoType {
MonoType::Record(types::Row::Cons(
"text-origin".to_string(),
Box::new(t_point()),
Box::new(types::Row::Cons(
"text-height".to_string(),
Box::new(t_length()),
Box::new(types::Row::Empty),
)),
))
}
fn t_page_parts() -> MonoType {
MonoType::Record(types::Row::Cons(
"header-origin".to_string(),
Box::new(t_point()),
Box::new(types::Row::Cons(
"header-content".to_string(),
Box::new(t_block_boxes()),
Box::new(types::Row::Cons(
"footer-origin".to_string(),
Box::new(t_point()),
Box::new(types::Row::Cons(
"footer-content".to_string(),
Box::new(t_block_boxes()),
Box::new(types::Row::Empty),
)),
)),
)),
))
}
pub(crate) fn t_option(ty: MonoType) -> MonoType {
MonoType::Variant("option".to_string(), vec![ty])
}
fn t_script() -> MonoType {
MonoType::Variant("script".to_string(), Vec::new())
}
fn t_language() -> MonoType {
MonoType::Variant("language".to_string(), Vec::new())
}
fn t_text_info() -> MonoType {
MonoType::Base(BaseType::TextInfo)
}
fn t_paddings() -> MonoType {
product(vec![t_length(), t_length(), t_length(), t_length()])
}
fn t_cell() -> MonoType {
MonoType::Variant("cell".to_string(), Vec::new())
}
fn t_dash() -> MonoType {
product(vec![t_length(), t_length(), t_length()])
}
fn t_graphics_output(version: RustyfiVersion) -> MonoType {
if version.graphics_is_collection() {
t_graphics()
} else {
list(t_graphics())
}
}
pub(crate) fn t_deco(version: RustyfiVersion) -> MonoType {
arrows(
vec![t_point(), t_length(), t_length(), t_length()],
t_graphics_output(version),
)
}
pub(crate) fn t_decoset(version: RustyfiVersion) -> MonoType {
product(vec![t_deco(version); 4])
}
pub(crate) fn t_font_key() -> MonoType {
MonoType::Base(BaseType::Font)
}
fn t_font_with_ratio(version: RustyfiVersion) -> MonoType {
let head = match version {
RustyfiVersion::V0_1 => t_font_key(),
_ => t_string(),
};
product(vec![head, t_float(), t_float()])
}
pub fn arrow(dom: MonoType, cod: MonoType) -> MonoType {
MonoType::Func(
Box::new(crate::types::Row::Empty),
Box::new(dom),
Box::new(cod),
)
}
fn arrows(doms: Vec<MonoType>, cod: MonoType) -> MonoType {
doms.into_iter().rev().fold(cod, |acc, dom| arrow(dom, acc))
}
pub fn list(t: MonoType) -> MonoType {
MonoType::List(Box::new(t))
}
pub fn reff(t: MonoType) -> MonoType {
MonoType::Ref(Box::new(t))
}
pub fn product(ts: Vec<MonoType>) -> MonoType {
MonoType::Product(ts)
}
fn inline_cmd(args: Vec<CmdArgType>) -> MonoType {
MonoType::InlineCmd(args)
}
pub(crate) fn mandatory(ty: MonoType) -> CmdArgType {
CmdArgType {
optional: false,
opt_labels: Vec::new(),
ty,
}
}
pub(crate) fn optional(ty: MonoType) -> CmdArgType {
CmdArgType {
optional: true,
opt_labels: Vec::new(),
ty,
}
}
pub(crate) fn labeled(opt_labels: Vec<(String, MonoType)>, ty: MonoType) -> CmdArgType {
CmdArgType {
optional: false,
opt_labels,
ty,
}
}
fn poly0(ty: MonoType) -> PolyType {
PolyType::mono(ty)
}
fn poly1<F: FnOnce(MonoType) -> MonoType>(f: F) -> PolyType {
let v = types::new_ty_var(0);
let body = f(MonoType::Var(v.clone()));
PolyType::from_vars(vec![v], Vec::new(), body)
}
pub fn primitive_type(name: &str) -> Option<PolyType> {
primitive_type_with_version(name, RustyfiVersion::V0_0)
}
pub fn primitive_type_with_version(name: &str, version: RustyfiVersion) -> Option<PolyType> {
Some(match name {
"get-axis-height"
| "math-pull-in-scripts"
| "math-color"
| "math-char-class"
| "math-variant-char"
| "text-in-math"
if version.math_is_split() =>
{
return None
}
"read-math" if version.math_is_split() => {
poly0(arrows(vec![t_context(), t_math_text()], t_math_boxes()))
}
"stringify-math" if version.math_is_split() => {
poly0(arrows(vec![t_text_info(), t_math_text()], t_string()))
}
"set-math-char" if version.math_is_split() => poly0(arrows(
vec![t_int(), t_int(), t_math_class(), t_context()],
t_context(),
)),
"set-math-char-class" if version.math_is_split() => {
poly0(arrows(vec![t_math_char_class(), t_context()], t_context()))
}
"get-math-char-class" if version.math_is_split() => {
poly0(arrow(t_context(), t_math_char_class()))
}
"embed-inline-to-math" if version.math_is_split() => poly0(arrows(
vec![t_math_class(), t_inline_boxes()],
t_math_boxes(),
)),
"get-math-axis-height-ratio" if version.math_is_split() => {
poly0(arrow(t_context(), t_float()))
}
"%math-attach-scripts" if version.math_is_split() => poly0(arrows(
vec![
t_context(),
t_math_boxes(),
t_option(t_math_text()),
t_option(t_math_text()),
],
t_math_boxes(),
)),
"load-hyphenation-dictionary" if version == RustyfiVersion::V0_1 => {
poly0(arrow(t_string(), t_hyphenation()))
}
"load-unicode-char-database" if version == RustyfiVersion::V0_1 => poly0(arrows(
vec![t_string(), t_string(), t_string()],
t_unicode_char_database(),
)),
"set-hyphenation-dictionary" if version == RustyfiVersion::V0_1 => {
poly0(arrows(vec![t_hyphenation(), t_context()], t_context()))
}
"set-unicode-char-database" if version == RustyfiVersion::V0_1 => poly0(arrows(
vec![t_unicode_char_database(), t_context()],
t_context(),
)),
"here" if version == RustyfiVersion::V0_1 => poly0(t_string()),
"read-inline" => poly0(arrow(t_context(), arrow(t_inline_text(), t_inline_boxes()))),
"read-block" => poly0(arrow(t_context(), arrow(t_block_text(), t_block_boxes()))),
"line-break" => poly0(arrows(
vec![t_bool(), t_bool(), t_context(), t_inline_boxes()],
t_block_boxes(),
)),
"page-break" => poly0(arrows(
vec![
t_page_or_geometry(version),
arrow(t_pbinfo(), t_page_content_scheme()),
arrow(t_pbinfo(), t_page_parts()),
t_block_boxes(),
],
t_document(),
)),
"page-break-multicolumn" => poly0(arrows(
vec![
t_page_or_geometry(version),
list(t_length()),
arrow(t_unit(), t_block_boxes()),
arrow(t_unit(), t_block_boxes()),
arrow(t_pbinfo(), t_page_content_scheme()),
arrow(t_pbinfo(), t_page_parts()),
t_block_boxes(),
],
t_document(),
)),
"page-break-two-column" => poly0(arrows(
vec![
t_page_or_geometry(version),
t_length(),
arrow(t_unit(), t_block_boxes()),
arrow(t_pbinfo(), t_page_content_scheme()),
arrow(t_pbinfo(), t_page_parts()),
t_block_boxes(),
],
t_document(),
)),
"+" => poly0(arrows(vec![t_int(), t_int()], t_int())),
"-" => poly0(arrows(vec![t_int(), t_int()], t_int())),
"*" => poly0(arrows(vec![t_int(), t_int()], t_int())),
"/" => poly0(arrows(vec![t_int(), t_int()], t_int())),
"mod" => poly0(arrows(vec![t_int(), t_int()], t_int())),
"==" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
"<>" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
"<" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
">" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
"<=" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
">=" => poly0(arrows(vec![t_int(), t_int()], t_bool())),
"&&" => poly0(arrows(vec![t_bool(), t_bool()], t_bool())),
"||" => poly0(arrows(vec![t_bool(), t_bool()], t_bool())),
"not" => poly0(arrow(t_bool(), t_bool())),
"+." => poly0(arrows(vec![t_float(), t_float()], t_float())),
"-." => poly0(arrows(vec![t_float(), t_float()], t_float())),
"*." => poly0(arrows(vec![t_float(), t_float()], t_float())),
"/." => poly0(arrows(vec![t_float(), t_float()], t_float())),
"float" => poly0(arrow(t_int(), t_float())),
"round" => poly0(arrow(t_float(), t_int())),
"+'" => poly0(arrows(vec![t_length(), t_length()], t_length())),
"-'" => poly0(arrows(vec![t_length(), t_length()], t_length())),
"*'" => poly0(arrows(vec![t_length(), t_float()], t_length())),
"/'" => poly0(arrows(vec![t_length(), t_length()], t_float())),
"<'" => poly0(arrows(vec![t_length(), t_length()], t_bool())),
">'" => poly0(arrows(vec![t_length(), t_length()], t_bool())),
"^" => poly0(arrows(vec![t_string(), t_string()], t_string())),
"arabic" => poly0(arrow(t_int(), t_string())),
"string-same" => poly0(arrows(vec![t_string(), t_string()], t_bool())),
"string-length" => poly0(arrow(t_string(), t_int())),
"string-sub" => poly0(arrows(vec![t_string(), t_int(), t_int()], t_string())),
"string-explode" => poly0(arrow(t_string(), list(t_int()))),
"regexp-of-string" => poly0(arrow(t_string(), t_string())),
"string-match" => poly0(arrows(vec![t_string(), t_string()], t_bool())),
"string-scan" => poly0(arrows(
vec![t_string(), t_string()],
t_option(product(vec![t_string(), t_string()])),
)),
"split-on-regexp" => poly0(arrows(
vec![t_string(), t_string()],
list(product(vec![t_int(), t_string()])),
)),
"::" => poly1(|a| arrow(a.clone(), arrow(list(a.clone()), list(a)))),
"!" => poly1(|a| arrow(reff(a.clone()), a)),
"embed-string" => poly0(arrow(t_string(), t_inline_text())),
"set-font-size" => poly0(arrow(t_length(), arrow(t_context(), t_context()))),
"get-font-size" => poly0(arrow(t_context(), t_length())),
"set-leading" => poly0(arrow(t_length(), arrow(t_context(), t_context()))),
"set-paragraph-margin" => poly0(arrows(
vec![t_length(), t_length(), t_context()],
t_context(),
)),
"get-text-width" => poly0(arrow(t_context(), t_length())),
"get-initial-context" => poly0(arrow(
t_length(),
arrow(inline_cmd(vec![mandatory(t_math_text())]), t_context()),
)),
"set-font-key" => poly0(arrow(t_int(), arrow(t_context(), t_context()))),
"++" => poly0(arrows(
vec![t_inline_boxes(), t_inline_boxes()],
t_inline_boxes(),
)),
"+++" => poly0(arrows(
vec![t_block_boxes(), t_block_boxes()],
t_block_boxes(),
)),
"inline-nil" => poly0(t_inline_boxes()),
"block-nil" => poly0(t_block_boxes()),
"inline-skip" => poly0(arrow(t_length(), t_inline_boxes())),
"inline-glue" => poly0(arrows(
vec![t_length(), t_length(), t_length()],
t_inline_boxes(),
)),
"block-skip" => poly0(arrow(t_length(), t_block_boxes())),
"list-mark" => poly0(arrow(t_int(), t_block_boxes())),
"inline-mark" => poly0(arrow(t_int(), t_inline_boxes())),
"load-image" => poly0(arrow(t_string(), t_image())),
"use-image-by-width" => poly0(arrows(vec![t_image(), t_length()], t_inline_boxes())),
"load-pdf-image" => poly0(arrows(vec![t_string(), t_int()], t_image())),
"inline-fil" => poly0(t_inline_boxes()),
"omit-skip-after" => poly0(t_inline_boxes()),
"clear-page" => poly0(t_block_boxes()),
"sin" => poly0(arrow(t_float(), t_float())),
"asin" => poly0(arrow(t_float(), t_float())),
"cos" => poly0(arrow(t_float(), t_float())),
"acos" => poly0(arrow(t_float(), t_float())),
"tan" => poly0(arrow(t_float(), t_float())),
"atan" => poly0(arrow(t_float(), t_float())),
"atan2" => poly0(arrows(vec![t_float(), t_float()], t_float())),
"log" => poly0(arrow(t_float(), t_float())),
"exp" => poly0(arrow(t_float(), t_float())),
"ceil" => poly0(arrow(t_float(), t_float())),
"floor" => poly0(arrow(t_float(), t_float())),
"show-float" => poly0(arrow(t_float(), t_string())),
"string-byte-length" => poly0(arrow(t_string(), t_int())),
"string-sub-bytes" => poly0(arrows(vec![t_string(), t_int(), t_int()], t_string())),
"string-unexplode" => poly0(arrow(list(t_int()), t_string())),
"display-message" => poly0(arrow(t_string(), t_unit())),
"abort-with-message" => poly1(|a| arrow(t_string(), a)),
"start-path" => poly0(arrow(t_point(), t_prepath())),
"line-to" => poly0(arrows(vec![t_point(), t_prepath()], t_prepath())),
"terminate-path" => poly0(arrow(t_prepath(), t_path())),
"close-with-line" => poly0(arrow(t_prepath(), t_path())),
"fill" => poly0(arrows(vec![t_color(), t_path()], t_graphics())),
"stroke" => poly0(arrows(vec![t_length(), t_color(), t_path()], t_graphics())),
"inline-graphics" => poly0(arrows(
vec![
t_length(),
t_length(),
t_length(),
arrow(t_point(), t_graphics_output(version)),
],
t_inline_boxes(),
)),
"tabular" => poly0(arrows(
vec![
list(list(t_cell())),
arrows(
vec![list(t_length()), list(t_length())],
t_graphics_output(version),
),
],
t_inline_boxes(),
)),
"inline-graphics-outer" => poly0(arrows(
vec![
t_length(),
t_length(),
arrows(vec![t_length(), t_point()], t_graphics_output(version)),
],
t_inline_boxes(),
)),
"bezier-to" => poly0(arrows(
vec![t_point(), t_point(), t_point(), t_prepath()],
t_prepath(),
)),
"close-with-bezier" => poly0(arrows(vec![t_point(), t_point(), t_prepath()], t_path())),
"shift-path" => poly0(arrows(vec![t_point(), t_path()], t_path())),
"linear-transform-path" => poly0(arrows(
vec![t_float(), t_float(), t_float(), t_float(), t_path()],
t_path(),
)),
"shift-graphics" => poly0(arrows(vec![t_point(), t_graphics()], t_graphics())),
"linear-transform-graphics" => poly0(arrows(
vec![t_float(), t_float(), t_float(), t_float(), t_graphics()],
t_graphics(),
)),
"get-graphics-bbox" => {
let bbox_ty = product(vec![t_point(), t_point()]);
if version.graphics_is_collection() {
poly0(arrow(t_graphics(), t_option(bbox_ty)))
} else {
poly0(arrow(t_graphics(), bbox_ty))
}
}
"unite-graphics" if version.graphics_is_collection() => {
poly0(arrow(list(t_graphics()), t_graphics()))
}
"clip-graphics-by-path" if version.graphics_is_collection() => {
poly0(arrows(vec![t_path(), t_graphics()], t_graphics()))
}
"get-path-bbox" => poly0(arrow(t_path(), product(vec![t_point(), t_point()]))),
"dashed-stroke" => poly0(arrows(
vec![t_length(), t_dash(), t_color(), t_path()],
t_graphics(),
)),
"draw-text" => poly0(arrows(vec![t_point(), t_inline_boxes()], t_graphics())),
"get-natural-metrics" => poly0(arrow(
t_inline_boxes(),
product(vec![t_length(), t_length(), t_length()]),
)),
"inline-frame-outer" => poly0(arrows(
vec![t_paddings(), t_deco(version), t_inline_boxes()],
t_inline_boxes(),
)),
"inline-frame-inner" => poly0(arrows(
vec![t_paddings(), t_deco(version), t_inline_boxes()],
t_inline_boxes(),
)),
"set-manual-rising" => poly0(arrow(t_length(), arrow(t_context(), t_context()))),
"script-guard" => poly0(arrows(vec![t_script(), t_inline_boxes()], t_inline_boxes())),
"discretionary" => poly0(arrows(
vec![
t_int(),
t_inline_boxes(),
t_inline_boxes(),
t_inline_boxes(),
],
t_inline_boxes(),
)),
"get-axis-height" => poly0(arrow(t_context(), t_length())),
"hook-page-break" => poly0(arrow(
arrows(vec![t_pbinfo(), t_point()], t_unit()),
t_inline_boxes(),
)),
"hook-page-break-block" => poly0(arrow(
arrows(vec![t_pbinfo(), t_point()], t_unit()),
t_block_boxes(),
)),
"register-cross-reference" => poly0(arrows(vec![t_string(), t_string()], t_unit())),
"get-cross-reference" => poly0(arrow(t_string(), t_option(t_string()))),
"probe-cross-reference" => poly0(arrow(t_string(), t_option(t_string()))),
"get-leftmost-script" => poly0(arrow(t_inline_boxes(), t_option(t_script()))),
"get-rightmost-script" => poly0(arrow(t_inline_boxes(), t_option(t_script()))),
"inline-frame-breakable" => poly0(arrows(
vec![t_paddings(), t_decoset(version), t_inline_boxes()],
t_inline_boxes(),
)),
"register-destination" => poly0(arrows(vec![t_string(), t_point()], t_unit())),
"register-link-to-uri" => poly0(arrows(
vec![
t_string(),
t_point(),
t_length(),
t_length(),
t_length(),
t_option(product(vec![t_length(), t_color()])),
],
t_unit(),
)),
"register-link-to-location" => poly0(arrows(
vec![
t_string(),
t_point(),
t_length(),
t_length(),
t_length(),
t_option(product(vec![t_length(), t_color()])),
],
t_unit(),
)),
"math-char" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_class(), t_string()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math_class(), t_string()], t_math()))
}
}
"math-big-char" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_class(), t_string()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math_class(), t_string()], t_math()))
}
}
"math-char-with-kern" => {
if version.math_is_split() {
poly0(arrows(
vec![
t_context(),
t_math_class(),
t_string(),
t_math_kern_func(),
t_math_kern_func(),
],
t_math_boxes(),
))
} else {
poly0(arrows(
vec![
t_math_class(),
t_string(),
t_math_kern_func(),
t_math_kern_func(),
],
t_math(),
))
}
}
"math-big-char-with-kern" => {
if version.math_is_split() {
poly0(arrows(
vec![
t_context(),
t_math_class(),
t_string(),
t_math_kern_func(),
t_math_kern_func(),
],
t_math_boxes(),
))
} else {
poly0(arrows(
vec![
t_math_class(),
t_string(),
t_math_kern_func(),
t_math_kern_func(),
],
t_math(),
))
}
}
"math-concat" => {
if version.math_is_split() {
poly0(arrows(vec![t_math_boxes(), t_math_boxes()], t_math_boxes()))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-group" => {
if version.math_is_split() {
poly0(arrows(
vec![t_math_class(), t_math_class(), t_math_boxes()],
t_math_boxes(),
))
} else {
poly0(arrows(
vec![t_math_class(), t_math_class(), t_math()],
t_math(),
))
}
}
"math-sup" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_script_fn()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-sub" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_script_fn()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-frac" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_boxes()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-radical" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_option(t_math_boxes()), t_math_boxes()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_option(t_math()), t_math()], t_math()))
}
}
"math-lower" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_script_fn()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-upper" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_script_fn()],
t_math_boxes(),
))
} else {
poly0(arrows(vec![t_math(), t_math()], t_math()))
}
}
"math-pull-in-scripts" => poly0(arrows(
vec![
t_math_class(),
t_math_class(),
arrows(vec![t_option(t_math()), t_option(t_math())], t_math()),
],
t_math(),
)),
"math-color" => poly0(arrows(vec![t_color(), t_math()], t_math())),
"math-char-class" => poly0(arrows(vec![t_math_char_class(), t_math()], t_math())),
"math-variant-char" => poly0(arrows(
vec![t_math_class(), t_math_variant_style()],
t_math(),
)),
"set-math-variant-char" => {
if version.math_is_split() {
poly0(arrows(
vec![t_int(), arrow(t_math_char_class(), t_int()), t_context()],
t_context(),
))
} else {
poly0(arrows(
vec![t_math_char_class(), t_int(), t_int(), t_context()],
t_context(),
))
}
}
"get-left-math-class" => {
if version.math_is_split() {
poly0(arrow(t_math_boxes(), t_option(t_math_class())))
} else {
poly0(arrows(
vec![t_context(), t_math()],
t_option(t_math_class()),
))
}
}
"get-right-math-class" => {
if version.math_is_split() {
poly0(arrow(t_math_boxes(), t_option(t_math_class())))
} else {
poly0(arrows(
vec![t_context(), t_math()],
t_option(t_math_class()),
))
}
}
"math-paren" => {
if version.math_is_split() {
poly0(arrows(
vec![
t_context(),
t_paren(version),
t_paren(version),
t_math_boxes(),
],
t_math_boxes(),
))
} else {
poly0(arrows(
vec![t_paren(version), t_paren(version), t_math()],
t_math(),
))
}
}
"math-paren-with-middle" => {
if version.math_is_split() {
poly0(arrows(
vec![
t_context(),
t_paren(version),
t_paren(version),
t_paren(version),
list(t_math_boxes()),
],
t_math_boxes(),
))
} else {
poly0(arrows(
vec![
t_paren(version),
t_paren(version),
t_paren(version),
list(t_math()),
],
t_math(),
))
}
}
"text-in-math" => poly0(arrows(
vec![t_math_class(), arrow(t_context(), t_inline_boxes())],
t_math(),
)),
"convert-string-for-math" => poly0(arrows(
vec![t_context(), t_math_char_class(), t_string()],
t_string(),
)),
"embed-math" => {
if version.math_is_split() {
poly0(arrows(vec![t_context(), t_math_boxes()], t_inline_boxes()))
} else {
poly0(arrows(vec![t_context(), t_math()], t_inline_boxes()))
}
}
"set-math-command" => poly0(arrow(
inline_cmd(vec![mandatory(t_math())]),
arrow(t_context(), t_context()),
)),
"set-math-font" => {
let dom = match version {
RustyfiVersion::V0_1 => t_font_key(),
_ => t_string(),
};
poly0(arrow(dom, arrow(t_context(), t_context())))
}
"load-single-font" if version == RustyfiVersion::V0_1 => {
poly0(arrow(t_string(), t_font_key()))
}
"space-between-maths" => {
if version.math_is_split() {
poly0(arrows(
vec![t_context(), t_math_boxes(), t_math_boxes()],
t_option(t_inline_boxes()),
))
} else {
poly0(arrows(
vec![t_context(), t_math(), t_math()],
t_option(t_inline_boxes()),
))
}
}
"raise-inline" => poly0(arrows(vec![t_length(), t_inline_boxes()], t_inline_boxes())),
"embed-block-breakable" => {
poly0(arrows(vec![t_context(), t_block_boxes()], t_inline_boxes()))
}
"unite-path" => poly0(arrows(vec![t_path(), t_path()], t_path())),
"set-min-gap-of-lines" => poly0(arrow(t_length(), arrow(t_context(), t_context()))),
"set-text-color" => poly0(arrow(t_color(), arrow(t_context(), t_context()))),
"get-text-color" => poly0(arrow(t_context(), t_color())),
"set-hyphen-penalty" => poly0(arrow(t_int(), arrow(t_context(), t_context()))),
"set-hyphen-min" => poly0(arrows(vec![t_int(), t_int(), t_context()], t_context())),
"set-space-ratio" => poly0(arrows(
vec![t_float(), t_float(), t_float(), t_context()],
t_context(),
)),
"set-space-ratio-between-scripts" => poly0(arrows(
vec![
t_float(),
t_float(),
t_float(),
t_script(),
t_script(),
t_context(),
],
t_context(),
)),
"split-into-lines" => poly0(arrow(t_string(), list(product(vec![t_int(), t_string()])))),
"block-frame-breakable" => poly0(arrows(
vec![
t_context(),
t_paddings(),
t_decoset(version),
arrow(t_context(), t_block_boxes()),
],
t_block_boxes(),
)),
"embed-block-top" => poly0(arrows(
vec![t_context(), t_length(), arrow(t_context(), t_block_boxes())],
t_inline_boxes(),
)),
"embed-block-bottom" => poly0(arrows(
vec![t_context(), t_length(), arrow(t_context(), t_block_boxes())],
t_inline_boxes(),
)),
"line-stack-bottom" => poly0(arrow(list(t_inline_boxes()), t_inline_boxes())),
"line-stack-top" => poly0(arrow(list(t_inline_boxes()), t_inline_boxes())),
"add-footnote" => poly0(arrow(t_block_boxes(), t_inline_boxes())),
"set-font" => poly0(arrows(
vec![t_script(), t_font_with_ratio(version), t_context()],
t_context(),
)),
"get-font" => poly0(arrows(
vec![t_script(), t_context()],
t_font_with_ratio(version),
)),
"set-code-text-command" => poly0(arrow(
inline_cmd(vec![mandatory(t_string())]),
arrow(t_context(), t_context()),
)),
"get-natural-length" => poly0(arrow(t_block_boxes(), t_length())),
"set-dominant-wide-script" => poly0(arrow(t_script(), arrow(t_context(), t_context()))),
"set-dominant-narrow-script" => poly0(arrow(t_script(), arrow(t_context(), t_context()))),
"set-language" => poly0(arrows(
vec![t_script(), t_language(), t_context()],
t_context(),
)),
"get-dominant-wide-script" => poly0(arrow(t_context(), t_script())),
"get-dominant-narrow-script" => poly0(arrow(t_context(), t_script())),
"get-language" => poly0(arrows(vec![t_script(), t_context()], t_language())),
"set-every-word-break" => poly0(arrows(
vec![t_inline_boxes(), t_inline_boxes(), t_context()],
t_context(),
)),
"register-outline" => poly0(arrow(
list(product(vec![t_int(), t_string(), t_string(), t_bool()])),
t_unit(),
)),
"extract-string" => poly0(arrow(t_inline_boxes(), t_string())),
"get-initial-text-info" => {
if version == RustyfiVersion::V0_1 {
poly0(arrows(
vec![
inline_cmd(vec![mandatory(t_math_text())]),
arrows(
vec![t_string(), t_option(t_string()), t_option(t_string())],
t_string(),
),
],
t_text_info(),
))
} else {
poly0(arrow(t_unit(), t_text_info()))
}
}
"deepen-indent" => poly0(arrows(vec![t_int(), t_text_info()], t_text_info())),
"break" => poly0(arrow(t_text_info(), t_string())),
"<<" | ">>" | "band" | "bor" | "bxor" if version == RustyfiVersion::V0_1 => {
poly0(arrows(vec![t_int(), t_int()], t_int()))
}
"bnot" if version == RustyfiVersion::V0_1 => poly0(arrow(t_int(), t_int())),
"normalize-string-to-nfc" | "normalize-string-to-nfd"
if version == RustyfiVersion::V0_1 =>
{
poly0(arrow(t_string(), t_string()))
}
"split-grapheme-cluster" if version == RustyfiVersion::V0_1 => {
poly0(arrow(t_string(), list(t_string())))
}
"read-file" => poly0(arrow(t_string(), list(t_string()))),
"register-document-information" if version == RustyfiVersion::V0_1 => {
poly0(arrow(t_doc_info_dictionary(), t_unit()))
}
">." | "<." | ">=." | "<=." if version == RustyfiVersion::V0_1 => {
poly0(arrows(vec![t_float(), t_float()], t_bool()))
}
_ => return None,
})
}
#[derive(Clone, Debug)]
pub struct VariantDecl {
pub name: String,
pub params: usize,
pub ctors: Vec<(String, Option<MonoType>)>,
pub param_vars: Vec<TyVarRef>,
}
impl VariantDecl {
pub(crate) fn instantiate_ctor(
&self,
ctor: &str,
args: &[MonoType],
) -> Option<(Option<MonoType>, MonoType)> {
if args.len() != self.params {
return None;
}
let (_, payload_tpl) = self.ctors.iter().find(|(n, _)| n == ctor)?;
let mut var_map: HashMap<usize, MonoType> = HashMap::new();
for (pv, arg) in self.param_vars.iter().zip(args.iter()) {
var_map.insert(types::ptr_key(pv), arg.clone());
}
let row_map = HashMap::new();
let payload = payload_tpl
.as_ref()
.map(|t| types::substitute(t, &var_map, &row_map));
Some((payload, MonoType::Variant(self.name.clone(), args.to_vec())))
}
}
pub fn builtin_variants_with_version(version: RustyfiVersion) -> Vec<VariantDecl> {
let option_param = types::new_ty_var(0);
let option_decl = VariantDecl {
name: "option".to_string(),
params: 1,
ctors: vec![
("None".to_string(), None),
(
"Some".to_string(),
Some(MonoType::Var(option_param.clone())),
),
],
param_vars: vec![option_param],
};
let itemize_decl = VariantDecl {
name: "itemize".to_string(),
params: 0,
ctors: vec![(
"Item".to_string(),
Some(product(vec![
t_inline_text(),
list(MonoType::Variant("itemize".to_string(), Vec::new())),
])),
)],
param_vars: Vec::new(),
};
let color_decl = VariantDecl {
name: "color".to_string(),
params: 0,
ctors: vec![
("Gray".to_string(), Some(t_float())),
(
"RGB".to_string(),
Some(product(vec![t_float(), t_float(), t_float()])),
),
(
"CMYK".to_string(),
Some(product(vec![t_float(), t_float(), t_float(), t_float()])),
),
],
param_vars: Vec::new(),
};
let script_decl = VariantDecl {
name: "script".to_string(),
params: 0,
ctors: vec![
("HanIdeographic".to_string(), None),
("Kana".to_string(), None),
("Latin".to_string(), None),
("OtherScript".to_string(), None),
],
param_vars: Vec::new(),
};
let language_decl = VariantDecl {
name: "language".to_string(),
params: 0,
ctors: vec![
("Japanese".to_string(), None),
("English".to_string(), None),
("NoLanguageSystem".to_string(), None),
],
param_vars: Vec::new(),
};
let page_decl = VariantDecl {
name: "page".to_string(),
params: 0,
ctors: vec![
("A0Paper".to_string(), None),
("A1Paper".to_string(), None),
("A2Paper".to_string(), None),
("A3Paper".to_string(), None),
("A4Paper".to_string(), None),
("A5Paper".to_string(), None),
("USLetter".to_string(), None),
("USLegal".to_string(), None),
(
"UserDefinedPaper".to_string(),
Some(product(vec![t_length(), t_length()])),
),
],
param_vars: Vec::new(),
};
let cell_decl = VariantDecl {
name: "cell".to_string(),
params: 0,
ctors: vec![
(
"NormalCell".to_string(),
Some(product(vec![t_paddings(), t_inline_boxes()])),
),
("EmptyCell".to_string(), None),
(
"MultiCell".to_string(),
Some(product(vec![
t_int(),
t_int(),
t_paddings(),
t_inline_boxes(),
])),
),
],
param_vars: Vec::new(),
};
let math_class_decl = VariantDecl {
name: "math-class".to_string(),
params: 0,
ctors: vec![
("MathOrd".to_string(), None),
("MathBin".to_string(), None),
("MathRel".to_string(), None),
("MathOp".to_string(), None),
("MathPunct".to_string(), None),
("MathOpen".to_string(), None),
("MathClose".to_string(), None),
("MathPrefix".to_string(), None),
("MathInner".to_string(), None),
],
param_vars: Vec::new(),
};
let mut math_char_class_ctors = vec![
("MathItalic".to_string(), None),
("MathBoldItalic".to_string(), None),
("MathRoman".to_string(), None),
("MathBoldRoman".to_string(), None),
("MathScript".to_string(), None),
("MathBoldScript".to_string(), None),
("MathFraktur".to_string(), None),
("MathBoldFraktur".to_string(), None),
("MathDoubleStruck".to_string(), None),
];
if version.math_is_split() {
math_char_class_ctors.extend([
("MathSansSerif".to_string(), None),
("MathBoldSansSerif".to_string(), None),
("MathItalicSansSerif".to_string(), None),
("MathBoldItalicSansSerif".to_string(), None),
("MathTypewriter".to_string(), None),
]);
}
let math_char_class_decl = VariantDecl {
name: "math-char-class".to_string(),
params: 0,
ctors: math_char_class_ctors,
param_vars: Vec::new(),
};
let mut decls = vec![
option_decl,
itemize_decl,
color_decl,
script_decl,
language_decl,
cell_decl,
math_class_decl,
math_char_class_decl,
];
if version.has_page_adt() {
decls.push(page_decl);
}
decls
}