zotica 1.0.0

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.
@@ -0,0 +1,543 @@
1
+ # coding: utf-8
2
+
3
+
4
+ require 'pp'
5
+ require 'rexml/document'
6
+ include REXML
7
+
8
+
9
+ module ZoticaSingleParserMethod
10
+
11
+ DATA = ZoticaBuilder::DATA
12
+
13
+ SPACE_ALTERNATIVES = {"sfun" => "afun", "sbin" => "abin", "srel" => "arel", "ssbin" => "asbin", "ssrel" => "asrel", "scas" => "acas", "quad" => "sgl", "qquad" => "dbl"}
14
+ PHANTOM_TYPES = {"ph" => "bth", "vph" => "ver", "hph" => "hor"}
15
+
16
+ def parse
17
+ if @block
18
+ inner_element = parse_math_root
19
+ raw_nodes = @block.call(@attributes, [inner_element])
20
+ nodes = raw_nodes.inject(Nodes[], :<<)
21
+ else
22
+ nodes = parse_math_root
23
+ end
24
+ return nodes
25
+ end
26
+
27
+ private
28
+
29
+ def create_math_element(name, attributes, children_list, options = {})
30
+ this = Nodes[]
31
+ options[:role] = determine_role(attributes)
32
+ options[:class] = attributes["class"]
33
+ options[:fonts] = @fonts
34
+ case name
35
+ when "n"
36
+ text = children_list[0].first.to_s
37
+ this << ZoticaBuilder.build_number(text, options)
38
+ when "i"
39
+ types = attributes["t"]&.split(/\s*,\s*/) || []
40
+ text = children_list[0].first.to_s
41
+ this << ZoticaBuilder.build_identifier(text, types, options)
42
+ when "bf"
43
+ text = children_list[0].first.to_s
44
+ this << ZoticaBuilder.build_identifier(text, ["bf"], options)
45
+ when "rm"
46
+ text = children_list[0].first.to_s
47
+ this << ZoticaBuilder.build_identifier(text, ["rm"], options)
48
+ when "bfrm"
49
+ text = children_list[0].first.to_s
50
+ this << ZoticaBuilder.build_identifier(text, ["bf", "rm"], options)
51
+ when "tt"
52
+ text = children_list[0].first.to_s
53
+ this << ZoticaBuilder.build_identifier(text, ["tt"], options)
54
+ when "bb", "varbb", "cal", "scr", "frak", "varfrak"
55
+ raw_text = children_list[0].first.value
56
+ text = ZoticaBuilder.fetch_alternative_identifier_text(name, raw_text)
57
+ this << ZoticaBuilder.build_identifier(text, ["alt"], options)
58
+ when "op"
59
+ text = children_list[0].first.to_s
60
+ this << ZoticaBuilder.build_identifier(text, ["fun", "rm"], options)
61
+ when DATA["identifier"].method(:key?)
62
+ char = ZoticaBuilder.fetch_identifier_char(name)
63
+ this << ZoticaBuilder.build_identifier(char, [], options)
64
+ when DATA["function"].method(:include?)
65
+ this << ZoticaBuilder.build_identifier(name, ["fun", "rm"], options)
66
+ when "o"
67
+ types = attributes["t"]&.split(/\s*,\s*/) || ["ord"]
68
+ symbol = children_list[0].first.to_s
69
+ this << ZoticaBuilder.build_operator(symbol, types, options)
70
+ when DATA["operator"].method(:key?)
71
+ symbol, types = ZoticaBuilder.fetch_operator_symbol(name)
72
+ this << ZoticaBuilder.build_operator(symbol, types, options)
73
+ when "text"
74
+ text = children_list[0].first.value
75
+ this << ZoticaBuilder.build_text(text, options)
76
+ when "fence"
77
+ stretch_level = attributes["s"]
78
+ left_kind = attributes["l"] || "paren"
79
+ right_kind = attributes["r"] || "paren"
80
+ left_symbol = ZoticaBuilder.fetch_fence_symbol(left_kind, 0, stretch_level)
81
+ right_symbol = ZoticaBuilder.fetch_fence_symbol(right_kind, 1, stretch_level)
82
+ modify = !stretch_level
83
+ this << ZoticaBuilder.build_fence(left_kind, right_kind, left_symbol, right_symbol, modify, options) do |content_this|
84
+ content_this << children_list.fetch(0, Nodes[])
85
+ end
86
+ when "set"
87
+ stretch_level = attributes["s"]
88
+ left_kind = attributes["l"] || "brace"
89
+ right_kind = attributes["r"] || "brace"
90
+ center_kind = attributes["c"] || "vert"
91
+ left_symbol = ZoticaBuilder.fetch_fence_symbol(left_kind, 0, stretch_level)
92
+ right_symbol = ZoticaBuilder.fetch_fence_symbol(right_kind, 1, stretch_level)
93
+ center_symbol = ZoticaBuilder.fetch_fence_symbol(center_kind, 0, stretch_level)
94
+ modify = !stretch_level
95
+ this << ZoticaBuilder.build_set(left_kind, right_kind, center_kind, left_symbol, right_symbol, center_symbol, modify, options) do |left_this, right_this|
96
+ left_this << children_list.fetch(0, Nodes[])
97
+ right_this << children_list.fetch(1, Nodes[])
98
+ end
99
+ when DATA["fence"].method(:key?)
100
+ stretch_level = attributes["s"]
101
+ left_symbol = ZoticaBuilder.fetch_fence_symbol(name, 0, stretch_level)
102
+ right_symbol = ZoticaBuilder.fetch_fence_symbol(name, 1, stretch_level)
103
+ modify = !stretch_level
104
+ this << ZoticaBuilder.build_fence(name, name, left_symbol, right_symbol, modify, options) do |content_this|
105
+ content_this << children_list.fetch(0, Nodes[])
106
+ end
107
+ when "intlike"
108
+ kind = attributes["k"] || "int"
109
+ size = (attributes["in"]) ? "inl" : "lrg"
110
+ symbol = ZoticaBuilder.fetch_integral_symbol(kind, size)
111
+ this << ZoticaBuilder.build_integral(symbol, size, options) do |sub_this, super_this|
112
+ sub_this << children_list.fetch(0, Nodes[])
113
+ super_this << children_list.fetch(1, Nodes[])
114
+ end
115
+ when DATA["integral"].method(:key?)
116
+ size = (attributes["in"]) ? "inl" : "lrg"
117
+ symbol = ZoticaBuilder.fetch_integral_symbol(name, size)
118
+ this << ZoticaBuilder.build_integral(symbol, size, options) do |sub_this, super_this|
119
+ sub_this << children_list.fetch(0, Nodes[])
120
+ super_this << children_list.fetch(1, Nodes[])
121
+ end
122
+ when "sumlike"
123
+ kind = attributes["k"] || "sum"
124
+ size = (attributes["in"]) ? "inl" : "lrg"
125
+ symbol = ZoticaBuilder.fetch_sum_symbol(kind, size)
126
+ this << ZoticaBuilder.build_sum(symbol, size, options) do |under_this, over_this|
127
+ under_this << children_list.fetch(0, Nodes[])
128
+ over_this << children_list.fetch(1, Nodes[])
129
+ end
130
+ when DATA["sum"].method(:key?)
131
+ size = (attributes["in"]) ? "inl" : "lrg"
132
+ symbol = ZoticaBuilder.fetch_sum_symbol(name, size)
133
+ this << ZoticaBuilder.build_sum(symbol, size, options) do |under_this, over_this|
134
+ under_this << children_list.fetch(0, Nodes[])
135
+ over_this << children_list.fetch(1, Nodes[])
136
+ end
137
+ when "accent"
138
+ kind = attributes["k"]
139
+ under_symbol = ZoticaBuilder.fetch_accent_symbol(kind, 0)
140
+ over_symbol = ZoticaBuilder.fetch_accent_symbol(kind, 1)
141
+ this << ZoticaBuilder.build_accent(under_symbol, over_symbol, options) do |base_this|
142
+ base_this << children_list.fetch(0, Nodes[])
143
+ end
144
+ when DATA["accent"].method(:key?)
145
+ under_symbol = ZoticaBuilder.fetch_accent_symbol(name, 0)
146
+ over_symbol = ZoticaBuilder.fetch_accent_symbol(name, 1)
147
+ this << ZoticaBuilder.build_accent(under_symbol, over_symbol, options) do |base_this|
148
+ base_this << children_list.fetch(0, Nodes[])
149
+ end
150
+ when "wide"
151
+ kind = attributes["k"]
152
+ stretch_level = attributes["s"]
153
+ under_symbol = ZoticaBuilder.fetch_wide_symbol(kind, 0, stretch_level)
154
+ over_symbol = ZoticaBuilder.fetch_wide_symbol(kind, 1, stretch_level)
155
+ modify = !stretch_level
156
+ this << ZoticaBuilder.build_wide(kind, under_symbol, over_symbol, modify, options) do |base_this|
157
+ base_this << children_list.fetch(0, Nodes[])
158
+ end
159
+ when DATA["wide"].method(:key?)
160
+ stretch_level = attributes["s"]
161
+ under_symbol = ZoticaBuilder.fetch_wide_symbol(name, 0, stretch_level)
162
+ over_symbol = ZoticaBuilder.fetch_wide_symbol(name, 1, stretch_level)
163
+ modify = !stretch_level
164
+ this << ZoticaBuilder.build_wide(name, under_symbol, over_symbol, modify, options) do |base_this|
165
+ base_this << children_list.fetch(0, Nodes[])
166
+ end
167
+ when "multi"
168
+ this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_this, left_super_this|
169
+ base_this << children_list.fetch(0, Nodes[])
170
+ sub_this << children_list.fetch(1, Nodes[])
171
+ super_this << children_list.fetch(2, Nodes[])
172
+ left_sub_this << children_list.fetch(3, Nodes[])
173
+ left_super_this << children_list.fetch(4, Nodes[])
174
+ end
175
+ when "sb"
176
+ this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element|
177
+ base_this << children_list.fetch(0, Nodes[])
178
+ sub_this << children_list.fetch(1, Nodes[])
179
+ end
180
+ when "sp"
181
+ this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element|
182
+ base_this << children_list.fetch(0, Nodes[])
183
+ super_this << children_list.fetch(1, Nodes[])
184
+ end
185
+ when "sbsp"
186
+ this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element|
187
+ base_this << children_list.fetch(0, Nodes[])
188
+ sub_this << children_list.fetch(1, Nodes[])
189
+ super_this << children_list.fetch(2, Nodes[])
190
+ end
191
+ when "unov"
192
+ this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this|
193
+ base_this << children_list.fetch(0, Nodes[])
194
+ under_this << children_list.fetch(1, Nodes[])
195
+ over_this << children_list.fetch(2, Nodes[])
196
+ end
197
+ when "un"
198
+ this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this|
199
+ base_this << children_list.fetch(0, Nodes[])
200
+ under_this << children_list.fetch(1, Nodes[])
201
+ end
202
+ when "ov"
203
+ this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this|
204
+ base_this << children_list.fetch(0, Nodes[])
205
+ over_this << children_list.fetch(1, Nodes[])
206
+ end
207
+ when "frac"
208
+ this << ZoticaBuilder.build_fraction(options) do |numerator_this, denominator_this|
209
+ numerator_this << children_list.fetch(0, Nodes[])
210
+ denominator_this << children_list.fetch(1, Nodes[])
211
+ end
212
+ when "sqrt"
213
+ stretch_level = attributes["s"]
214
+ symbol = ZoticaBuilder.fetch_radical_symbol(stretch_level)
215
+ modify = !stretch_level
216
+ this << ZoticaBuilder.build_radical(symbol, modify, options) do |content_this, index_this|
217
+ content_this << children_list.fetch(0, Nodes[])
218
+ index_this << children_list.fetch(1, Nodes[])
219
+ end
220
+ when "table"
221
+ type = attributes["t"]
222
+ align_config = attributes["align"]
223
+ raw = !!attributes["raw"]
224
+ this << ZoticaBuilder.build_table(type, align_config, raw, options) do |table_this|
225
+ table_this << children_list.fetch(0, Nodes[])
226
+ end
227
+ when "array"
228
+ align_config = attributes["align"]
229
+ this << ZoticaBuilder.build_table("std", align_config, true, options) do |table_this|
230
+ table_this << children_list.fetch(0, Nodes[])
231
+ end
232
+ when "stack"
233
+ this << ZoticaBuilder.build_table("stk", nil, true, options) do |table_this|
234
+ table_this << children_list.fetch(0, Nodes[])
235
+ end
236
+ when "matrix"
237
+ this << ZoticaBuilder.build_table("mat", nil, false, options) do |table_this|
238
+ table_this << children_list.fetch(0, Nodes[])
239
+ end
240
+ when "case"
241
+ left_symbol = ZoticaBuilder.fetch_fence_symbol("brace", 0, nil)
242
+ right_symbol = ZoticaBuilder.fetch_fence_symbol("none", 1, nil)
243
+ this << ZoticaBuilder.build_fence("brace", "none", left_symbol, right_symbol, true, options) do |this|
244
+ this << ZoticaBuilder.build_table("cas", "ll", false) do |table_this|
245
+ table_this << children_list.fetch(0, Nodes[])
246
+ end
247
+ end
248
+ when "diag"
249
+ vertical_gaps_string = attributes["ver"]
250
+ horizontal_gaps_string = attributes["hor"]
251
+ this << ZoticaBuilder.build_diagram(vertical_gaps_string, horizontal_gaps_string, options) do |table_this|
252
+ table_this << children_list.fetch(0, Nodes[])
253
+ end
254
+ when "c"
255
+ this << ZoticaBuilder.build_table_cell(options) do |cell_this|
256
+ cell_this << children_list.fetch(0, Nodes[])
257
+ end
258
+ when "cc"
259
+ children_list.each do |children|
260
+ this << ZoticaBuilder.build_table_cell(options) do |cell_this|
261
+ cell_this << children
262
+ end
263
+ end
264
+ this << Element.new("math-sys-br")
265
+ when "v"
266
+ vertex_name = attributes["name"]
267
+ this << ZoticaBuilder.build_diagram_vertex(vertex_name, options) do |vertex_this|
268
+ vertex_this << children_list.fetch(0, Nodes[])
269
+ end
270
+ when "vv"
271
+ children_list.each do |children|
272
+ this << ZoticaBuilder.build_diagram_vertex(options) do |vertex_this|
273
+ vertex_this << children
274
+ end
275
+ end
276
+ this << Element.new("math-sys-br")
277
+ when "ar"
278
+ configs = {}
279
+ configs[:start_config] = attributes["s"]
280
+ configs[:end_config] = attributes["e"]
281
+ configs[:tip_kinds] = attributes["tip"]
282
+ configs[:bend_angle] = attributes["bend"]
283
+ configs[:shift] = attributes["shift"]
284
+ configs[:line_count] = attributes["line"]
285
+ configs[:dashed] = attributes["dash"]
286
+ configs[:label_position] = attributes["pos"]
287
+ configs[:inverted] = attributes["inv"]
288
+ configs[:mark] = attributes["mark"]
289
+ arrow_name = attributes["name"]
290
+ this << ZoticaBuilder.build_arrow(arrow_name, configs, options) do |label_this|
291
+ label_this << children_list.fetch(0, Nodes[])
292
+ end
293
+ when "tree"
294
+ this << ZoticaBuilder.build_tree(options) do |content_this|
295
+ content_this << children_list.fetch(0, Nodes[])
296
+ end
297
+ when "axm"
298
+ this << ZoticaBuilder.build_tree_axiom(options) do |content_this|
299
+ content_this << children_list.fetch(0, Nodes[])
300
+ end
301
+ when "infr"
302
+ number = attributes["n"].to_i
303
+ this << ZoticaBuilder.build_tree_inference(number, options) do |content_this, right_label_this, left_label_this|
304
+ content_this << children_list.fetch(0, Nodes[])
305
+ right_label_this << children_list.fetch(1, Nodes[])
306
+ left_label_this << children_list.fetch(2, Nodes[])
307
+ end
308
+ when "br"
309
+ this << Element.new("math-sys-br")
310
+ when "g"
311
+ transform_configs = {}
312
+ transform_configs[:rotate] = attributes["rotate"]
313
+ this << ZoticaBuilder.build_group(transform_configs, options) do |content_this|
314
+ content_this << children_list.fetch(0, Nodes[])
315
+ end
316
+ when "ph", "vph", "hph"
317
+ type = PHANTOM_TYPES[name] || attributes["t"] || "bth"
318
+ this << ZoticaBuilder.build_phantom(type, options) do |content_this|
319
+ content_this << children_list.fetch(0, Nodes[])
320
+ end
321
+ when "s"
322
+ type = attributes["t"] || "medium"
323
+ this << ZoticaBuilder.build_space(type, options)
324
+ when SPACE_ALTERNATIVES.method(:key?)
325
+ type = SPACE_ALTERNATIVES[name]
326
+ this << ZoticaBuilder.build_space(type, options)
327
+ else
328
+ this << Element.build(name) do |this|
329
+ attributes.each do |key, value|
330
+ this[key] = value
331
+ end
332
+ this << children_list.fetch(0, Nodes[])
333
+ end
334
+ end
335
+ return this
336
+ end
337
+
338
+ def create_math_text(text, options = {})
339
+ this = Nodes[]
340
+ options[:fonts] = @fonts
341
+ text.each_char do |char|
342
+ if char =~ /\p{Number}/
343
+ this << ZoticaBuilder.build_number(char, options)
344
+ elsif char =~ /\p{Letter}|\p{Mark}/
345
+ this << ZoticaBuilder.build_identifier(char, [], options)
346
+ elsif char == "'"
347
+ symbol, types = ZoticaBuilder.fetch_operator_symbol("pr")
348
+ this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this|
349
+ super_this << ZoticaBuilder.build_operator(symbol, types, options)
350
+ end
351
+ elsif char !~ /\s/
352
+ char = DATA["replacement"][char] || char
353
+ name = DATA["operator"].find{|s, (t, u)| char == t}&.first || char
354
+ symbol, kinds = DATA["operator"][name] || [name, ["bin"]]
355
+ this << ZoticaBuilder.build_operator(symbol, kinds, options)
356
+ end
357
+ end
358
+ return this
359
+ end
360
+
361
+ def create_math_escape(char, options = {})
362
+ next_char = char
363
+ if DATA["greek"].key?(char)
364
+ next_char = DATA["greek"][char]
365
+ end
366
+ return next_char
367
+ end
368
+
369
+ def parse_math_root
370
+ element = Element.new("math-root")
371
+ children = parse_nodes({})
372
+ if @exact
373
+ parse_eof
374
+ end
375
+ children.each do |child|
376
+ element.add(child)
377
+ end
378
+ return element
379
+ end
380
+
381
+ def determine_options(name, marks, attributes, macro, options)
382
+ if DATA["leaf"].include?(name)
383
+ options = options.clone
384
+ options[:math_leaf] = true
385
+ return options
386
+ else
387
+ return super
388
+ end
389
+ end
390
+
391
+ def determine_role(attributes)
392
+ role = nil
393
+ roles = ZoticaBuilder::ROLES
394
+ roles.each do |each_role|
395
+ if attributes[each_role]
396
+ role = each_role
397
+ end
398
+ end
399
+ return role
400
+ end
401
+
402
+ def create_element(name, marks, attributes, children_list, options)
403
+ element = create_math_element(name, attributes, children_list)
404
+ return element
405
+ end
406
+
407
+ def create_special_element(kind, children, options)
408
+ element = create_math_element("g", {}, [children])
409
+ return element
410
+ end
411
+
412
+ def create_text(raw_text, options)
413
+ if !options[:math_leaf]
414
+ text = create_math_text(raw_text)
415
+ else
416
+ text = super
417
+ end
418
+ return text
419
+ end
420
+
421
+ def create_escape(place, char, options)
422
+ if place == :text
423
+ escape = create_math_escape(char)
424
+ else
425
+ escape = super
426
+ end
427
+ return escape
428
+ end
429
+
430
+ end
431
+
432
+
433
+ class ZoticaSingleParser < ZenithalParser
434
+
435
+ include ZoticaSingleParserMethod
436
+
437
+ attr_accessor :exact
438
+ attr_accessor :fonts
439
+
440
+ def initialize(source)
441
+ super(source)
442
+ @exact = false
443
+ @fonts = {}
444
+ @attributes = nil
445
+ @block = nil
446
+ end
447
+
448
+ def setup(attributes, block)
449
+ @attributes = attributes
450
+ @block = block
451
+ end
452
+
453
+ def load_font(path)
454
+ if path
455
+ @fonts[:main] = JSON.parse(File.read(path))
456
+ end
457
+ end
458
+
459
+ end
460
+
461
+
462
+ class ZoticaParser < ZenithalParser
463
+
464
+ def initialize(source)
465
+ super(source)
466
+ @raw_macro_names = []
467
+ @math_macros = {}
468
+ @fonts = {}
469
+ end
470
+
471
+ def load_font(path)
472
+ if path
473
+ @fonts[:main] = JSON.parse(File.read(path))
474
+ end
475
+ end
476
+
477
+ def register_math_macro(name, &block)
478
+ outer_self = self
479
+ register_plugin(name) do |attributes|
480
+ parser = ZoticaSingleParser.new(@source)
481
+ @raw_macro_names.each do |raw_macro_name|
482
+ parser.register_plugin(raw_macro_name) do |_|
483
+ raw_parser = outer_self.clone
484
+ raw_parser.exact = false
485
+ raw_parser.whole = false
486
+ next raw_parser
487
+ end
488
+ end
489
+ @math_macros.each do |math_macro_name, math_macro_block|
490
+ parser.register_plugin(math_macro_name) do |_|
491
+ math_parser = parser.clone
492
+ math_parser.setup(attributes, math_macro_block)
493
+ next math_parser
494
+ end
495
+ end
496
+ parser.setup(attributes, block)
497
+ parser.fonts = @fonts
498
+ next parser
499
+ end
500
+ @math_macros[name] = block
501
+ end
502
+
503
+ def register_simple_math_macro(name)
504
+ register_math_macro(name) do |attributes, children_list|
505
+ next [children_list.first]
506
+ end
507
+ end
508
+
509
+ def simple_math_macro_name=(name)
510
+ warn("This method is now obsolete. Use 'register_simple_math_macro' instead.", uplevel: 1)
511
+ register_simple_math_macro(name)
512
+ end
513
+
514
+ def register_raw_macro(name)
515
+ @raw_macro_names << name
516
+ end
517
+
518
+ def raw_macro_name=(name)
519
+ warn("This method is now obsolete. Use 'register_raw_macro' instead.", uplevel: 1)
520
+ register_raw_macro(name)
521
+ end
522
+
523
+ def register_resource_macro(name)
524
+ register_macro(name) do |attributes, children_list|
525
+ style_string = ZoticaBuilder.create_style_string(attributes["font-url"])
526
+ script_string = ZoticaBuilder.create_script_string
527
+ nodes = Nodes[]
528
+ nodes << Element.build("style") do |element|
529
+ element << Text.new(style_string, true, nil, true)
530
+ end
531
+ nodes << Element.build("script") do |element|
532
+ element << CData.new(script_string)
533
+ end
534
+ next nodes
535
+ end
536
+ end
537
+
538
+ def resource_macro_name=(name)
539
+ warn("This method is now obsolete. Use 'register_resource_macro' instead.", uplevel: 1)
540
+ register_resource_macro(name)
541
+ end
542
+
543
+ end