/
tolua_common_a.pkg
399 lines (341 loc) · 14.2 KB
/
tolua_common_a.pkg
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*****************************************************************************
Freeciv - Copyright (C) 2005 - The Freeciv Project
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*****************************************************************************/
/*****************************************************************************
ADVERTISEMENT: do not attempt to change the name of the API functions.
They may be in use in Lua scripts in savefiles, so once released, the
name and signature cannot change shape even in new major versions of
Freeciv, until the relevant save format version can no longer be loaded.
If you really like to change a function name, be sure to keep also the
old one running.
*****************************************************************************/
$#ifdef HAVE_CONFIG_H
$#include <fc_config.h>
$#endif
/* common/scriptcore */
$#include "api_common_intl.h"
$#include "api_common_utilities.h"
$#include "luascript.h"
$#include "luascript_types.h"
/* Classes. */
struct Nonexistent {
};
$[
-- Nonexistent methods.
function Nonexistent:exists()
return false
end
$]
/* Intl module. */
const char *api_intl__
@ _ (lua_State *L, const char *untranslated);
const char *api_intl_N_
@ N_ (lua_State *L, const char *untranslated);
const char *api_intl_Q_
@ Q_ (lua_State *L, const char *untranslated);
const char *api_intl_PL_
@ PL_ (lua_State *L, const char *singular, const char *plural, int n);
/* Log module. */
module log {
module level {
enum log_level {
LOG_FATAL @ FATAL,
LOG_ERROR @ ERROR,
LOG_WARN @ WARN,
LOG_NORMAL @ NORMAL,
LOG_VERBOSE @ VERBOSE,
LOG_DEBUG @ DEBUG
};
}
void api_utilities_log_base
@ base (lua_State *L, int log_level, const char *message);
void api_utilities_deprecation_warning
@ deprecation_warning(lua_State *L, char *method, char *replacement, char *deprecated_since);
}
$[
-- Log module implementation.
function log.fatal(fmt, ...)
log.base(log.level.FATAL, string.format(fmt, ...))
end
function log.error(fmt, ...)
log.base(log.level.ERROR, string.format(fmt, ...))
end
function log.warn(fmt, ...)
log.base(log.level.WARN, string.format(fmt, ...))
end
function log.normal(fmt, ...)
log.base(log.level.NORMAL, string.format(fmt, ...))
end
function log.verbose(fmt, ...)
log.base(log.level.VERBOSE, string.format(fmt, ...))
end
function log.debug(fmt, ...)
log.base(log.level.DEBUG, string.format(fmt, ...))
end
-- ***************************************************************************
-- Old logging functions
-- Deprecated. New logging functions are listed above.
-- ***************************************************************************
function error_log(msg)
log.error(msg)
end
function debug_log(msg)
log.debug(msg)
end
$]
/* Utilities module. */
int api_utilities_random
@ random (lua_State *L, int min, int max);
const char *api_utilities_fc_version
@ fc_version (lua_State *L);
const char *api_utilities_name_version
@ name_version (lua_State *L);
const char *api_utilities_comparable_version
@ comparable_version (lua_State *L);
const char *api_utilities_version_string
@ version_string (lua_State *L);
int api_utilities_versions_compare
@ versions_compare (lua_State *L, const char *ver1, const char *ver2);
$[
-- ***************************************************************************
-- Dump the state of user scalar variables to a Lua code string.
-- ***************************************************************************
function _freeciv_state_dump()
local res = ''
for k, v in pairs(_G) do
if k == '_VERSION' then
-- ignore _VERSION variable.
elseif type(v) == 'boolean'
or type(v) == 'number' then
-- FIXME: depending on locale, the number formatting can use a
-- comma as radix point, whereas we always want '.'. HRM #722300
local rvalue = tostring(v)
res = res .. k .. '=' .. rvalue .. '\n'
elseif type(v) == 'string' then
local rvalue = string.format('%q', v)
res = res .. k .. '=' .. rvalue .. '\n'
elseif type(v) == 'userdata' then
local method = string.lower(tolua.type(v))
res = res .. k .. '=find.' .. method
if method == 'city' or method == 'unit' then
res = res .. '(nil,' .. string.format("%d", v.id) .. ')'
elseif type(v.rule_name) == 'function' then
res = res .. '(' .. string.format("'%s'", v.rule_name(v)) .. ')'
elseif type(v.name) == 'function' then
res = res .. '(' .. string.format("'%s'", v.name(v)) .. ')'
elseif v.name ~= nil then
res = res .. '(' .. string.format("'%s'", v.name) .. ')'
elseif v.id then
res = res .. '(' .. string.format("%d", v.id) .. ')'
else
res = res .. '()'
end
res = res .. '\n'
end
end
return res
end
-- ***************************************************************************
-- List all defined lua variables (functions, tables)
-- ***************************************************************************
function listenv()
fce(_G)
end
-- ***************************************************************************
-- List environment.
-- Implementation by nef:
-- https://forum.freeciv.org/f/viewtopic.php?f=14&t=91972&p=103953#p103948
-- nef version 2 20211221
--
-- Arguments: (all for advanced use)
-- arg_1. datum is the top level datum to be examined (usually a table).
-- Default: _ENV.
-- arg_2. depth: provides a way to limit the depth of sub table parsing.
-- If this is an INTEGER >= 0 then the parsing will be limited
-- to that depth. Zero will mean NO parsing of the table.
-- One means just the table specified. Default: -1 (no limit).
-- arg_3. prefix: can be used to provide leading characters on each line
-- of the printout. Default (if prefix is not a string): null string.
-- arg_4. condition to enable parsing of the metatable for data of
-- type string. Default nil (no parsing).
-- ***************************************************************************
function fce(datum, depth, prefix, string_parse)
-- The corountinue is responsible for analysing the data and preparing the printout;
-- one datum and attached chain of metadata per thread.
--
-- The mainline code is responsible for printing the printout with some extra
-- detail in the desired order, and parsing the table hierarchy.
--************* COROUTINE UPVALUES ********************
local s = " %s ";
local q = " %q "
local function q_fmt (d) return ("%q"):format(d) end
local function s_fmt (d) return ("%s"):format(d) end
local lists = setmetatable ( {}, {
__index = function (t, T) t[T] = {n = 0}; return t[T] end;
} )
local function tabular (datum, Type, id) -- upvalue: lists
local list = lists [Type]; local inx = list [datum]
if inx then return inx.."=", Type
elseif id then list [datum] = id; list.n = math.max(id, list.n)
return id, Type, ""
else inx = list.n +1; list [datum] = inx; list.n = inx;
return inx, Type, inx
end
end
local TT = setmetatable ( { -- upvalues: tabular, q_fmt, s_fmt
number = function (d, T) return s_fmt(d), math.type(d) end;
string = function (d, T)
local str, count, inx, new = d:gsub ("[%c\x80-\xFF]", "*")
if count ~= 0 then inx, T, new = tabular(d, "STRING"..count) end
return q_fmt(str)..(inx and " ".. inx or ""),
d:find("^[_%a][_%a%d]*$") and "identifier" or T,
nil -- change this (inter alia) for a detail line
end;
["function"] = tabular;
thread = tabular;
table = tabular;
userdata = function (d, T) T = tolua.type(d); local id = d.id;
if d.rule_name then return("%s %q "):format(id,d:rule_name()),T
else return tabular (d, T, id)
end
end;
}, {
__index = function () return (function (d,T) return q_fmt(d),T end) end;
__call = function (t, d) local T = type(d); return t [T] (d, T) end;
} ) -- TT
local mt = " meta %s "
local function do_datum (text, datum, Type) -- upvalues: TT, mt
-- local meta, val, T, new = datum and getmetatable (datum);
local meta, val, T, new = getmetatable (datum);
-- if meta
if type(meta) ~= "nil"
then val, T, new = TT(meta); text = text..mt:format(T)..val
end;
coroutine.yield (text, datum, Type);
if new then return meta, val, T end
end
local function co (text, d1, prefix) -- upvalues: TT, mt, do_datum
local v1, T1, new = TT(d1) -- prepare k,v line part
local d2, v2, T2 =
do_datum (text.." ("..T1..") "..v1, d1, T1)
if new then -- prepare hdr/detail then 'real' table, etc.
coroutine.yield (prefix..s:format(d1)..new, d1, T1)
end
-- prepare chain of 'meta' hdr&table
while d2 do d2, v2, T2 =
do_datum (prefix..mt:format(d2)..v2, d2, T2)
end
end -- co()
--************* MAINLINE UPVALUES and locals ********************
local printit = log.error
local function part_0 (datum, co_text) -- upvalue: co (coroutine section)
return {co_t = coroutine.wrap(co); datum = datum; co_text = co_text;}
end
local function part_1 (co_s, prefix)
-- the co_t args only used for k,v (no return values from yield)
return co_s.co_t (co_s.co_text, co_s.datum, prefix)
end
local details -- forward declaration
local function part_x (co_ss, depth, prefix)--upvalues: part_1, printit, details
local text, sep = prefix, ""
for c, co_s in ipairs (co_ss) -- c not used
do text, sep = text..sep..part_1 (co_s, prefix), "; "
end; printit (text) -- print the k, v line
for c, co_s in ipairs (co_ss) do -- c not used
for text, datum, Type in part_1, co_s, "" do -- print the tables etc.
details [Type] (prefix..text, datum, depth, prefix)
end
end -- in ipairs
end -- part_x ()
local MF = math.floor
local function pp_tile (d) -- upvalue: MF
return (" (%s,%s) "):format( MF(d.x), MF(d.y) )
end
details = setmetatable ({ --upvalues: printit, part_0, part_x
table = function (text, d, depth, prefix)
if depth == 0
then printit (text.." limit reached")
else printit (text); for key, val in next, d, nil do
part_x({ part_0 (key, "key"); part_0 (val, "value"); },
depth -1, prefix..".")
end -- in next
end
end;
thread = function (text, d)
printit (text..s:format(d)..coroutine.status(d)..
-- ( coroutine.is_yieldable(d) and "+" or "-") ..
" " )
end;
Direction = function (text, d) end;
Tile = function (text, d) printit (text..pp_tile (d) ) end;
Player = function (text, d) printit (text..(" %s%s (%s:%s)"):
format( d.nation, d.ai_controlled and "-" or "+",
MF(d:num_cities()), MF(d:num_units())) )
end;
City = function (text, d) printit (text..(" %q (%s) %s %s"):
format( d.name, d.size, d.owner, d.tile)..pp_tile (d.tile) )
end;
Unit = function (text, d) printit (text..(" %s, %s %s"):
format( d.utype, d.owner, d:get_homecity() or "no home city") )
end;
-- disable the next line to print function detail lines (memory address)
["function"] = function (text, d) end;
},{
__index = function (t, T) return printit end;
}) -- details
--************* MAINLINE SCRIPT ********************
-- locals: string_parse; tabular (coroutine section)
if string_parse then else tabular(getmetatable(""), "table") end -- arg_4
-- note that the k, v is only the v; k is not available here
-- locals: datum, depth, prefix, part_0, part_x; lists (coroutine section)
-- part_x ({ part_0 (datum or _ENV, datum and "head" or "_ENV") }, -- arg_1
part_x ({ part_0 (datum, "head" )}, -- arg_1
type (depth) == "number" and depth or -1, -- arg_2
type (prefix) == "string" and prefix or "") -- arg_3
return lists
end
-- ***************************************************************************
-- Flexible "constant" implementation
-- source: http://developer.anscamobile.com/code/\
-- universal-constants-module-very-easy-usage
-- written in 2010 by Hans Raaf - use as you wish!
-- ***************************************************************************
const = {}
local data = {}
const_mt = {
__newindex = function(a,b,c)
if data[b] == nil then
if type(c) == 'table' then
-- make that table readonly
local proxy = {}
-- create metatable
local mt = {
__index = c,
__newindex = function (t,k,v)
log.error([["Attempt to update read-only table '%s' index '%s' "
"with '%s'."]], b, tostring(k), tostring(v))
end
}
setmetatable(proxy, mt)
data[b] = proxy
else
data[b] = c
end
else
log.error("Illegal assignment to constant '%s'.", tostring(b))
end
end,
__index = function(a,b)
return data[b]
end
}
setmetatable(const, const_mt)
$]