plurimath 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec-opal +1 -1
- data/.rubocop.yml +9 -5
- data/.rubocop_todo.yml +0 -0
- data/Gemfile +7 -5
- data/README.adoc +57 -1
- data/Rakefile +11 -0
- data/lib/plurimath/asciimath/parse.rb +0 -1
- data/lib/plurimath/asciimath/parser.rb +0 -3
- data/lib/plurimath/asciimath.rb +5 -0
- data/lib/plurimath/cli.rb +28 -1
- data/lib/plurimath/errors.rb +0 -4
- data/lib/plurimath/formatter/numbers.rb +12 -0
- data/lib/plurimath/formatter/numeric_formatter.rb +4 -1
- data/lib/plurimath/formatter/standard.rb +0 -1
- data/lib/plurimath/formatter.rb +6 -9
- data/lib/plurimath/html/parse.rb +0 -1
- data/lib/plurimath/html/parser.rb +0 -3
- data/lib/plurimath/html.rb +5 -0
- data/lib/plurimath/latex/parse.rb +0 -1
- data/lib/plurimath/latex/parser.rb +2 -5
- data/lib/plurimath/latex.rb +5 -0
- data/lib/plurimath/math/core.rb +6 -2
- data/lib/plurimath/math/formula/mrow.rb +2 -41
- data/lib/plurimath/math/formula/mstyle.rb +6 -0
- data/lib/plurimath/math/formula.rb +59 -301
- data/lib/plurimath/math/function/abs.rb +0 -1
- data/lib/plurimath/math/function/arccos.rb +0 -1
- data/lib/plurimath/math/function/arcsin.rb +0 -1
- data/lib/plurimath/math/function/arctan.rb +0 -1
- data/lib/plurimath/math/function/arg.rb +0 -1
- data/lib/plurimath/math/function/bar.rb +0 -1
- data/lib/plurimath/math/function/base.rb +0 -3
- data/lib/plurimath/math/function/binary_function.rb +5 -3
- data/lib/plurimath/math/function/cancel.rb +0 -1
- data/lib/plurimath/math/function/ceil.rb +0 -1
- data/lib/plurimath/math/function/color.rb +0 -1
- data/lib/plurimath/math/function/cos.rb +0 -1
- data/lib/plurimath/math/function/cosh.rb +0 -1
- data/lib/plurimath/math/function/cot.rb +0 -1
- data/lib/plurimath/math/function/coth.rb +0 -1
- data/lib/plurimath/math/function/csc.rb +0 -1
- data/lib/plurimath/math/function/csch.rb +0 -1
- data/lib/plurimath/math/function/ddot.rb +0 -1
- data/lib/plurimath/math/function/deg.rb +0 -1
- data/lib/plurimath/math/function/det.rb +0 -1
- data/lib/plurimath/math/function/dim.rb +0 -1
- data/lib/plurimath/math/function/dot.rb +0 -1
- data/lib/plurimath/math/function/exp.rb +0 -1
- data/lib/plurimath/math/function/fenced.rb +1 -197
- data/lib/plurimath/math/function/floor.rb +0 -1
- data/lib/plurimath/math/function/font_style/bold-fraktur.rb +0 -1
- data/lib/plurimath/math/function/font_style/bold-italic.rb +0 -1
- data/lib/plurimath/math/function/font_style/bold-sans-serif.rb +0 -1
- data/lib/plurimath/math/function/font_style/bold-script.rb +0 -1
- data/lib/plurimath/math/function/font_style/bold.rb +0 -1
- data/lib/plurimath/math/function/font_style/double_struck.rb +0 -1
- data/lib/plurimath/math/function/font_style/fraktur.rb +0 -1
- data/lib/plurimath/math/function/font_style/italic.rb +0 -1
- data/lib/plurimath/math/function/font_style/monospace.rb +0 -1
- data/lib/plurimath/math/function/font_style/normal.rb +0 -1
- data/lib/plurimath/math/function/font_style/sans-serif-bold-italic.rb +0 -1
- data/lib/plurimath/math/function/font_style/sans-serif-italic.rb +0 -1
- data/lib/plurimath/math/function/font_style/sans-serif.rb +0 -1
- data/lib/plurimath/math/function/font_style/script.rb +0 -1
- data/lib/plurimath/math/function/font_style.rb +29 -2
- data/lib/plurimath/math/function/frac.rb +0 -3
- data/lib/plurimath/math/function/gcd.rb +0 -1
- data/lib/plurimath/math/function/glb.rb +0 -1
- data/lib/plurimath/math/function/hat.rb +0 -1
- data/lib/plurimath/math/function/hom.rb +0 -1
- data/lib/plurimath/math/function/inf.rb +1 -2
- data/lib/plurimath/math/function/int.rb +2 -3
- data/lib/plurimath/math/function/intent.rb +0 -1
- data/lib/plurimath/math/function/ker.rb +0 -1
- data/lib/plurimath/math/function/lcm.rb +0 -1
- data/lib/plurimath/math/function/left.rb +0 -1
- data/lib/plurimath/math/function/lg.rb +0 -1
- data/lib/plurimath/math/function/lim.rb +1 -2
- data/lib/plurimath/math/function/liminf.rb +0 -1
- data/lib/plurimath/math/function/limits.rb +0 -1
- data/lib/plurimath/math/function/limsup.rb +0 -1
- data/lib/plurimath/math/function/linebreak.rb +0 -1
- data/lib/plurimath/math/function/ln.rb +0 -1
- data/lib/plurimath/math/function/log.rb +1 -2
- data/lib/plurimath/math/function/longdiv.rb +0 -3
- data/lib/plurimath/math/function/lub.rb +0 -1
- data/lib/plurimath/math/function/max.rb +0 -1
- data/lib/plurimath/math/function/mbox.rb +0 -1
- data/lib/plurimath/math/function/menclose.rb +0 -3
- data/lib/plurimath/math/function/merror.rb +0 -3
- data/lib/plurimath/math/function/mglyph.rb +0 -3
- data/lib/plurimath/math/function/min.rb +0 -1
- data/lib/plurimath/math/function/mlabeledtr.rb +0 -20
- data/lib/plurimath/math/function/mod.rb +0 -1
- data/lib/plurimath/math/function/mpadded.rb +0 -3
- data/lib/plurimath/math/function/ms.rb +1 -77
- data/lib/plurimath/math/function/msgroup.rb +0 -27
- data/lib/plurimath/math/function/msline.rb +0 -3
- data/lib/plurimath/math/function/multiscript.rb +0 -14
- data/lib/plurimath/math/function/nary.rb +4 -0
- data/lib/plurimath/math/function/none.rb +1 -4
- data/lib/plurimath/math/function/norm.rb +0 -1
- data/lib/plurimath/math/function/obrace.rb +0 -1
- data/lib/plurimath/math/function/oint.rb +2 -3
- data/lib/plurimath/math/function/over.rb +0 -3
- data/lib/plurimath/math/function/overset.rb +3 -3
- data/lib/plurimath/math/function/phantom.rb +0 -3
- data/lib/plurimath/math/function/power.rb +0 -3
- data/lib/plurimath/math/function/power_base.rb +0 -3
- data/lib/plurimath/math/function/prod.rb +2 -3
- data/lib/plurimath/math/function/right.rb +0 -1
- data/lib/plurimath/math/function/root.rb +0 -3
- data/lib/plurimath/math/function/rule.rb +0 -1
- data/lib/plurimath/math/function/scarries.rb +0 -3
- data/lib/plurimath/math/function/scarry.rb +22 -0
- data/lib/plurimath/math/function/sec.rb +0 -1
- data/lib/plurimath/math/function/sech.rb +0 -1
- data/lib/plurimath/math/function/semantics.rb +0 -15
- data/lib/plurimath/math/function/sin.rb +0 -1
- data/lib/plurimath/math/function/sinh.rb +0 -1
- data/lib/plurimath/math/function/sqrt.rb +0 -3
- data/lib/plurimath/math/function/stackrel.rb +0 -3
- data/lib/plurimath/math/function/substack.rb +0 -1
- data/lib/plurimath/math/function/sum.rb +2 -3
- data/lib/plurimath/math/function/sup.rb +0 -1
- data/lib/plurimath/math/function/table/align.rb +0 -1
- data/lib/plurimath/math/function/table/array.rb +0 -1
- data/lib/plurimath/math/function/table/bmatrix.rb +0 -1
- data/lib/plurimath/math/function/table/cases.rb +0 -1
- data/lib/plurimath/math/function/table/eqarray.rb +0 -1
- data/lib/plurimath/math/function/table/matrix.rb +0 -1
- data/lib/plurimath/math/function/table/multline.rb +0 -1
- data/lib/plurimath/math/function/table/pmatrix.rb +0 -1
- data/lib/plurimath/math/function/table/split.rb +0 -1
- data/lib/plurimath/math/function/table/vmatrix.rb +0 -1
- data/lib/plurimath/math/function/table.rb +10 -23
- data/lib/plurimath/math/function/tan.rb +0 -1
- data/lib/plurimath/math/function/tanh.rb +0 -1
- data/lib/plurimath/math/function/td.rb +0 -4
- data/lib/plurimath/math/function/ternary_function.rb +6 -2
- data/lib/plurimath/math/function/text.rb +1 -6
- data/lib/plurimath/math/function/tilde.rb +4 -1
- data/lib/plurimath/math/function/tr.rb +0 -13
- data/lib/plurimath/math/function/ubrace.rb +0 -1
- data/lib/plurimath/math/function/ul.rb +4 -1
- data/lib/plurimath/math/function/underover.rb +0 -3
- data/lib/plurimath/math/function/underset.rb +22 -45
- data/lib/plurimath/math/function/unitsml.rb +2 -1
- data/lib/plurimath/math/function/vec.rb +4 -1
- data/lib/plurimath/math/function.rb +107 -10
- data/lib/plurimath/math/number.rb +9 -7
- data/lib/plurimath/math/symbols/comma.rb +1 -1
- data/lib/plurimath/math/symbols/plus.rb +1 -1
- data/lib/plurimath/math/symbols/symbol.rb +17 -4
- data/lib/plurimath/math.rb +8 -26
- data/lib/plurimath/mathml/constants.rb +1 -0
- data/lib/plurimath/mathml/formula_transformation.rb +442 -0
- data/lib/plurimath/mathml/parser.rb +11 -50
- data/lib/plurimath/mathml/translator.rb +584 -0
- data/lib/plurimath/mathml/utility/formula_transformation.rb +2 -341
- data/lib/plurimath/mathml.rb +5 -0
- data/lib/plurimath/number_formatter.rb +2 -1
- data/lib/plurimath/omml/parser.rb +10 -7
- data/lib/plurimath/omml/transform.rb +17 -5
- data/lib/plurimath/omml.rb +3 -0
- data/lib/plurimath/setup/opal.rb.erb +3 -4
- data/lib/plurimath/unicode_math/parse.rb +0 -5
- data/lib/plurimath/unicode_math/parser.rb +1 -6
- data/lib/plurimath/unicode_math/parsing_rules/absence_rules.rb +0 -1
- data/lib/plurimath/unicode_math/parsing_rules/common_rules.rb +0 -1
- data/lib/plurimath/unicode_math/parsing_rules/constants_rules.rb +0 -1
- data/lib/plurimath/unicode_math/parsing_rules/masked.rb +0 -1
- data/lib/plurimath/unicode_math/parsing_rules/sub_sup.rb +0 -1
- data/lib/plurimath/unicode_math/parsing_rules.rb +14 -0
- data/lib/plurimath/unicode_math.rb +6 -0
- data/lib/plurimath/utility.rb +1 -1
- data/lib/plurimath/version.rb +1 -1
- data/lib/plurimath/xml_engine/oga.rb +6 -6
- data/lib/plurimath/xml_engine/ox_engine.rb +2 -2
- data/lib/plurimath/xml_engine.rb +2 -0
- data/lib/plurimath.rb +43 -18
- data/plurimath.gemspec +5 -4
- metadata +33 -15
- data/lib/plurimath/mathml/utility/empty_defined_methods.rb +0 -483
- data/lib/plurimath/mathml/utility.rb +0 -369
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mml"
|
|
4
|
+
|
|
5
|
+
module Plurimath
|
|
6
|
+
class Mathml
|
|
7
|
+
class Translator
|
|
8
|
+
include Mathml::FormulaTransformation
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@memoized = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Main entry point: Mml model → Plurimath model
|
|
15
|
+
def mml_to_plurimath(mml_node)
|
|
16
|
+
return nil if mml_node.nil?
|
|
17
|
+
|
|
18
|
+
case mml_node
|
|
19
|
+
when String then text_node_to_plurimath(mml_node)
|
|
20
|
+
when Mml::V4::Math then math_to_formula(mml_node)
|
|
21
|
+
when Mml::V4::Mrow then mrow_to_mrow(mml_node)
|
|
22
|
+
when Mml::V4::Mover then mover_to_overset(mml_node)
|
|
23
|
+
when Mml::V4::Munder then munder_to_underset(mml_node)
|
|
24
|
+
when Mml::V4::Munderover then munderover_to_underover(mml_node)
|
|
25
|
+
when Mml::V4::Msup then msup_to_power(mml_node)
|
|
26
|
+
when Mml::V4::Msub then msub_to_base(mml_node)
|
|
27
|
+
when Mml::V4::Msubsup then msubsup_to_powerbase(mml_node)
|
|
28
|
+
when Mml::V4::Mfrac then mfrac_to_frac(mml_node)
|
|
29
|
+
when Mml::V4::Mfraction then mfrac_to_frac(mml_node)
|
|
30
|
+
when Mml::V4::Msqrt then msqrt_to_sqrt(mml_node)
|
|
31
|
+
when Mml::V4::Mroot then mroot_to_root(mml_node)
|
|
32
|
+
when Mml::V4::Mi then mi_to_symbol(mml_node)
|
|
33
|
+
when Mml::V4::Mo then mo_to_symbol(mml_node)
|
|
34
|
+
when Mml::V4::Mn then mn_to_number(mml_node)
|
|
35
|
+
when Mml::V4::Mtext then mtext_to_text(mml_node)
|
|
36
|
+
when Mml::V4::Mstyle then mstyle_to_mstyle(mml_node)
|
|
37
|
+
when Mml::V4::Mtable then mtable_to_table(mml_node)
|
|
38
|
+
when Mml::V4::Mtr then mtr_to_tr(mml_node)
|
|
39
|
+
when Mml::V4::Mtd then mtd_to_td(mml_node)
|
|
40
|
+
when Mml::V4::Mfenced then mfenced_to_fenced(mml_node)
|
|
41
|
+
when Mml::V4::Mphantom then mphantom_to_phantom(mml_node)
|
|
42
|
+
when Mml::V4::Menclose then menclose_to_menclose(mml_node)
|
|
43
|
+
when Mml::V4::Merror then merror_to_merror(mml_node)
|
|
44
|
+
when Mml::V4::Mlongdiv then mlongdiv_to_longdiv(mml_node)
|
|
45
|
+
when Mml::V4::Mstack then mstack_to_stackrel(mml_node)
|
|
46
|
+
when Mml::V4::Msrow then msrow_to_formula(mml_node)
|
|
47
|
+
when Mml::V4::Msgroup then msgroup_to_msgroup(mml_node)
|
|
48
|
+
when Mml::V4::Msline then msline_to_msline(mml_node)
|
|
49
|
+
when Mml::V4::Mpadded then mpadded_to_mpadded(mml_node)
|
|
50
|
+
when Mml::V4::Mglyph then mglyph_to_mglyph(mml_node)
|
|
51
|
+
when Mml::V4::Mmultiscripts then mmultiscripts_to_multiscript(mml_node)
|
|
52
|
+
when Mml::V4::Mlabeledtr then mlabeledtr_to_mlabeledtr(mml_node)
|
|
53
|
+
when Mml::V4::Semantics then semantics_to_semantics(mml_node)
|
|
54
|
+
when Mml::V4::None then none_to_none
|
|
55
|
+
when Mml::V4::Ms then ms_to_ms(mml_node)
|
|
56
|
+
when Mml::V4::Mscarries then mscarries_to_scarries(mml_node)
|
|
57
|
+
when Mml::V4::Mscarry then mscarry_to_mscarry(mml_node)
|
|
58
|
+
when Mml::V4::Annotation then nil
|
|
59
|
+
when Mml::V4::AnnotationXml then nil
|
|
60
|
+
when Mml::V4::Malignmark then nil
|
|
61
|
+
when Mml::V4::Maligngroup then nil
|
|
62
|
+
when Mml::V4::Mspace then mspace_to_space(mml_node)
|
|
63
|
+
when Mml::V4::Mprescripts then mprescripts_to_prescripts(mml_node)
|
|
64
|
+
else
|
|
65
|
+
raise "Unknown mml node type: #{mml_node.class}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# MathML element: <math>
|
|
72
|
+
def math_to_formula(math)
|
|
73
|
+
children = ordered_children(math)
|
|
74
|
+
formula_values = children.map { |child| mml_to_plurimath(child) }.compact
|
|
75
|
+
formula_values = nary_check(formula_values)
|
|
76
|
+
display_style = boolean_to_displaystyle(math.display)
|
|
77
|
+
|
|
78
|
+
if formula_values.length == 1 && formula_values.first.respond_to?(:is_mstyle?) && formula_values.first.is_mstyle?
|
|
79
|
+
mstyle = formula_values.first
|
|
80
|
+
formula_values = Array(mstyle.value)
|
|
81
|
+
display_style = mstyle.displaystyle
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Plurimath::Math::Formula.new(
|
|
85
|
+
formula_values,
|
|
86
|
+
display_style: display_style,
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# MathML element: <mrow>
|
|
91
|
+
def mrow_to_mrow(mrow)
|
|
92
|
+
children = ordered_children(mrow)
|
|
93
|
+
formula_values = children.map { |child| mml_to_plurimath(child) }.compact
|
|
94
|
+
return nil if formula_values.empty?
|
|
95
|
+
|
|
96
|
+
combined = nary_check(combine_function_with_parens(formula_values))
|
|
97
|
+
mrow_obj = Plurimath::Math::Formula::Mrow.new(combined)
|
|
98
|
+
mrow_obj.send(:organize_value)
|
|
99
|
+
preserve_explicit_nary_body!(mrow_obj.value)
|
|
100
|
+
fill_ternary_third_values(mrow_obj.value)
|
|
101
|
+
return mrow_obj.value.first if mrow_obj.value.length == 1
|
|
102
|
+
|
|
103
|
+
if mrow.respond_to?(:intent) && mrow.intent && !mrow.intent.empty?
|
|
104
|
+
content = mrow_obj.is_a?(Plurimath::Math::Formula) ? mrow_obj : Plurimath::Math::Formula.new([mrow_obj])
|
|
105
|
+
return Plurimath::Math::Function::Intent.new(
|
|
106
|
+
content,
|
|
107
|
+
Plurimath::Math::Function::Text.new(mrow.intent),
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
Plurimath::Math::Formula.new(mrow_obj.value)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# MathML element: <mover> base overscript
|
|
115
|
+
# Note: Overset convention is parameter_one=overscript, parameter_two=base
|
|
116
|
+
# (reversed from MathML document order) to match rendering methods
|
|
117
|
+
def mover_to_overset(mover)
|
|
118
|
+
children = content_children(mover)
|
|
119
|
+
base = filter_child(mml_to_plurimath(children[0]))
|
|
120
|
+
overscript = filter_child(mml_to_plurimath(children[1]))
|
|
121
|
+
options = {}
|
|
122
|
+
options[:accent] = true if truthy_mathml_bool?(mover.accent)
|
|
123
|
+
|
|
124
|
+
case overscript&.class_name
|
|
125
|
+
when "obrace", "ubrace"
|
|
126
|
+
overscript.parameter_one = base
|
|
127
|
+
overscript
|
|
128
|
+
when "hat", "ddot", "vec", "tilde"
|
|
129
|
+
overscript.parameter_one = base
|
|
130
|
+
overscript.attributes = options if overscript.respond_to?(:attributes=)
|
|
131
|
+
overscript
|
|
132
|
+
when "period", "dot"
|
|
133
|
+
new_element = overscript.is_a?(Plurimath::Math::Symbols::Period) ? Plurimath::Math::Function::Dot.new : overscript
|
|
134
|
+
new_element.parameter_one = base
|
|
135
|
+
new_element.attributes = options if new_element.respond_to?(:attributes=)
|
|
136
|
+
new_element
|
|
137
|
+
when "bar"
|
|
138
|
+
overscript.parameter_one = base
|
|
139
|
+
overscript
|
|
140
|
+
when "ul", "underline"
|
|
141
|
+
Plurimath::Math::Function::Bar.new(base, options)
|
|
142
|
+
else
|
|
143
|
+
Plurimath::Math::Function::Overset.new(overscript, base, options)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# MathML element: <munder> base underscript
|
|
148
|
+
def munder_to_underset(munder)
|
|
149
|
+
children = content_children(munder)
|
|
150
|
+
base = mml_to_plurimath(children[0])
|
|
151
|
+
underscript = mml_to_plurimath(children[1])
|
|
152
|
+
options = {}
|
|
153
|
+
options[:accentunder] = true if truthy_mathml_bool?(munder.accentunder)
|
|
154
|
+
|
|
155
|
+
if base.is_a?(Plurimath::Math::Function::Vec) ||
|
|
156
|
+
(base.respond_to?(:is_ternary_function?) && base.is_ternary_function? && !base.any_value_exist?)
|
|
157
|
+
base.parameter_one = underscript
|
|
158
|
+
base.attributes = options if base.respond_to?(:attributes=)
|
|
159
|
+
return base
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if base.respond_to?(:is_binary_function?) && base.is_binary_function? && !base.any_value_exist?
|
|
163
|
+
base.parameter_one = underscript
|
|
164
|
+
return base
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
case underscript&.class_name
|
|
168
|
+
when "obrace", "ubrace", "ul", "underline"
|
|
169
|
+
underscript.parameter_one = base
|
|
170
|
+
underscript
|
|
171
|
+
when "bar"
|
|
172
|
+
Plurimath::Math::Function::Ul.new(base, options)
|
|
173
|
+
else
|
|
174
|
+
Plurimath::Math::Function::Underset.new(underscript, base, options)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# MathML element: <munderover> base underscript overscript
|
|
179
|
+
def munderover_to_underover(munderover)
|
|
180
|
+
children = content_children(munderover)
|
|
181
|
+
base = filter_child(mml_to_plurimath(children[0]))
|
|
182
|
+
underscript = filter_child(mml_to_plurimath(children[1]))
|
|
183
|
+
overscript = filter_child(mml_to_plurimath(children[2]))
|
|
184
|
+
|
|
185
|
+
if base&.is_ternary_function? && !base.any_value_exist?
|
|
186
|
+
base.parameter_one = underscript
|
|
187
|
+
base.parameter_two = overscript
|
|
188
|
+
base
|
|
189
|
+
elsif base&.is_nary_symbol?
|
|
190
|
+
Plurimath::Math::Function::Nary.new(
|
|
191
|
+
base,
|
|
192
|
+
underscript,
|
|
193
|
+
overscript,
|
|
194
|
+
nil,
|
|
195
|
+
{ type: "undOvr" },
|
|
196
|
+
)
|
|
197
|
+
else
|
|
198
|
+
Plurimath::Math::Function::Underover.new(base, underscript, overscript)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# MathML element: <msup> base superscript
|
|
203
|
+
def msup_to_power(sup)
|
|
204
|
+
children = content_children(sup)
|
|
205
|
+
base = filter_child(mml_to_plurimath(children[0]))
|
|
206
|
+
superscript = filter_child(mml_to_plurimath(children[1]))
|
|
207
|
+
if base&.is_binary_function? && !base.any_value_exist?
|
|
208
|
+
base.parameter_one = superscript
|
|
209
|
+
return base
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
Plurimath::Math::Function::Power.new(base, superscript)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# MathML element: <msub> base subscript
|
|
216
|
+
def msub_to_base(sub)
|
|
217
|
+
children = content_children(sub)
|
|
218
|
+
base = filter_child(mml_to_plurimath(children[0]))
|
|
219
|
+
subscript = filter_child(mml_to_plurimath(children[1]))
|
|
220
|
+
if base&.is_binary_function? && !base.any_value_exist?
|
|
221
|
+
base.parameter_one = subscript
|
|
222
|
+
return base
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
Plurimath::Math::Function::Base.new(base, subscript)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# MathML element: <msubsup> base subscript superscript
|
|
229
|
+
def msubsup_to_powerbase(subsup)
|
|
230
|
+
children = content_children(subsup)
|
|
231
|
+
base = filter_child(mml_to_plurimath(children[0]))
|
|
232
|
+
subscript = filter_child(mml_to_plurimath(children[1]))
|
|
233
|
+
superscript = filter_child(mml_to_plurimath(children[2]))
|
|
234
|
+
|
|
235
|
+
if base&.is_ternary_function? && !base.any_value_exist?
|
|
236
|
+
base.parameter_one = subscript
|
|
237
|
+
base.parameter_two = superscript
|
|
238
|
+
return base
|
|
239
|
+
elsif base&.is_binary_function? && !base.any_value_exist?
|
|
240
|
+
base.parameter_one = subscript
|
|
241
|
+
base.parameter_two = superscript
|
|
242
|
+
return base
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
Plurimath::Math::Function::PowerBase.new(base, subscript, superscript)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# MathML element: <mi> - identifier
|
|
249
|
+
def mi_to_symbol(mi)
|
|
250
|
+
value = text_value(mi.value)
|
|
251
|
+
return nil if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
|
252
|
+
|
|
253
|
+
apply_font_style(mi, mathml_symbol(value))
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# MathML element: <mo> - operator
|
|
257
|
+
def mo_to_symbol(mo)
|
|
258
|
+
value = text_value(mo.value)
|
|
259
|
+
# Handle linebreak="newline" attribute - creates a Linebreak wrapper
|
|
260
|
+
if mo.linebreak == "newline"
|
|
261
|
+
attributes = {}
|
|
262
|
+
attributes[:linebreakstyle] = mo.linebreakstyle if mo.linebreakstyle
|
|
263
|
+
symbol =
|
|
264
|
+
if value.nil? || value == ""
|
|
265
|
+
Plurimath::Math::Symbols::Symbol.new(nil)
|
|
266
|
+
else
|
|
267
|
+
mathml_symbol(value)
|
|
268
|
+
end
|
|
269
|
+
symbol = Plurimath::Math::Symbols::Symbol.new(value) if symbol.nil? || symbol.is_a?(Array)
|
|
270
|
+
return Plurimath::Math::Function::Linebreak.new(
|
|
271
|
+
symbol,
|
|
272
|
+
attributes
|
|
273
|
+
)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
if value.nil? || value == ""
|
|
277
|
+
result = Plurimath::Math::Symbols::Symbol.new(nil)
|
|
278
|
+
options = {}
|
|
279
|
+
options[:rspace] = mo.rspace if mo.respond_to?(:rspace) && mo.rspace
|
|
280
|
+
result.options = options if options.any?
|
|
281
|
+
return result
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
result = mathml_symbol(value)
|
|
285
|
+
result = Plurimath::Math::Symbols::Symbol.new(value) if result.nil? || result.is_a?(Array)
|
|
286
|
+
if result.instance_of?(Plurimath::Math::Symbols::Symbol)
|
|
287
|
+
options = {}
|
|
288
|
+
options[:rspace] = mo.rspace if mo.respond_to?(:rspace) && mo.rspace
|
|
289
|
+
result.options = options if options.any?
|
|
290
|
+
end
|
|
291
|
+
apply_font_style(mo, result)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# MathML element: <mn> - number
|
|
295
|
+
def mn_to_number(mn)
|
|
296
|
+
value = text_value(mn.value) || ""
|
|
297
|
+
Plurimath::Math::Number.new(value)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# MathML element: <mtext> - text
|
|
301
|
+
def mtext_to_text(mtext)
|
|
302
|
+
text_obj = Plurimath::Math::Function::Text.new
|
|
303
|
+
text_obj.value = text_value(mtext.value)
|
|
304
|
+
text_obj
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# MathML element: <none>
|
|
308
|
+
def none_to_none
|
|
309
|
+
nil
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# MathML element: <ms> - string
|
|
313
|
+
def ms_to_ms(ms)
|
|
314
|
+
children = ordered_children(ms)
|
|
315
|
+
text_content = children.filter_map { |child| extract_ms_text(child) }.join(" ")
|
|
316
|
+
Plurimath::Math::Function::Ms.new(text_content.empty? ? nil : text_content)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# MathML element: <mfrac> numerator denominator
|
|
320
|
+
def mfrac_to_frac(frac)
|
|
321
|
+
children = content_children(frac)
|
|
322
|
+
numerator = mml_to_plurimath(children[0])
|
|
323
|
+
denominator = mml_to_plurimath(children[1])
|
|
324
|
+
options = {}
|
|
325
|
+
options[:linethickness] = frac.linethickness if frac.linethickness
|
|
326
|
+
options[:bevelled] = frac.bevelled if frac.bevelled
|
|
327
|
+
Plurimath::Math::Function::Frac.new(numerator, denominator, options)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# MathML element: <msqrt> - square root
|
|
331
|
+
def msqrt_to_sqrt(sqrt)
|
|
332
|
+
children = content_children(sqrt)
|
|
333
|
+
radicand = children.map { |child| mml_to_plurimath(child) }.compact
|
|
334
|
+
radicand = radicand.first if radicand.size == 1
|
|
335
|
+
Plurimath::Math::Function::Sqrt.new(radicand)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# MathML element: <mroot> radicand index
|
|
339
|
+
def mroot_to_root(root)
|
|
340
|
+
children = content_children(root)
|
|
341
|
+
radicand = filter_child(mml_to_plurimath(children[0]))
|
|
342
|
+
index = filter_child(mml_to_plurimath(children[1]))
|
|
343
|
+
Plurimath::Math::Function::Root.new(index, radicand)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
# MathML element: <mphantom> - phantom
|
|
347
|
+
def mphantom_to_phantom(phantom)
|
|
348
|
+
children = ordered_children(phantom)
|
|
349
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
350
|
+
content_obj = wrap_children(content)
|
|
351
|
+
content_obj = normalize_phantom_child(content_obj)
|
|
352
|
+
Plurimath::Math::Function::Phantom.new(content_obj)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# MathML element: <menclose> - enclose
|
|
356
|
+
def menclose_to_menclose(enclose)
|
|
357
|
+
children = ordered_children(enclose)
|
|
358
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
359
|
+
notation = enclose.notation
|
|
360
|
+
content_obj = content.size == 1 ? content.first : Plurimath::Math::Formula.new(content)
|
|
361
|
+
Plurimath::Math::Function::Menclose.new(notation, content_obj)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# MathML element: <merror> - error
|
|
365
|
+
def merror_to_merror(error)
|
|
366
|
+
children = ordered_children(error)
|
|
367
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
368
|
+
Plurimath::Math::Function::Merror.new(wrap_children(content))
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# MathML element: <mstyle> - style
|
|
372
|
+
def mstyle_to_mstyle(style)
|
|
373
|
+
children = ordered_children(style)
|
|
374
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
375
|
+
content_obj = wrap_children(content)
|
|
376
|
+
|
|
377
|
+
has_color = style.respond_to?(:mathcolor) && style.mathcolor && !style.mathcolor.empty?
|
|
378
|
+
has_variant = style.respond_to?(:mathvariant) && style.mathvariant && !style.mathvariant.empty?
|
|
379
|
+
|
|
380
|
+
if has_color
|
|
381
|
+
content_obj = Plurimath::Math::Function::Color.new(
|
|
382
|
+
Plurimath::Math::Function::Text.new(style.mathcolor),
|
|
383
|
+
content_obj,
|
|
384
|
+
)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
if has_variant
|
|
388
|
+
font_class = Plurimath::Utility::FONT_STYLES[style.mathvariant.to_sym]
|
|
389
|
+
return font_class.new(content_obj, style.mathvariant) if font_class
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
return content_obj if has_color
|
|
393
|
+
|
|
394
|
+
fill_ternary_third_values(content)
|
|
395
|
+
Plurimath::Math::Formula::Mstyle.new(
|
|
396
|
+
content,
|
|
397
|
+
display_style: boolean_to_displaystyle(style.displaystyle),
|
|
398
|
+
)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# MathML element: <mfenced> - fenced
|
|
402
|
+
def mfenced_to_fenced(fenced)
|
|
403
|
+
children = ordered_children(fenced)
|
|
404
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact.map { |child| filter_child(child) }
|
|
405
|
+
open_value = fenced.open || default_fenced_open(fenced)
|
|
406
|
+
close_value = fenced.close || default_fenced_close(fenced)
|
|
407
|
+
|
|
408
|
+
Plurimath::Math::Function::Fenced.new(
|
|
409
|
+
resolve_paren(open_value),
|
|
410
|
+
content,
|
|
411
|
+
resolve_paren(close_value),
|
|
412
|
+
{ separators: fenced.separators }.compact,
|
|
413
|
+
)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# MathML element: <mtable> - table
|
|
417
|
+
def mtable_to_table(table)
|
|
418
|
+
table_content = ordered_children(table).filter_map { |row| mml_to_plurimath(row) }
|
|
419
|
+
table_obj = Plurimath::Math::Function::Table.new(table_content)
|
|
420
|
+
# Set table attributes
|
|
421
|
+
table_obj.frame = table.frame if table.respond_to?(:frame) && table.frame
|
|
422
|
+
table_obj.rowlines = table.rowlines if table.respond_to?(:rowlines) && table.rowlines
|
|
423
|
+
table_obj.columnlines = table.columnlines if table.respond_to?(:columnlines) && table.columnlines
|
|
424
|
+
table_obj
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# MathML element: <mtr> - table row
|
|
428
|
+
def mtr_to_tr(tr)
|
|
429
|
+
cells = ordered_children(tr).map { |cell| mml_to_plurimath(cell) }
|
|
430
|
+
Plurimath::Math::Function::Tr.new(cells)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# MathML element: <mtd> - table cell
|
|
434
|
+
def mtd_to_td(td)
|
|
435
|
+
children = ordered_children(td)
|
|
436
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
437
|
+
Plurimath::Math::Function::Td.new(content)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
# MathML element: <mlongdiv> - long division
|
|
441
|
+
def mlongdiv_to_longdiv(longdiv)
|
|
442
|
+
children = ordered_children(longdiv)
|
|
443
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
444
|
+
Plurimath::Math::Function::Longdiv.new(content)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# MathML element: <mstack> - stacked
|
|
448
|
+
def mstack_to_stackrel(stack)
|
|
449
|
+
children = ordered_children(stack)
|
|
450
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
451
|
+
Plurimath::Math::Function::Stackrel.new(wrap_children(content))
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# MathML element: <msrow> - stack row
|
|
455
|
+
def msrow_to_formula(msrow)
|
|
456
|
+
children = ordered_children(msrow)
|
|
457
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
458
|
+
return nil if content.empty?
|
|
459
|
+
|
|
460
|
+
Plurimath::Math::Formula.new(content)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# MathML element: <msgroup> - group
|
|
464
|
+
def msgroup_to_msgroup(sgroup)
|
|
465
|
+
content = ordered_children(sgroup).filter_map do |child|
|
|
466
|
+
if child.is_a?(String)
|
|
467
|
+
next if child.strip.empty?
|
|
468
|
+
|
|
469
|
+
Plurimath::Math::Function::Text.new(child)
|
|
470
|
+
else
|
|
471
|
+
mml_to_plurimath(child)
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
Plurimath::Math::Function::Msgroup.new(content)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
# MathML element: <msline> - line
|
|
478
|
+
def msline_to_msline(sline)
|
|
479
|
+
children = ordered_children(sline)
|
|
480
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
481
|
+
Plurimath::Math::Function::Msline.new(wrap_children(content))
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# MathML element: <mpadded> - padded
|
|
485
|
+
def mpadded_to_mpadded(padded)
|
|
486
|
+
children = ordered_children(padded)
|
|
487
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
488
|
+
options = {}
|
|
489
|
+
options[:height] = padded.height if padded.height
|
|
490
|
+
options[:depth] = padded.depth if padded.depth
|
|
491
|
+
options[:width] = padded.width if padded.width
|
|
492
|
+
Plurimath::Math::Function::Mpadded.new(wrap_children(content), options)
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# MathML element: <mglyph> - glyph
|
|
496
|
+
def mglyph_to_mglyph(glyph)
|
|
497
|
+
src = glyph.src
|
|
498
|
+
alt = glyph.alt
|
|
499
|
+
index = glyph.index
|
|
500
|
+
Plurimath::Math::Function::Mglyph.new(src: src, alt: alt, index: index)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# MathML element: <mmultiscripts> - multiscripts
|
|
504
|
+
def mmultiscripts_to_multiscript(multiscripts)
|
|
505
|
+
children = ordered_children(multiscripts)
|
|
506
|
+
return Plurimath::Math::Function::Multiscript.new if children.empty?
|
|
507
|
+
|
|
508
|
+
base = convert_multiscript_child(children[0])
|
|
509
|
+
has_prescripts = !multiscripts.mprescripts_value.nil?
|
|
510
|
+
element_order = multiscripts.element_order
|
|
511
|
+
mpre_index = element_order.index { |el| el.name == "mprescripts" }
|
|
512
|
+
|
|
513
|
+
if has_prescripts && mpre_index
|
|
514
|
+
post_element_count = multiscript_post_element_count(element_order, mpre_index)
|
|
515
|
+
post_children, pre_children = split_multiscript_children(children, post_element_count)
|
|
516
|
+
|
|
517
|
+
post_subs, post_sups = split_script_pairs(post_children)
|
|
518
|
+
pre_subs, pre_sups = split_script_pairs(pre_children, compact: true)
|
|
519
|
+
base_with_posts = attach_postscripts(base, post_subs, post_sups)
|
|
520
|
+
Plurimath::Math::Function::Multiscript.new(base_with_posts, pre_subs, pre_sups)
|
|
521
|
+
else
|
|
522
|
+
remaining = convert_multiscript_children(children[1..-1])
|
|
523
|
+
subscripts, superscripts = split_script_pairs(remaining, compact: true)
|
|
524
|
+
base_with_posts = attach_postscripts(base, subscripts, superscripts)
|
|
525
|
+
Plurimath::Math::Function::Multiscript.new(base_with_posts)
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# MathML element: <mlabeledtr> - labeled row
|
|
530
|
+
def mlabeledtr_to_mlabeledtr(labeledtr)
|
|
531
|
+
children = ordered_children(labeledtr)
|
|
532
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
533
|
+
label = labeledtr.id && Plurimath::Math::Function::Text.new(labeledtr.id)
|
|
534
|
+
Plurimath::Math::Function::Mlabeledtr.new(content, label)
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# MathML element: <semantics> - semantics
|
|
538
|
+
def semantics_to_semantics(semantics)
|
|
539
|
+
children = ordered_children(semantics)
|
|
540
|
+
content = filter_child(wrap_children(children.map { |child| mml_to_plurimath(child) }.compact))
|
|
541
|
+
annotations = []
|
|
542
|
+
annotations += build_annotation_entries(semantics.annotation_value, :annotation)
|
|
543
|
+
annotations += build_annotation_entries(semantics.annotation_xml_value, :"annotation-xml")
|
|
544
|
+
Plurimath::Math::Function::Semantics.new(content, annotations.empty? ? nil : annotations)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
# MathML element: <mscarries> - carries
|
|
548
|
+
def mscarries_to_scarries(scarries)
|
|
549
|
+
children = ordered_children(scarries)
|
|
550
|
+
content = children.map { |child| mml_to_plurimath(child) }.compact
|
|
551
|
+
Plurimath::Math::Function::Scarries.new(wrap_children(content))
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
# MathML element: <mscarry> - carry
|
|
555
|
+
# The legacy MathML flow treated <mscarry> as a layout marker inside
|
|
556
|
+
# <mscarries>, so it was removed before AST construction.
|
|
557
|
+
def mscarry_to_mscarry(_scarry)
|
|
558
|
+
nil
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
# MathML element: <mprescripts> - prescripts marker
|
|
562
|
+
# This is a marker element, returns nil (filtered out)
|
|
563
|
+
def mprescripts_to_prescripts(_)
|
|
564
|
+
nil
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
# MathML element: <mspace> - space
|
|
568
|
+
def mspace_to_space(space)
|
|
569
|
+
if space.linebreak && !space.linebreak.empty?
|
|
570
|
+
Plurimath::Math::Function::Linebreak.new(
|
|
571
|
+
nil,
|
|
572
|
+
{ linebreak: space.linebreak },
|
|
573
|
+
)
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def text_node_to_plurimath(text)
|
|
578
|
+
return nil if text.nil? || text.match?(/\A[[:space:]]*\z/)
|
|
579
|
+
|
|
580
|
+
mathml_symbol(text)
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
end
|