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