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
data/lib/plurimath/math.rb
CHANGED
|
@@ -1,33 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "errors"
|
|
4
|
-
require_relative "asciimath"
|
|
5
|
-
require_relative "omml"
|
|
6
|
-
require_relative "unicode_math"
|
|
7
|
-
require_relative "mathml"
|
|
8
|
-
require_relative "html"
|
|
9
|
-
require_relative "latex"
|
|
10
|
-
require_relative "unitsml"
|
|
11
|
-
require_relative "number_formatter"
|
|
12
|
-
require_relative "formatter/standard"
|
|
13
|
-
require_relative "math/core"
|
|
14
|
-
require_relative "math/number"
|
|
15
|
-
require_relative "math/symbols"
|
|
16
|
-
require_relative "math/formula"
|
|
17
|
-
require_relative "math/formula/mrow"
|
|
18
|
-
require_relative "math/formula/mstyle"
|
|
19
|
-
require_relative "math/function"
|
|
20
|
-
require_relative "asciimath/parser"
|
|
21
|
-
require_relative "unicode_math/parser"
|
|
22
|
-
require_relative "mathml/parser"
|
|
23
|
-
require_relative "latex/parser"
|
|
24
|
-
require_relative "html/parser"
|
|
25
|
-
require_relative "omml/parser"
|
|
26
|
-
require_relative "utility"
|
|
27
|
-
require "yaml"
|
|
28
|
-
|
|
29
3
|
module Plurimath
|
|
30
4
|
module Math
|
|
5
|
+
autoload :Core, "#{__dir__}/math/core"
|
|
6
|
+
autoload :Formula, "#{__dir__}/math/formula"
|
|
7
|
+
autoload :Function, "#{__dir__}/math/function"
|
|
8
|
+
autoload :InvalidTypeError, "#{__dir__}/errors/invalid_type_error"
|
|
9
|
+
autoload :Number, "#{__dir__}/math/number"
|
|
10
|
+
autoload :ParseError, "#{__dir__}/errors/parse_error"
|
|
11
|
+
autoload :Symbols, "#{__dir__}/math/symbols"
|
|
12
|
+
|
|
31
13
|
VALID_TYPES = {
|
|
32
14
|
omml: Omml,
|
|
33
15
|
html: Html,
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plurimath
|
|
4
|
+
class Mathml
|
|
5
|
+
module FormulaTransformation
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
# Use each_mixed_content to get children in document order.
|
|
9
|
+
def ordered_children(node)
|
|
10
|
+
children = []
|
|
11
|
+
node.each_mixed_content { |child| children << child }
|
|
12
|
+
children
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def text_value(value)
|
|
16
|
+
return if value.nil?
|
|
17
|
+
return value if value.is_a?(String)
|
|
18
|
+
|
|
19
|
+
Array(value).join
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def mathml_symbol(value)
|
|
23
|
+
Plurimath::Utility.mathml_unary_classes([value], lang: :mathml)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Alignment markers affect MathML layout only; the old parser dropped them
|
|
27
|
+
# before building the Plurimath AST.
|
|
28
|
+
def content_children(node)
|
|
29
|
+
ordered_children(node).reject do |child|
|
|
30
|
+
child.is_a?(Mml::V4::Malignmark) || child.is_a?(Mml::V4::Maligngroup)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def default_fenced_open(fenced)
|
|
35
|
+
"(" unless fenced.close
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def default_fenced_close(fenced)
|
|
39
|
+
")" unless fenced.open
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def resolve_paren(value)
|
|
43
|
+
return nil unless value
|
|
44
|
+
|
|
45
|
+
mathml_symbol(value)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def extract_ms_text(node)
|
|
49
|
+
return (node.empty? ? nil : node) if node.is_a?(String)
|
|
50
|
+
|
|
51
|
+
if ms_token_element?(node)
|
|
52
|
+
return Array(node.value).join
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if node.respond_to?(:each_mixed_content)
|
|
56
|
+
return ordered_children(node).filter_map { |child| extract_ms_text(child) }.join(" ")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
Array(node.value).join if node.respond_to?(:value)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ms_token_element?(node)
|
|
63
|
+
node.is_a?(Mml::V4::Mi) ||
|
|
64
|
+
node.is_a?(Mml::V4::Mn) ||
|
|
65
|
+
node.is_a?(Mml::V4::Mo) ||
|
|
66
|
+
node.is_a?(Mml::V4::Ms) ||
|
|
67
|
+
node.is_a?(Mml::V4::Mtext)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def normalize_phantom_child(child)
|
|
71
|
+
return child unless child.respond_to?(:value=) && child.respond_to?(:value)
|
|
72
|
+
return child if child.instance_of?(Math::Symbols::Symbol)
|
|
73
|
+
return child unless child.value.is_a?(String)
|
|
74
|
+
return child unless child.value.match?(/\A[[:space:]]|[[:space:]]\z/)
|
|
75
|
+
|
|
76
|
+
child.value = nil
|
|
77
|
+
child
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def boolean_to_displaystyle(value)
|
|
81
|
+
case value
|
|
82
|
+
when "true", true then true
|
|
83
|
+
when "false", false then false
|
|
84
|
+
else true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def truthy_mathml_bool?(value)
|
|
89
|
+
[true, "true"].include?(value)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def filter_child(value)
|
|
93
|
+
return nil if value.nil?
|
|
94
|
+
return value unless value.is_a?(Math::Formula)
|
|
95
|
+
return value if value.value.nil? || value.value.empty?
|
|
96
|
+
|
|
97
|
+
value.value.length == 1 ? value.value.first : value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def wrap_children(children)
|
|
101
|
+
case children.length
|
|
102
|
+
when 0 then nil
|
|
103
|
+
when 1 then children.first
|
|
104
|
+
else Math::Formula.new(children)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def nary_check(children)
|
|
109
|
+
return children unless children.length == 2
|
|
110
|
+
|
|
111
|
+
first = children.first
|
|
112
|
+
second = children.last
|
|
113
|
+
|
|
114
|
+
if first.is_a?(Math::Function::PowerBase) && first.parameter_one&.is_nary_symbol?
|
|
115
|
+
[Math::Function::Nary.new(
|
|
116
|
+
first.parameter_one,
|
|
117
|
+
first.parameter_two,
|
|
118
|
+
first.parameter_three,
|
|
119
|
+
second,
|
|
120
|
+
)]
|
|
121
|
+
elsif first.is_a?(Math::Function::Overset) && first.parameter_two&.is_nary_symbol?
|
|
122
|
+
[Math::Function::Nary.new(
|
|
123
|
+
first.parameter_two,
|
|
124
|
+
nil,
|
|
125
|
+
first.parameter_one,
|
|
126
|
+
second,
|
|
127
|
+
{ type: "undOvr" },
|
|
128
|
+
)]
|
|
129
|
+
elsif first.is_a?(Math::Function::Power) && first.parameter_one&.is_nary_symbol?
|
|
130
|
+
[Math::Function::Nary.new(
|
|
131
|
+
first.parameter_one,
|
|
132
|
+
nil,
|
|
133
|
+
first.parameter_two,
|
|
134
|
+
second,
|
|
135
|
+
{ type: "subSup" },
|
|
136
|
+
)]
|
|
137
|
+
else
|
|
138
|
+
children
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def fill_ternary_third_values(values)
|
|
143
|
+
return unless values.is_a?(Array) && values.length > 1
|
|
144
|
+
|
|
145
|
+
first = values.first
|
|
146
|
+
return if preserve_separate_nary_body?(first, values[1])
|
|
147
|
+
|
|
148
|
+
if first.is_a?(Math::Function::Nary)
|
|
149
|
+
first.parameter_four ||= values.delete_at(1)
|
|
150
|
+
elsif first.respond_to?(:is_nary_function?) && first.is_nary_function? && !first.all_values_exist?
|
|
151
|
+
if first.respond_to?(:new_nary_function) && !first.any_value_exist?
|
|
152
|
+
values[0] = first.new_nary_function(values.delete_at(1))
|
|
153
|
+
elsif first.any_value_exist?
|
|
154
|
+
first.parameter_three = values.delete_at(1)
|
|
155
|
+
end
|
|
156
|
+
elsif value_is_ternary_or_nary?(values)
|
|
157
|
+
first.parameter_three = values.delete_at(1)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def unwrap_single(value)
|
|
162
|
+
return nil if value.nil? || (value.is_a?(Array) && value.empty?)
|
|
163
|
+
return value unless value.is_a?(Array)
|
|
164
|
+
|
|
165
|
+
value.length == 1 ? value.first : Math::Formula.new(value)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def preserve_separate_nary_body?(first, second)
|
|
169
|
+
return false unless first.respond_to?(:is_nary_function?) && first.is_nary_function?
|
|
170
|
+
|
|
171
|
+
normalized_second = filter_child(second)
|
|
172
|
+
|
|
173
|
+
normalized_second.is_a?(Math::Function::Base) ||
|
|
174
|
+
normalized_second.is_a?(Math::Function::PowerBase)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def preserve_explicit_nary_body!(values)
|
|
178
|
+
return unless values.is_a?(Array) && values.any?
|
|
179
|
+
|
|
180
|
+
first = values.first
|
|
181
|
+
return unless first.is_a?(Math::Function::Nary)
|
|
182
|
+
return unless first.options&.[](:type) == "undOvr"
|
|
183
|
+
|
|
184
|
+
body = filter_child(first.parameter_four)
|
|
185
|
+
return unless body.is_a?(Math::Function::Base) ||
|
|
186
|
+
body.is_a?(Math::Function::PowerBase)
|
|
187
|
+
|
|
188
|
+
replacement =
|
|
189
|
+
if first.parameter_three.nil?
|
|
190
|
+
Math::Function::Underset.new(first.parameter_two, first.parameter_one)
|
|
191
|
+
else
|
|
192
|
+
Math::Function::Underover.new(
|
|
193
|
+
first.parameter_one,
|
|
194
|
+
first.parameter_two,
|
|
195
|
+
first.parameter_three,
|
|
196
|
+
)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
values[0] = replacement
|
|
200
|
+
values.insert(1, body)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def convert_multiscript_child(child)
|
|
204
|
+
return Math::Function::None.new if child.is_a?(Mml::V4::None) || child.is_a?(Mml::V3::None)
|
|
205
|
+
return Math::Function::None.new if child.respond_to?(:value) && Array(child.value).join.empty?
|
|
206
|
+
|
|
207
|
+
mml_to_plurimath(child) || Math::Function::None.new
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def convert_multiscript_children(children)
|
|
211
|
+
Array(children).map { |child| convert_multiscript_child(child) }
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def multiscript_post_element_count(element_order, prescript_index)
|
|
215
|
+
post_names = element_order[0...prescript_index]
|
|
216
|
+
.select { |element| element.node_type == :element }
|
|
217
|
+
.map(&:name)
|
|
218
|
+
post_names.size - 1
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def split_multiscript_children(children, post_element_count)
|
|
222
|
+
[
|
|
223
|
+
convert_multiscript_children(children[1..post_element_count]),
|
|
224
|
+
convert_multiscript_children(children[(post_element_count + 1)..-1]),
|
|
225
|
+
]
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def split_script_pairs(children, compact: false)
|
|
229
|
+
pairs = children.each_slice(2).to_a
|
|
230
|
+
subscripts = pairs.map { |pair| pair[0] if pair[0] }
|
|
231
|
+
superscripts = pairs.map { |pair| pair[1] if pair[1] }
|
|
232
|
+
|
|
233
|
+
if compact
|
|
234
|
+
[subscripts.compact, superscripts.compact]
|
|
235
|
+
else
|
|
236
|
+
[subscripts, superscripts]
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def attach_postscripts(base, subscripts, superscripts)
|
|
241
|
+
normalized_base = filter_child(base)
|
|
242
|
+
return normalized_base unless subscripts.any? || superscripts.any?
|
|
243
|
+
|
|
244
|
+
Math::Function::PowerBase.new(
|
|
245
|
+
normalized_base,
|
|
246
|
+
unwrap_single(subscripts),
|
|
247
|
+
unwrap_single(superscripts),
|
|
248
|
+
)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def build_annotation_entries(entries, tag_name)
|
|
252
|
+
return [] unless entries&.any?
|
|
253
|
+
|
|
254
|
+
entries.map do |annotation|
|
|
255
|
+
value = annotation.respond_to?(:value) ? annotation.value : annotation.to_s
|
|
256
|
+
{ tag_name => [Math::Symbols::Symbol.new(value)] }
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Heuristic: combine function name with following opening parenthesis.
|
|
261
|
+
def combine_function_with_parens(values)
|
|
262
|
+
return values if values.size < 2
|
|
263
|
+
|
|
264
|
+
result = []
|
|
265
|
+
i = 0
|
|
266
|
+
while i < values.size
|
|
267
|
+
current = values[i]
|
|
268
|
+
if i + 1 < values.size && can_combine_with_paren?(current)
|
|
269
|
+
next_elem = values[i + 1]
|
|
270
|
+
if opening_paren?(next_elem)
|
|
271
|
+
paren = if next_elem.respond_to?(:paren?) && next_elem.paren?
|
|
272
|
+
next_elem
|
|
273
|
+
else
|
|
274
|
+
Math::Symbols::Paren::Lround.new
|
|
275
|
+
end
|
|
276
|
+
result << current.class.new(paren)
|
|
277
|
+
i += 2
|
|
278
|
+
next
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
result << current
|
|
282
|
+
i += 1
|
|
283
|
+
end
|
|
284
|
+
result
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def opening_paren?(obj)
|
|
288
|
+
return true if obj.is_a?(Math::Symbols::Symbol) && obj.value == "("
|
|
289
|
+
return true if obj.class_name == "lround"
|
|
290
|
+
return true if obj.respond_to?(:paren?) && obj.paren? && obj.respond_to?(:to_asciimath) && obj.to_asciimath(options: {}) == "("
|
|
291
|
+
|
|
292
|
+
false
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def can_combine_with_paren?(obj)
|
|
296
|
+
return false unless obj.respond_to?(:class)
|
|
297
|
+
|
|
298
|
+
obj.class < Math::Function::UnaryFunction
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def apply_font_style(element, result)
|
|
302
|
+
return result unless element.respond_to?(:mathvariant)
|
|
303
|
+
|
|
304
|
+
variant = element.mathvariant
|
|
305
|
+
return result if variant.nil? || variant.empty?
|
|
306
|
+
|
|
307
|
+
font_class = Plurimath::Utility::FONT_STYLES[variant.to_sym]
|
|
308
|
+
return result unless font_class
|
|
309
|
+
|
|
310
|
+
font_class.new(result, variant)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def filter_values(value, array_to_instance: false, replacing_order: true)
|
|
314
|
+
return value unless value.is_a?(Array)
|
|
315
|
+
return array_to_instance ? nil : value if value.empty?
|
|
316
|
+
|
|
317
|
+
if is_a?(Math::Formula) && value.length == 1 && value.first.is_mstyle?
|
|
318
|
+
@displaystyle = value.first.displaystyle
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
if value.length == 1 && value.all? { |val| val.is_a?(Math::Formula) }
|
|
322
|
+
if array_to_instance
|
|
323
|
+
filter_values(value.first.value, array_to_instance: true)
|
|
324
|
+
else
|
|
325
|
+
value.first.value
|
|
326
|
+
end
|
|
327
|
+
elsif value.is_a?(Array) && value.any?(Math::Formula::Mrow)
|
|
328
|
+
value.each_with_index do |element, index|
|
|
329
|
+
next unless element.is_a?(Math::Formula::Mrow)
|
|
330
|
+
|
|
331
|
+
value[index] = filter_values(
|
|
332
|
+
Array(element),
|
|
333
|
+
array_to_instance: true,
|
|
334
|
+
replacing_order: replacing_order,
|
|
335
|
+
)
|
|
336
|
+
end
|
|
337
|
+
value
|
|
338
|
+
elsif value_is_ternary_or_nary?(value)
|
|
339
|
+
value.first.parameter_three = value.delete_at(1)
|
|
340
|
+
filter_values(
|
|
341
|
+
Array(value),
|
|
342
|
+
array_to_instance: array_to_instance,
|
|
343
|
+
replacing_order: replacing_order,
|
|
344
|
+
)
|
|
345
|
+
elsif ternary_naryable?(value)
|
|
346
|
+
[
|
|
347
|
+
Math::Function::Nary.new(
|
|
348
|
+
value.first.parameter_one,
|
|
349
|
+
value.first.parameter_two,
|
|
350
|
+
value.first.parameter_three,
|
|
351
|
+
value.last,
|
|
352
|
+
),
|
|
353
|
+
]
|
|
354
|
+
elsif overset_naryable?(value)
|
|
355
|
+
[
|
|
356
|
+
Math::Function::Nary.new(
|
|
357
|
+
value.first.parameter_two,
|
|
358
|
+
nil,
|
|
359
|
+
value.first.parameter_one,
|
|
360
|
+
value.last,
|
|
361
|
+
{ type: "undOvr" },
|
|
362
|
+
),
|
|
363
|
+
]
|
|
364
|
+
elsif power_naryable?(value)
|
|
365
|
+
[
|
|
366
|
+
Math::Function::Nary.new(
|
|
367
|
+
value.first.parameter_one,
|
|
368
|
+
nil,
|
|
369
|
+
value.first.parameter_two,
|
|
370
|
+
value.last,
|
|
371
|
+
{ type: "subSup" },
|
|
372
|
+
),
|
|
373
|
+
]
|
|
374
|
+
elsif array_to_instance && replacing_order
|
|
375
|
+
value.length > 1 ? Math::Formula.new(value) : value.first
|
|
376
|
+
else
|
|
377
|
+
value
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def validate_symbols(value)
|
|
382
|
+
case value
|
|
383
|
+
when Array
|
|
384
|
+
array_validations(value)
|
|
385
|
+
when Math::Symbols::Symbol
|
|
386
|
+
return value if value.value.nil?
|
|
387
|
+
|
|
388
|
+
instance = mathml_symbol_to_class(value.value)
|
|
389
|
+
if value&.options&.any? && instance.is_a?(Math::Symbols::Symbol)
|
|
390
|
+
instance.options = value.options
|
|
391
|
+
end
|
|
392
|
+
instance
|
|
393
|
+
when String
|
|
394
|
+
mathml_symbol_to_class(value)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def array_validations(value)
|
|
399
|
+
value.each_with_index do |val, index|
|
|
400
|
+
next unless val.is_a?(Math::Symbols::Symbol)
|
|
401
|
+
|
|
402
|
+
value[index] = mathml_symbol_to_class(val.value) unless val.value.nil?
|
|
403
|
+
end
|
|
404
|
+
value
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def mathml_symbol_to_class(symbol)
|
|
408
|
+
Plurimath::Utility.mathml_unary_classes(
|
|
409
|
+
Array(symbol),
|
|
410
|
+
lang: :mathml,
|
|
411
|
+
)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def value_is_ternary_or_nary?(value)
|
|
415
|
+
return if value.any?(String)
|
|
416
|
+
|
|
417
|
+
value.length >= 2 &&
|
|
418
|
+
value.first.is_ternary_function? &&
|
|
419
|
+
value.first.parameter_three.nil? &&
|
|
420
|
+
(!value.first.parameter_one.nil? || !value.first.parameter_two.nil?)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def ternary_naryable?(value)
|
|
424
|
+
value.length == 2 &&
|
|
425
|
+
value.first.is_a?(Math::Function::PowerBase) &&
|
|
426
|
+
value.first.parameter_one.is_nary_symbol?
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def overset_naryable?(value)
|
|
430
|
+
value.length == 2 &&
|
|
431
|
+
value.first.is_a?(Math::Function::Overset) &&
|
|
432
|
+
value.first.parameter_two.is_nary_symbol?
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def power_naryable?(value)
|
|
436
|
+
value.length == 2 &&
|
|
437
|
+
value.first.is_a?(Math::Function::Power) &&
|
|
438
|
+
value.first.parameter_one.is_nary_symbol?
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
end
|
|
@@ -1,67 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "constants"
|
|
4
|
-
require "mml"
|
|
5
|
-
|
|
6
3
|
module Plurimath
|
|
7
4
|
class Mathml
|
|
8
5
|
class Parser
|
|
9
|
-
CONFIGURATION = {
|
|
10
|
-
Mml::MathWithNilNamespace => Plurimath::Math::Formula,
|
|
11
|
-
Mml::MathWithNamespace => Plurimath::Math::Formula,
|
|
12
|
-
Mml::Mmultiscripts => Plurimath::Math::Function::Multiscript,
|
|
13
|
-
Mml::Mlabeledtr => Plurimath::Math::Function::Mlabeledtr,
|
|
14
|
-
Mml::Munderover => Plurimath::Math::Function::Underover,
|
|
15
|
-
Mml::Semantics => Plurimath::Math::Function::Semantics,
|
|
16
|
-
Mml::Mscarries => Plurimath::Math::Function::Scarries,
|
|
17
|
-
Mml::Mfraction => Plurimath::Math::Function::Frac,
|
|
18
|
-
Mml::Menclose => Plurimath::Math::Function::Menclose,
|
|
19
|
-
Mml::Mlongdiv => Plurimath::Math::Function::Longdiv,
|
|
20
|
-
Mml::Mphantom => Plurimath::Math::Function::Phantom,
|
|
21
|
-
Mml::Msubsup => Plurimath::Math::Function::PowerBase,
|
|
22
|
-
Mml::Msgroup => Plurimath::Math::Function::Msgroup,
|
|
23
|
-
Mml::Mpadded => Plurimath::Math::Function::Mpadded,
|
|
24
|
-
Mml::Mfenced => Plurimath::Math::Function::Fenced,
|
|
25
|
-
Mml::Mstack => Plurimath::Math::Function::Stackrel,
|
|
26
|
-
Mml::Munder => Plurimath::Math::Function::Underset,
|
|
27
|
-
Mml::Msline => Plurimath::Math::Function::Msline,
|
|
28
|
-
Mml::Merror => Plurimath::Math::Function::Merror,
|
|
29
|
-
Mml::Mtable => Plurimath::Math::Function::Table,
|
|
30
|
-
Mml::Mstyle => Plurimath::Math::Formula::Mstyle,
|
|
31
|
-
Mml::Mglyph => Plurimath::Math::Function::Mglyph,
|
|
32
|
-
Mml::Mover => Plurimath::Math::Function::Overset,
|
|
33
|
-
Mml::Msqrt => Plurimath::Math::Function::Sqrt,
|
|
34
|
-
Mml::Mroot => Plurimath::Math::Function::Root,
|
|
35
|
-
Mml::Mtext => Plurimath::Math::Function::Text,
|
|
36
|
-
Mml::Mfrac => Plurimath::Math::Function::Frac,
|
|
37
|
-
Mml::Msrow => Plurimath::Math::Formula,
|
|
38
|
-
Mml::Msup => Plurimath::Math::Function::Power,
|
|
39
|
-
Mml::Msub => Plurimath::Math::Function::Base,
|
|
40
|
-
Mml::None => Plurimath::Math::Function::None,
|
|
41
|
-
Mml::Mrow => Plurimath::Math::Formula::Mrow,
|
|
42
|
-
Mml::Mtd => Plurimath::Math::Function::Td,
|
|
43
|
-
Mml::Mtr => Plurimath::Math::Function::Tr,
|
|
44
|
-
Mml::Mi => Plurimath::Math::Symbols::Symbol,
|
|
45
|
-
Mml::Mo => Plurimath::Math::Symbols::Symbol,
|
|
46
|
-
Mml::Ms => Plurimath::Math::Function::Ms,
|
|
47
|
-
Mml::Mn => Plurimath::Math::Number,
|
|
48
|
-
}
|
|
49
6
|
attr_accessor :text
|
|
50
|
-
@@models_set = false
|
|
51
7
|
|
|
52
8
|
def initialize(text)
|
|
53
|
-
mml_config unless @@models_set
|
|
54
9
|
@text = text
|
|
55
10
|
end
|
|
56
11
|
|
|
57
12
|
def parse
|
|
58
|
-
|
|
59
|
-
|
|
13
|
+
mml_tree = Mml.parse(
|
|
14
|
+
text,
|
|
15
|
+
version: 4,
|
|
16
|
+
namespace_exist: namespace_exist?,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
Mathml::Translator.new.mml_to_plurimath(mml_tree)
|
|
60
20
|
end
|
|
61
21
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def namespace_exist?
|
|
25
|
+
text.split(">").first.include?(" xmlns=")
|
|
65
26
|
end
|
|
66
27
|
end
|
|
67
28
|
end
|