our
@EXPORT
= (
qw( &DefOpenMath )
,
qw( &om_expr )
,
);
my
$omMimeType
=
'application/openmath+xml'
;
sub
preprocess {
my
(
$self
,
$doc
,
@nodes
) =
@_
;
$$self
{hackplane1} = 0
unless
$$self
{hackplane1};
$$self
{plane1} = 1
if
$$self
{hackplane1} || !
defined
$$self
{plane1};
$doc
->adjust_latexml_doctype(
'OpenMath'
);
$doc
->addNamespace(
$omURI
,
'om'
);
return
; }
sub
outerWrapper {
my
(
$self
,
$doc
,
$xmath
,
$om
) =
@_
;
my
$wrapped
= [
'om:OMOBJ'
, {},
$om
];
$self
->associateNode(
$wrapped
,
$xmath
, 1);
return
$wrapped
; }
sub
convertNode {
my
(
$self
,
$doc
,
$xmath
) =
@_
;
my
(
$item
,
@rest
) = element_nodes(
$xmath
);
return
{
processor
=>
$self
,
encoding
=>
'OpenMath'
,
mimetype
=>
$omMimeType
,
xml
=> (!
$item
||
@rest
? om_unparsed(
$item
,
@rest
) : om_expr(
$item
)) }; }
sub
combineParallel {
my
(
$self
,
$doc
,
$xmath
,
$primary
,
@secondaries
) =
@_
;
my
$id
=
$xmath
->getAttribute(
'fragid'
);
my
@attr
= ();
foreach
my
$secondary
(
@secondaries
) {
my
$mimetype
=
$$secondary
{mimetype} ||
'unknown'
;
if
(
$mimetype
eq
$omMimeType
) {
push
(
@attr
,
[
'om:OMS'
, {
cd
=>
"Alternate"
,
name
=>
$mimetype
}],
$$secondary
{xml}); }
elsif
(
my
$xml
=
$$secondary
{xml}) {
push
(
@attr
,
[
'om:OMS'
, {
cd
=>
"Alternate"
,
name
=>
$mimetype
}],
[
'om:OMFOREIGN'
, {},
$$secondary
{processor}->outerWrapper(
$doc
,
$xmath
,
$xml
)]); }
elsif
(
my
$string
=
$$secondary
{string}) {
push
(
@attr
,
[
'om:OMS'
, {
cd
=>
"Alternate"
,
name
=>
$mimetype
}],
[
'om:OMSTR'
, {},
$string
]); }
}
return
{
processor
=>
$self
,
mimetype
=>
$omMimeType
,
xml
=> [
'om:OMATTR'
, {},
@attr
,
$$primary
{xml}] }; }
sub
getQName {
my
(
$node
) =
@_
;
return
$LaTeXML::Post::DOCUMENT
->getQName(
$node
); }
sub
rawIDSuffix {
return
'.om'
; }
sub
canConvert {
my
(
$sefl
,
$doc
,
$math
) =
@_
;
return
LaTeXML::Post::MathProcessor::mathIsParsed(
$doc
,
$math
); }
our
$OMTable
= {};
sub
DefOpenMath {
my
(
$key
,
$sub
) =
@_
;
$$OMTable
{
$key
} =
$sub
;
return
; }
sub
om_expr {
my
(
$node
) =
@_
;
$node
=
$LaTeXML::Post::DOCUMENT
->realizeXMNode(
$node
);
my
$result
= om_expr_aux(
$node
);
$LaTeXML::Post::MATHPROCESSOR
->associateNode(
$result
,
$node
);
return
$result
; }
sub
om_expr_aux {
my
(
$node
) =
@_
;
return
OMError(
"Missing Subexpression"
)
unless
$node
;
my
$tag
= getQName(
$node
);
if
((
$tag
eq
'ltx:XMWrap'
) || (
$tag
eq
'ltx:XMArg'
)) {
my
(
$item
,
@rest
) = element_nodes(
$node
);
return
(!
$item
||
@rest
? om_unparsed(
$item
,
@rest
) : om_expr(
$item
)); }
elsif
(
$tag
eq
'ltx:XMDual'
) {
my
(
$content
,
$presentation
) = element_nodes(
$node
);
return
om_expr(
$content
); }
elsif
(
$tag
eq
'ltx:XMApp'
) {
if
(
my
$meaning
=
$node
->getAttribute(
'meaning'
)) {
my
$sub
= lookupConverter(
'Token'
,
$node
->getAttribute(
'role'
),
$meaning
);
return
&$sub
(
$node
); }
my
(
$op
,
@args
) = element_nodes(
$node
);
return
OMError(
"Missing Operator"
)
unless
$op
;
my
$sub
= lookupConverter(
'Apply'
,
$op
->getAttribute(
'role'
),
$op
->getAttribute(
'meaning'
));
return
&$sub
(
$op
,
@args
); }
elsif
(
$tag
eq
'ltx:XMTok'
) {
my
$sub
= lookupConverter(
'Token'
,
$node
->getAttribute(
'role'
),
$node
->getAttribute(
'meaning'
));
return
&$sub
(
$node
); }
elsif
(
$tag
eq
'ltx:XMHint'
) {
return
(); }
elsif
(
$tag
eq
'ltx:XMText'
) {
if
(
scalar
(element_nodes(
$node
))) {
return
[
'om:OMATTR'
, {},
[
'om:OMATP'
, {},
[
'om:OMS'
, {
cd
=>
'OMDoc'
,
name
=>
'verbalizes'
}],
[
'om:OMFOREIGN'
, {
encoding
=>
'mtext'
},
$LaTeXML::Post::MATHPROCESSOR
->convertXMTextContent(
$LaTeXML::Post::DOCUMENT
, 0,
$node
->childNodes)]],
[
'om:OMS'
, {
cd
=>
'OMDoc'
,
name
=>
'infObj'
}]] }
else
{
return
[
'om:OMSTR'
, {},
$node
->textContent]; } }
else
{
return
[
'om:OMSTR'
, {},
$node
->textContent]; } }
sub
om_unparsed {
my
(
@nodes
) =
@_
;
if
(!
@nodes
) {
return
[
'om:OME'
, {},
[
'om:OMS'
, {
name
=>
'unexpected'
,
cd
=>
'moreerrors'
}],
[
'om:OMSTR'
, {},
"Missing Subexpression"
]]; }
else
{
my
@om
= ();
foreach
my
$node
(
@nodes
) {
$node
=
$LaTeXML::Post::DOCUMENT
->realizeXMNode(
$node
);
my
$tag
= getQName(
$node
);
if
(
$tag
eq
'ltx:XMHint'
) { }
elsif
((
$tag
eq
'ltx:XMTok'
) && ((
$node
->getAttribute(
'role'
) ||
'UNKNOWN'
) eq
'UNKNOWN'
)) {
push
(
@om
, [
'om:OMS'
, {
cd
=>
'unknown'
,
name
=>
$node
->textContent }]); }
else
{
push
(
@om
, om_expr_aux(
$node
)); } }
return
[
'om:OME'
, {}, [
'om:OMS'
, {
cd
=>
'ambiguous'
,
name
=>
'fragments'
}],
@om
]; } }
sub
lookupConverter {
my
(
$mode
,
$role
,
$name
) =
@_
;
$name
=
'?'
unless
$name
;
$role
=
'?'
unless
$role
;
return
$$OMTable
{
"$mode:$role:$name"
} ||
$$OMTable
{
"$mode:?:$name"
}
||
$$OMTable
{
"$mode:$role:?"
} ||
$$OMTable
{
"$mode:?:?"
}; }
sub
OMError {
my
(
$msg
) =
@_
;
return
[
'om:OME'
, {},
[
'om:OMS'
, {
name
=>
'unexpected'
,
cd
=>
'moreerrors'
}],
[
'om:OMS'
, {},
$msg
]]; }
DefOpenMath(
'Token:?:?'
,
sub
{
my
(
$token
) =
@_
;
if
(
my
$meaning
=
$token
->getAttribute(
'meaning'
)) {
my
$cd
=
$token
->getAttribute(
'omcd'
) ||
'latexml'
;
return
[
'om:OMS'
, {
name
=>
$meaning
,
cd
=>
$cd
}]; }
else
{
my
(
$name
,
%mmlattr
) = LaTeXML::Post::MathML::stylizeContent(
$token
,
'om:OMV'
);
if
(
my
$mv
=
$mmlattr
{mathvariant}) {
$name
=
$mv
.
"-"
.
$name
; }
return
[
'om:OMV'
, {
name
=>
$name
}]; } });
DefOpenMath(
'Token:NUMBER:?'
,
sub
{
my
(
$node
) =
@_
;
my
$value
=
$node
->getAttribute(
'meaning'
);
$value
=
$node
->textContent
unless
defined
$value
;
if
(
$value
=~ /\./) {
return
[
'om:OMF'
, {
dec
=>
$value
}]; }
else
{
return
[
'om:OMI'
, {},
$value
]; } });
DefOpenMath(
'Token:SUPERSCRIPTOP:?'
,
sub
{
return
[
'om:OMS'
, {
name
=>
'superscript'
,
cd
=>
'ambiguous'
}]; });
DefOpenMath(
'Token:SUBSCRIPTOP:?'
,
sub
{
return
[
'om:OMS'
, {
name
=>
'subscript'
,
cd
=>
'ambiguous'
}]; });
DefOpenMath(
"Token:?:\x{2062}"
,
sub
{
return
[
'om:OMS'
, {
name
=>
'times'
,
cd
=>
'arith1'
}]; });
DefOpenMath(
'Apply:?:?'
,
sub
{
my
(
$op
,
@args
) =
@_
;
return
[
'om:OMA'
, {},
map
{ om_expr(
$_
) }
$op
,
@args
]; });
DefOpenMath(
'Apply:LambdaBinding:?'
,
sub
{
my
(
$op
,
$expr
,
@vars
) =
@_
;
return
[
'om:OMBIND'
, {},
[
'om:OMS'
, {
name
=>
"lambda"
,
cd
=>
'fns1'
},
[
'om:OMBVAR'
, {},
map
{ om_expr(
$_
) }
@vars
],
om_expr(
$expr
)]]; });
1;