1if not modules then modules = { } end modules ['math-ini'] = {
2 version = 1.001,
3 comment = "companion to math-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23local next, type = next, type
24local formatters, find, nospaces = string.formatters, string.find, string.nospaces
25local utfchar, utfbyte = utf.char, utf.byte
26local sortedhash = table.sortedhash
27local toboolean = toboolean
28
29local context = context
30local implement = interfaces.implement
31
32local ctx_doifelsesomething = commands.doifelsesomething
33
34local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
35
36local report_math = logs.reporter("mathematics","initializing")
37
38mathematics = mathematics or { }
39local mathematics = mathematics
40
41mathematics.extrabase = fonts.privateoffsets.mathextrabase
42mathematics.privatebase = fonts.privateoffsets.mathbase
43
44local unsetvalue = attributes.unsetvalue
45local allocate = utilities.storage.allocate
46local chardata = characters.data
47
48local texsetattribute = tex.setattribute
49local setmathcode = tex.setmathcode
50local setdelcode = tex.setdelcode
51local texintegerdef = tex.integerdef
52
53local getfontoffamily = tex.getfontoffamily
54
55local fontchardata = fonts.hashes.characters
56
57setdelcode = function() end
58
59
60
61local classes = allocate { unset = 64 }
62local classnames = allocate { }
63local maxengineclass = 63
64local lastengineclass = 0
65local lastprivateclass = maxengineclass
66
67for k, v in next, nodes.noadcodes do
68 if type(k) == "string" then
69 classes[k] = v
70
71
72
73
74 elseif k > lastengineclass then
75 lastengineclass = k
76 end
77end
78
79local ordinary_class = classes.ordinary
80local operator_class = classes.operator
81local binary_class = classes.binary
82local relation_class = classes.relation
83local open_class = classes.open
84local close_class = classes.close
85local punctuation_class = classes.punctuation
86local middle_class = classes.middle
87local accent_class = classes.accent
88local radical_class = classes.radical
89local fraction_class = classes.fraction
90local under_class = classes.under
91local over_class = classes.over
92local fenced_class = classes.fenced
93local ghost_class = classes.ghost
94
95
96
97classes.ord = ordinary_class
98classes.op = operator_class
99classes.bin = binary_class
100classes.rel = relation_class
101classes.opening = open_class
102classes.closing = close_class
103classes.punct = punctuation_class
104classes.frac = fraction_class
105classes.rad = radical_class
106classes.fen = fenced_class
107classes.gst = ghost_class
108
109
110
111classes.limop = operator_class
112classes.limoperator = operator_class
113classes.nolop = operator_class
114classes.nolimoperator = operator_class
115classes.large = operator_class
116classes.largeoperator = operator_class
117
118
119
120local function registerengineclass(name,short)
121 local class = classes[name]
122 if not class then
123 if lastengineclass < maxengineclass then
124 lastengineclass = lastengineclass + 1
125 class = lastengineclass
126 classnames[class] = short or name
127 else
128 class = ordinary_class
129 end
130 else
131 classnames[class] = short or name
132 end
133 classes[class] = name
134 classes[name] = class
135 return class
136end
137
138
139
140registerengineclass("ordinary", "ord")
141registerengineclass("operator", "ope")
142registerengineclass("binary", "bin")
143registerengineclass("relation", "rel")
144registerengineclass("open", "ope")
145registerengineclass("close", "clo")
146registerengineclass("punctuation", "pun")
147registerengineclass("variable", "var")
148registerengineclass("active", "act")
149registerengineclass("inner", "inn")
150registerengineclass("middle", "mid")
151registerengineclass("accent", "acc")
152registerengineclass("radical", "rad")
153registerengineclass("fraction", "fra")
154registerengineclass("under", "und")
155registerengineclass("over", "ove")
156registerengineclass("fenced", "fen")
157registerengineclass("ghost", "gho")
158registerengineclass("vcenter", "vce")
159
160
161
162registerengineclass("explicit", "xpl")
163registerengineclass("imaginary", "img")
164registerengineclass("differential", "dif")
165registerengineclass("exponential", "exp")
166registerengineclass("integral", "int")
167registerengineclass("ellipsis", "ell")
168registerengineclass("function", "fnc")
169registerengineclass("digit", "dig") local division_class =
170registerengineclass("division", "div")
171registerengineclass("factorial", "fac")
172registerengineclass("wrapped", "wra")
173registerengineclass("construct", "con")
174registerengineclass("dimension", "dim")
175registerengineclass("unary", "una")
176registerengineclass("textpunctuation", "tpu")
177registerengineclass("unspaced", "uns")
178registerengineclass("experimental", "exp")
179registerengineclass("fake", "fak")
180registerengineclass("numbergroup", "ngr")
181
182registerengineclass("maybeordinary", "mor")
183registerengineclass("mayberelation", "mre")
184registerengineclass("maybebinary", "mbi")
185
186registerengineclass("chemicalbond", "chb")
187registerengineclass("implication", "imp")
188
189local specialclasses = tex.specialmathclasscodes
190
191classes["all"] = specialclasses["all"] classnames[specialclasses["all"] ] = "all"
192classes["begin"] = specialclasses["begin"] classnames[specialclasses["begin"]] = "beg"
193classes["end"] = specialclasses["end"] classnames[specialclasses["end"] ] = "end"
194
195callbacks.register("get_noad_class", function(n) return classnames[n] end,"provide math class name")
196
197local function registerprivateclass(name,parent)
198 local class = parent and classes[parent] or classes[name]
199 if not class then
200 lastprivateclass = lastprivateclass + 1
201 class = lastprivateclass
202 classes[name] = class
203
204 end
205 return class
206end
207
208local function toengineclass(class)
209 if type(class) == "string" then
210 return classes[class] or ordinary_class
211 elseif class > lastengineclass then
212 return ordinary_class
213 else
214 return class
215 end
216end
217
218implement {
219 name = "registerengineclass",
220 public = true,
221 protected = true,
222 arguments = { "optional", "optional" },
223 actions = registerengineclass,
224}
225
226local topaccent_class = registerprivateclass("topaccent")
227local bottomaccent_class = registerprivateclass("bottomaccent")
228local delimiter_class = registerprivateclass("delimiter")
229local root_class = registerprivateclass("root")
230local prime_class = registerprivateclass("prime")
231
232registerprivateclass("botaccent","bottomaccent")
233
234local accents = allocate {
235 accent = true,
236 topaccent = true, [topaccent_class] = true,
237 bottomaccent = true, [bottomaccent_class] = true,
238 botaccent = true,
239 under = true, [under_class] = true,
240 over = true, [over_class] = true,
241 unknown = false,
242}
243
244local integer_value = tokens.values.integer
245
246implement {
247 name = "mathclassvalue",
248
249 public = true,
250 arguments = "string",
251 actions = function(name)
252
253 context(tostring(classes[name] or ordinary_class))
254 end
255}
256
257
258
259
260local codes = allocate {
261 ordinary = ordinary_class, [ordinary_class] = "ordinary",
262 largeoperator = operator_class, [operator_class] = "largeoperator",
263 binaryoperator = binary_class, [binary_class] = "binaryoperator",
264 relation = relation_class, [relation_class] = "relation",
265 openingsymbol = open_class, [open_class] = "openingsymbol",
266 closingsymbol = close_class, [close_class] = "closingsymbol",
267 punctuation = punctuation_class, [punctuation_class] = "punctuation",
268 middlesymbol = middle_class, [middle_class] = "middlesymbol",
269}
270
271local extensibles = allocate {
272 unknown = 0,
273 l = 1, left = 1,
274 r = 2, right = 2,
275 h = 3, horizontal = 3,
276 u = 5, up = 4,
277 d = 5, down = 5,
278 v = 6, vertical = 6,
279 m = 7, mixed = 7,
280}
281
282table.setmetatableindex(extensibles,function(t,k) t[k] = 0 return 0 end)
283
284local virtualized = allocate {
285}
286
287function mathematics.virtualize(unicode,virtual)
288
289 local function virtualize(k,v)
290 local c = virtualized[k]
291 if c == v then
292 report_math("character %C is already virtualized to %C",k,v)
293 elseif c then
294 report_math("character %C is already virtualized to %C, ignoring mapping to %C",k,c,v)
295 else
296 virtualized[k] = v
297 end
298 end
299
300 if type(unicode) == "table" then
301 for k, v in next, unicode do
302 virtualize(k,v)
303 end
304 elseif type(unicode) == "number" and type(virtual) == "number" then
305 virtualize(unicode,virtual)
306
307
308 end
309end
310
311mathematics.extensibles = extensibles
312mathematics.classes = classes
313mathematics.toengineclass = toengineclass
314mathematics.classnames = classnames
315mathematics.codes = codes
316
317mathematics.virtualized = virtualized
318
319
320
321do
322
323 local dictionaries = mathematics.dictionaries or { }
324 mathematics.dictionaries = dictionaries
325
326 local names = dictionaries.names or utilities.storage.allocate()
327 local groups = dictionaries.groups or utilities.storage.allocate()
328 local data = dictionaries.data or utilities.storage.allocate()
329 local sets = dictionaries.sets or utilities.storage.allocate()
330 local variants = dictionaries.variants or utilities.storage.allocate()
331 local defaults = dictionaries.defaults or utilities.storage.allocate()
332
333 storage.register("mathematics/dictionaries/names", names, "mathematics.dictionaries.names")
334 storage.register("mathematics/dictionaries/groups", groups, "mathematics.dictionaries.groups")
335 storage.register("mathematics/dictionaries/data", data, "mathematics.dictionaries.data")
336 storage.register("mathematics/dictionaries/sets", sets, "mathematics.dictionaries.sets")
337 storage.register("mathematics/dictionaries/variants", variants, "mathematics.dictionaries.variants")
338 storage.register("mathematics/dictionaries/defaults", defaults, "mathematics.dictionaries.defaults")
339
340 dictionaries.names = dictionaries.names or names
341 dictionaries.groups = dictionaries.groups or groups
342 dictionaries.data = dictionaries.data or data
343 dictionaries.sets = dictionaries.sets or sets
344 dictionaries.variants = dictionaries.variants or variants
345 dictionaries.defaults = dictionaries.defaults or defaults
346
347 if not sets.n then
348 sets.n = 0
349 end
350
351 function dictionaries.registergroup(name)
352 local group = rawget(names,name)
353 if not group then
354 group = #groups + 1
355 names[name] = group
356 names[group] = group
357 groups[group] = name
358 data[group] = { }
359 local csname = "math" .. nospaces(name) .. "dictionary"
360 texintegerdef(csname,group,"immutable")
361 end
362 return group
363 end
364
365 function dictionaries.registergroupset(name,set)
366 local s = sets[name]
367 if not s then
368 local d = dictionaries.registergroup(name)
369 local n = sets.n + 1
370 local l = utilities.parsers.settings_to_array(set)
371 local g = { }
372 for i=1,#l do
373 local n = names[l[i]]
374 if n then
375 g[#g+1] = n
376 end
377 end
378 s = {
379 names = l,
380 groups = g,
381 group = d,
382 }
383 sets[name] = s
384 sets[d] = s
385
386 end
387 end
388
389 function dictionaries.groupset(name)
390 return sets[name] or { }
391 end
392
393 function dictionaries.groupsetgroup(name)
394 local s = sets[name]
395 if s then
396 return s.group
397 else
398 return names[name] or 0
399 end
400 end
401
402 function dictionaries.registercharacter(group,index,description,class)
403 local d = names[group]
404 if d then
405 data[d][index] = description or true
406 local v = variants[index]
407 if type(class) == "string" then
408 class = classes[class]
409 end
410 if not class then
411 class = true
412 end
413 if v then
414 v[d] = class
415 else
416 variants[index] = { [d] = class }
417 end
418 if not defaults[index] then
419 defaults[index] = d
420 end
421 end
422 end
423
424 implement {
425 name = "registergroupset",
426 arguments = "2 strings",
427 actions = dictionaries.registergroupset,
428 }
429
430 implement {
431 name = "groupsetgroup",
432 arguments = "string",
433 actions = { dictionaries.groupsetgroup, context },
434 }
435
436 local f_dictionary = false
437 local whatdetail = "all"
438
439 local function trace(n,properties,group,index,font,char)
440
441 if whatdetail and (properties ~= 0 or group ~= 0 or index ~= 0) then
442 local char = fontchardata[font][char]
443 if char or whatdetail == "all" then
444 local unicode = char and char.unicode
445 if unicode then
446 local groupname = groups[group]
447 local indexname = false
448 if groupname then
449 indexname = data[group][index]
450 else
451 groupname = "unknown"
452 end
453 if not indexname or indexname == true then
454 indexname = chardata[unicode]
455 indexname = indexname and indexname.description or "unknown"
456 end
457 if not f_dictionary then
458 f_dictionary = formatters["properties [%04X:%04X:%04X] [%s] %U : %s"]
459 end
460 return f_dictionary(properties,group,index,groupname,unicode,indexname)
461 end
462 end
463 end
464 end
465
466 trackers.register("math.dictionaries",function(v) whatdetail = v end)
467
468 callbacks.register("get_math_dictionary",trace,"provide math dictionary details")
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 if environment.initex then
489
490 local registergroup = mathematics.dictionaries.registergroup
491
492 registergroup("default")
493 registergroup("binary arithmetic")
494 registergroup("binary linear algebra")
495 registergroup("binary logical")
496 registergroup("binary relation")
497 registergroup("binary set")
498 registergroup("constant arithmetic")
499 registergroup("constant set")
500 registergroup("differential")
501 registergroup("integral")
502 registergroup("interval")
503 registergroup("lambda")
504 registergroup("limit")
505 registergroup("nary arithmetic")
506 registergroup("nary constructor")
507 registergroup("nary functional")
508 registergroup("nary linear algebra")
509 registergroup("nary logical")
510 registergroup("nary minmax")
511 registergroup("nary relation")
512 registergroup("nary set list")
513 registergroup("nary set relation")
514 registergroup("nary set")
515 registergroup("nary statistics")
516 registergroup("partial")
517 registergroup("product")
518 registergroup("quantifier")
519 registergroup("unary arithmetic")
520 registergroup("unary elementary")
521 registergroup("unary functional")
522 registergroup("unary linear algebra")
523 registergroup("unary logical")
524 registergroup("unary set")
525 registergroup("unary vector")
526
527 end
528
529
530
531
532
533
534
535end
536
537do
538
539 local skip = {
540 [accent_class] = true,
541 [topaccent_class] = true,
542 [bottomaccent_class] = true,
543 [over_class] = true,
544 [under_class] = true,
545 [radical_class] = true,
546 [root_class] = true,
547 }
548
549 local registercharacter = mathematics.dictionaries.registercharacter
550 local groupnames = mathematics.dictionaries.names
551
552 local setmathcharacter = function(class,family,slot,unicode,mset,dset,group)
553 if mset and class ~= ordinary_class then
554 setmathcode("global",slot,class,family,unicode)
555 mset = false
556 end
557
558
559
560
561 if group then
562 group = groupnames[group] or 0
563 if group ~= 0 then
564
565 registercharacter(group,unicode,nil,class)
566
567 end
568 end
569 return mset, dset
570 end
571
572 local function report(class,family,unicode,name)
573 local nametype = type(name)
574 if nametype == "string" then
575 report_math("class %a, family %a, char %C, name %a",class,family,unicode,name)
576 elseif nametype == "number" then
577 report_math("class %a, family %a, char %C, number %U",class,family,unicode,name)
578 else
579 report_math("class %a, family %a, char %C",class,family,unicode)
580 end
581 end
582
583 local texmathchardef = tex.mathchardef
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 local setmathsymbol = function(name,class,family,slot,stretch,group)
606 if skip[class] then
607 return
608
609 else
610 if class == delimiter_class then
611 class = ordinary_class
612 end
613 if group then
614 group = groupnames[group] or 0
615 if group ~= 0 then
616 texmathchardef(name,class,family,slot,"permanent",0x1,group,slot)
617 return
618 end
619 end
620 texmathchardef(name,class,family,slot,"permanent")
621 end
622 end
623
624 function mathematics.define()
625 if trace_defining then
626 logs.startfilelogging(report_math,"math defined from character definitions")
627 end
628 local family = 0
629 local data = characters.data
630
631 local function remap(first,last)
632 for unicode=utfbyte(first),utfbyte(last) do
633 setmathcode("global",unicode,ordinary_class,family,unicode)
634 end
635 end
636 remap("0","9")
637 remap("A","Z")
638 remap("a","z")
639
640 setdelcode("global",0x2E,0,0,0,0)
641
642 for unicode, character in sortedhash(data) do
643 local symbol = character.mathsymbol
644 local mset = true
645 local dset = true
646 if symbol then
647 local other = data[symbol]
648 local class = other.mathclass
649 if class then
650 local engine = toengineclass(class)
651 if trace_defining then
652 report(engine,family,unicode,symbol)
653 end
654 mset, dset = setmathcharacter(engine,family,unicode,symbol,mset,dset,group)
655 end
656 local spec = other.mathspec
657 if spec then
658 for i=1,#spec do
659 local m = spec[i]
660 local class = m.class
661 if class then
662 local engine = toengineclass(class)
663
664 mset, dset = setmathcharacter(engine,family,unicode,symbol,mset,dset,group)
665 end
666 end
667 end
668 end
669 local class = character.mathclass
670 local spec = character.mathspec
671 local name = character.mathname
672 local stretch = character.mathstretch
673 local group = character.mathgroup
674 if spec then
675 local done = false
676 if class then
677 if name then
678 report_math("fatal error, conflicting mathclass and mathspec for %C",unicode)
679 os.exit()
680 else
681 class = classes[class] or ordinary_class
682 local engine = toengineclass(class)
683 if trace_defining then
684 report(engine,family,unicode)
685 end
686 mset, dset = setmathcharacter(engine,family,unicode,unicode,mset,dset,group)
687 done = true
688 end
689 end
690 for i=1,#spec do
691 local m = spec[i]
692 local name = m.name
693 local class = m.class or class
694 local group = m.group or group
695 local stretch = m.stretch or stretch
696 if class then
697 class = classes[class] or ordinary_class
698 else
699 class = ordinary_class
700 end
701 if class then
702 local engine = toengineclass(class)
703 if name then
704 if trace_defining then
705 report(engine,family,unicode,name)
706 end
707 setmathsymbol(name,engine,family,unicode,stretch,group)
708 else
709 name = (class == classes.ordinary or class == classes.digit) and character.adobename
710 if name and trace_defining then
711 report(engine,family,unicode,name)
712 end
713 end
714 if not done then
715 mset, dset = setmathcharacter(engine,family,unicode,m.unicode or unicode,mset,dset,group)
716 done = true
717 end
718 end
719 end
720 else
721 if class then
722 class = classes[class] or ordinary_class
723 else
724 class = ordinary_class
725 end
726 if name ~= nil then
727 local engine = toengineclass(class)
728 if name == false then
729 if trace_defining then
730 report(engine,family,unicode,name)
731 end
732 mset, dset = setmathcharacter(engine,family,unicode,unicode,mset,dset,group)
733 else
734
735
736
737 if name then
738 if trace_defining then
739 report(engine,family,unicode,name)
740 end
741 setmathsymbol(name,engine,family,unicode,stretch,group)
742 else
743 if trace_defining then
744 report(engine,family,unicode,character.adobename)
745 end
746 end
747 mset, dset = setmathcharacter(engine,family,unicode,unicode,mset,dset,group)
748 end
749 elseif class ~= ordinary_class then
750 local engine = toengineclass(class)
751 if trace_defining then
752 report(engine,family,unicode,character.adobename)
753 end
754 mset, dset = setmathcharacter(engine,family,unicode,unicode,mset,dset,group)
755 end
756 end
757 end
758
759 if trace_defining then
760 logs.stopfilelogging()
761 end
762 end
763
764end
765
766
767
768
769
770do
771
772 local lpegmatch = lpeg.match
773 local utf8byte = lpeg.patterns.utf8byte * lpeg.P(-1)
774
775
776
777
778
779
780 local somechar = table.setmetatableindex(function(t,k)
781 if k then
782 local b = lpegmatch(utf8byte,k)
783 local v = b and chardata[b] or false
784 t[k] = v
785 return v
786 end
787 end)
788
789 local function utfmathclass(chr, default)
790 local cd = somechar[chr]
791 return cd and cd.mathclass or default or "unknown"
792 end
793
794 local function utfmathlimop(chr)
795 local cd = somechar[chr]
796 return cd and (cd.mathclass == "operator" or cd.mathclass == "integral") or false
797 end
798
799 local function utfmathaccent(chr,default,asked1,asked2)
800 local cd = somechar[chr]
801 if not cd then
802 return default or false
803 end
804 if asked1 and asked1 ~= "" then
805 local mc = cd.mathclass
806 if mc and (mc == asked1 or mc == asked2) then
807 return true
808 end
809 local ms = cd.mathspec
810 if not ms then
811 local mp = cd.mathparent
812 if mp then
813 ms = chardata[mp].mathspec
814 end
815 end
816 if ms then
817 for i=1,#ms do
818 local msi = ms[i]
819 local mc = msi.class
820 if mc and (mc == asked1 or mc == asked2) then
821 return true
822 end
823 end
824 end
825 else
826 local mc = cd.mathclass
827 if mc then
828 return accents[mc] or default or false
829 end
830 local ms = cd.mathspec
831 if ms then
832 for i=1,#ms do
833 local msi = ms[i]
834 local mc = msi.class
835 if mc then
836 return accents[mc] or default or false
837 end
838 end
839 end
840 end
841 return default or false
842 end
843
844 local function utfmathstretch(chr,default)
845 local cd = somechar[chr]
846 return cd and cd.mathstretch or default or ""
847 end
848
849 local function utfmathcommand(chr,default,asked1,asked2)
850 local cd = somechar[chr]
851 if not cd then
852 return default or ""
853 end
854 if asked1 then
855 local mn = cd.mathname
856 local mc = cd.mathclass
857 if mn and mc and (mc == asked1 or mc == asked2) then
858 return mn
859 end
860 local ms = cd.mathspec
861 if not ms then
862 local mp = cd.mathparent
863 if mp then
864 ms = chardata[mp].mathspec
865 end
866 end
867 if ms then
868 for i=1,#ms do
869 local msi = ms[i]
870 local mn = msi.name
871 if mn then
872 local mc = msi.class
873 if mc == asked1 or mc == asked2 then
874 return mn
875 end
876 end
877 end
878 end
879 else
880 local mn = cd.mathname
881 if mn then
882 return mn
883 end
884 local ms = cd.mathspec
885 if ms then
886 for i=1,#ms do
887 local msi = ms[i]
888 local mn = msi.name
889 if mn then
890 return mn
891 end
892 end
893 end
894 end
895 return default or ""
896 end
897
898 local function utfmathfiller(chr, default)
899 local cd = somechar[chr]
900 local cmd = cd and cd.mathfiller
901 return cmd or default or ""
902 end
903
904 mathematics.utfmathclass = utfmathclass
905 mathematics.utfmathstretch = utfmathstretch
906 mathematics.utfmathcommand = utfmathcommand
907 mathematics.utfmathfiller = utfmathfiller
908 mathematics.utfmathaccent = utfmathaccent
909
910
911
912 implement {
913 name = "utfmathclass",
914 public = true,
915 actions = { utfmathclass, context },
916 arguments = "argument"
917 }
918
919 implement {
920 name = "utfmathstretch",
921 public = true,
922 actions = { utfmathstretch, context },
923 arguments = "argument"
924 }
925
926 implement {
927 name = "utfmathcommand",
928 public = true,
929 actions = { utfmathcommand, context },
930 arguments = "argument"
931 }
932
933 implement {
934 name = "utfmathfiller",
935 public = true,
936 actions = { utfmathfiller, context },
937 arguments = "argument"
938 }
939
940 implement {
941 name = "utfmathcommandabove",
942 public = true,
943 actions = { utfmathcommand, context },
944 arguments = { "argument", false, "'topaccent'","'over'" }
945 }
946
947 implement {
948 name = "utfmathcommandbelow",
949 public = true,
950 actions = { utfmathcommand, context },
951 arguments = { "argument", false, "'bottomaccent'","'under'" }
952 }
953
954 implement {
955 name = "utfmathcommandfiller",
956 public = true,
957 actions = { utfmathfiller, context },
958 arguments = "argument"
959 }
960
961
962
963 implement {
964 name = "doifelseutfmathabove",
965 public = true,
966 actions = { utfmathaccent, ctx_doifelsesomething },
967 arguments = { "argument", false, "'topaccent'", "'over'" }
968 }
969
970 implement {
971 name = "doifelseutfmathbelow",
972 public = true,
973 actions = { utfmathaccent, ctx_doifelsesomething },
974 arguments = { "argument", false, "'bottomaccent'", "'under'" }
975 }
976
977 implement {
978 name = "doifelseutfmathaccent",
979 public = true,
980 actions = { utfmathaccent, ctx_doifelsesomething },
981 arguments = "argument",
982 }
983
984 implement {
985 name = "doifelseutfmathfiller",
986 public = true,
987 actions = { utfmathfiller, ctx_doifelsesomething },
988 arguments = "argument",
989 }
990
991 implement {
992 name = "doifelseutfmathlimop",
993 public = true,
994 actions = { utfmathlimop, ctx_doifelsesomething },
995 arguments = "argument"
996 }
997
998end
999
1000
1001
1002
1003
1004
1005
1006
1007
1008function mathematics.big(tfmdata,unicode,n,method)
1009 local t = tfmdata.characters
1010 local c = t[unicode]
1011 if c and n > 0 then
1012 if method == 1 or method == 2 or method == 5 then
1013 if method == 5 then
1014 local b = tfmdata.bigslots
1015 if b then
1016 n = (n > #b and b[#b]) or b[n] or n
1017 end
1018 elseif method == 2 then
1019 n = n * 2
1020 end
1021 local next = c.next
1022 while next do
1023 if n <= 1 then
1024 return next
1025 else
1026 n = n - 1
1027 local tn = t[next].next
1028 if tn then
1029 next = tn
1030 else
1031 return next
1032 end
1033 end
1034 end
1035 elseif method >= 3 then
1036 local size = 1.33^n
1037 if method == 4 then
1038 size = tfmdata.parameters.size * size
1039 else
1040 size = (c.height + c.depth) * size
1041 end
1042 local next = c.next
1043 while next do
1044 local cn = t[next]
1045 if (cn.height + cn.depth) >= size then
1046 return next
1047 else
1048 local tn = cn.next
1049 if tn then
1050 next = tn
1051 else
1052 return next
1053 end
1054 end
1055 end
1056 end
1057 end
1058 return unicode
1059end
1060
1061do
1062
1063 local categories = { }
1064 mathematics.categories = categories
1065
1066 local a_mathcategory = attributes.private("mathcategory")
1067
1068 local functions = storage.allocate()
1069 categories.functions = functions
1070 local noffunctions = 1000
1071
1072 implement {
1073 name = "tagmfunctiontxt",
1074 arguments = { "string", "conditional" },
1075 actions = function(tag,apply)
1076 local delta = apply and 1000 or 0
1077 texsetattribute(a_mathcategory,1000 + delta)
1078 end
1079 }
1080
1081 implement {
1082 name = "tagmfunctionlab",
1083 arguments = { "string", "conditional" },
1084 actions = function(tag,apply)
1085 local delta = apply and 1000 or 0
1086 local n = functions[tag]
1087 if not n then
1088 noffunctions = noffunctions + 1
1089 functions[noffunctions] = tag
1090 functions[tag] = noffunctions
1091 texsetattribute(a_mathcategory,noffunctions + delta)
1092 else
1093 texsetattribute(a_mathcategory,n + delta)
1094 end
1095 end
1096 }
1097
1098end
1099
1100do
1101
1102 local list
1103
1104 function mathematics.resetattributes()
1105 if not list then
1106 list = { }
1107 for k, v in next, attributes.numbers do
1108 if find(k,"^math") then
1109 list[#list+1] = v
1110 end
1111 end
1112 end
1113 for i=1,#list do
1114 texsetattribute(list[i],unsetvalue)
1115 end
1116 end
1117
1118end
1119
1120implement {
1121 name = "resetmathattributes",
1122 public = true,
1123 protected = true,
1124 actions = mathematics.resetattributes
1125}
1126
1127
1128
1129implement {
1130 name = "enableasciimode",
1131 onlyonce = true,
1132 actions = resolvers.macros.enablecomment,
1133}
1134
1135implement {
1136 name = "nofmathvariants",
1137 public = true,
1138 usage = "value",
1139 arguments = "integer",
1140 actions = function(n)
1141 local char = fontchardata[getfontoffamily(0)]
1142 local data = char[n]
1143 local size = 1
1144 while data do
1145 local next = data.next
1146 if next then
1147 size = size + 1
1148 data = char[next]
1149 else
1150 break
1151 end
1152 end
1153 return integer_value, size
1154 end,
1155}
1156
1157implement {
1158 name = "getmathvariant",
1159 public = true,
1160 usage = "value",
1161 arguments = "2 integers",
1162 actions = function(m,n)
1163 local char = fontchardata[getfontoffamily(0)]
1164 local data = char[n]
1165 local slot = n
1166 if data then
1167 while data and m > 1 do
1168 local next = data.next
1169 if next then
1170 m = m - 1
1171 data = char[next]
1172 slot = next
1173 else
1174 break
1175 end
1176 end
1177 end
1178 return integer_value, slot
1179 end,
1180}
1181
1182implement {
1183 name = "getmathcharone",
1184 public = true,
1185 usage = "value",
1186 arguments = "integer",
1187 actions = function(n)
1188 local char = fontchardata[getfontoffamily(0)]
1189 local data = char[n]
1190 return integer_value, data and data.smaller or n
1191 end,
1192}
1193
1194implement {
1195 name = "getmathchartwo",
1196 public = true,
1197 usage = "value",
1198 arguments = "integer",
1199 actions = function(n)
1200 local char = fontchardata[getfontoffamily(0)]
1201 local data = char[n]
1202 local slot = data and data.smaller
1203 if slot then
1204 data = char[slot]
1205 n = slot
1206 end
1207 return integer_value, data and data.smaller or n
1208 end,
1209}
1210 |