summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@samsung.com>2014-12-11 16:59:27 +0000
committerDaniel Kolesa <d.kolesa@samsung.com>2014-12-11 16:59:27 +0000
commitc65221c0ae94833590fd34fca3384f56f2301960 (patch)
treeb988063f231e7692d88ae80a8b4c708f9b97325b /src/bin
parentaa6f9ea4a9b9185907007be807f3738c8a55f48d (diff)
elua: move core scripts to src/scripts
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/elua/apps/lualian.lua65
-rw-r--r--src/bin/elua/apps/xgettext.lua428
-rw-r--r--src/bin/elua/core/gettext.lua92
-rw-r--r--src/bin/elua/core/module.lua126
-rw-r--r--src/bin/elua/core/util.lua355
-rw-r--r--src/bin/elua/main.c8
-rw-r--r--src/bin/elua/modules/benchmark.lua97
-rw-r--r--src/bin/elua/modules/getopt.lua294
-rw-r--r--src/bin/elua/modules/lualian.lua697
-rw-r--r--src/bin/elua/modules/xgettext/generator.lua128
-rw-r--r--src/bin/elua/modules/xgettext/lexer.lua353
-rw-r--r--src/bin/elua/modules/xgettext/parser.lua267
12 files changed, 4 insertions, 2906 deletions
diff --git a/src/bin/elua/apps/lualian.lua b/src/bin/elua/apps/lualian.lua
deleted file mode 100644
index 4ffbf58ee1..0000000000
--- a/src/bin/elua/apps/lualian.lua
+++ /dev/null
@@ -1,65 +0,0 @@
1-- Lualian application
2-- for use with Elua
3
4local lualian = require("lualian")
5local getopt = require("getopt")
6
7local gen_file = function(opts, i, fname)
8 local printv = opts["v"] and print or function() end
9 printv("Generating for file: " .. fname)
10 local ofile = opts["o"] and opts["o"][i] or nil
11 local fstream = io.stdout
12 if ofile then
13 printv(" Output file: " .. ofile)
14 fstream = io.open(ofile, "w")
15 if not fstream then
16 error("Cannot open output file: " .. ofile)
17 end
18 else
19 printv(" Output file: printing to stdout...")
20 end
21 lualian.generate(fname, fstream)
22end
23
24getopt.parse {
25 usage = "Usage: %prog [OPTIONS] file1.eo file2.eo ... fileN.eo",
26 args = arg,
27 descs = {
28 { category = "General" },
29
30 { "h", "help", nil, help = "Show this message.", metavar = "CATEGORY",
31 callback = getopt.help_cb(io.stdout)
32 },
33 { "v", "verbose", false, help = "Be verbose." },
34
35 { category = "Generator" },
36
37 { "I", "include", true, help = "Include a directory.", metavar = "DIR",
38 list = {}
39 },
40 { "o", "output", true, help = "Specify output file name(s), by "
41 .. "default goes to stdout.",
42 list = {}
43 }
44 },
45 error_cb = function(parser, msg)
46 io.stderr:write(msg, "\n")
47 getopt.help(parser, io.stderr)
48 end,
49 done_cb = function(parser, opts, args)
50 if not opts["h"] then
51 for i, v in ipairs(opts["I"] or {}) do
52 lualian.include_dir(v)
53 end
54 if os.getenv("EFL_RUN_IN_TREE") then
55 lualian.system_directory_scan()
56 end
57 lualian.load_eot_files()
58 for i, fname in ipairs(args) do
59 gen_file(opts, i, fname)
60 end
61 end
62 end
63}
64
65return true
diff --git a/src/bin/elua/apps/xgettext.lua b/src/bin/elua/apps/xgettext.lua
deleted file mode 100644
index 6d3b613739..0000000000
--- a/src/bin/elua/apps/xgettext.lua
+++ /dev/null
@@ -1,428 +0,0 @@
1-- Xgettext application
2-- provides a drop-in replacement of xgettext that supports Lua (but not any
3-- other language)
4
5local util = require("util")
6local cutil = require("cutil")
7local getopt = require("getopt")
8
9local generator = require("xgettext.generator")
10
11local VERSION = "1.0.0"
12
13local input_sources = {}
14local search_dirs = {}
15local excluded_files = {}
16local keywords = {}
17local flags = { valid = {} }
18
19local opts_final = {}
20local opts_nolua = {}
21
22local add_loc = true
23
24local opts, args = getopt.parse {
25 usage = "Usage: %prog [OPTION] [INPUTFILE]...",
26 args = arg,
27 descs = {
28 { category = "Input file location" },
29
30 { metavar = "INPUTFILE ...", help = "input files" },
31 { "f", "files-from", true, metavar = "FILE",
32 help = "get list of input files from FILE", list = input_sources
33 },
34 { "D", "directory", true, help = "add DIRECTORY to list for input "
35 .. "files search\nIf input file is -, standard input is read.",
36 list = search_dirs, opts = opts_nolua
37 },
38
39 { category = "Output file location" },
40
41 { "d", "default-domain", true, metavar = "NAME",
42 help = "use NAME.po for output (instead of messages.po)",
43 opts = opts_final
44 },
45 { "o", "output", true, metavar = "FILE",
46 help = "write output to specified file", opts = opts_final
47 },
48 { "p", "output-dir", true, metavar = "DIR", help = "output files "
49 .. "will be placed in directory DIR\nIf output file is -, "
50 .. "output is written to standard output.",
51 opts = opts_final
52 },
53
54 { category = "Input file interpretation" },
55
56 { "L", "language", true, help = false },
57 { "C", "c++", false, help = false,
58 callback = function(desc, parser, val, opts) opts["L"] = "C++" end
59 },
60 { nil, "from-code", true, metavar = "NAME", help = "encoding of "
61 .. "input files\nOnly relevant for non-Lua inputs "
62 .. "(Lua is always assumed to be UTF-8).", opts = opts_nolua
63 },
64
65 { category = "Operation mode" },
66
67 { "j", "join-existing", false,
68 help = "join messages with existing file", opts = opts_final
69 },
70 { "x", "exclude-file", true, metavar = "FILE.po",
71 help = "entries from FILE.po are not extracted",
72 list = excluded_files
73 },
74 { "c", "add-comments", nil, metavar = "TAG", help = "place comment "
75 .. "blocks (optionally starting with TAG) and preceding "
76 .. "keyword lines in output file", opts = opts_nolua
77 },
78
79 { category = "Language specific options" },
80
81 { "a", "extract-all", false, help = "extract all strings",
82 opts = opts_nolua
83 },
84 { "k", "keyword", nil, metavar = "WORD", help = "look for WORD as an "
85 .. "additional keyword or if not given, do no use default keywords",
86 opts = opts_nolua, list = keywords
87 },
88 { nil, "flag", true, metavar = "WORD:ARG:FLAG", help = "additional "
89 .. "flag for strings inside the argument number ARG of keyword WORD",
90 opts = opts_nolua, list = flags
91 },
92 { "T", "trigraphs", false, help = false, opts = opts_nolua },
93 { nil, "qt", false, help = false, opts = opts_nolua },
94 { nil, "kde", false, help = false, opts = opts_nolua },
95 { nil, "boost", false, help = false, opts = opts_nolua },
96 { nil, "debug", false, help = "more detailed formatstring "
97 .. "recognition results", opts = opts_nolua
98 },
99
100 { category = "Output details" },
101
102 { nil, "color", nil, metavar = "WHEN", help = "use colors and other "
103 .. "text attributes always or if WHEN. WHEN may be 'always', "
104 .. "'never', 'auto', or 'html'", opts = opts_final
105 },
106 { nil, "style", true, metavar = "STYLEFILE", help = "specify CSS "
107 .. "style rule file for --color", opts = opts_final
108 },
109 { nil, "force-po", false, help = "write PO file even if empty",
110 opts = opts_final
111 },
112 { "i", "indent", false, help = "write the .po file using indented "
113 .. "style", opts = opts_final
114 },
115 { nil, "no-location", false, help = "do not write '#: filename:line' "
116 .. "lines", opts = opts_nolua,
117 callback = function() add_loc = false end
118 },
119 { "n", "add-location", false, help = "generate '#: filename:line' "
120 .. "lines (default)", opts = opts_nolua,
121 callback = function() add_loc = true end
122 },
123 { nil, "strict", false, help = "write out strict Uniforum "
124 .. "conforming .po file", opts = opts_final
125 },
126 { nil, "properties-output", false, help = "write out a Java "
127 .. ".properties file", opts = opts_final
128 },
129 { nil, "stringtable-output", false, help = "write out a NeXTstep/"
130 .. "GNUstep .strings file", opts = opts_final
131 },
132 { "w", "width", true, metavar = "NUMBER", help = "set output page "
133 .. "width", opts = opts_final
134 },
135 { nil, "no-wrap", false, "do not break long message lines, longer "
136 .. "than the output page width, into several lines",
137 opts = opts_final
138 },
139 { "s", "sort-output", false, help = "generate sorted output",
140 opts = opts_final
141 },
142 { "F", "sort-by-file", false, help = "sort output by file location",
143 opts = opts_final
144 },
145 { nil, "omit-header", false, help = "don't write header with "
146 .. "'msgid \"\"' entry", opts = opts_final
147 },
148 { nil, "copyright-holder", true, metavar = "STRING", help = "set "
149 .. "copyright holder in output", opts = opts_final
150 },
151 { nil, "foreign-user", false, help = "omit copyright in output "
152 .. "for foreign user", opts = opts_final
153 },
154 { nil, "package-name", true, metavar = "PACKAGE", help = "set package "
155 .. "name in output", opts = opts_final
156 },
157 { nil, "package-version", true, metavar = "VERSION", help = "set "
158 .. "package version in output", opts = opts_final
159 },
160 { nil, "msgid-bugs-address", true, metavar = "EMAIL@ADDRESS", help =
161 "set report address for msgid bugs", opts = opts_final
162 },
163 { "m", "msgstr-prefix", true, metavar = "STRING", help = "use STRING "
164 .. "or \"\" as prefix for msgstr values", opts = opts_final
165 },
166 { "M", "msgstr-suffix", true, metavar = "STRING", help = "use STRING "
167 .. "or \"\" as suffix for msgstr values", opts = opts_final
168 },
169
170 { category = "Binaries" },
171
172 { "X", "xgettext", true, metavar = "PATH", help = "path to xgettext." },
173
174 { category = "Informative output" },
175
176 { "h", "help", nil, help = "display this help and exit",
177 callback = getopt.help_cb(io.stdout)
178 },
179 { "v", "version", false, help = "output version information and exit",
180 callback = function(p, d)
181 print("elua-xgettext (EFL) " .. VERSION)
182 end
183 },
184 error_cb = function(parser, msg)
185 io.stderr:write(msg, "\n")
186 getopt.help(parser, io.stderr)
187 end,
188 done_cb = function(parser, opts, args)
189 end
190 }
191}
192
193if not opts or opts["h"] or opts["v"] then
194 return true
195end
196
197-- default keywords
198if #keywords == 0 then
199 keywords = { "_", "gettext.gettext" , "gettext.dgettext:2",
200 "gettext.dcgettext:2" , "gettext.ngettext:1,2",
201 "gettext.dngettext:2,3", "gettext.dcngettext:2,3" }
202end
203
204-- transform some lists into mappings
205for i = 1, #excluded_files do
206 excluded_files[excluded_files[i]] = true
207 excluded_files[i] = nil
208end
209for i = 1, #keywords do
210 local kw = keywords[i]
211 local kwb, specs = kw:match("^(.+):(.+)$")
212 local n1, n1c, n2, n2c, n3, n3c, xcmt, argnum
213 if not kwb then
214 kwb = kw
215 else
216 n1, n1c, n2, n2c, n3, n3c, xcmt
217 = specs:match("^(%d+)(c?),(%d+)(c?),(%d+)(c?)(.*)$")
218 if not n1 then
219 n1, n1c, n2, n2c, xcmt = specs:match("^(%d+)(c?),(%d+)(c?)(.*)$")
220 if not n1 then
221 n1, n1c, xcmt = specs:match("^(%d+)(c?)(.*)$")
222 if not n1 then error("invalid keyword specifier") end
223 end
224 end
225 end
226 -- all matched, sanitize now
227 if n1c == "" then n1c = nil end
228 if n2c == "" then n2c = nil end
229 if n3c == "" then n3c = nil end
230 if xcmt == "" then xcmt = nil end
231 -- sanitize/retrieve comment and potential total number of args
232 if n3 and xcmt == "t" then
233 if n3c then error("invalid keyword specifier") end
234 argnum = n3
235 n3 = nil
236 elseif n2 and xcmt == "t" then
237 if n2c then error("invalid keyword specifier") end
238 argnum = n2
239 n2 = nil
240 elseif n1 and xcmt == "t" then
241 if n1c then error("invalid keyword specifier") end
242 argnum = n1
243 n1 = nil
244 elseif xcmt then
245 local xcmtm, rest = xcmt:match('^,"(.+)"(.*)$')
246 if not xcmtm then
247 xcmtm, rest = xcmt:match("^,'(.+)'(.*)$")
248 end
249 if xcmtm then
250 xcmt = xcmtm
251 else
252 rest = xcmt
253 xcmt = nil
254 end
255 argnum = rest:match("^,(%d+)t$")
256 -- the rest doesn't match either comment nor argnum nor both
257 if not xcmt and not argnum then
258 error("invalid keyword specifier")
259 end
260 end
261 -- allow only one context arg
262 if (n1c and n2c) or (n2c and n3c) or (n1c and n3c) then
263 error("invalid keyword specifier")
264 end
265 -- retrieve context
266 local context
267 if n1c then
268 context = tonumber(n1)
269 n1 = n2
270 n2 = n3
271 n3 = nil
272 elseif n2c then
273 context = tonumber(n2)
274 n2 = n3
275 n3 = nil
276 elseif n3c then
277 context = tonumber(n3)
278 elseif n1 and n2 and n3 then -- 3 regular args, forbidden
279 error("invalid keyword specifier")
280 end
281
282 if keywords[kwb] then
283 error("cannot specify the same keyword more than twice")
284 end
285
286 -- all sanitized, store :)
287 keywords[kwb] = { context = context, argnum = tonumber(argnum),
288 xcomment = xcmt, tonumber(n1) or 1, tonumber(n2) }
289 keywords[i] = nil
290end
291
292-- at least one default path
293if #search_dirs == 0 then
294 search_dirs[1] = "."
295end
296
297local build_opt = function(opt)
298 local buf = {}
299 if opt.short then
300 buf[1] = "-"
301 buf[2] = opt.short
302 if opt.val then
303 buf[3] = opt.val
304 end
305 else
306 buf[1] = "--"
307 buf[2] = opt.long
308 if opt.val then
309 buf[3] = "="
310 buf[4] = opt.val
311 end
312 end
313 return table.concat(buf)
314end
315
316local onlylua = opts["L"] and opts["L"]:lower() == "lua"
317local neverlua = opts["L"] and opts["L"]:lower() ~= "lua"
318
319local hasxgettext = opts["X"]
320if not hasxgettext then
321 hasxgettext = os.getenv("XGETTEXT")
322end
323
324if not hasxgettext then
325 return true
326end
327
328local f = io.open(hasxgettext)
329if not f then
330 return true
331end
332f:close()
333
334local input_files = {}
335for i, v in ipairs(input_sources) do
336 local f = io.open(v)
337 if f then
338 for line in f:lines() do
339 input_files[#input_files + 1] = line
340 end
341 end
342end
343for i, v in ipairs(args) do
344 input_files[#input_files + 1] = v
345end
346
347local args_nolua = {}
348for i, opt in ipairs(opts_nolua) do
349 args_nolua[#args_nolua + 1] = build_opt(opt)
350end
351args_nolua[#args_nolua + 1] = "--omit-header"
352args_nolua[#args_nolua + 1] = "--output=-"
353args_nolua[#args_nolua + 1] = false
354
355local found_files = {}
356
357-- make sure all files exist first
358for i, fname in ipairs(input_files) do
359 if fname ~= "-" and not excluded_files[fname] then
360 local ff = util.find_file(fname, search_dirs)
361 if not ff then
362 error(fname .. ": no such file or directory")
363 end
364 found_files[fname] = ff
365 end
366end
367
368-- mapping to real flags
369local allowed_lua_flags = {
370 ["lua-format" ] = true,
371 ["pass-lua-format"] = true,
372 ["no-lua-format" ] = true
373}
374
375local parsed_files = {}
376for i, fname in ipairs(input_files) do
377 if not excluded_files[fname] then
378 if onlylua or (not neverlua and fname:lower():match("^.+%.lua$")) then
379 -- parse lua files here
380 local fcontents, fpath
381 -- handle stdin if needed
382 if fname == "-" then
383 fpath, fcontents = "=stdin", io.stdin:read("*all")
384 else
385 fpath = found_files[fname]
386 local f = io.open(fpath, "r")
387 fcontents = f:read("*all")
388 f:close()
389 fpath = "@" .. fpath
390 end
391 local actual_flags = { valid = flags.valid }
392 for i, v in ipairs(flags) do
393 local word, argn, flag = v:match("([^:]+):(%d+):([%a-]+)")
394 if word and allowed_lua_flags[flag] then
395 actual_flags[#actual_flags + 1] = { word,
396 tonumber(argn), flag }
397 local ft = actual_flags[word]
398 if not ft then
399 ft = {}
400 actual_flags[word] = ft
401 end
402 ft[#ft + 1] = { tonumber(argn), flag }
403 end
404 end
405 parsed_files[#parsed_files + 1] = generator.init(fpath, fcontents,
406 keywords, actual_flags, add_loc, opts)
407 else
408 args_nolua[#args_nolua] = fname
409 local f = assert(cutil.popenv(hasxgettext, "r",
410 unpack(args_nolua)))
411 local s = f:read("*all")
412 parsed_files[#parsed_files + 1] = s
413 f:close()
414 end
415 end
416end
417
418local args_final = {}
419for i, opt in ipairs(opts_final) do
420 args_final[#args_final + 1] = build_opt(opt)
421end
422args_final[#args_final + 1] = "--language=PO"
423args_final[#args_final + 1] = "-"
424local f = assert(cutil.popenv(hasxgettext, "w", unpack(args_final)))
425f:write(table.concat(parsed_files, "\n\n"))
426f:close()
427
428return true
diff --git a/src/bin/elua/core/gettext.lua b/src/bin/elua/core/gettext.lua
deleted file mode 100644
index a77d50abc8..0000000000
--- a/src/bin/elua/core/gettext.lua
+++ /dev/null
@@ -1,92 +0,0 @@
1-- elua gettext module
2
3local ffi = require("ffi")
4
5local M = {}
6
7local gettext = ...
8
9local bind_textdomain = gettext.bind_textdomain
10local bind_textdomain_codeset = gettext.bind_textdomain_codeset
11local dgettext = gettext.dgettext
12local dngettext = gettext.dngettext
13
14if dgettext then
15 dgettext = ffi.cast("char *(*)(const char*, const char*)", dgettext)
16 dngettext = ffi.cast("char *(*)(const char*, const char*, const char*, "
17 .. "unsigned long)", dngettext)
18end
19
20local domains = {}
21
22local default_domain
23
24M.register_domain = function(dom, dir)
25 local d, err = bind_textdomain(dom, dir)
26 if not d then
27 return false, err
28 end
29 domains[dom] = d
30 return true
31end
32
33M.get_domain = function(dom)
34 return domains[dom]
35end
36
37M.set_default_domain = function(dom)
38 if not domains[dom] then return false end
39 default_domain = dom
40 return true
41end
42
43local cast, ffistr = ffi.cast, ffi.string
44local floor = math.floor
45local type = type
46
47if dgettext then
48 M.gettext = function(dom, msgid)
49 if not msgid then
50 msgid = dom
51 dom = default_domain
52 end
53 if not domains[dom] or not msgid then return msgid end
54 local cmsgid = cast("const char*", msgid)
55 local lmsgid = dgettext(dom, cmsgid)
56 if cmsgid == lmsgid then
57 return msgid
58 end
59 return ffistr(lmsgid)
60 end
61 M.dgettext = M.gettext
62 M.ngettext = function(dom, msgid, plmsgid, n)
63 if not n then
64 plmsgid = msgid
65 msgid = dom
66 dom = default_domain
67 end
68 n = (type(n) == "number") and floor(n) or 0
69 if not domains[dom] then
70 if not msgid or n == 1 then return msgid end
71 return plmsgid
72 end
73 local cmsgid = cast("const char*", msgid)
74 local cplmsgid = cast("const char*", plmsgid)
75 local lmsgid = dngettext(dom, cmsgid, cplmsgid, n)
76 if n == 1 then
77 if cmsgid == lmsgid then return msgid end
78 else
79 if cplmsgid == lmsgid then return plmsgid end
80 end
81 return ffistr(lmsgid)
82 end
83 M.dngettext = M.ngettext
84else
85 M.gettext = function(dom, msgid) return msgid end
86 M.ngettext = function(dom, msgid, plmsgid, n)
87 if n == 1 then return msgid end
88 return plmsgid
89 end
90end
91
92return M
diff --git a/src/bin/elua/core/module.lua b/src/bin/elua/core/module.lua
deleted file mode 100644
index 041548084d..0000000000
--- a/src/bin/elua/core/module.lua
+++ /dev/null
@@ -1,126 +0,0 @@
1-- elua module system
2
3local M = {}
4
5local cutil = select(2, ...)
6
7local preload = {
8 ffi = package.preload["ffi"],
9 cutil = function() return cutil end
10}
11
12local loaded = {
13}
14
15M.loaded = loaded
16M.preload = preload
17
18for k, v in pairs(package.loaded) do loaded[k] = v end
19
20M.path = "./?.lua;/?/init.lua"
21M.cpath = ""
22M.apath = "./?.lua"
23
24local loadlib = package.loadlib
25
26local cloader_load = function(soname, modname)
27 local hyp = modname:find("%-")
28 if hyp then modname = modname:sub(hyp + 1) end
29 local f, err = loadlib(soname, "luaopen_" .. (modname:gsub("%.", "_")))
30 if not f then
31 error("error loading module '" .. modname .. "' from file '"
32 .. fname .. "':\n" .. err, 3)
33 end
34 return f
35end
36
37local loaders = {
38 function(modname)
39 local v = preload[modname]
40 if not v then
41 return ("\no field preload['%s']"):format(modname)
42 end
43 return v
44 end,
45 function(modname)
46 local fname, err = package.searchpath(modname, M.path)
47 if not fname then return err end
48 local f, err = loadfile(fname)
49 if not f then
50 error("error loading module '" .. modname .. "' from file '"
51 .. fname .. "':\n" .. err, 2)
52 end
53 return f
54 end,
55 function(modname)
56 local fname, err = package.searchpath(modname, M.cpath)
57 if not fname then return err end
58 local hyp = modname:find("%-")
59 if hyp then modname = modname:sub(hyp + 1) end
60 return cloader_load(fname, modname)
61 end,
62 function(modname)
63 local rootname, dot = modname, modname:find("%.")
64 if dot then
65 rootname = rootname:sub(dot + 1)
66 end
67 local fname, err = package.searchpath(rootname, M.cpath)
68 if not fname then return err end
69 return cloader_load(fname, modname)
70 end
71}
72M.loaders = loaders
73
74local find_loader = function(modname, env)
75 env = env or _G
76 local err = { ("module '%s' not found\n"):format(modname) }
77 for i = 1, #loaders do
78 local v = loaders[i](modname)
79 if type(v) == "function" then
80 local status, ret = pcall(function() return setfenv(v, env) end)
81 return status and ret or v
82 elseif type(v) == "string" then
83 err[#err + 1] = v
84 end
85 end
86 return nil, table.concat(err)
87end
88
89M.require = function(modname, ...)
90 local v = loaded[modname]
91 if v ~= nil then return v end
92 local loader, err = find_loader(modname)
93 if not loader then error(err, 2) end
94 local ret = loader(modname, ...)
95 if ret ~= nil then
96 loaded[modname] = ret
97 return ret
98 elseif loaded[modname] == nil then
99 loaded[modname] = true
100 return true
101 end
102 return loaded[modname]
103end
104
105M.load_app = function(appname)
106 local fname, err = package.searchpath(appname, M.apath)
107 if not fname then return nil, err end
108 local f, err = loadfile(fname)
109 if not f then return nil, err end
110 return f
111end
112
113M.preload = preload
114M.loaded = loaded
115
116-- register require
117M.path, M.apath = (...)(M.require, M.load_app, M.path, M.apath)
118
119M.config = package.config
120M.searchpath = package.searchpath
121M.loadlib = package.loadlib
122
123_G["require"] = M.require
124_G["package"] = M
125
126return M
diff --git a/src/bin/elua/core/util.lua b/src/bin/elua/core/util.lua
deleted file mode 100644
index b273054177..0000000000
--- a/src/bin/elua/core/util.lua
+++ /dev/null
@@ -1,355 +0,0 @@
1-- elua core utilities used in other modules
2
3local ffi = require("ffi")
4local cast = ffi.cast
5local new = ffi.new
6local copy = ffi.copy
7local str = ffi.string
8local gc = ffi.gc
9
10local C = ffi.C
11
12local M = {}
13
14local getmetatable, setmetatable = getmetatable, setmetatable
15
16M.Object = {
17 __call = function(self, ...)
18 local r = self:clone()
19 if self.__ctor then return r, self.__ctor(r, ...) end
20 return r
21 end,
22
23 clone = function(self, o)
24 o = o or {}
25 o.__index, o.__proto, o.__call = self, self, self.__call
26 if not o.__tostring then
27 o.__tostring = self.__tostring
28 end
29 setmetatable(o, o)
30 return o
31 end,
32
33 is_a = function(self, base)
34 if self == base then return true end
35 local pt = self.__proto
36 local is = (pt == base)
37 while not is and pt do
38 pt = pt.__proto
39 is = (pt == base)
40 end
41 return is
42 end,
43
44 mixin = function(self, obj)
45 for k, v in pairs(obj) do self[k] = v end
46 end,
47
48 __tostring = function(self)
49 return ("Object: %s"):format(self.name or "unnamed")
50 end
51}
52
53local newproxy = newproxy
54
55M.Readonly_Object = M.Object:clone {}
56M.Readonly_Object.__call = function(self, ...)
57 local r = newproxy(true)
58 local rmt = getmetatable(r)
59 rmt.__index = self
60 rmt.__tostring = self.__tostring
61 rmt.__metatable = false
62 if self.__ctor then return r, self.__ctor(r, rmt, ...) end
63 return r
64end
65
66local loaded_libs = {}
67local loaded_libc = {}
68
69local load_lib_win = function(libname, ev)
70 local succ, v
71 if not ev or ev == "" then
72 succ, v = pcall(ffi.load, libname)
73 if not succ then
74 succ, v = pcall(ffi.load, "lib" .. libname)
75 end
76 else
77 succ, v = pcall(ffi.load, ev .. "\\" .. libname .. ".dll")
78 if not succ then
79 succ, v = pcall(ffi.load, ev .. "\\lib" .. libname .. ".dll")
80 end
81 end
82 return succ, v
83end
84
85local load_lib = function(libname, ev)
86 local succ, v
87 if ffi.os == "Windows" then
88 succ, v = load_lib_win(libname, ev)
89 elseif not ev or ev == "" then
90 succ, v = pcall(ffi.load, libname)
91 else
92 local ext = (ffi.os == "OSX") and ".dylib" or ".so"
93 succ, v = pcall(ffi.load, ev .. "/lib" .. libname .. ext)
94 end
95 return succ, v
96end
97
98-- makes sure we only keep one handle for each lib
99-- reference counted
100M.lib_load = function(libname)
101 local lib = loaded_libs[libname]
102 if not lib then
103 local ev = os.getenv("ELUA_" .. libname:upper() .. "_LIBRARY_PATH")
104 local succ, v = load_lib(libname, ev)
105 if not succ then
106 error(v, 2)
107 end
108 lib = v
109 loaded_libs[libname] = lib
110 loaded_libc[libname] = 0
111 end
112 loaded_libc[libname] = loaded_libc[libname] + 1
113 return lib
114end
115
116M.lib_unload = function(libname)
117 local cnt = loaded_libc[libname]
118 if not cnt then return end
119 if cnt == 1 then
120 loaded_libs[libname], loaded_libc[libname] = nil, nil
121 else
122 loaded_libc[libname] = cnt - 1
123 end
124end
125
126-- string fmt
127
128ffi.cdef [[
129 typedef struct _Str_Buf {
130 char *buf;
131 size_t len, cap;
132 } Str_Buf;
133
134 void *malloc(size_t);
135 void free(void*);
136 size_t strlen(const char *str);
137
138 int isalnum(int c);
139 int isdigit(int c);
140]]
141
142local fmt = string.format
143local pcall = pcall
144local error = error
145local type = type
146local tostr = tostring
147
148local bytes = { ("cdeEfgGiopuxXsq"):byte(1, #("cdeEfgGiopuxXsq")) }
149for i, v in ipairs(bytes) do bytes[v] = true end
150
151local Str_Buf = ffi.metatype("Str_Buf", {
152 __new = function(self)
153 local r = new("Str_Buf")
154 r.buf = C.malloc(8)
155 r.len = 0
156 r.cap = 8
157 gc(r, self.free)
158 return r
159 end,
160 __tostring = function(self)
161 return str(self.buf, self.len)
162 end,
163 __index = {
164 free = function(self)
165 C.free(self.buf)
166 self.buf = nil
167 self.len = 0
168 self.cap = 0
169 end,
170 clear = function(self)
171 self.len = 0
172 end,
173 grow = function(self, newcap)
174 local oldcap = self.cap
175 if oldcap >= newcap then return end
176 local buf = C.malloc(newcap)
177 if self.len ~= 0 then copy(buf, self.buf, self.len) end
178 if self.buf ~= nil then C.free(self.buf) end
179 self.buf = buf
180 self.cap = newcap
181 end,
182 append_char = function(self, c)
183 local len = self.len
184 self:grow (len + 1)
185 self.buf [len] = c
186 self.len = len + 1
187 end,
188 append_str = function(self, str, strlen)
189 if type(str) == "string" then strlen = strlen or #str end
190 local strp = cast("const char*", str)
191 strlen = strlen or C.strlen(strp)
192 local len = self.len
193 self:grow(len + strlen)
194 for i = 0, strlen - 1 do
195 self.buf[len + i] = strp[i]
196 end
197 self.len = len + strlen
198 end
199 }
200})
201
202local fmterr = function(idx, msg, off)
203 local argerr = (type(idx) == "number")
204 and ("#" .. idx)
205 or ("'" .. idx .. "'")
206 error("bad argument " .. argerr .. " to '%' (" .. msg .. ")",
207 3 + (off or 0))
208end
209
210-- simulates lua's coercion
211local checktype = function(c, idx, val)
212 if c == 115 or c == 112 then -- s, p
213 return val
214 end
215 local tv = type(val)
216 if c == 113 then -- q
217 if tv ~= "string" or tv ~= "number" then
218 fmterr(idx, "string expected, got " .. tv, 1)
219 end
220 return val
221 end
222 if tv == "number" then return val end
223 if tv == "string" then
224 local v = tonumber(val)
225 if v then return v end
226 end
227 fmterr(idx, "number expected, got " .. tv, 1)
228end
229
230getmetatable("").__mod = function(fmts, params)
231 if not fmts then return nil end
232 if type(params) ~= "table" then
233 params = { params }
234 end
235
236 local buf, nbuf = Str_Buf(), Str_Buf()
237 local s = cast("const char*", fmts)
238 local c, s = s[0], s + 1
239 local argn = 1
240
241 while c ~= 0 do
242 if c == 37 then -- %
243 c, s = s[0], s + 1
244 if c ~= 37 then
245 while c ~= 0 and C.isalnum(c) ~= 0 do
246 nbuf:append_char(c)
247 c, s = s[0], s + 1
248 end
249 if c == 36 then -- $
250 c, s = s[0], s + 1
251 local n = tostr(nbuf)
252 nbuf:clear()
253 while C.isdigit(c) ~= 0 or c == 45 or c == 46 do -- -, .
254 nbuf:append_char(c)
255 c, s = s[0], s + 1
256 end
257 if not bytes[c] then
258 buf:append_str(n)
259 buf:append_char(36) -- $
260 buf:append_char(c)
261 else
262 nbuf:append_char(c)
263 local idx = tonumber(n) or n
264 if type(idx) == "number" and idx > #params then
265 fmterr(idx, "no value")
266 end
267 local v = params[idx]
268 v = checktype(c, idx, v)
269 buf:append_str(("%" .. tostr(nbuf)):format(v))
270 nbuf:clear()
271 end
272 else
273 local fmtmark = (nbuf.len > 0) and nbuf.buf[0] or nil
274 if not fmtmark then
275 while c ~= 0 and (C.isdigit(c) ~= 0 or c == 45
276 or c == 46) do
277 nbuf:append_char(c)
278 c, s = s[0], s + 1
279 end
280 if bytes[c] then fmtmark = c end
281 end
282 if fmtmark then
283 if argn > #params then
284 fmterr(argn, "no value")
285 end
286 local v = params[argn]
287 v = checktype(fmtmark, argn, v)
288 buf:append_str(("%" .. tostr(nbuf)):format(v))
289 nbuf:clear()
290 argn = argn + 1
291 else
292 buf:append_str(nbuf.buf, nbuf.len)
293 nbuf:clear()
294 end
295 if c ~= 0 then buf:append_char(c) end
296 end
297 else
298 buf:append_char(c)
299 end
300 else
301 buf:append_char(c)
302 end
303 c, s = s[0], s + 1
304 end
305 nbuf:free()
306 local ret = tostr(buf)
307 buf:free()
308 return ret
309end
310
311-- file utils
312
313M.find_file = function(fname, paths)
314 for i, path in ipairs(paths) do
315 local actual_path
316 if path:match(".*/") then
317 actual_path = path .. fname
318 else
319 actual_path = path .. "/" .. fname
320 end
321 local f = io.open(actual_path)
322 if f then
323 f:close()
324 return actual_path
325 end
326 end
327end
328
329-- table utils
330
331table.uniq = function(tbl)
332 local ret = {}
333 local used = {}
334 for i, v in ipairs(tbl) do
335 if not used[v] then
336 ret[#ret + 1], used[v] = v, true
337 end
338 end
339 return ret
340end
341
342M.get_namespace = function(M, nspaces)
343 local last_m = M
344 for i, v in ipairs(nspaces) do
345 local nsp = M[v]
346 if not nsp then
347 nsp = {}
348 last_m[v] = nsp
349 end
350 last_m = nsp
351 end
352 return last_m
353end
354
355return M
diff --git a/src/bin/elua/main.c b/src/bin/elua/main.c
index 8d789db950..4b8b40fa2f 100644
--- a/src/bin/elua/main.c
+++ b/src/bin/elua/main.c
@@ -133,9 +133,9 @@ elua_register_require(lua_State *L)
133 elua_appload_ref = luaL_ref(L, LUA_REGISTRYINDEX); 133 elua_appload_ref = luaL_ref(L, LUA_REGISTRYINDEX);
134 if (getenv("EFL_RUN_IN_TREE")) 134 if (getenv("EFL_RUN_IN_TREE"))
135 { 135 {
136 corepath = PACKAGE_SRC_DIR "/src/bin/elua/core"; 136 corepath = PACKAGE_SRC_DIR "/src/scripts/elua/core";
137 modpath = PACKAGE_SRC_DIR "/src/bin/elua/modules"; 137 modpath = PACKAGE_SRC_DIR "/src/scripts/elua/modules";
138 appspath = PACKAGE_SRC_DIR "/src/bin/elua/apps"; 138 appspath = PACKAGE_SRC_DIR "/src/scripts/elua/apps";
139 } 139 }
140 else 140 else
141 { 141 {
@@ -474,7 +474,7 @@ elua_main(lua_State *L)
474 v->type = ARG_LIBDIR; 474 v->type = ARG_LIBDIR;
475 v->value = PACKAGE_SRC_DIR "/src/bindings/luajit"; 475 v->value = PACKAGE_SRC_DIR "/src/bindings/luajit";
476 largs = eina_list_append(largs, v); 476 largs = eina_list_append(largs, v);
477 coref = PACKAGE_SRC_DIR "/src/bin/elua/core"; 477 coref = PACKAGE_SRC_DIR "/src/scripts/elua/core";
478 } 478 }
479 else if (!(coref = coredir)) 479 else if (!(coref = coredir))
480 { 480 {
diff --git a/src/bin/elua/modules/benchmark.lua b/src/bin/elua/modules/benchmark.lua
deleted file mode 100644
index 412ff971bc..0000000000
--- a/src/bin/elua/modules/benchmark.lua
+++ /dev/null
@@ -1,97 +0,0 @@
1-- Elua benchmark module
2
3local cutil = require("cutil")
4local util = require("util")
5local counter = require("eina.counter")
6local log = require("eina.log")
7
8local Counter = counter.Counter
9
10local M = {}
11
12local dom
13
14cutil.init_module(function()
15 dom = log.Domain("elua_benchmark")
16 if not dom:is_valid() then
17 log.err("Could not register log domain: elua_benchmark")
18 error("could not register log domain: elua_benchmark")
19 end
20end, function()
21 dom:unregister()
22 dom = nil
23end)
24
25local PLOT_MASK = "bench_%s_%s.gnuplot"
26local DATA_MASK = "bench_%s_%s.%s.data"
27
28M.Benchmark = util.Object:clone {
29 __ctor = function(self, name, run)
30 self.name, self.run = name, run
31 self.runs = {}
32 end,
33
34 register = function(self, name, bench_cb, c_start, c_end, c_step)
35 self.runs[#self.runs + 1] = {
36 cb = bench_cb, name = name, c_start = c_start, c_end = c_end,
37 c_step = c_step
38 }
39 return true
40 end,
41
42 run = function(self, pmask, dmask)
43 pmask, dmask = pmask or PLOT_MASK, dmask or DATA_MASK
44 local fname = pmask:format(self.name, self.run)
45 local plots = io.open(fname, "w")
46 if not plots then
47 return nil
48 end
49 local fnames = {}
50 fnames[#fnames + 1] = fname
51 plots:write(([[
52set autoscale # scale axes automatically
53unset log # remove any log-scaling
54unset label # remove any previous labels
55set xtic auto # set xtics automatically
56set ytic auto # set ytics automatically
57set terminal png size 1024,768
58set output "output_%s_%s.png"
59set title "%s %s"
60set xlabel "tests"
61set ylabel "time"
62plot ]]):format(self.name, self.run, self.name, self.run))
63 local first = false
64 for i, run in ipairs(self.runs) do
65 local fname = dmask:format(self.name, self.run, run.name)
66 local datas = io.open(fname, "w")
67 if datas then
68 fnames[#fnames + 1] = fname
69 local cnt = Counter(run.name)
70 for i = run.c_start, run.c_end, run.c_step do
71 io.stderr:write("Run ", run.name, ": ", i, "\n")
72 cnt:start()
73 run.cb(i)
74 cnt:stop(i)
75 end
76 local ret = cnt:dump()
77 if ret then
78 datas:write(ret)
79 end
80 cnt:free()
81 datas:close()
82 if not first then
83 first = true
84 else
85 plots:write(", \\\n")
86 end
87 plots:write(("\"%s\" using 1:2 title \'%s\' with line")
88 :format(fname, run.name))
89 end
90 end
91 plots:write("\n")
92 plots:close()
93 return fnames
94 end
95}
96
97return M
diff --git a/src/bin/elua/modules/getopt.lua b/src/bin/elua/modules/getopt.lua
deleted file mode 100644
index 6ac5be83c3..0000000000
--- a/src/bin/elua/modules/getopt.lua
+++ /dev/null
@@ -1,294 +0,0 @@
1-- Elua getopt module
2
3local M = {}
4
5local prefixes = { "-", "--" }
6
7local get_desc = function(opt, j, descs)
8 for i, v in ipairs(descs) do
9 if v[j] == opt then
10 return v
11 end
12 end
13 error("option " .. prefixes[j] .. opt .. " not recognized", 4)
14end
15
16local is_arg = function(opt, j, descs)
17 if opt == "--" then return true end
18 for i, v in ipairs(descs) do
19 if v[j] and opt == (prefixes[j] .. v[j]) then
20 return true
21 end
22 end
23 return false
24end
25
26local parse_l = function(opts, opt, descs, args, parser)
27 local optval
28 local i = opt:find("=")
29 if i then
30 opt, optval = opt:sub(1, i - 1), opt:sub(i + 1)
31 end
32
33 local desc = get_desc(opt, 2, descs)
34 local argr = desc[3]
35 if argr or argr == nil then
36 if not optval then
37 if #args == 0 then
38 if argr then
39 error("option --" .. opt .. " requires an argument", 3)
40 end
41 elseif argr or not is_arg(args[1], 2, descs) then
42 optval = table.remove(args, 1)
43 end
44 end
45 elseif optval then
46 error("option --" .. opt .. " cannot have an argument", 3)
47 end
48 local rets
49 if desc.callback then
50 rets = { desc:callback(parser, optval, opts) }
51 end
52 if not rets or #rets == 0 then rets = { optval } end
53 local optn = desc.alias or desc[1] or desc[2]
54 opts[#opts + 1] = { optn, short = desc[1], long = desc[2],
55 alias = desc.alias, val = optval, unpack(rets) }
56 local optret = #rets > 1 and rets or rets[1]
57 if desc.list then
58 desc.list[#desc.list + 1] = optret
59 opts[optn] = desc.list
60 else
61 opts[optn] = optret or true
62 end
63 local dopts = desc.opts
64 if dopts then
65 dopts[#dopts + 1] = opts[#opts]
66 dopts[optn] = opts[optn ]
67 end
68end
69
70local parse_s = function(opts, optstr, descs, args, parser)
71 while optstr ~= "" do
72 local optval
73 local opt = optstr:sub(1, 1)
74 optstr = optstr:sub(2)
75 local desc = get_desc(opt, 1, descs)
76 local argr = desc[3]
77 if argr or argr == nil then
78 if optstr == "" then
79 if #args == 0 then
80 if argr then
81 error("option -" .. opt .. " requires an argument", 3)
82 end
83 elseif argr or not is_arg(args[1], 1, descs) then
84 optstr = table.remove(args, 1)
85 end
86 end
87 optval, optstr = optstr, ""
88 end
89 local rets
90 if desc.callback then
91 rets = { desc:callback(parser, optval, opts) }
92 end
93 if not rets or #rets == 0 then rets = { optval } end
94 local optn = desc.alias or desc[1] or desc[2]
95 opts[#opts + 1] = { optn, short = desc[1], long = desc[2],
96 alias = desc.alias, val = optval, unpack(rets) }
97 local optret = #rets > 1 and rets or rets[1]
98 if desc.list then
99 desc.list[#desc.list + 1] = optret
100 opts[optn] = desc.list
101 else
102 opts[optn] = optret or true
103 end
104 local dopts = desc.opts
105 if dopts then
106 dopts[#dopts + 1] = opts[#opts]
107 dopts[optn] = opts[optn ]
108 end
109 end
110end
111
112local getopt_u = function(parser)
113 local args = { unpack(parser.args) }
114 local descs = parser.descs
115 local opts = {}
116 while #args > 0 and args[1]:sub(1, 1) == "-" and args[1] ~= "-" do
117 local v = table.remove(args, 1)
118 if v == "--" then break end
119 if v:sub(1, 2) == "--" then
120 parse_l(opts, v:sub(3), descs, args, parser)
121 else
122 parse_s(opts, v:sub(2), descs, args, parser)
123 end
124 end
125 return opts, args
126end
127
128M.parse = function(parser)
129 local ret, opts, args = pcall(getopt_u, parser)
130 if not ret then
131 if parser.error_cb then
132 parser:error_cb(opts)
133 end
134 return nil, opts
135 end
136 if parser.done_cb then
137 parser:done_cb(opts, args)
138 end
139 return opts, args, parser
140end
141local parse = M.parse
142
143local repl_prog = function(str, progn)
144 return (str:gsub("%f[%%]%%prog", progn):gsub("%%%%prog", "%%prog"))
145end
146
147local buf_write = function(self, ...)
148 local vs = { ... }
149 for i, v in ipairs(vs) do self[#self + 1] = v end
150end
151
152local get_metavar = function(desc)
153 local mv = desc.metavar
154 if not mv and (desc[3] or desc[3] == nil) then
155 mv = desc[2] and desc[2]:upper() or "VAL"
156 elseif desc[3] == false then
157 mv = nil
158 end
159 return mv
160end
161
162local help = function(parser, f, category)
163 local usage = parser.usage
164 local progn = parser.prog or parser.args[0] or "program"
165 if usage then
166 usage = repl_prog(usage, progn)
167 else
168 usage = ("Usage: %s [OPTIONS]"):format(progn)
169 end
170 local buf = { write = buf_write }
171 buf:write(usage, "\n")
172 if parser.header then
173 buf:write("\n", repl_prog(parser.header, progn), "\n")
174 end
175 local nignore = 0
176 for i, desc in ipairs(parser.descs) do
177 if desc.help == false then nignore = nignore + 1 end
178 end
179 if #parser.descs > nignore then
180 local ohdr = parser.optheader
181 buf:write("\n", ohdr and repl_prog(ohdr, progn)
182 or "The following options are supported:", "\n\n")
183 local lls = 0
184 for i, desc in ipairs(parser.descs) do
185 if desc.help ~= false and desc[1] then
186 local mv = get_metavar(desc)
187 if mv then
188 lls = math.max(lls, #mv + ((desc[3] == nil) and 5 or 4))
189 else
190 lls = math.max(lls, 2)
191 end
192 end
193 end
194 local lns = {}
195 local lln = 0
196 local iscat = false
197 local wascat = false
198 for i, desc in ipairs(parser.descs) do
199 local nign = desc.help ~= false
200 if nign and (not category or iscat)
201 and (desc[1] or desc[2] or desc.metavar) then
202 local mv = get_metavar(desc)
203 local ln = {}
204 ln[#ln + 1] = " "
205 if desc[1] then
206 ln[#ln + 1] = "-" .. desc[1]
207 if mv then ln[#ln + 1] = (desc[3] and "[" or "[?")
208 .. mv .. "]" end
209 local sln = #table.concat(ln) - 2
210 local sdf = lls - sln
211 if desc[2] then ln[#ln + 1] = ", " end
212 if sdf > 0 then
213 ln[#ln + 1] = (" "):rep(sdf)
214 end
215 elseif not desc[2] and mv then
216 ln[#ln + 1] = mv
217 else
218 ln[#ln + 1] = (" "):rep(lls + 2)
219 end
220 if desc[2] then
221 ln[#ln + 1] = "--" .. desc[2]
222 if mv then ln[#ln + 1] = (desc[3] and "=[" or "=[?")
223 .. mv .. "]" end
224 end
225 ln = table.concat(ln)
226 lln = math.max(lln, #ln)
227 lns[#lns + 1] = { ln, desc.help }
228 elseif nign and desc.category then
229 local lcat = category and category:lower() or nil
230 local alias = desc.alias and desc.alias:lower() or nil
231 iscat = (not category) or (alias == lcat)
232 or (desc.category:lower() == lcat)
233 if iscat then
234 wascat = true
235 lns[#lns + 1] = { false, desc.category }
236 end
237 end
238 end
239 if category and not wascat then
240 error("no such category: '" .. category .. "'", 0)
241 end
242 local fcat = true
243 for i, lnt in ipairs(lns) do
244 local ln = lnt[1]
245 local hp = lnt[2]
246 if ln == false then
247 if not fcat then
248 buf:write("\n")
249 end
250 buf:write(hp, ":\n")
251 fcat = false
252 else
253 fcat = false
254 buf:write(ln)
255 if hp then buf:write((" "):rep(lln - #ln), " ", hp) end
256 buf:write("\n")
257 end
258 end
259 end
260 if parser.footer then
261 buf:write("\n", repl_prog(parser.footer, progn), "\n")
262 end
263 f:write(table.concat(buf))
264end
265
266M.help = function(parser, category, f)
267 if category and type(category) ~= "string" then
268 f, category = category, f
269 end
270 f = f or io.stderr
271 local ret, err = pcall(help, parser, f, category)
272 if not ret then
273 f:write(err, "\n\n")
274 help(parser, f)
275 return false, err
276 end
277 return true
278end
279
280M.geometry_parse_cb = function(desc, parser, v)
281 return v:match("^(%d+):(%d+):(%d+):(%d+)$")
282end
283
284M.size_parse_cb = function(desc, parser, v)
285 return v:match("^(%d+)x(%d+)$")
286end
287
288M.help_cb = function(fstream)
289 return function(desc, parser, v)
290 M.help(parser, v, fstream)
291 end
292end
293
294return M
diff --git a/src/bin/elua/modules/lualian.lua b/src/bin/elua/modules/lualian.lua
deleted file mode 100644
index 85208e17db..0000000000
--- a/src/bin/elua/modules/lualian.lua
+++ /dev/null
@@ -1,697 +0,0 @@
1-- Elua lualian module
2
3local cutil = require("cutil")
4local util = require("util")
5local log = require("eina.log")
6local eolian = require("eolian")
7
8local M = {}
9
10local dom
11
12cutil.init_module(function()
13 dom = log.Domain("lualian")
14 if not dom:is_valid() then
15 log.err("Could not register log domain: lualian")
16 error("Could not register log domain: lualian")
17 end
18end, function()
19 dom:unregister()
20 dom = nil
21end)
22
23local lua_kw = {
24 ["and"] = true, ["end"] = true, ["in"] = true, ["local"] = true,
25 ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true,
26 ["then"] = true, ["until"] = true
27}
28
29local kw_t = function(n)
30 if lua_kw[n] then
31 return n .. "_"
32 end
33 return n
34end
35
36local int_builtin = {
37 ["byte" ] = true, ["short"] = true, ["int"] = true, ["long"] = true,
38 ["llong"] = true,
39
40 ["int8" ] = true, ["int16"] = true, ["int32"] = true, ["int64"] = true,
41 ["int128"] = true,
42
43 ["intptr"] = true
44}
45
46local num_others = {
47 ["size" ] = true, ["ssize" ] = true, ["ptrdiff"] = true,
48 ["float"] = true, ["double"] = true
49}
50
51local is_num = function(x)
52 if num_others [x ] then return true end
53 if int_builtin[x ] then return true end
54 if int_builtin["u" .. x] then return true end
55 return false
56end
57
58local known_out = {
59 ["Evas_Coord"] = function(expr) return ("tonumber(%s)"):format(expr) end,
60 ["bool"] = function(expr) return ("((%s) ~= 0)"):format(expr) end,
61 ["char"] = function(expr) return ("string.char(%s)"):format(expr) end
62}
63
64local known_in = {
65 ["Evas_Coord"] = function(expr) return expr end,
66 ["bool"] = function(expr) return expr end
67}
68
69local known_ptr_out = {
70 ["const char"] = function(expr) return ("ffi.string(%s)"):format(expr) end
71}
72
73local known_ptr_in = {
74 ["const char"] = function(expr) return expr end
75}
76
77local convfuncs = {}
78
79local build_calln = function(tps, expr, isin)
80 return expr
81end
82
83local typeconv = function(tps, expr, isin)
84 if tps:type_get() == eolian.type_type.POINTER then
85 local base = tps:base_type_get()
86 local f = (isin and known_ptr_in or known_ptr_out)[base:c_type_get()]
87 if f then return f(expr) end
88 return build_calln(tps, expr, isin)
89 end
90
91 local tp = tps:name_get()
92
93 if is_num(tp) then
94 return isin and expr or ("tonumber(%s)"):format(expr)
95 end
96
97 local f = (isin and known_in or known_out)[tp]
98 if f then
99 return f(expr)
100 end
101
102 return build_calln(tps, expr, isin)
103end
104
105local Node = util.Object:clone {
106 generate = function(self, s)
107 end,
108
109 gen_children = function(self, s)
110 local len = #self.children
111
112 local evs = self.events
113 local evslen
114 if evs then evslen = #evs end
115 local hasevs = evs and evslen > 0
116
117 local hasprops = false
118 local nprops = 0
119 local props = {}
120
121 for i, v in ipairs(self.children) do
122 v.parent_node = self
123 if v.generate_prop then
124 if v:generate_prop(props) then
125 nprops = nprops + 1
126 end
127 hasprops = true
128 end
129 v:generate(s, (not hasevs) and (not hasprops) and (i == len))
130 end
131
132 if hasevs then
133 s:write(" __events = {\n")
134 for i, v in ipairs(evs) do
135 v.parent_node = self
136 v:generate(s, i == evslen)
137 end
138 s:write(" }", hasprops and "," or "", "\n")
139 end
140
141 if hasprops then
142 if hasevs then
143 s:write("\n")
144 end
145 s:write(" __properties = {\n")
146 local pi = 0
147 for k, v in pairs(props) do
148 pi = pi + 1
149 s:write(" [\"", k, "\"] = { ", table.concat(v, ", "),
150 " }", pi ~= nprops and "," or "", "\n")
151 end
152 s:write(" }\n")
153 end
154 end
155}
156
157local Method = Node:clone {
158 __ctor = function(self, meth)
159 self.method = meth
160 end,
161
162 gen_proto = function(self)
163 if self.cached_proto then return self.cached_proto end
164
165 local meth = self.method
166 local pars = meth:parameters_get()
167 local rett = meth:return_type_get(eolian.function_type.METHOD)
168
169 local proto = {
170 name = meth:name_get()
171 }
172 proto.ret_type = rett and rett:c_type_get() or "void"
173 local args, cargs, vargs = { "self" }, {}, {}
174 proto.args, proto.cargs, proto.vargs = args, cargs, vargs
175 local rets = {}
176 proto.rets = rets
177 local allocs = {}
178 proto.allocs = allocs
179
180 proto.full_name = meth:full_c_name_get()
181
182 local dirs = eolian.parameter_dir
183
184 local fulln = proto.full_name
185
186 if rett then
187 rets[#rets + 1] = typeconv(rett, "v", false)
188 end
189
190 for v in pars do
191 local dir, tps, nm = v:direction_get(), v:type_get(), kw_t(v:name_get())
192 local tp = tps:c_type_get()
193 if dir == dirs.OUT or dir == dirs.INOUT then
194 if dir == dirs.INOUT then
195 args[#args + 1] = nm
196 end
197 cargs [#cargs + 1] = tp .. " *" .. nm
198 vargs [#vargs + 1] = nm
199 allocs[#allocs + 1] = { tp, nm, (dir == dirs.INOUT)
200 and typeconv(tps, nm, true) or nil }
201 rets [#rets + 1] = typeconv(tps, nm .. "[0]", false)
202 else
203 args [#args + 1] = nm
204 cargs [#cargs + 1] = tp .. " " .. nm
205 vargs [#vargs + 1] = typeconv(tps, nm, true)
206 end
207 end
208
209 if #cargs == 0 then cargs[1] = "void" end
210
211 self.cached_proto = proto
212
213 return proto
214 end,
215
216 generate = function(self, s, last)
217 local proto = self:gen_proto()
218 s:write(" ", proto.name, proto.suffix or "", " = function(",
219 table.concat(proto.args, ", "), ")\n")
220 s:write( " eo.__do_start(self, __class)\n")
221 for i, v in ipairs(proto.allocs) do
222 s:write(" local ", v[2], " = ffi.new(\"", v[1], "[1]\")\n")
223 end
224 local genv = (proto.ret_type ~= "void")
225 s:write(" ", genv and "local v = " or "", "__lib.",
226 proto.full_name, "(", table.concat(proto.vargs, ", "), ")\n")
227 s:write(" eo.__do_end()\n")
228 if #proto.rets > 0 then
229 s:write(" return ", table.concat(proto.rets, ", "), "\n")
230 end
231 s:write(" end", last and "" or ",", last and "\n" or "\n\n")
232 end,
233
234 gen_ffi = function(self, s)
235 local proto = self:gen_proto()
236 local ret = proto.ret_type
237 if ret:match("[a-zA-Z0-9_]$") then
238 ret = ret .. " "
239 end
240 local cproto = {
241 " ", ret, proto.full_name, "(", table.concat(proto.cargs, ", "),
242 ");\n"
243 }
244 s:write(table.concat(cproto))
245 end
246}
247
248local Property = Method:clone {
249 __ctor = function(self, prop, ftype)
250 self.property = prop
251 self.isget = (ftype == eolian.function_type.PROP_GET)
252 self.ftype = ftype
253 end,
254
255 gen_proto = function(self)
256 if self.cached_proto then return self.cached_proto end
257
258 local prop = self.property
259 local keys = prop:property_keys_get():to_array()
260 local vals = prop:property_values_get():to_array()
261 local rett = prop:return_type_get(self.ftype)
262
263 local proto = {
264 name = prop:name_get(),
265 suffix = (self.isget and "_get" or "_set"),
266 nkeys = #keys,
267 nvals = #vals
268 }
269 proto.ret_type = rett and rett:c_type_get() or "void"
270 local args, cargs, vargs = { "self" }, {}, {}
271 proto.args, proto.cargs, proto.vargs = args, cargs, vargs
272 local rets = {}
273 proto.rets = rets
274 local allocs = {}
275 proto.allocs = allocs
276
277 proto.full_name = prop:full_c_name_get() .. proto.suffix
278
279 local dirs = eolian.parameter_dir
280
281 local fulln = proto.full_name
282 if #keys > 0 then
283 for i, v in ipairs(keys) do
284 local nm = kw_t(v:name_get())
285 local tps = v:type_get()
286 local tp = tps:c_type_get()
287 args [#args + 1] = nm
288 cargs[#cargs + 1] = tp .. " " .. nm
289 vargs[#vargs + 1] = typeconv(tps, nm, true)
290 end
291 end
292 proto.kprop = #keys > 0
293
294 if #vals > 0 then
295 if self.isget then
296 if #vals == 1 and not rett then
297 local tps = vals[1]:type_get()
298 proto.ret_type = tps:c_type_get()
299 rets[#rets + 1] = typeconv(tps, "v", false)
300 else
301 for i, v in ipairs(vals) do
302 local dir, tps, nm = v:direction_get(), v:type_get(),
303 kw_t(v:name_get())
304 local tp = tps:c_type_get()
305 cargs [#cargs + 1] = tp .. " *" .. nm
306 vargs [#vargs + 1] = nm
307 allocs[#allocs + 1] = { tp, nm }
308 rets [#rets + 1] = typeconv(tps, nm .. "[0]", false)
309 end
310 end
311 else
312 for i, v in ipairs(vals) do
313 local dir, tps, nm = v:direction_get(), v:type_get(),
314 kw_t(v:name_get())
315 local tp = tps:c_type_get()
316 args [#args + 1] = nm
317 cargs[#cargs + 1] = tp .. " " .. nm
318 vargs[#vargs + 1] = typeconv(tps, nm, true)
319 end
320 end
321 end
322
323 if #cargs == 0 then cargs[1] = "void" end
324
325 self.cached_proto = proto
326
327 return proto
328 end,
329
330 generate_prop = function(self, props)
331 local proto = self:gen_proto()
332 local prop = props[proto.name]
333 if prop then
334 if self.isget then
335 prop[3] = "true"
336 else
337 prop[4] = "true"
338 end
339 return false
340 else
341 props[proto.name] = { proto.nkeys, math.max(proto.nvals, 1),
342 tostring(self.isget), tostring(not self.isget) }
343 return true
344 end
345 end
346}
347
348local Event = Node:clone {
349 __ctor = function(self, ename, etype, edesc, ecname)
350 self.ename = ename
351 self.etype = etype
352 self.edesc = edesc
353 self.ecname = ecname
354 end,
355
356 generate = function(self, s, last)
357 s:write(" [\"", self.ename, "\"] = __lib.",
358 "_" .. self.ecname, last and "\n" or ",\n")
359 end,
360
361 gen_ffi = function(self, s)
362 s:write(" extern const Eo_Event_Description ",
363 "_" .. self.ecname, ";\n")
364 end
365}
366
367local gen_ns = function(klass, s)
368 local nspaces = klass:namespaces_get():to_array()
369 if #nspaces > 1 then
370 local lnspaces = {}
371 for i = 2, #nspaces do
372 lnspaces[i - 1] = '"' .. nspaces[i]:lower() .. '"'
373 end
374 s:write("local __M = util.get_namespace(M, { ",
375 table.concat(lnspaces, ", "), " })\n")
376 return "__M"
377 else
378 return "M"
379 end
380end
381
382local Mixin = Node:clone {
383 __ctor = function(self, klass, ch, evs)
384 self.klass = klass
385 self.children = ch
386 self.events = evs
387 end,
388
389 generate = function(self, s)
390 dom:log(log.level.INFO, " Generating for interface/mixin: "
391 .. self.klass:full_name_get())
392
393 s:write("ffi.cdef [[\n")
394 self:gen_ffi(s)
395 s:write("]]\n\n")
396
397 gen_ns(self.klass, s)
398
399 s:write("__body = {\n")
400 self:gen_children(s)
401 s:write("}\n")
402 end,
403
404 gen_ffi = function(self, s)
405 s:write(" const Eo_Class *", self.klass:c_get_function_name_get(),
406 "(void);\n")
407 for i, v in ipairs(self.children) do
408 v.parent_node = self
409 v:gen_ffi(s)
410 end
411 if self.events then
412 for i, v in ipairs(self.events) do
413 v.parent_node = self
414 v:gen_ffi(s)
415 end
416 end
417 end
418}
419
420local build_pn = function(fn, pn)
421 if fn == pn then
422 return kw_t(pn)
423 end
424 return fn .. "_" .. pn
425end
426
427local Class = Node:clone {
428 __ctor = function(self, klass, parent, mixins, ch, evs)
429 self.klass = klass
430 self.parent = parent
431 self.interfaces = interfaces
432 self.mixins = mixins
433 self.children = ch
434 self.events = evs
435 end,
436
437 generate = function(self, s)
438 dom:log(log.level.INFO, " Generating for class: "
439 .. self.klass:full_name_get())
440
441 s:write("ffi.cdef [[\n")
442 self:gen_ffi(s)
443 s:write("]]\n\n")
444
445 local mname = gen_ns(self.klass, s)
446
447 s:write("__body = {\n")
448 self:gen_ctor(s)
449 self:gen_children(s)
450 s:write("}\n")
451
452 -- write the constructor
453 s:write(([[
454
455%s.%s = function(parent, ...)
456 return eo.__ctor_common(__class, parent, eo.class_get("%s").__eo_ctor,
457 1, ...)
458end
459]]):format(mname, self.klass:name_get(), self.klass:full_name_get():gsub("%.",
460 "_")))
461 end,
462
463 gen_ffi = Mixin.gen_ffi,
464
465 gen_ctor = function(self, s)
466 local ctors = self.klass:constructors_get()
467 if not ctors then return end
468 -- collect constructor information
469 local ftp = eolian.function_type
470 local dir = eolian.parameter_dir
471 s:write(" __eo_ctor = function(self, ")
472 local cfuncs, parnames, upars = {}, {}, {}
473 for ctor in ctors do
474 local cfunc = ctor:function_get()
475 local cn = cfunc:name_get()
476 local tp = cfunc:type_get()
477 if tp == ftp.PROPERTY or tp == ftp.PROP_SET or tp == ftp.METHOD then
478 cfuncs[#cfuncs + 1] = cfunc
479 if tp ~= ftp.METHOD then
480 for par in cfunc:property_keys_get() do
481 parnames[#parnames + 1] = build_pn(cn, par:name_get())
482 end
483 end
484 for par in cfunc:parameters_get() do
485 if par:direction_get() ~= dir.OUT then
486 parnames[#parnames + 1] = build_pn(cn, par:name_get())
487 end
488 end
489 end
490 end
491 s:write(table.concat(parnames, ", "))
492 if #parnames == 0 then
493 s:write("__func")
494 else
495 s:write(", __func")
496 end
497 s:write(")\n")
498 -- write ctor body
499 local j = 1
500 for i, cfunc in ipairs(cfuncs) do
501 s:write(" self:", cfunc:name_get())
502 if cfunc:type_get() ~= ftp.METHOD then
503 s:write("_set")
504 end
505 s:write("(")
506 local fpars = {}
507 if cfunc:type_get() ~= ftp.METHOD then
508 for par in cfunc:property_keys_get() do
509 fpars[#fpars + 1] = parnames[j]
510 j = j + 1
511 end
512 end
513 for par in cfunc:parameters_get() do
514 if par:direction_get() ~= dir.OUT then
515 fpars[#fpars + 1] = parnames[j]
516 j = j + 1
517 end
518 end
519 s:write(table.concat(fpars, ", "))
520 s:write(")\n")
521 end
522 s:write(" if __func then __func() end\n")
523 s:write(" end")
524 if #self.children > 0 then
525 s:write(",\n\n")
526 else
527 s:write("\n")
528 end
529 end
530}
531
532local File = Node:clone {
533 __ctor = function(self, fname, klass, ch)
534 self.fname = fname:match(".+/(.+)") or fname
535 self.klass = klass
536 self.children = ch
537 end,
538
539 generate = function(self, s)
540 local kls = self.klass
541 local ckls = self.children[1]
542
543 local kn = kls:full_name_get()
544 local par = ckls.parent
545
546 dom:log(log.level.INFO, "Generating for file: " .. self.fname)
547 dom:log(log.level.INFO, " Class : " .. kn)
548
549 local knu = kn:gsub("%.", "_")
550 local paru = par and ('"' .. par:gsub("%.", "_") .. '"') or "nil"
551
552 s:write(([[
553-- EFL LuaJIT bindings: %s (class %s)
554-- For use with Elua; automatically generated, do not modify
555
556local cutil = require("cutil")
557local util = require("util")
558local ffi = require("ffi")
559local eo = require("eo")
560
561local M, __lib = ...
562
563local __class
564local __body
565
566local init = function()
567 __class = __lib.%s()
568 eo.class_register("%s", %s, __body, __class)
569]]):format(self.fname, kn, kls:c_get_function_name_get(), knu, paru))
570
571 if ckls.mixins then for i, v in ipairs(ckls.mixins) do
572 s:write((" eo.class_mixin(\"%s\", \"%s\")\n"):format(knu,
573 v:gsub("%.", "_")))
574 end end
575
576 s:write([[
577end
578
579cutil.init_module(init, function() end)
580
581]])
582
583 self:gen_children(s)
584
585 s:write([[
586
587return M
588]])
589
590 local first = true
591 for name, v in pairs(convfuncs) do
592 if first then
593 print("\nRequired conversion functions:")
594 first = false
595 end
596 print(" " .. name)
597 end
598 end
599}
600
601local gen_contents = function(klass)
602 local cnt = {}
603 local ft = eolian.function_type
604 -- first try properties
605 local props = klass:functions_get(ft.PROPERTY):to_array()
606 for i, v in ipairs(props) do
607 if v:scope_get() == eolian.object_scope.PUBLIC and not v:is_c_only() then
608 local ftype = v:type_get()
609 local fread = (ftype == ft.PROPERTY or ftype == ft.PROP_GET)
610 local fwrite = (ftype == ft.PROPERTY or ftype == ft.PROP_SET)
611 if fwrite then
612 cnt[#cnt + 1] = Property(v, ft.PROP_SET)
613 end
614 if fread then
615 cnt[#cnt + 1] = Property(v, ft.PROP_GET)
616 end
617 end
618 end
619 -- then methods
620 local meths = klass:functions_get(ft.METHOD):to_array()
621 for i, v in ipairs(meths) do
622 if v:scope_get() == eolian.object_scope.PUBLIC and not v:is_c_only() then
623 cnt[#cnt + 1] = Method(v)
624 end
625 end
626 -- events
627 local evs = {}
628 local events = klass:events_get():to_array()
629 for i, v in ipairs(events) do
630 evs[#evs + 1] = Event(v:name_get(), v:type_get(), v:description_get(),
631 v:c_name_get())
632 end
633 return cnt, evs
634end
635
636local gen_mixin = function(klass)
637 return Mixin(klass, gen_contents(klass))
638end
639
640local gen_class = function(klass)
641 local inherits = klass:inherits_get()
642 local parent
643 local mixins = {}
644 local ct = eolian.class_type
645 for v in inherits do
646 local tp = eolian.class_get_by_name(v):type_get()
647 if tp == ct.REGULAR or tp == ct.ABSTRACT then
648 if parent then
649 error(klass:full_name_get() .. ": more than 1 parent!")
650 end
651 parent = v
652 elseif tp == ct.MIXIN or tp == ct.INTERFACE then
653 mixins[#mixins + 1] = v
654 else
655 error(klass:full_name_get() .. ": unknown inherit " .. v)
656 end
657 end
658 return Class(klass, parent, mixins, gen_contents(klass))
659end
660
661M.include_dir = function(dir)
662 if not eolian.directory_scan(dir) then
663 error("Failed including directory: " .. dir)
664 end
665end
666
667M.load_eot_files = function()
668 return eolian.all_eot_files_parse()
669end
670
671M.system_directory_scan = function()
672 return eolian.system_directory_scan()
673end
674
675M.generate = function(fname, fstream)
676 if not eolian.eo_file_parse(fname) then
677 error("Failed parsing file: " .. fname)
678 end
679 if not eolian.database_validate() then
680 error("Failed validating database.")
681 end
682 local sfn = fname:match(".*[\\/](.+)$") or fname
683 local klass = eolian.class_get_by_file(sfn)
684 local tp = klass:type_get()
685 local ct = eolian.class_type
686 local cl
687 if tp == ct.MIXIN or tp == ct.INTERFACE then
688 cl = gen_mixin(klass)
689 elseif tp == ct.REGULAR or tp == ct.ABSTRACT then
690 cl = gen_class(klass)
691 else
692 error(klass:full_name_get() .. ": unknown type")
693 end
694 File(fname, klass, { cl }):generate(fstream or io.stdout)
695end
696
697return M
diff --git a/src/bin/elua/modules/xgettext/generator.lua b/src/bin/elua/modules/xgettext/generator.lua
deleted file mode 100644
index 3854f2380b..0000000000
--- a/src/bin/elua/modules/xgettext/generator.lua
+++ /dev/null
@@ -1,128 +0,0 @@
1-- Elua xgettext: generator
2
3local lexer = require("xgettext.lexer")
4local parser = require("xgettext.parser")
5
6local tconc = table.concat
7
8local gen_comment = function(cmt)
9 local cmtret = {}
10 for line in cmt:gmatch("([^\n]+)") do
11 cmtret[#cmtret + 1] = "#. " .. line:match("^%s*(.+)$")
12 end
13 return tconc(cmtret, "\n")
14end
15
16local gen_message = function(str)
17 local mline = not not str:find("\n")
18 if not mline then
19 return '"' .. str .. '"'
20 end
21 local ret = { '""' }
22 for line in cmt:gmatch("([^\n]+)") do
23 ret[#ret + 1] = '"' .. line .. '\\n"'
24 end
25 return tconc(ret, "\n")
26end
27
28local gen_msgstr = function(str, prefix, suffix)
29 if not prefix and not suffix then
30 return '""'
31 end
32 return gen_message(tconc(prefix
33 and { prefix, str, suffix } or { str, suffix }))
34end
35
36local cmp_msgs = function(msg1, msg2)
37 return msg1[1] == msg2[1] and msg1.context == msg2.context
38end
39
40local new_msg = function(msg)
41 local copyflags = {}
42 for i, v in ipairs(msg.flags) do copyflags[#copyflags + 1] = v end
43 return {
44 msg[1], msg[2], msg.context, comments = { msg.comment },
45 xcomment = msg.xcomment, lines = { msg.line }, flags = copyflags
46 }
47end
48
49local gen_grouped_messages = function(ps)
50 local msg = ps()
51 local ret = { new_msg(msg) }
52 msg = ps()
53 while msg do
54 local found = false
55 for i, amsg in ipairs(ret) do
56 if cmp_msgs(msg, amsg) then
57 if not amsg[2] then
58 amsg[2] = msg[2]
59 end
60 amsg.lines [#amsg.lines + 1] = msg.line
61 amsg.comments[#amsg.comments + 1] = msg.comment
62 for i, v in ipairs(msg.flags) do
63 amsg.flags[#amsg.flags + 1] = v
64 end
65 found = true
66 break
67 end
68 end
69 if not found then
70 ret[#ret + 1] = new_msg(msg)
71 end
72 msg = ps()
73 end
74 for i, msg in ipairs(ret) do
75 msg.flags = table.uniq(msg.flags)
76 end
77 return ret
78end
79
80local gen_line_info = function(chunkname, lines)
81 local cname = lexer.source_to_msg(chunkname)
82 local linestrs = {}
83 local linestr = "#:"
84 local i = 1
85 while i <= #lines do
86 local tmps = linestr .. tconc { " ", cname, ":", lines[i] }
87 if #tmps > 80 then
88 linestrs[#linestrs + 1] = linestr
89 linestr = "#:"
90 else
91 linestr = tmps
92 i = i + 1
93 end
94 end
95 linestrs[#linestrs + 1] = linestr
96 return tconc(linestrs, "\n")
97end
98
99return { init = function(chunkname, input, keywords, flags, add_loc, opts)
100 local rets = {}
101 for i, msg in ipairs(gen_grouped_messages(parser.init(chunkname,
102 input, keywords, flags, opts))) do
103 local ret = {}
104 if msg.xcomment then
105 ret[#ret + 1] = gen_comment(msg.xcomment)
106 end
107 for i, cmt in ipairs(msg.comments) do
108 ret[#ret + 1] = gen_comment(cmt)
109 end
110 if msg.context then
111 ret[#ret + 1] = "msgctxt " .. gen_message(msg.context)
112 end
113 if add_loc then
114 ret[#ret + 1] = gen_line_info(chunkname, msg.lines)
115 end
116 ret[#ret + 1] = "msgid " .. gen_message(msg[1])
117 local spf, ssf = opts["m"], opts["M"]
118 if msg[2] then
119 ret[#ret + 1] = "msgid_plural " .. gen_message(msg[2])
120 ret[#ret + 1] = "msgstr[0] " .. gen_msgstr(msg[1], spf, ssf)
121 ret[#ret + 1] = "msgstr[1] " .. gen_msgstr(msg[2], spf, ssf)
122 else
123 ret[#ret + 1] = "msgstr " .. gen_msgstr(msg[1], spf, ssf)
124 end
125 rets[#rets + 1] = tconc(ret, "\n")
126 end
127 return tconc(rets, "\n\n")
128end }
diff --git a/src/bin/elua/modules/xgettext/lexer.lua b/src/bin/elua/modules/xgettext/lexer.lua
deleted file mode 100644
index 0c8ebd5d11..0000000000
--- a/src/bin/elua/modules/xgettext/lexer.lua
+++ /dev/null
@@ -1,353 +0,0 @@
1-- Elua xgettext: lexer
2
3local yield = coroutine.yield
4local tconc = table.concat
5
6local keywords = {
7 ["and" ] = true, ["break" ] = true, ["do" ] = true, ["else"] = true,
8 ["elseif" ] = true, ["end" ] = true, ["false"] = true, ["for" ] = true,
9 ["function"] = true, ["goto" ] = true, ["if" ] = true, ["in" ] = true,
10 ["local" ] = true, ["nil" ] = true, ["not" ] = true, ["or" ] = true,
11 ["repeat" ] = true, ["return"] = true, ["then" ] = true, ["true"] = true,
12 ["until" ] = true, ["while" ] = true
13}
14
15local tokens = {
16 "..", "...", "==", ">=", "<=", "~=", "::",
17 "<name>", "<string>", "<number>", "<eof>"
18}
19
20local max_custom_len = 79
21local max_fname_len = 72
22local max_str_len = 63
23
24local source_to_msg = function(source)
25 local c = source:sub(1, 1)
26 local srclen = #source
27 if c == "@" then
28 if srclen <= (max_fname_len + 1) then
29 return source:sub(2)
30 else
31 return "..." .. source:sub(srclen - max_fname_len + 1)
32 end
33 elseif c == "=" then
34 return source:sub(2, max_custom_len + 1)
35 else
36 return '[string "' .. source:sub(1, max_str_len)
37 .. ((srclen > max_str_len) and '..."]' or '"]')
38 end
39end
40
41local lex_error = function(ls, msg, tok)
42 msg = ("%s:%d: %s"):format(source_to_msg(ls.source), ls.line_number, msg)
43 if tok then
44 msg = msg .. " near '" .. tok .. "'"
45 end
46 error(msg, 0)
47end
48
49local syntax_error = function(ls, msg)
50 lex_error(ls, msg, ls.token.value or ls.token.name)
51end
52
53local next_char = function(ls)
54 local c = ls.reader()
55 ls.current = c
56 return c
57end
58
59local next_line = function(ls, cs)
60 local old = ls.current
61 assert(old == "\n" or old == "\r")
62 local c = next_char(ls)
63 if (c == "\n" or c == "\r") and c ~= old then
64 c = next_char(ls)
65 end
66 ls.line_number = ls.line_number + 1
67 return c
68end
69
70local read_number = function(ls, beg)
71 local buf = {}
72 if beg then buf[1] = beg end
73 local c = ls.current
74 while c == "." or c:match("%d") do
75 buf[#buf + 1] = c
76 c = next_char(ls)
77 end
78 if c == "e" or c == "E" then
79 buf[#buf + 1] = c
80 c = next_char(ls)
81 if c == "+" or c == "-" then
82 buf[#buf + 1] = c
83 c = next_char(ls)
84 end
85 end
86 while c:match("%w") do
87 buf[#buf + 1] = c
88 c = next_char(ls)
89 end
90 local str = tconc(buf)
91 if not tonumber(str) then
92 lex_error(ls, "malformed number", str)
93 end
94 return str
95end
96
97local skip_sep = function(ls, buf)
98 local cnt = 0
99 local s = ls.current
100 assert(s == "[" or s == "]")
101 buf[#buf + 1] = s
102 local c = next_char(ls)
103 while c == "=" do
104 buf[#buf + 1] = c
105 c = next_char(ls)
106 cnt = cnt + 1
107 end
108 return c == s and cnt or ((-cnt) - 1)
109end
110
111local read_long_string = function(ls, sep, cmt)
112 local buf = {}
113 local c = next_char(ls)
114 if c == "\n" or c == "\r" then c = next_line(ls) end
115 while true do
116 if not c then
117 lex_error(ls, tok and cmt and "unfinished long comment"
118 or "unfinished long string", "<eof>")
119 elseif c == "]" then
120 local tbuf = {}
121 if skip_sep(ls, tbuf) == sep then
122 c = next_char(ls)
123 break
124 else
125 buf[#buf + 1] = tconc(tbuf)
126 end
127 c = ls.current
128 else
129 buf[#buf + 1] = c
130 c = next_char(ls)
131 end
132 end
133 return tconc(buf)
134end
135
136local read_string = function(ls)
137 local delim = ls.current
138 local buf = {}
139 local c = next_char(ls)
140 while c ~= delim do
141 if not c then lex_error(ls, "unfinished string", "<eof>")
142 elseif c == "\n" or c == "\r" then
143 lex_error(ls, "unfinished string", tconc(buf))
144 elseif c == "\\" then
145 c = next_char(ls)
146 if c == "n" then
147 buf[#buf + 1] = "\n"
148 else
149 buf[#buf + 1] = "\\" .. c
150 end
151 c = next_char(ls)
152 else
153 buf[#buf + 1] = c
154 c = next_char(ls)
155 end
156 end
157 next_char(ls)
158 return tconc(buf)
159end
160
161local last_comment = false
162
163local match_comment = function(ls, cmt)
164 cmt = cmt:match("^%s*(.+)%s*$")
165 if ls.flags[cmt] then
166 return "<flagcomment>", cmt
167 end
168 local lcmt = ls.lex_cmt
169 if not lcmt then return nil end
170 if type(lcmt) ~= "string" then
171 return "<comment>", cmt
172 end
173 lcmt = lcmt:match("^%s*(.+)%s*$")
174 if last_comment or cmt:sub(1, #lcmt) == lcmt then
175 return "<comment>", cmt
176 end
177 return nil
178end
179
180local lex_tbl = {
181 ["\n"] = function(ls) next_line(ls) end,
182 [" " ] = function(ls) next_char(ls) end,
183 ["-" ] = function(ls)
184 local c = next_char(ls)
185 if c ~= "-" then
186 return "-"
187 end
188 c = next_char(ls)
189 if c == "[" then
190 local sep = skip_sep(ls, {})
191 if sep >= 0 then
192 return match_comment(ls, read_long_string(ls, sep, true))
193 end
194 end
195 local buf = {}
196 while ls.current and ls.current ~= "\n" and ls.current ~= "\r" do
197 buf[#buf + 1] = ls.current
198 next_char(ls)
199 end
200 return match_comment(ls, tconc(buf))
201 end,
202 ["[" ] = function(ls)
203 local buf = {}
204 local sep = skip_sep(ls, {})
205 if sep >= 0 then
206 return "<string>", read_long_string(ls, sep)
207 elseif sep == -1 then
208 return "["
209 else
210 lex_error(ls, "invalid long string delimiter", tconc(buf))
211 end
212 end,
213 ["="] = function(ls)
214 local oc = ls.current
215 local c = next_char(ls)
216 if c ~= "=" then return c
217 else next_char(ls); return c .. "=" end
218 end,
219 ['"' ] = function(ls)
220 return "<string>", read_string(ls)
221 end,
222 ["." ] = function(ls)
223 local c = next_char(ls)
224 if c == "." then
225 c = next_char(ls)
226 if c == "." then
227 next_char(ls)
228 return "..."
229 else
230 return ".."
231 end
232 elseif c:match("%d") then
233 return "<number>", read_number(ls, ".")
234 else
235 return "."
236 end
237 end,
238 ["0" ] = function(ls)
239 return "<number>", read_number(ls)
240 end
241}
242lex_tbl["\r"] = lex_tbl["\n"]
243lex_tbl["\f"] = lex_tbl[" " ]
244lex_tbl["\t"] = lex_tbl[" " ]
245lex_tbl["\v"] = lex_tbl[" " ]
246lex_tbl["<" ] = lex_tbl["=" ]
247lex_tbl[">" ] = lex_tbl["=" ]
248lex_tbl["~" ] = lex_tbl["=" ]
249lex_tbl["'" ] = lex_tbl['"' ]
250lex_tbl["1" ] = lex_tbl["0" ]
251lex_tbl["2" ] = lex_tbl["0" ]
252lex_tbl["3" ] = lex_tbl["0" ]
253lex_tbl["4" ] = lex_tbl["0" ]
254lex_tbl["5" ] = lex_tbl["0" ]
255lex_tbl["6" ] = lex_tbl["0" ]
256lex_tbl["7" ] = lex_tbl["0" ]
257lex_tbl["8" ] = lex_tbl["0" ]
258lex_tbl["9" ] = lex_tbl["0" ]
259
260local lex_default = function(ls)
261 local c = ls.current
262 if c == "_" or c:match("%a") then
263 local buf = {}
264 repeat
265 buf[#buf + 1] = c
266 c = next_char(ls)
267 if not c then break end
268 until not (c == "_" or c:match("%w"))
269 local str = tconc(buf)
270 if keywords[str] then
271 return str
272 end
273 return "<name>", str
274 else
275 next_char(ls)
276 return c
277 end
278end
279
280local lex_main = function(ls)
281 yield()
282 while true do
283 local c = ls.current
284 if c == nil then
285 return "<eof>"
286 end
287 local opt = lex_tbl[c]
288 if opt then
289 local t, v = opt(ls)
290 if t then
291 last_comment = t == "<comment>"
292 yield(t, v)
293 end
294 else
295 last_comment = false
296 yield(lex_default(ls))
297 end
298 end
299end
300
301local strstream = function(str)
302 return str:gmatch(".")
303end
304
305local skip_bom = function(rdr)
306 local c = rdr()
307 if c ~= 0xEF then return c end
308 c = rdr()
309 if c ~= 0xBB then return c end
310 c = rdr()
311 if c ~= 0xBF then return c end
312 return rdr()
313end
314
315local skip_shebang = function(rdr)
316 local c = skip_bom(rdr)
317 if c == 35 then -- #
318 repeat
319 c = rdr()
320 until not c or is_newline(c)
321 local e = c
322 c = rdr()
323 if (e == 10 and c == 13) or (e == 13 and c == 10) then -- LF, CR
324 c = rdr()
325 end
326 end
327 return c
328end
329
330local ls_get = function(self)
331 local tok = self.token
332 tok.name, tok.value = self.coro()
333 return tok
334end
335
336return { init = function(chunkname, input, flags, opts)
337 local reader = type(input) == "string" and strstream(input) or input
338 local current = skip_shebang(reader)
339 local ls = {
340 reader = reader,
341 token = {},
342 source = chunkname,
343 current = current,
344 line_number = 1,
345 get = ls_get,
346 lex_cmt = opts["c"],
347 flags = flags.valid
348 }
349 local coro = coroutine.wrap(lex_main, ls)
350 ls.coro = coro
351 coro(ls)
352 return ls
353end, syntax_error = syntax_error, source_to_msg = source_to_msg }
diff --git a/src/bin/elua/modules/xgettext/parser.lua b/src/bin/elua/modules/xgettext/parser.lua
deleted file mode 100644
index 1d6c252701..0000000000
--- a/src/bin/elua/modules/xgettext/parser.lua
+++ /dev/null
@@ -1,267 +0,0 @@
1-- Elua xgettext: parser
2
3local util = require("util")
4local lexer = require("xgettext.lexer")
5
6local syntax_error = lexer.syntax_error
7
8local yield = coroutine.yield
9local tconc = table.concat
10
11local String = util.Object:clone {
12 __ctor = function(self, sing, plu, ctx, cmt, xcmt, flags, line)
13 self.singular = sing
14 self.plural = plu
15 self.context = ctx
16 self.comment = cmt
17 self.xcomment = xcmt
18 self.flags = flags
19 self.line = line
20 end,
21
22 guess_flags = function(self, flags)
23 end,
24
25 gen_flags = function(self)
26 local flags = {}
27 for i, v in ipairs(self.flags) do flags[i] = v end
28 if self.parent then
29 self.parent:add_flags(self, flags)
30 end
31 self:guess_flags(flags)
32 return flags
33 end,
34
35 generate = function(self)
36 yield {
37 self.singular, self.plural, context = self.context,
38 comment = self.xcomment, comment = self.comment, line = self.line,
39 flags = self:gen_flags()
40 }
41 end
42}
43
44local Call = util.Object:clone {
45 __ctor = function(self, flags, args)
46 self.flags = flags
47 self.args = args
48 for i, v in ipairs(args) do
49 v.parent = self
50 end
51 end,
52
53 add_flags = function(self, argo, flags, flagstr)
54 local argn
55 for i, a in ipairs(self.args) do
56 if a == argo then
57 argn = i
58 break
59 end
60 end
61 for i, flag in ipairs(self.flags) do
62 if flag[1] == argn then
63 local pass = flag[2]:match("^pass%-(.+)$")
64 if not flagstr or flagstr == pass or flagstr == flag[2] then
65 if pass then
66 self.parent:add_flags(self, flags, pass)
67 else
68 flags[#flags + 1] = flag[2]
69 end
70 end
71 end
72 end
73 end,
74
75 generate = function(self)
76 for i, v in ipairs(self.args) do
77 v:generate()
78 end
79 end
80}
81
82local saved_flagcomments = {}
83local saved_comments = {}
84
85local check_match = function(ls, a, b, line)
86 if ls.token.name ~= a then
87 if line == ls.line_number then
88 syntax_error(ls, "'" .. a .. "' expected")
89 else
90 syntax_error(ls, "'" .. a .. "' expected (to close '" .. b
91 .. "' at line " .. line .. ")")
92 end
93 end
94end
95
96local parse_simple_expr = function(ls)
97 local tok = ls.token
98 local tn = tok.name
99 if tn == "(" then
100 local line = ls.line_number
101 ls:get()
102 local v, tn = parse_expr(ls)
103 check_match(ls, ")", "(", line)
104 ls:get()
105 return v, tn
106 elseif tn == "<string>" or tn == "<number>" or tn == "<name>" then
107 local v = tok.value
108 ls:get()
109 return v, tn
110 else
111 syntax_error(ls, "unexpected symbol")
112 end
113end
114
115local parse_expr
116parse_expr = function(ls)
117 local tok = ls.token
118 local line = ls.line_number
119 local lhs, tn = parse_simple_expr(ls)
120 while true do
121 if tok.name ~= ".." then break end
122 if tn ~= "<string>" and tn ~= "<number>" then
123 syntax_error(ls, "invalid lhs for concat")
124 end
125 tn = "<string>"
126 ls:get()
127 local rhs, rtn = parse_expr(ls)
128 if rtn ~= "<string>" and rtn ~= "<number>" then
129 syntax_error(ls, "invalid rhs for concat")
130 end
131 lhs = lhs .. rhs
132 end
133 return lhs, tn
134end
135
136local parse_arglist = function(ls)
137 local tok = ls.token
138 local rets = {}
139 while true do
140 rets[#rets + 1] = { parse_expr(ls) }
141 if tok.name == "," then
142 ls:get()
143 else
144 break
145 end
146 end
147 return rets
148end
149
150local parse_kwcall = function(ls)
151 local tok = ls.token
152 if tok.name == "(" then
153 local line = ls.line_number
154 ls:get()
155 if tok.name == ")" then
156 ls:get()
157 return {}
158 end
159 local al = parse_arglist(ls)
160 check_match(ls, ")", "(", line)
161 ls:get()
162 return al
163 elseif tok.name == "<string>" then
164 local v = tok.value
165 ls:get()
166 return { { v, "<string>" } }
167 else
168 return nil
169 end
170end
171
172local parse_kw = function(ls, keywords)
173 local tok = ls.token
174 local line = ls.line_number
175 local kw = keywords[tok.value]
176 ls:get()
177 local args = parse_kwcall(ls)
178 local n1, n2, cx, an = kw[1], kw[2], kw.context, kw.argnum
179 local n1arg, n2arg, cxarg = args[n1], args[n2], args[cx]
180 local n1argt, n2argt, cxargt = n1arg and (n1arg[2] ~= "<name>"),
181 n2arg and (n2arg[2] ~= "<name>"),
182 cxarg and (cxarg[2] ~= "<name>")
183 if not args then return false end
184 if an and #args ~= an then return false end
185 if #args < n1 then return false end
186 if n2 and #args < n2 then return false end
187 if cx and #args < cx then return false end
188 if not n1argt then return false end
189 if n2 and not n2argt then return false end
190 if cx and not cxargt then return false end
191 local sc = saved_comments
192 saved_comments = {}
193 sc = tconc(sc, "\n")
194 local fsc = saved_flagcomments
195 saved_flagcomments = {}
196 return String(n1arg[1], n2 and n2arg[1] or nil, cx and cxarg[1] or nil,
197 sc, kw.xcomment, fsc, line)
198end
199
200local parse_fg = function(ls, flags, keywords)
201 error("NYI")
202end
203
204local parse = function(ls, keywords, flags)
205 yield()
206 local tok = ls.token
207 while tok.name ~= "<eof>" do
208 if tok.name == "<comment>" then
209 saved_comments[#saved_comments + 1] = tok.value
210 ls:get()
211 elseif tok.name == "<flagcomment>" then
212 saved_flagcomments[#saved_flagcomments + 1] = tok.value
213 ls:get()
214 elseif tok.name == "<name>" then
215 if keywords[tok.value] then
216 local status, str = pcall(parse_kw, keywords)
217 if status and str then
218 str:generate()
219 end
220 elseif flags[tok.value] then
221 local status, call = pcall(parse_fg, flags, keywords)
222 if status then
223 call:generate()
224 end
225 else
226 ls:get()
227 end
228 else
229 ls:get()
230 end
231 end
232end
233
234local parse_all = function(ls)
235 yield()
236 local tok = ls.token
237 while tok.name ~= "<eof>" do
238 if tok.name == "<comment>" then
239 saved_comments[#saved_comments + 1] = tok.value
240 ls:get()
241 elseif tok.name == "<flagcomment>" then
242 saved_flagcomments[#saved_flagcomments + 1] = tok.value
243 ls:get()
244 elseif tok.name == "<string>" then
245 local line = ls.line_number
246 local val = tok.value
247 local sc = saved_comments
248 saved_comments = {}
249 sc = tconc(sc, "\n")
250 local fsc = saved_flagcomments
251 saved_flagcomments = {}
252 ls:get()
253 String(val, nil, nil, sc, nil, fsc, line):generate()
254 else
255 ls:get()
256 end
257 end
258end
259
260return { init = function (chunkname, input, keywords, flags, opts)
261 local ls = lexer.init(chunkname, input, flags, opts)
262 ls:get()
263 local coro = coroutine.wrap(opts["a"] and parse_all or parse, ls,
264 keywords, flags)
265 coro(ls, keywords)
266 return coro
267end }