1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
if not modules then modules = { } end modules ['cldf-scn'] = {
version = 1.001,
comment = "companion to cldf-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
local load, type = load, type
local formatters = string.formatters
local char = string.char
local concat = table.concat
local lpegmatch = lpeg.match
local p_unquoted = lpeg.Cs(lpeg.patterns.unquoted)
local f_action_f = formatters["action%s(%s)"]
local f_action_s = formatters["local action%s = action[%s]"]
local f_command = formatters["local action = tokens._action\n%\nt\nreturn function(%s) return %s end"]
local interfaces = interfaces
local commands = commands
local scanners = interfaces.scanners
local compile = tokens.compile or function() end
local dummy = function() end
local report = logs.reporter("interfaces","implementor")
function interfaces.implement(specification)
local actions = specification.actions
local name = specification.name
local arguments = specification.arguments
local private = specification.scope == "private"
local onlyonce = specification.onlyonce
if not actions then
if name then
report("error: no actions for %a",name)
else
report("error: no actions and no name")
end
return
end
if name == "" then
name = nil
end
local scanner
local resetter = onlyonce and name and commands.ctxresetter(name)
if resetter then
local scan = compile(specification)
if private then
scanner = function()
resetter()
return scan()
end
else
scanner = function()
commands[name] = dummy
resetter()
return scan()
end
end
else
scanner = compile(specification)
end
if not name then
return scanner
end
if scanners[name] and not specification.overload then
report("warning: 'scanners.%s' is redefined",name)
end
scanners[name] = scanner
if private then
return
end
local command
if onlyonce then
if type(actions) == "function" then
actions = { actions }
elseif #actions == 1 then
actions = { actions[1] }
end
end
if type(actions) == "function" then
command = actions
elseif #actions == 1 then
command = actions[1]
else
-- this one is not yet complete .. compare tokens
tokens._action = actions
local f = { }
local args
if not arguments then
args = ""
elseif type(arguments) == "table" then
local a = { }
for i=1,#arguments do
local v = arguments[i]
local t = type(v)
if t == "boolean" then
a[i] = tostring(v)
elseif t == "number" then
a[i] = tostring(v)
elseif t == "string" then
local s = lpegmatch(p_unquoted,v)
if s and v ~= s then
a[i] = v -- a string, given as "'foo'" or '"foo"'
else
a[i] = char(96+i)
end
else
-- nothing special for tables
a[i] = char(96+i)
end
end
args = concat(a,",")
else
args = "a"
end
command = args
for i=1,#actions do
command = f_action_f(i,command)
f[i] = f_action_s(i,i)
end
command = f_command(f,args,command)
command = load(command)
if command then
if resetter then
local cmd = command()
command = function()
commands[name] = dummy
resetter()
cmd()
end
else
command = command()
end
end
tokens._action = nil
end
if commands[name] and not specification.overload then
report("warning: 'commands.%s' is redefined",name)
end
commands[name] = command
-- return scanner, command
end
-- it's convenient to have copies here:
interfaces.defined = tokens.defined
interfaces.setmacro = tokens.setters.macro
interfaces.setcount = tokens.setters.count
interfaces.setdimen = tokens.setters.dimen
interfaces.strings = table.setmetatableindex(function(t,k)
local v = { }
for i=1,k do
v[i] = "string"
end
t[k] = v
return v
end)
|