core-env.lmt /size: 9117 b    last modification: 2024-01-16 09:02
1if not modules then modules = { } end modules ['core-env'] = {
2    version   = 1.001,
3    comment   = "companion to core-env.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-- maybe this will move to the context name space although the
10-- plurals are unlikely to clash with future tex primitives
11--
12-- if tex.modes['xxxx'] then .... else .... end
13
14local rawset = rawset
15
16local P, C, S, lpegmatch, patterns = lpeg.P, lpeg.C, lpeg.S, lpeg.match, lpeg.patterns
17local gmatch = string.gmatch
18
19local context              = context
20local ctxcore              = context.core
21
22local texgetintegervalue   = token.getinteger -- todo
23
24local allocate             = utilities.storage.allocate
25local setmetatableindex    = table.setmetatableindex
26local setmetatablenewindex = table.setmetatablenewindex
27local setmetatablecall     = table.setmetatablecall
28
29local createtoken          = token.create
30local isdefined            = tokens.isdefined
31
32texmodes                   = allocate { }  tex.modes        = texmodes
33texsystemmodes             = allocate { }  tex.systemmodes  = texsystemmodes
34texconstants               = allocate { }  tex.constants    = texconstants
35texconditionals            = allocate { }  tex.conditionals = texconditionals
36texifs                     = allocate { }  tex.ifs          = texifs
37texisdefined               = allocate { }  tex.isdefined    = texisdefined
38
39local implement            = interfaces.implement
40
41-- we could use the built-in tex.is[count|dimen|skip|toks] here but caching
42-- at the lua end is not that bad (and we need more anyway)
43
44local cache = tokens.cache
45
46-- we can have a modes cache too
47
48local commandcodes  = tokens.commands
49local iftrue        = cache["iftrue"].index
50
51local conditioncode = commandcodes.if_test
52local integercode   = commandcodes.integer
53
54-- local dimencode     = commandcodes.register_dimenension
55-- local countcode     = commandcodes.register_integer
56-- local tokencode     = commandcodes.register_toks
57-- local skipcode      = commandcodes.register_glue
58-- local muskipcode    = commandcodes.register_mu_glue
59--
60-- local types = {
61--     [dimencode]     = "dimen",
62--     [countcode]     = "count",
63--     [tokencode]     = "token",
64--     [skipcode]      = "skip",
65--     [muskipcode]    = "muskip",
66--  -- [attributecode] = "attribute",
67--     [conditioncode] = "condition",
68--     [integercode]   = "integer",
69-- }
70
71-- setmetatableindex(texmodes, function(t,k)
72--     local m = modes[k]
73--     if not m then
74--         local n = "mode>" .. k
75--         m = function() return texgetintegervalue(n) == 1 end
76--         rawset(modes,k,m)
77--     end
78--     return m()
79-- end)
80
81-- setmetatableindex(texsystemmodes, function(t,k)
82--     local m = systemmodes[k]
83--     if not m then
84--         local n = "mode>*" .. k
85--         m = function() return texgetintegervalue(n) == 1 end
86--         rawset(modes,k,m)
87--     end
88--     return m()
89-- end)
90
91do
92
93    local modes         = { }
94    local systemmodes   = { }
95
96    local texiscount    = tex.iscount
97    local texgetcount   = tex.getcount
98
99    local boolean_value = tokens.values.boolean
100
101    local function nomode()
102        return false
103    end
104
105    setmetatableindex(texmodes, function(t,k)
106        local m = modes[k]
107        if not m then
108            local n = "mode>" .. k
109            local i = texiscount(n)
110            if i then
111                m = i and function() return texgetcount(i) == 1 end or nomode
112                rawset(modes,k,m)
113            else
114                return false
115            end
116        end
117        return m()
118    end)
119
120    setmetatableindex(texsystemmodes, function(t,k)
121        local m = systemmodes[k]
122        if not m then
123            local n = "mode>*" .. k
124            local i = texiscount(n)
125            if i then
126                m = i and function() return texgetcount(i) == 1 end or nomode
127                rawset(systemmodes,k,m)
128            else
129                return false
130            end
131        end
132        return m()
133    end)
134
135    local c_trialtypesetting = tex.iscount("mode>*trialtypesetting")
136
137    context.settrialtypesettingmethod(function()
138     -- return texsystemmodes.trialtypesetting
139        -- upto three times faster:
140        return texgetcount(c_trialtypesetting) == 1
141    end)
142
143    implement {
144        name      = "ifmode",
145        public    = true,
146        usage     = "condition",
147        arguments = "argument",
148        actions   = function(m)
149            return boolean_value, texmodes[m]
150        end
151    }
152
153    implement {
154        name      = "ifsystemmode",
155        public    = true,
156        usage     = "condition",
157        arguments = "argument",
158        actions   = function(m)
159            return boolean_value, texsystemmodes[m]
160        end
161    }
162
163--     local settings_to_array = utilities.parsers.settings_to_array
164
165--     local cache = table.setmetatableindex(function(t,k)
166--         local v = settings_to_array(k)
167--         if #v < 2 then
168--             v = false
169--         end
170--         t[k] = v
171--         return v
172--     end)
173
174    local cache = utilities.parsers.hashes.settings_to_list
175
176    implement {
177        name      = "ifmodes",
178        public    = true,
179        usage     = "condition",
180        arguments = "argument",
181        actions   = function(m)
182            local c = cache[m]
183            local n = #c
184            if n > 1 then
185                for i=1,n do
186                    if texmodes[c[i]] then
187                        return boolean_value, true
188                    end
189                end
190                return boolean_value, false
191            else
192                return boolean_value, texmodes[m]
193            end
194        end
195    }
196
197    implement {
198        name      = "ifallmodes",
199        public    = true,
200        usage     = "condition",
201        arguments = "argument",
202        actions   = function(m)
203            local c = cache[m]
204            if c then
205                for i=1,#c do
206                    if not texmodes[c[i]] then
207                        return boolean_value, false
208                    end
209                end
210                return boolean_value, true
211            else
212                return boolean_value, texmodes[m]
213            end
214        end
215    }
216
217end
218
219do
220
221    local namespace = interfaces.getnamespace("setup")
222
223    implement {
224        name      = "ifsetups",
225        public    = true,
226        usage     = "condition",
227        arguments = "argument",
228        actions   = function(m)
229            return boolean_value, isdefined(namespace .. m)
230        end
231    }
232
233end
234
235-- also a call method
236
237setmetatablenewindex(texmodes,        function(t,k) report_mode("you cannot set the %s named %a this way","mode",       k) end)
238setmetatablenewindex(texsystemmodes,  function(t,k) report_mode("you cannot set the %s named %a this way","systemmode", k) end)
239setmetatablenewindex(texconstants,    function(t,k) report_mode("you cannot set the %s named %a this way","constant",   k) end)
240setmetatablenewindex(texconditionals, function(t,k) report_mode("you cannot set the %s named %a this way","conditional",k) end)
241setmetatablenewindex(texifs,          function(t,k) end)
242
243-- if we really need performance we can have a dedicated cache for each
244-- kind of variable ... maybe we no longer have to cache anyway (in lmtx)
245
246setmetatableindex(texconstants, function(t,k)
247    return cache[k].command == integercode and texgetintegervalue(k) or 0
248end)
249
250setmetatableindex(texconditionals, function(t,k) -- 0 == true
251    return cache[k].command == integercode and texgetintegervalue(k) == 0
252end)
253
254setmetatableindex(texifs, function(t,k)
255    local c = cache[k]
256    return c.command == conditioncode and c.index == iftrue
257end)
258
259tex.isdefined = isdefined
260
261-- function tex.type(name)
262--     return types[cache[name].command] or "macro"
263-- end
264
265function context.setconditional(name,value)
266    if value then
267        ctxcore.settruevalue(name)
268    else
269        ctxcore.setfalsevalue(name)
270    end
271end
272
273function context.setmode(name,value)
274    if value then
275        ctxcore.setmode(name)
276    else
277        ctxcore.resetmode(name)
278    end
279end
280
281function context.setsystemmode(name,value)
282    if value then
283        ctxcore.setsystemmode(name)
284    else
285        ctxcore.resetsystemmode(name)
286    end
287end
288
289context.modes        = texmodes
290context.systemmodes  = texsystemmodes
291context.conditionals = texconditionals
292-------.constants    = texconstants
293-------.ifs          = texifs
294
295do
296
297    local sep = S("), ")
298    local str = C((1-sep)^1)
299    local tag = P("(") * C((1-S(")" ))^1) * P(")")
300    local arg = P("(") * C((1-S("){"))^1) * P("{") * C((1-P("}"))^0) * P("}") * P(")")
301
302    local pattern = (
303         P("lua") * tag        / ctxcore.luasetup
304      +  P("xml") * arg        / ctxcore.setupwithargument -- or xmlw as xmlsetup has swapped arguments
305      + (P("tex") * tag + str) / ctxcore.texsetup
306      +             sep^1
307    )^1
308
309    implement {
310        name      = "autosetups",
311        actions   = function(str) lpegmatch(pattern,str) end,
312        arguments = "string"
313    }
314
315end
316