use std::collections::BTreeMap;
use tectonic_errors::prelude::*;
use super::HasPrimitive;
use crate::{
symbols::{HasSymbol, SymbolCategory, SymbolTable},
FormatVersion,
};
enum DynamicEnumValueSource {
Next,
Same,
Delta(isize),
Symbol(&'static str, isize),
ScaledSymbol(&'static str, isize, isize),
}
struct DynamicEnumItemDescription<T> {
absval: Option<T>,
symbol_name: &'static str,
since: FormatVersion,
value_source: DynamicEnumValueSource,
}
#[derive(Debug)]
pub struct DynamicEnumResolver<T> {
values: BTreeMap<isize, T>,
}
impl<T: Copy + std::fmt::Debug> DynamicEnumResolver<T> {
fn build(
version: FormatVersion,
symbols: &mut SymbolTable,
cat: SymbolCategory,
items: &[DynamicEnumItemDescription<T>],
) -> Result<Self> {
let mut cur_val = -1;
let mut values = BTreeMap::new();
for item in items {
if item.since > version {
continue;
}
let next_val = match item.value_source {
DynamicEnumValueSource::Next => cur_val + 1,
DynamicEnumValueSource::Same => cur_val,
DynamicEnumValueSource::Delta(d) => cur_val + d,
DynamicEnumValueSource::Symbol(sym, d) => symbols.lookup(sym) + d,
DynamicEnumValueSource::ScaledSymbol(sym, f, d) => f * symbols.lookup(sym) + d,
};
ensure!(
next_val >= cur_val,
"dynamic enum values must be nondecreasing"
);
cur_val = next_val;
symbols.add(cat, item.symbol_name.to_owned(), cur_val)?;
if let Some(v) = item.absval {
ensure!(
values.insert(cur_val, v).is_none(),
"duplicated dynamic enum variant value"
);
}
}
Ok(DynamicEnumResolver { values })
}
pub fn resolve(&self, value: isize) -> Option<T> {
self.values.get(&value).copied()
}
pub fn active(&self) -> impl Iterator<Item = (&isize, &T)> {
self.values.iter()
}
}
macro_rules! inner_declare_primitive_value {
(_) => {
None
};
($primname:ident) => {
Some(stringify!($primname))
};
}
macro_rules! inner_declare_enum {
(@inner $enumname:ident $doc:expr; $($(var $($v:literal)?)? $(not)?: $varname:tt $symname:ident $primname:tt,)*) => {
#[doc = $doc]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum $enumname { $($($($v)? $varname,)?)* }
impl HasSymbol for $enumname {
fn symbol(&self) -> &'static str {
match *self {
$($($($v)? Self::$varname => stringify!($symname),)?)*
}
}
}
impl HasPrimitive for $enumname {
fn primitive(&self) -> Option<&'static str> {
match *self {
$($($($v)? Self::$varname => inner_declare_primitive_value!($primname),)?)*
}
}
}
};
($enumname:ident $doc:expr; $($x:ident $varname:tt $symname:ident $primname:tt $since:literal [$($val:tt)+],)*) => {
inner_declare_enum! { @inner $enumname $doc; $($x: $varname $symname $primname,)* }
};
}
macro_rules! inner_declare_desc_item {
(var $varname:tt $symname:ident $since:literal [$($val:tt)+]) => {
DynamicEnumItemDescription {
absval: Some(Self::$varname),
symbol_name: stringify!($symname),
since: $since,
value_source: DynamicEnumValueSource::$($val)+,
}
};
(not $ignore:tt $symname:ident $since:literal [$($val:tt)+]) => {
DynamicEnumItemDescription {
absval: None,
symbol_name: stringify!($symname),
since: $since,
value_source: DynamicEnumValueSource::$($val)+,
}
};
}
macro_rules! inner_declare_desc {
($enumname:ident; $($flag:ident $varname:tt $symname:ident $primname:tt $since:literal [$($val:tt)+],)*) => {
impl $enumname {
fn get_description() -> &'static [DynamicEnumItemDescription<Self>] {
&[
$(
inner_declare_desc_item!($flag $varname $symname $since [$($val)+]),
)*
]
}
}
};
}
macro_rules! declare {
(#[doc = $doc:expr] $enumname:ident {
$($contents:tt)+
}) => {
inner_declare_enum! { $enumname $doc; $($contents)+ }
inner_declare_desc! { $enumname; $($contents)+ }
impl $enumname {
pub fn build_resolver(
version: FormatVersion,
symbols: &mut SymbolTable,
) -> Result<DynamicEnumResolver<Self>> {
DynamicEnumResolver::build(version, symbols, SymbolCategory::$enumname, Self::get_description())
}
}
}
}
declare! {
BoxCodes {
var Box BOX_CODE box 0 [Next],
var Copy COPY_CODE copy 0 [Next],
var LastBox LAST_BOX_CODE lastbox 0 [Next],
var VSplit VSPLIT_CODE vsplit 0 [Next],
var VTop VTOP_CODE vtop 0 [Next],
var VBox TT_VBOX_CODE vbox 0 [Symbol("VMODE", 4)],
var HBox TT_HBOX_CODE hbox 0 [Symbol("HMODE", 4)],
}
}
declare! {
ConvertCodes {
var Number NUMBER_CODE number 0 [Next],
var RomanNumeral ROMAN_NUMERAL_CODE romannumeral 0 [Next],
var String STRING_CODE string 0 [Next],
var Meaning MEANING_CODE meaning 0 [Next],
var FontName FONT_NAME_CODE fontname 0 [Next],
not var ETEX_CONVERT_BASE _ 0 [Next],
var EtexRevision ETEX_REVISION_CODE eTeXrevision 0 [Same],
not var ETEX_CONVERT_CODES _ 0 [Next],
var Expanded EXPANDED_CODE expanded 0 [Same],
not var PDFTEX_FIRST_EXPAND_CODE _ 0 [Next], var LeftMarginKern LEFT_MARGIN_KERN_CODE leftmarginkern 0 [Delta(9)], var RightMarginKern RIGHT_MARGIN_KERN_CODE rightmarginkern 0 [Next],
var PdfStrcmp PDF_STRCMP_CODE strcmp 0 [Next], var PdfCreationDate PDF_CREATION_DATE_CODE creationdate 0 [Delta(4)], var PdfFileModDate PDF_FILE_MOD_DATE_CODE filemoddate 0 [Next],
var PdfFileSize PDF_FILE_SIZE_CODE filesize 0 [Next],
var PdfMd5Sum PDF_MDFIVE_SUM_CODE mdfivesum 0 [Next],
var PdfFileDump PDF_FILE_DUMP_CODE filedump 0 [Next], var UniformDeviate UNIFORM_DEVIATE_CODE uniformdeviate 0 [Delta(3)], var NormalDeviate NORMAL_DEVIATE_CODE normaldeviate 0 [Next], not var PDFTEX_CONVERT_CODES _ 0 [Delta(3)], not var XETEX_FIRST_EXPAND_CODE _ 0 [Same], var XetexRevision XETEX_REVISION_CODE XeTeXrevision 0 [Same], var XetexVariationName XETEX_VARIATION_NAME_CODE XeTeXvariationname 0 [Next],
var XetexFeatureName XETEX_FEATURE_NAME_CODE XeTeXfeaturename 0 [Next],
var XetexSelectorName XETEX_SELECTOR_NAME_CODE XeTeXselectorname 0 [Next],
var XetexGlyphName XETEX_GLYPH_NAME_CODE XeTeXglyphname 0 [Next],
var XetexUChar XETEX_UCHAR_CODE Uchar 0 [Next],
var XetexUCharCat XETEX_UCHARCAT_CODE Ucharcat 0 [Next],
var JobName JOB_NAME_CODE jobname 0 [Next],
not var XETEX_CONVERT_CODES _ 0 [Same],
}
}
declare! {
ExtensionCodes {
var Open OPEN_NODE openout 0 [Next], var Write WRITE_NODE write 0 [Next], var Close CLOSE_NODE closeout 0 [Next], var Special SPECIAL_NODE special 0 [Next], var Immediate IMMEDIATE_CODE immediate 0 [Next],
var SetLanguage SET_LANGUAGE_CODE setlanguage 0 [Next],
var PdfSavePos PDF_SAVE_POS_NODE pdfsavepos 0 [Symbol("PDF_SAVE_POS_NODE", 0)], var ResetTimer RESET_TIMER_CODE resettimer 0 [Delta(10)], var SetRandomSeed SET_RANDOM_SEED_CODE setrandomseed 0 [Delta(2)], var PicFile PIC_FILE_CODE XeTeXpicfile 0 [Delta(8)], var PdfFile PDF_FILE_CODE XeTeXpdffile 0 [Next], var Glyph GLYPH_CODE XeTeXglyph 0 [Next], var XetexInputEncoding XETEX_INPUT_ENCODING_EXTENSION_CODE XeTeXinputencoding 0 [Next],
var XetexDefaultEncoding XETEX_DEFAULT_ENCODING_EXTENSION_CODE XeTeXdefaultencoding 0 [Next],
var XetexLinebreakLocale XETEX_LINEBREAK_LOCALE_EXTENSION_CODE XeTeXlinebreaklocale 0 [Next],
}
}
declare! {
MathNoadTypes {
var LeftRightMiddleMode TT_LEFT_RIGHT_MIDDLE_MODE _ 0 [Delta(2)], var Ordinary ORD_NOAD _ 0 [Symbol("UNSET_NODE", 3)], var BigOperator OP_NOAD _ 0 [Next],
var BinaryOperator BIN_NOAD _ 0 [Next],
var Relation REL_NOAD _ 0 [Next],
var Opening OPEN_NOAD _ 0 [Next],
var Closing CLOSE_NOAD _ 0 [Next],
var Punctuation PUNCT_NOAD _ 0 [Next],
var Inner INNER_NOAD _ 0 [Next],
var Radical RADICAL_NOAD _ 0 [Next],
var Fraction FRACTION_NOAD _ 0 [Next],
var Underline UNDER_NOAD _ 0 [Next],
var Overline OVER_NOAD _ 0 [Next],
var Accented ACCENT_NOAD _ 0 [Next],
var VCenter VCENTER_NOAD _ 0 [Next],
var Left LEFT_NOAD _ 0 [Next],
var Right RIGHT_NOAD _ 0 [Next],
}
}
declare! {
LastItemCodes {
var IntVal INT_VAL lastpenalty 0 [Next],
var DimenVal DIMEN_VAL lastkern 0 [Next],
var GlueVal GLUE_VAL lastskip 0 [Next],
var LastNodeType LAST_NODE_TYPE_CODE lastnodetype 0 [Next],
var InputLineNo INPUT_LINE_NO_CODE inputlineno 0 [Next],
var Badness BADNESS_CODE badness 0 [Next],
not var PDFTEX_FIRST_RINT_CODE _ 0 [Next],
var PdfLastXPos PDF_LAST_X_POS_CODE pdflastxpos 0 [Delta(6)],
var PdfLastYPos PDF_LAST_Y_POS_CODE pdflastypos 0 [Next],
var ElapsedTime ELAPSED_TIME_CODE elapsedtime 0 [Delta(3)],
var PdfShellEscape PDF_SHELL_ESCAPE_CODE shellescape 0 [Next],
var RandomSeed RANDOM_SEED_CODE randomseed 0 [Next],
not var ETEX_INT _ 0 [Next],
var ETexVersion ETEX_VERSION_CODE eTeXversion 0 [Same],
var CurrentGroupLevel CURRENT_GROUP_LEVEL_CODE currentgrouplevel 0 [Next],
var CurrentGroupType CURRENT_GROUP_TYPE_CODE currentgrouptype 0 [Next],
var CurrentIfLevel CURRENT_IF_LEVEL_CODE currentiflevel 0 [Next],
var CurrentIfType CURRENT_IF_TYPE_CODE currentiftype 0 [Next],
var CurrentIfBranch CURRENT_IF_BRANCH_CODE currentifbranch 0 [Next],
var GlueStretchOrder GLUE_STRETCH_ORDER_CODE gluestretchorder 0 [Next],
var GlueShrinkOrder GLUE_SHRINK_ORDER_CODE glueshrinkorder 0 [Next],
not var XETEX_INT _ 0 [Next],
var XetexVersion XETEX_VERSION_CODE XeTeXversion 0 [Same],
var XetexCountGlyphs XETEX_COUNT_GLYPHS_CODE XeTeXcountglyphs 0 [Next],
var XetexCountVariatons XETEX_COUNT_VARIATIONS_CODE XeTeXcountvariations 0 [Next],
var XetexVariation XETEX_VARIATION_CODE XeTeXvariation 0 [Next],
var XetexFindVariationByName XETEX_FIND_VARIATION_BY_NAME_CODE XeTeXfindvariationbyname 0 [Next],
var XetexVariationMin XETEX_VARIATION_MIN_CODE XeTeXvariationmin 0 [Next],
var XetexVariationMax XETEX_VARIATION_MAX_CODE XeTeXvariationmax 0 [Next],
var XetexVariationDefault XETEX_VARIATION_DEFAULT_CODE XeTeXvariationdefault 0 [Next],
var XetexCountFeatures XETEX_COUNT_FEATURES_CODE XeTeXcountfeatures 0 [Next],
var XetexFeatureCode XETEX_FEATURE_CODE_CODE XeTeXfeaturecode 0 [Next],
var XetexFindFeatureByName XETEX_FIND_FEATURE_BY_NAME_CODE XeTeXfindfeaturebyname 0 [Next],
var XetexIsExclusiveFeature XETEX_IS_EXCLUSIVE_FEATURE_CODE XeTeXisexclusivefeature 0 [Next],
var XetexCountSelectors XETEX_COUNT_SELECTORS_CODE XeTeXcountselectors 0 [Next],
var XetexSelectorCode XETEX_SELECTOR_CODE_CODE XeTeXselectorcode 0 [Next],
var XetexFindSelectorByName XETEX_FIND_SELECTOR_BY_NAME_CODE XeTeXfindselectorbyname 0 [Next],
var XetexIsDefaultSelector XETEX_IS_DEFAULT_SELECTOR_CODE XeTeXisdefaultselector 0 [Next],
var XetexOTCountScripts XETEX_OT_COUNT_SCRIPTS_CODE XeTeXOTcountscripts 0 [Next],
var XetexOTCountLanguages XETEX_OT_COUNT_LANGUAGES_CODE XeTeXOTcountlanguages 0 [Next],
var XetexOTCountFeatures XETEX_OT_COUNT_FEATURES_CODE XeTeXOTcountfeatures 0 [Next],
var XetexOTScript XETEX_OT_SCRIPT_CODE XeTeXOTscripttag 0 [Next],
var XetexOTLanguage XETEX_OT_LANGUAGE_CODE XeTeXOTlanguagetag 0 [Next],
var XetexOTFeature XETEX_OT_FEATURE_CODE XeTeXOTfeaturetag 0 [Next],
var XetexMapCharToGlyph XETEX_MAP_CHAR_TO_GLYPH_CODE XeTeXcharglyph 0 [Next],
var XetexGlyphIndex XETEX_GLYPH_INDEX_CODE XeTeXglyphindex 0 [Next],
var XetexFontType XETEX_FONT_TYPE_CODE XeTeXfonttype 0 [Next],
var XetexFirstChar XETEX_FIRST_CHAR_CODE XeTeXfirstfontchar 0 [Next],
var XetexLastChar XETEX_LAST_CHAR_CODE XeTeXlastfontchar 0 [Next],
var XetexPdfPageCount XETEX_PDF_PAGE_COUNT_CODE XeTeXpdfpagecount 0 [Next],
not var XETEX_LAST_ITEM_CODES _ 0 [Same],
not var XETEX_DIM _ 0 [Next],
var XetexGlyphBounds XETEX_GLYPH_BOUNDS_CODE XeTeXglyphbounds 0 [Same],
not var XETEX_LAST_DIM_CODES _ 0 [Same],
not var ETEX_DIM _ 0 [Next],
var FontCharWidth FONT_CHAR_WD_CODE fontcharwd 0 [Same],
var FontCharHeight FONT_CHAR_HT_CODE fontcharht 0 [Next],
var FontCharDepth FONT_CHAR_DP_CODE fontchardp 0 [Next],
var FontCharItalicCorrection FONT_CHAR_IC_CODE fontcharic 0 [Next],
var ParShapeLength PAR_SHAPE_LENGTH_CODE parshapelength 0 [Next],
var ParShapeIndent PAR_SHAPE_INDENT_CODE parshapeindent 0 [Next],
var ParShapeDimen PAR_SHAPE_DIMEN_CODE parshapedimen 0 [Next],
var GlueStretch GLUE_STRETCH_CODE gluestretch 0 [Next],
var GlueShrink GLUE_SHRINK_CODE glueshrink 0 [Next],
not var ETEX_GLUE _ 0 [Next],
var MuToGlue MU_TO_GLUE_CODE mutoglue 0 [Same],
not var ETEX_MU _ 0 [Next],
var GluetoMu GLUE_TO_MU_CODE gluetomu 0 [Same],
not var ETEX_EXPR _ 0 [Next],
var EtexNumExpr TT_ETEX_NUM_EXPR_CODE numexpr 0 [Same],
var EtexDimExpr TT_ETEX_DIM_EXPR_CODE dimexpr 0 [Next],
var EtexGlueExpr TT_ETEX_GLUE_EXPR_CODE glueexpr 0 [Next],
var EtexMuExpr TT_ETEX_MU_EXPR_CODE muexpr 0 [Next],
}
}
declare! {
Modes {
var Vertical VMODE _ 0 [Delta(2)],
var Horizontal HMODE _ 0 [Symbol("MAX_COMMAND", 2)],
var Math MMODE _ 0 [ScaledSymbol("MAX_COMMAND", 2, 3)],
}
}
declare! {
TabCrCodes {
var Span SPAN_CODE _ 0 [Symbol("SPECIAL_CHAR", 0)],
var Cr CR_CODE _ 0 [Symbol("SPECIAL_CHAR", 1)],
var CrCr CR_CR_CODE _ 0 [Symbol("SPECIAL_CHAR", 2)],
}
}