Compare commits

..

1347 Commits

Author SHA1 Message Date
Cloud Wu
f97c72d341 Release 1.7.0 2023-11-13 15:13:08 +08:00
shencyx
f7453973f8 避免 sharedata 误用大于32位数字做 key 时,可能导致程序崩溃 (#1820)
Co-authored-by: shencyx <yixin.cen@alibaba-inc.com>
2023-11-07 11:52:58 +08:00
ykxpb
0e6423484f 修复 openssl3 deprecated warning ERR_load_BIO_strings (#1816) 2023-10-30 18:15:27 +08:00
HYbutterfly
adf0cc5a6f check enablessl == "true" (#1815) 2023-10-27 17:16:48 +08:00
Cloud Wu
5ec02a4a2c Add a rare case 2023-09-28 20:15:29 +08:00
Cloud Wu
f3f7e725e8 check session == nil 2023-09-28 14:40:02 +08:00
云风
172278bc8f check conflict (#1798)
* rewind check conflict

* Use auxsend instead of c.send
2023-09-28 13:48:35 +08:00
Cloud Wu
c178c398b9 don't report error when session == 0 2023-07-31 21:31:21 +08:00
Cloud Wu
93ea565bcb Improve README, See #1785 2023-07-31 10:19:40 +08:00
华仔
bb90b64c3f websocket添加is_close方法 (#1781)
* websocket添加is_close方法

* 代码优化
2023-07-19 20:01:41 +08:00
Whislly
c6a8976bc3 findOne优化 (#1772)
1、直接调用runCommand方法
2、增加"limit": 1参数,限制只返回一条数据
2023-07-10 12:29:16 +08:00
Whislly
074426e273 pipline方法优化 (#1771)
1、增加sort_statge、skip_statge、limit_statge、count_statge替换临时table
2、改成for i = 1, 2 do self.__pipeline[len + i] = nil end清除老数据
2023-07-07 20:11:36 +08:00
Whislly
b402837628 聚合方法返回游标对象 (#1769)
* 聚合方法返回游标对象

* 使用table.move()替换for循环拷贝

* 改成使用类似继承的方法

1、返回aggregate_cursor不修改mongo_cursor,直接拷贝mongo_cursor的sort、skip、limit、next、close方法
2、修改了mongo_cursor:count,不再使用unpack
3、aggregate_cursor:count和aggregate_cursor:hasNext方法里options为nil时,不使用unpack
4、mongo_collection:aggregate方法里拷贝了pipeline和options
2023-07-07 15:14:37 +08:00
yzj
272af34736 修改delete使用send_command (#1770)
Co-authored-by: xingfan.yzj <xingfan.yzj@alibaba-inc.com>
2023-07-06 17:44:02 +08:00
Jin Xiao
69420bdfde upgrade lpeg to 1.1.0 (#1766)
* upgrade lpeg to 1.1.0

* fix lpeg compiler error
2023-06-27 16:28:21 +08:00
Cloud Wu
2f9d0c805a include stdint.h for uintptr_t 2023-06-14 23:05:40 +08:00
Cloud Wu
4893fa39ee remove unused code 2023-05-16 16:18:19 +08:00
Cloud Wu
a5af5f6ba7 Overload socket_read(), See #1750 2023-05-16 15:59:43 +08:00
Cloud Wu
8b55660274 Update lua 5.4.6 rc1 2023-05-08 19:08:11 +08:00
twinklinggu
d56cf80f95 Fix socket not closed when clusteragent exit (#1741)
Co-authored-by: twinklinggu <twinkling.gu@gmail.com>
2023-04-14 17:36:23 +08:00
Cloud Wu
aedfb9288d See #1529 2023-03-29 16:25:49 +08:00
子熏
223bd599ba 修复设置 callback导致的crash问题 (#1726)
* fix set callback in resolve _cb

* 调整注释

* 使用预处理callback 来解决引用问题

* add cb_pre and forward_pre

* delete precb_context

* format tab

---------

Co-authored-by: zixun <lb151450@alibaba-inc.com>
2023-03-29 10:42:31 +08:00
子熏
b9a5cec191 update sproto (#1720)
Co-authored-by: zixun <lb151450@alibaba-inc.com>
2023-03-21 21:37:03 +08:00
子熏
1e45d4a9be 添加get_protocol接口 (#1712)
* 添加get_protocol接口

* 添加_proto字段

---------

Co-authored-by: zixun <lb151450@alibaba-inc.com>
2023-03-15 12:44:08 +08:00
丁大龙
6fe520a7cb cluster.open添加maxclient参数 (#1705) 2023-02-18 00:57:39 +08:00
丁大龙
f344a49755 修复client_number计数错误 (#1704) 2023-02-17 14:36:32 +08:00
Cloud Wu
39f3ddbc10 update lua 2023-01-29 11:08:14 +08:00
华仔
cc562547a5 ignore .vscode (#1689)
Co-authored-by: Faker2 <faker@git.com>
2023-01-06 11:23:22 +08:00
Cloud Wu
58b1bda0d9 first key can't can be in hash part, see #1484 2022-11-21 19:26:16 +08:00
Cloud Wu
98311b9b91 release 1.6.0 2022-11-16 10:46:35 +08:00
Cloud Wu
499610965a Update lua 2022-11-16 10:28:38 +08:00
Cloud Wu
94a76269aa Fix #1668 2022-10-27 15:30:06 +08:00
learno
ae35b3c4e8 bugfix: mongo getMore command field batchSize cannot replace with limit (#1666) 2022-10-19 17:04:49 +08:00
子云
1a1d8abd2e read 'x-real-ip' header from nginx in websocket lib. (#1665)
* read 'x-real-ip' header from nginx in websocket lib.

* change default real_ip value to nil
2022-10-17 19:29:33 +08:00
samoyedsun
feeda06e9d fix annotation (#1655) 2022-09-27 10:54:22 +08:00
ykxpb
bc4800f326 修复 mongo 游标没有数据 hasNext 返回 true,以及无效关闭游标的问题 (#1653)
Co-authored-by: yy151474 <yy151474@alibaba-inc.com>
2022-09-24 08:41:37 +08:00
ykxpb
ccfdc9440a Revert lua makefile of "update lua" (#1652)
This reverts commit dfc706615e.

Co-authored-by: yy151474 <yy151474@alibaba-inc.com>
2022-09-22 14:51:04 +08:00
ykxpb
182a1a8d56 修复 mongo 编译告警,删除 unused function (#1650)
Co-authored-by: yy151474 <yy151474@alibaba-inc.com>
2022-09-20 22:20:14 +08:00
ykxpb
44e2583dc2 mongodb 交互协议调整为 OP_MSG (#1649)
* mongodb 交互协议调整为 OP_MSG

* Update

Co-authored-by: yy151474 <yy151474@alibaba-inc.com>
2022-09-20 10:56:33 +08:00
Cloud Wu
7b76bcd039 cluster.open(0) returns addr, port 2022-09-04 15:42:59 +08:00
Cloud Wu
2d5e4ae528 cluster.open returns addr, port 2022-09-04 14:32:31 +08:00
Cloud Wu
b61daaccf1 watchdog returns addr,port 2022-09-04 14:22:13 +08:00
Cloud Wu
01314de8e1 Add assert 2022-09-04 00:20:38 +08:00
Cloud Wu
c8197328a4 socket.listen returns addr,port 2022-09-04 00:13:49 +08:00
Cloud Wu
800a3376d6 Revert "Update the return values of socket.listen, also return the real port bind to zero (#1638)"
This reverts commit c1eeba215d.
2022-09-03 22:03:11 +08:00
Cloud Wu
6dda5f7f98 Revert "udp socket bugfix (#1640)"
This reverts commit 2a8c095e38.
2022-09-03 22:02:45 +08:00
CKT
2a8c095e38 udp socket bugfix (#1640)
Co-authored-by: chenkete <kete.chen@centurygame.com>
2022-09-03 20:51:19 +08:00
caiyiheng
01b5d67b11 Update .gitignore (#1639) 2022-09-03 13:45:22 +08:00
zaxbbun
c1eeba215d Update the return values of socket.listen, also return the real port bind to zero (#1638) 2022-09-03 07:19:03 +08:00
Cloud Wu
6bd6f53ab8 update lua 2022-08-25 15:14:01 +08:00
Cloud Wu
dfc706615e update lua 2022-08-25 11:51:58 +08:00
云风
8efad53631 Emfile (#1626)
* Close the connection when EMFILE, See #1625

* close reserve_fd
2022-08-17 13:12:51 +08:00
yfy
0c1491ba99 修复https读取数据返回0报错 (#1622)
* 修复https读取数据返回0报错

./skynet/lualib/skynet.lua:861: ./skynet/lualib/skynet.lua:333: ./skynet/lualib/http/httpc.lua:109: ./skynet/lualib/http/tlshelper.lua:54: SSL_read error:6
stack traceback:
        [C]: in function 'error'
        ./skynet/lualib/http/httpc.lua:109: in function 'http.httpc.request'

* http请求header中host头修改为默认的Host名字
2022-08-06 06:05:09 +08:00
yfy
1b54306509 http请求头host字段改为Host (#1623) 2022-08-05 10:02:11 +08:00
fanyh
3911e0738b 修改clusterd node closed 后再次命中__index 会继续触发 call changenode (#1614) 2022-06-20 20:06:08 +08:00
dxb218
fad27d7775 Update interface.lua (#1612)
string.format语法错误
2022-06-11 20:22:22 +08:00
Cloud Wu
e98378e874 Fix #1609 2022-06-09 08:05:26 +08:00
子熏
389146167f export queryproto (#1605)
Co-authored-by: zixun <lb151450@alibaba-inc.com>
2022-05-30 23:18:08 +08:00
Cloud Wu
73c0e306cf update jemalloc 5.3.0 2022-05-09 10:41:58 +08:00
云风
6d86016247 Update issue templates 2022-04-27 16:25:06 +08:00
云风
acefd8de27 Update issue templates 2022-04-27 16:24:27 +08:00
涵曦
448fe14b9e fix comment: profile default is on. (#1581) 2022-04-22 16:35:46 +08:00
涵曦
341b7924a0 remove unused function skynet_module_insert #1579 (#1580) 2022-04-20 17:18:23 +08:00
caiyiheng
013cb42122 feat: add mongo safe batch delete (#1577) 2022-04-15 16:20:00 +08:00
Cloud Wu
bcd012f9cf uintptr_t need stdint.h 2022-04-15 10:57:37 +08:00
Cloud Wu
c4da547259 fix retireall, see #1576 2022-04-15 08:19:20 +08:00
IAN.Z
6ad379b7a7 feat: add mongo safe batch update (#1575)
Co-authored-by: zhuyin.zhu <zhuyin.zhu@alibaba-inc.com>
2022-04-14 12:35:54 +08:00
涵曦
ee103e97cd Fix handle register when slot[0] is null will segmentation fault (#1574) 2022-04-13 22:36:47 +08:00
云风
e37eb3cba0 Callback (#1571)
* Use independent thread for callback

* bugfix: use new cb_ctx when changing callback
2022-04-12 11:11:08 +08:00
Cloud Wu
0ddd938400 Clear callback function in main thread 2022-04-12 10:08:07 +08:00
涵曦
2d42adb739 fix typo: remove duplicate include (#1570) 2022-04-10 15:35:46 +08:00
Bruce
9fd7a51b34 Compat lua compile as cpp (#1568)
* Compat lua compile as cpp

* Compat lua compile as cpp
2022-04-07 17:22:32 +08:00
Cloud Wu
2660b10442 fix #1567 2022-04-07 15:19:53 +08:00
coder
969d3291b6 删除无用forwarding数据 (#1565) 2022-04-02 19:30:46 +08:00
coder
c84f7354ff 删除多余snlua定义 (#1564) 2022-04-02 16:06:04 +08:00
JTrancender
b555aa19e7 feat: add cluster.unregister (#1563) 2022-04-02 12:17:47 +08:00
liaodaiguo123
f72573a2aa base64:To improve compatibility, there may not be enough equal signs (#1561) 2022-03-31 18:57:03 +08:00
caiyiheng
bee8a0e731 update lpeg to 1.0.2 (#1557) 2022-03-29 16:16:51 +08:00
t0350
5d48c02725 see #1554, handle nomore message after skynet.exit (#1556)
Co-authored-by: jietao.cjt <jietao.cjt@alibaba-inc.com>
2022-03-23 09:38:20 +08:00
子熏
fad62566dc #1544 fix playload_len (#1553)
Co-authored-by: zixun <lvzxiun@gmail.com>
2022-03-21 13:23:03 +08:00
Cloud Wu
d1ce950dc1 Fix #1552 2022-03-19 07:10:52 +08:00
JTrancender
eaba8f969c perf: add sharetable queryall default behavior(all share data) (#1537) 2022-02-16 11:22:59 +08:00
JTrancender
40ee98b40e feat: add sharetable queryall (#1536)
Co-authored-by: Jason <jie-email@jie-trancender.org>
2022-02-15 21:01:54 +08:00
Cloud Wu
b13281b77d bugfix : See #1535 2022-02-14 07:52:46 +08:00
t0350
3c4f673740 panic while reading from stdin (#1529)
Co-authored-by: jietao.cjt <jietao.cjt@alibaba-inc.com>
2022-02-08 20:27:29 +08:00
xjdrew
6d6be8dec6 skynet.service: add close (#1526)
Co-authored-by: drew.zxj <drew.zxj@alibaba-inc.com>
2022-01-21 10:34:00 +08:00
Cloud Wu
923651ada3 Happy New Year 2022-01-17 10:24:24 +08:00
Cloud Wu
8304747d8e Lua 5.4.4 rc3 2022-01-17 10:22:31 +08:00
Cloud Wu
5b5d5906cb Update Lua lua 5.4.4 rc2 2021-12-22 11:11:25 +08:00
Cloud Wu
9d3edae797 Check self.__sock before dispatch, See #1513 2021-12-14 17:01:50 +08:00
Cloud Wu
208be03a6f Disconnected during auth, See #1513 2021-12-10 20:56:18 +08:00
Cloud Wu
3b54b3bd80 Revert "raise socket error during auth"
This reverts commit 839975415d.
2021-12-10 20:26:46 +08:00
Cloud Wu
839975415d raise socket error during auth 2021-12-10 19:31:36 +08:00
Cloud Wu
27866518ef Fix #1506 2021-11-19 08:48:27 +08:00
zhuilang
53292d1c93 update mysql (#1507) 2021-11-18 18:42:33 +08:00
Cloud Wu
1e2ed7e6ff Use table.pack to support nil in table, See #1505 2021-11-17 15:55:14 +08:00
Cloud Wu
350248a7cc fix #1504 2021-11-17 13:11:10 +08:00
Cloud Wu
d115e626e6 Update Lua 5.4.4 rc1 2021-11-17 10:57:20 +08:00
涵曦
38e5b1ca1c fix wrong date (#1501) 2021-11-09 13:55:55 +08:00
Cloud Wu
a0a138c002 Release v1.5.0 2021-11-09 13:37:17 +08:00
子熏
e35cad3053 fix #1494 socket read阻塞问题 (#1495)
* fix #1494 socket read阻塞问题

* 优化readfunc

Co-authored-by: zixun <lb151450@alibaba-inc.com>
2021-10-29 13:55:54 +08:00
yxt945
8f7e19310c add json support (#1493) 2021-10-27 21:00:25 +08:00
云风
c008476417 Support string address, see #1490 (#1491) 2021-10-22 17:43:07 +08:00
Cloud Wu
599181ceaf bugfix 2021-10-22 10:14:33 +08:00
Cloud Wu
432b0c07f9 array may hash part only 2021-10-13 23:02:40 +08:00
Cloud Wu
58da8a1a22 Use lua_isinteger instead 2021-10-13 15:41:30 +08:00
Cloud Wu
0e11c78575 avoid string number 2021-10-13 15:36:19 +08:00
Cloud Wu
f80e2cd9b1 bugfix: See #1484 2021-10-13 12:57:55 +08:00
Cloud Wu
0ae839b2dd Check req size , See #1481 2021-09-30 11:24:36 +08:00
云风
0ebecb4e6d add ispurewhite : is white and not shared object, see #1479 (#1480) 2021-09-27 11:26:28 +08:00
Cloud Wu
9cbab6f5ec avoid warnings 2021-09-27 08:52:23 +08:00
Cloud Wu
edbed9f980 bugfix: Don't need inc sending since dw_buffer is not NULL 2021-09-26 11:57:32 +08:00
zhuilang
987bb3df47 modify from http folder (#1470)
* delete unused var and add used arg

* use interface from stream
2021-09-01 07:12:27 +08:00
云风
54e733a76f Request stream (#1463)
* split request/response

* stream api

* fix: global variable (#1464)

* fix global variable

* fix global variable

* Add httpc.head

Co-authored-by: JTrancender <jie-email@jie-trancender.org>
2021-08-30 10:00:57 +08:00
colin
6ee8d23ac4 ssl request support sni(Server Name Indication) (#1460)
* ssl support sni(Server Name Indication)

* ssl support sni(Server Name Indication)
2021-08-23 16:54:01 +08:00
JTrancender
fdc4b35281 feat: add mongo self batch insert (#1456)
* feat: add mongo self batch insert

* perf: add safe batch insert test

* perf: modify some words
2021-08-18 15:11:40 +08:00
Cloud Wu
740b91533d Fix #1452 2021-08-09 19:31:32 +08:00
coder
0207b9210a Update service_logger.c (#1451)
格式化时间改为通用的结构,修复windows上时间显示不正确问题
2021-08-05 16:36:49 +08:00
mrCerberus
0e9c0c34a9 'http请求C没有大写' (#1444)
Co-authored-by: 王羽平.Cerberus <wangyuping.cerberus@snda.com>
2021-07-21 20:33:22 +08:00
noname
d9762b8f38 sharedata 去掉多余的value字段 (#1442) 2021-07-15 20:14:05 +08:00
云风
72a6182601 bugfix #1434 (#1439) 2021-07-15 09:35:31 +08:00
涵曦
39e0aaa27e Fix typo (#1436) 2021-07-10 07:24:07 +08:00
colin
338f53fbe0 use _mm_pause (#1433) 2021-07-01 19:29:48 +08:00
colin
5c154d34dc improve spinlock (#1431)
* improve spinlock

* improve spinlock

* typo

Co-authored-by: colin <linzhengqun@163.com>
2021-06-30 12:42:58 +08:00
子熏
2bfecfceae fix lua-seri rb_read (#1427)
Co-authored-by: zixun <lvzxiun@gmail.com>
2021-06-23 15:52:46 +08:00
cm
3900067026 bugfix:params changed when cluster sender is connecting (#1420)
Co-authored-by: LiuYang <cm.yang@alibaba-inc.com>
2021-06-08 17:03:20 +08:00
zhuilang
c90e288601 Update skynet.lua (#1416)
update skynet.wait
2021-06-05 00:35:28 +08:00
colin
c2c585f73a freebsd compile error (#1414) 2021-06-03 19:13:30 +08:00
zhuilang
219b15e9ec Update skynet.lua (#1415)
update skynet.ret
2021-06-03 19:11:54 +08:00
Cloud Wu
30b534b558 ignore break sessions, See issue #1413 2021-06-03 08:13:22 +08:00
喜欢兰花山丘
f5eee7dcbb Update socket_server.c (#1410)
1. 去除冗余代码
2. fix 保存第一现场的错误码
2021-05-30 06:52:02 +08:00
Cloud Wu
ef4af820d5 Do not resume the fd after closing, see #1408 2021-05-21 10:15:21 +08:00
Cloud Wu
71317d8502 Add socket.resolve, see #1398 2021-05-17 11:16:24 +08:00
t0350
6ad8da0993 when skynet.init require the loading module caused circular dependency (#1403) 2021-05-16 22:26:39 +08:00
蒋祥龙
28d47d96b9 1.修复前一个ssl错误没清,导致后面的正常ssl调用操作 获取到这个错误 (#1401) 2021-05-14 21:07:27 +08:00
t0350
1e6781bd41 add coroutine close for skynetco (#1392)
Co-authored-by: jietao.cjt <jietao.cjt@alibaba-inc.com>
2021-04-29 14:40:37 +08:00
Cloud Wu
f61a27ac6b fix #1388 2021-04-19 18:45:56 +08:00
Cloud Wu
1020c403dc revert wakeup_response 2021-04-15 08:58:29 +00:00
云风
f0d24ac718 Bugfix #1385 (#1387) 2021-04-15 10:52:57 +08:00
云风
52d65c5dcb Redis ACL (#1381)
* Support redis ACL
See #1380
2021-04-10 07:02:38 +08:00
busymage
2b71c2755a Fix boostrap only support 1 param. (#1377) 2021-04-07 19:08:29 +08:00
Cloud Wu
df2803469e Add report_error(), this may fix issue #1376 2021-04-07 07:26:02 +00:00
Cloud Wu
bc71164a99 close may be better than shutdown 2021-04-07 03:47:19 +00:00
Cloud Wu
e69f876867 raise error on start, fix #1374 2021-04-07 03:39:22 +00:00
Cloud Wu
f9dc6a3756 fix SOCKET_CLOSE event after socket.close() See #1373 2021-04-07 03:25:55 +00:00
Cloud Wu
0f5867534c remove unused socket.lock/socket.unlock 2021-04-07 02:54:09 +00:00
Cloud Wu
ceb278adf6 Add shutdown to client_socket for testing 2021-04-06 16:46:14 +08:00
Cloud Wu
85dde52107 minor bugfix : socket_server_poll never returns -1 2021-04-06 16:45:51 +08:00
Cloud Wu
8ad6622936 halfclose_read should call before force_close 2021-04-06 15:47:32 +08:00
Cloud Wu
ba26c8a432 Do not close on error, see #1373 2021-04-06 10:46:41 +08:00
Cloud Wu
96c702bb3c bugfix 2021-04-02 10:33:23 +08:00
Cloud Wu
811ef52b3d fix build 2021-03-30 14:55:02 +08:00
Cloud Wu
e0d4fda24e Update lua 5.4.3 2021-03-30 10:09:43 +08:00
Cloud Wu
11165ce727 fix #1368 2021-03-29 14:27:37 +08:00
Cloud Wu
22b5fbf3b8 fix #1369 2021-03-29 14:23:40 +08:00
云风
9228b05dfe socket.onclose() (#1364)
* Add socket.onclose() and close socket immediately when socket channel closed by peer

* Revert read_socket(), Add SOCKET_MORE, See #1358

* remove warning log , because it's not a rare case any more. See #1358
2021-03-19 18:52:09 +08:00
风---自由
a39c9b8b10 clean时增加对macosx下的编译目录生效 (#1361)
* fix: macosx build error

* 🐎ci(makefile): clean时增加macosx下的编译目录

Co-authored-by: xiaojin <xiaojin@onemt.com.cn>
2021-03-11 15:18:13 +08:00
Cloud Wu
037c3a5c48 do not close fd if no handler.disconnect, #1358 2021-03-11 12:31:37 +08:00
Cloud Wu
094b20aae7 fix half close issue, #1358 2021-03-11 11:32:27 +08:00
风---自由
bf5eacfe80 fix: macosx build error (#1360)
Co-authored-by: xiaojin <xiaojin@onemt.com.cn>
2021-03-10 17:35:17 +08:00
Cloud Wu
fd12f2ea8e Merge branch 'master' of github.com:cloudwu/skynet 2021-03-10 15:25:14 +08:00
Cloud Wu
7c0c13b07b close unmanaged socket, see issue #1358 2021-03-10 15:24:33 +08:00
EfveZombie
b0dda0483d fix websocket bugs (#1359)
* fix websocket bugs

* revert write_frame

Co-authored-by: 郑非凡 <efve.zff@alibaba-inc.com>
2021-03-10 12:35:56 +08:00
Cloud Wu
6f2866e5c4 avoid warnings 2021-03-10 12:11:02 +08:00
Cloud Wu
213c9966e4 fix build 2021-03-10 12:01:15 +08:00
Cloud Wu
072d782651 Update lua 5.4.3 rc1 2021-03-10 11:53:37 +08:00
Cloud Wu
600a64327e fix halfclose bug, See detail #1358 2021-03-09 17:45:03 +08:00
Cloud Wu
0d9bfcb721 Atomic variable should be volatile, #1356 #1317 2021-03-09 10:54:49 +08:00
Cloud Wu
8d895ab2f0 See #1317 2021-03-05 21:36:52 +08:00
Cloud Wu
c12a7d1b99 Remove unused include 2021-03-04 11:40:15 +08:00
Cloud Wu
77c965e9e8 Don't support old MacOSX 2021-03-03 17:08:12 +08:00
Cloud Wu
0d949678b9 shutdown write when write error, See #1346 2021-03-01 11:18:56 +08:00
Cloud Wu
29a212db8e Shutdown SHUT_RD after read 0, See #1346 for detail 2021-02-25 22:36:36 +08:00
Cloud Wu
ccac1d4526 fix #1348 2021-02-25 19:59:12 +08:00
Cloud Wu
4bb883b989 report write error 2021-02-24 17:02:23 +08:00
Cloud Wu
6a8ca29d99 set result for SOCKET_CLOSE, see #1347 2021-02-24 11:54:47 +08:00
Cloud Wu
6a4a2482fc expand buffer faster 2021-02-24 11:33:35 +08:00
Cloud Wu
04dd921c5f Fix socket half close issues, see #1346 for details 2021-02-24 10:57:54 +08:00
Cloud Wu
8e32cc5283 Merge branch 'master' of github.com:cloudwu/skynet 2021-02-23 16:19:15 +08:00
Cloud Wu
8e45679d3d bugfix : coroutine.wrap for snlua 2021-02-23 16:19:01 +08:00
风---自由
b626198592 fix global var (#1342)
Co-authored-by: xiaojin <xiaojin@onemt.com.cn>
2021-02-22 12:24:00 +08:00
Cloud Wu
eebd44da9d fix #1341 2021-02-22 12:00:32 +08:00
Cloud Wu
51a942d095 bugfix: disable fd reading flag after shutdown read 2021-02-22 09:41:59 +08:00
Cloud Wu
6d941a6de1 support nil in array, fix #1340 2021-02-22 08:40:16 +08:00
云风
1a0461a9af Halfclose (#1338)
* post SOCKET_CLOSE when HALFCLOSE_READ, see #1331

* Add closing status

* Add closing stat in info, See #1333
2021-02-03 16:49:40 +08:00
Cloud Wu
e23ad8fc6b fix type 2021-02-03 16:04:01 +08:00
Cloud Wu
4534fb5269 pcall execute_module, #1331 2021-01-25 20:31:04 +08:00
Cloud Wu
41cc6d226c remove debug print 2021-01-25 10:47:06 +08:00
Cloud Wu
4532d4f146 Fix skynet.require recursion issue, See #1331 2021-01-25 10:34:01 +08:00
Cloud Wu
30279f2f8d Add gameserver embed mode, see #1326 2021-01-18 16:56:46 +08:00
风---自由
4c9c9ce6bd debug_console add dbgcmd command (#1325) 2021-01-18 10:41:30 +08:00
hong
cfb638243f skynet.exit (#1324) 2021-01-14 11:03:32 +08:00
云风
4cb84ac881 skynet.init rework, See #1322 (#1323)
* skynet.init rework, See #1322

* restore init_list #1322

* xpcall init_all, See #1322
2021-01-14 10:23:58 +08:00
lsg2020
53a74ca029 websocket upgrade (#1279) 2021-01-12 10:43:42 +08:00
子熏
2e06706323 fix atomic of macosx (#1320) See #1317
Co-authored-by: zixun <lvzxiun@gmail.com>
2021-01-11 17:41:03 +08:00
Cloud Wu
649aee1a23 use unsigned long instead of uint32_t to match atomic ulong 2021-01-11 17:32:37 +08:00
Cloud Wu
933dbbd570 lua-bson atomic #1317 2021-01-11 17:30:04 +08:00
Cloud Wu
1e5e8354d7 stm_copy.reference is _Atomic type, #1317 2021-01-11 17:20:16 +08:00
Cloud Wu
bc2fba560f CAS expected should not be _Atomic type, #1317 2021-01-11 17:10:26 +08:00
Cloud Wu
1ed4fdf94d Use _Atomic type for socket.sending and socket.udpconnecting. See #1317 2021-01-11 16:57:25 +08:00
子熏
c0e3421462 bugfix ltls init #1314 (#1318)
* bugfix ltls init #1314

* 修改init失败信息

* fix destructor

Co-authored-by: zixun <lvzxiun@gmail.com>
2021-01-11 15:15:25 +08:00
云风
b164e3a8a9 use stdatomic (#1317) 2021-01-11 10:54:34 +08:00
coder
284df5430b service_logger.c localtime崩溃,换成线程安全的localtime_r (#1311) 2020-12-28 15:42:16 +08:00
Cloud Wu
4d88f96ed6 bugfix: make proto shared 2020-12-18 19:20:15 +08:00
Cloud Wu
8022a53e50 O(1) fork_queue pop, See #1277 2020-12-16 23:05:52 +08:00
t0350
698d032a9b fix #1275 (#1276)
Co-authored-by: jietao.cjt <jietao.cjt@alibaba-inc.com>
2020-12-14 10:16:56 +08:00
Cloud Wu
8eac155b1b reset connection if node_sender exist, see issue #1273 2020-12-12 14:44:28 +08:00
Cloud Wu
e8a48483ab Check address changes before raise error, fix #1273 2020-12-11 12:02:32 +08:00
涵曦
4faa6499e8 fixed mongodb werror return errmsg (#1271) 2020-12-08 08:47:14 +08:00
涵曦
704194226d remove duplicate include directory (#1270) 2020-12-07 17:10:13 +08:00
Cloud Wu
ad06d232a6 This may fix #1268 2020-12-04 18:27:55 +08:00
8aa1587245 并发请求 sharedata.query 返回增加缓存状态检查 (#1266) 2020-12-04 16:42:41 +08:00
Cloud Wu
3af6b72aed close thread in suspend, See #1261 2020-12-04 15:42:35 +08:00
子熏
56c70dc7ac fix socket half close (#1263)
Co-authored-by: zixun <lvzxiun@gmail.com>
2020-12-03 15:47:51 +08:00
hong
693b962b43 to-be-closed (#1261) 2020-12-01 11:51:35 +08:00
najoast
5248d443dc Fix typo: Causes an error when resp is false (#1260)
Co-authored-by: zhouyan <zhouyan@onemt.com.cn>
2020-11-24 18:32:28 +08:00
Cloud Wu
9eb37198ea update lua 5.4.2 2020-11-16 10:51:36 +08:00
t0350
c7dc8751c7 sync sproto weak type (#1259) 2020-11-14 21:36:58 +08:00
Cloud Wu
2a076d8192 init extra stack 2020-11-04 11:24:53 +08:00
Cloud Wu
f27930e7f7 bugfix 2020-11-04 10:48:35 +08:00
Cloud Wu
902fb94274 Revert "bugfix"
This reverts commit cb445f17d4.
2020-11-04 10:47:14 +08:00
Cloud Wu
cb445f17d4 bugfix 2020-11-04 10:20:26 +08:00
Cloud Wu
3f8a2f69df update lua 5.4.2 2020-11-04 10:18:33 +08:00
涵曦
84e600bed3 #855 add test runCommond for testmongodb (#1255) 2020-10-29 14:05:16 +08:00
Cloud Wu
80b60f23c9 use CAS to finish set 2020-10-23 19:20:31 +08:00
Cloud Wu
6b74773f52 Merge branch 'master' of https://github.com/cloudwu/skynet 2020-10-23 18:21:45 +08:00
Cloud Wu
a6adc69090 Use atomic instruct to avoid concurrence signal 0 2020-10-23 18:21:16 +08:00
子熏
1e945a1dec fix sharetable update and tail call (#1253)
Co-authored-by: zixun <lvzxiun@gmail.com>
2020-10-23 14:42:31 +08:00
Cloud Wu
6c3e969e91 shutdown read while halfclose 2020-10-19 11:05:08 +08:00
Cloud Wu
1dfddc0d84 add reading and writing into netstat 2020-10-16 13:06:01 +08:00
Cloud Wu
bae00163b2 Merge branch 'master' of https://github.com/cloudwu/skynet 2020-10-16 12:06:24 +08:00
Cloud Wu
8a7c2b41a1 luaS_hash changed 2020-10-16 12:04:40 +08:00
Cloud Wu
394a065ea2 move yield from suspend to pause, see #1248 2020-10-16 11:49:38 +08:00
Cloud Wu
8ea74c2b93 update to lua 5.4.2 2020-10-16 11:09:39 +08:00
Cloud Wu
6dfdebc1a2 reset pause after wait 2020-10-15 20:25:29 +08:00
Cloud Wu
2eea8be7ac don't pause again 2020-10-15 18:00:25 +08:00
Cloud Wu
e241920949 enable read when closing 2020-10-15 17:34:44 +08:00
Cloud Wu
e669913b2a log debug console client ip 2020-10-14 17:10:29 +08:00
Cloud Wu
55f207c1d2 fix debug console command : kill 2020-10-14 16:24:04 +08:00
Cloud Wu
b6354a0490 Add skynet.killthread() and debugcommand killtask 2020-10-14 14:12:29 +08:00
Cloud Wu
064e61d40f debug GC and socket.resume should wait for message queue 2020-10-14 11:12:13 +08:00
Cloud Wu
0971ce9912 enable write in socket thread 2020-10-13 14:21:38 +08:00
Cloud Wu
77311c7243 enable error handle 2020-10-13 12:04:08 +08:00
Cloud Wu
e75d033066 fix kqueue 2020-10-13 10:53:33 +08:00
Cloud Wu
a4221deac1 enable read 2020-10-12 22:34:46 +08:00
Cloud Wu
f3acbe46df bugfix: pause will disable write event 2020-10-12 18:28:24 +08:00
Cloud Wu
471c7d1101 add socket.pause 2020-10-12 16:12:01 +08:00
Cloud Wu
a87b039c6d use new lua userdata api 2020-10-10 19:19:33 +08:00
Cloud Wu
623d8182eb fix #1246 2020-10-10 18:04:20 +08:00
Cloud Wu
992fd028f0 remove global buffer_pool 2020-10-10 17:01:13 +08:00
Cloud Wu
299d12e1cd Update history 2020-10-10 14:06:57 +08:00
Cloud Wu
4484c1ed50 Add map for sproto 2020-10-10 13:55:15 +08:00
云风
eaa60ca8dd Update to lua 5.4 (#1174)
* update to lua 5.4.0-rc1

* remove LUA_ERRGCMM

* use age bits for shared

* remove unused lbitlib.c

* use luaV_fastget

* fix #1174

* suspend函数tailcall优化

* 防止没有session导致未调用suspend

* luaH_setint check shared (#1184)

* set LUA_GCGEN by default

* fix #1174 (#1186)

checkshared in sweeplist

* update to lua 5.4 rc2

* update to lua 5.4 rc4

* move skynet.profile into snlua

* Use lua_sethook to interrupt tight loops

* remove lua_checksig

* critical condition for signals

* update to lua 5.4 released

* lua 5.4 bugfix

* update lua bugfix

* fix lua_sharestring (#1224)

* update lua

* update lua 5.4

* update README

* add skynet.select

* add test

* test error & discard

* yield session

* request error has no error message

* add timeout to skynet.select

* bugfix

* for lua 5.4

* new version

* bugfix

* bugfix

* use if instead of while

* make local

* yield in select for

* update lua 5.4.1

* change lua version (#1245)

Co-authored-by: xiaojin <xiaojin@onemt.com.cn>

* update lua version number

Co-authored-by: hong <hongling0@gmail.com>
Co-authored-by: hong <hongling-0@qq.com>
Co-authored-by: 风---自由 <996442717qqcom@gmail.com>
Co-authored-by: xiaojin <xiaojin@onemt.com.cn>
2020-10-10 13:36:59 +08:00
Whislly
eef2b1fc62 增加一个指定数据类型为int64的方法 (#1241)
* Update lua-bson.c

* 增加一个指定数据类型为int64的方法

* 修改一些类型错误

* Invalid date -> Invalid int64
2020-09-15 15:12:44 +08:00
Fanrncho
a4c31ac64e Update internal.lua (#1237)
修正小错误。
2020-09-07 13:13:48 +08:00
Cloud Wu
280f0251da Add traffic control for socket 2020-09-04 12:26:13 +08:00
Dirk Chang
55efa75fdf Invalid addrinfo pointer casues skynet asserted in freeaddrinfo on OpenWRT (arm cpu) (#1236) 2020-08-31 16:48:50 +08:00
Cloud Wu
ce52533c74 remove time() 2020-08-11 16:32:22 +08:00
Cloud Wu
d3d5e3063a use luaL_buffinitsize 2020-08-11 14:08:25 +08:00
Cloud Wu
3025e4765a csec 2020-08-11 11:50:45 +08:00
Cloud Wu
446dafdc0b use skynet_now for timestamp 2020-08-11 11:47:33 +08:00
Cloud Wu
c7386fe768 open log file in append mode 2020-08-11 10:54:40 +08:00
Cloud Wu
d80ed7483d add timestamp for logging to file 2020-08-11 10:32:46 +08:00
Cloud Wu
c8d0b1014d add a warning message 2020-08-10 16:54:15 +08:00
Cloud Wu
51fd63213e bugfix: switch reading status 2020-08-10 16:35:55 +08:00
Cloud Wu
a4dc6b9094 add api skynet_socket_pause 2020-08-10 10:57:59 +08:00
子熏
c35c8f173b #1229 fix sharetable update (#1230)
Co-authored-by: zixun <lvzxiun@gmail.com>
2020-08-07 16:46:49 +08:00
冉朋
ddedffc753 mysql预处理执行支持nil参数,nil==NULL (#1228) 2020-08-06 08:42:03 +08:00
子熏
44485b195c update sproto double array (#1227)
Co-authored-by: zixun <lvzxiun@gmail.com>
2020-08-03 22:54:04 +08:00
hong
950389599d 错误数据有可能导致死循环 (#1225) 2020-07-29 07:13:57 +08:00
Cloud Wu
c749b13010 Revert "srv may be a local name, see #1220"
This reverts commit 875b7683c6.
2020-07-28 16:13:05 +08:00
Cloud Wu
875b7683c6 srv may be a local name, see #1220 2020-07-28 15:59:00 +08:00
子熏
bfc19ee7b9 add sproto double type (#1221)
Co-authored-by: zixun <lvzxiun@gmail.com>
2020-07-27 17:57:55 +08:00
fanlix
f2b1bd7319 stat: add mem stat for jemalloc (#1218)
1, add opts arg for mallctl,dumpinfo
2, collect jemalloc.mem info
3, add debug_console cmd: jmem

Co-authored-by: fx <fx@f.x>
2020-07-22 19:26:39 +08:00
子熏
693176efc8 优化sharetable更新 (#1208)
Co-authored-by: zixun <lb151450@alibaba-inc.com>
2020-06-24 16:25:50 +08:00
wudeng
435aa384c8 fix sproto write_ff buffer overflow (#1205)
* bugfix , see #1205

* fix bug

Co-authored-by: Cloud Wu <cloudwu@gmail.com>
2020-06-19 16:19:49 +08:00
Fanrncho
9f86498872 Update socket.lua (#1197)
如果监听套接字在accept时异常(例如:errno == EMFILE),那么不应该关闭监听套接字本身,输出异常信息即可。
2020-06-03 20:44:22 +08:00
Cloud Wu
1f22216d7c fix #1188 2020-05-12 11:58:34 +08:00
Zhongyue Yue
b68b27f26b mysql : 修复读写负数导致溢出处错误 (#1182) (#1183)
* mysql : 修复读写负数导致溢出处错误 #1182

* modify mysql test cases

* 对于db内部整型值的处理使用独立函数
2020-04-25 19:26:27 +08:00
yxt945
87cde31c28 mysql : 修复读写负数导致溢出处错误 (#1182)
* mysql : 修复读写负数导致益处错误

* 注释增加字段类型 _binary_parser 参考 enum_field_types
2020-04-23 17:56:35 +08:00
Bruce
949d943c32 DES crypt use standard padding mode PKCS7 (#1179)
* DES crypt use standard padding PKCS7

* add more desencode(pkcs7 padding mode) test case
2020-04-23 15:19:57 +08:00
Cloud Wu
2389772c73 add padding mode for DES, see #1179 2020-04-23 11:45:47 +08:00
风---自由
22f25bad55 format. 2020-04-15 10:41:28 +08:00
xiaojin
9222ff8d7a del charset todo 2020-04-15 10:41:28 +08:00
xiaojin
d94fbb6493 change mysql default charset 2020-04-15 10:41:28 +08:00
xiaojin
98434708c4 add support for charset encoding 2020-04-15 10:41:28 +08:00
zixun
fd27676869 add message type 2020-03-30 17:48:43 +08:00
风---自由(fisherman)
7efa79906d 修改 mysql 测试用例
https://github.com/cloudwu/skynet/issues/1165
2020-03-29 06:36:42 +08:00
Fanrncho
892189ff90 Update websocket.lua
根据Issue(https://github.com/cloudwu/skynet/issues/1163#issue-587403602)提出修改建议
2020-03-27 12:58:42 +08:00
shuax
f6b8eba01e https://tools.ietf.org/html/rfc6455#section-5.5.3
A Pong frame sent in response to a Ping frame must have identical
   "Application data" as found in the message body of the Ping frame
   being replied to.
2020-03-03 14:51:00 +08:00
Jay Li
3c425b76bc ignore comment line in resolv.conf 2020-03-01 11:18:20 +08:00
Cloud Wu
6de4a012a7 fix #1154 2020-02-18 16:05:47 +08:00
zixun
99d43388ab fix handshake error 2020-02-14 22:45:11 +08:00
Cloud Wu
ac38fd620b see #1150 2020-02-14 16:38:16 +08:00
Cloud Wu
409646a240 happy new year 2020-01-19 20:23:26 +08:00
Cloud Wu
da4360787f Improve socketchannel, try the next host in backup list when auth failed. See issue #1145 2020-01-19 20:22:34 +08:00
Cloud Wu
d3a6b8d80b fix #1141 2019-12-30 10:57:44 +08:00
yxt945
672bdcf39f 增加mysql存贮过程和blob读写示例 2019-12-30 10:56:49 +08:00
Cloud Wu
d232af70f2 fix #1139 2019-12-25 17:58:03 +08:00
zixun
c075de7425 use SSL_CTX_use_certificate_chain_file instead of SSL_CTX_use_certificate_file 2019-12-23 19:25:39 +08:00
冉朋
f2d3bc3e5c 测试单元 2019-12-17 20:06:18 +08:00
冉朋
386c709f42 修改制表符 2019-12-17 20:06:18 +08:00
冉朋
64d6baa176 修改制表符 2019-12-17 20:06:18 +08:00
冉朋
ed6dd39670 支持预处理句柄重置和释放 2019-12-17 20:06:18 +08:00
fisherman
5527e9e32e 增加 查询错误 提示 2019-12-13 16:15:54 +08:00
Hanlei Qin
3c7279a6b7 1. disambiguation: testdb --> testcoll (test collection)
2. let `c` as cllient, `db` as `c[db_name]`
3. clear up as lua-check
2019-12-10 12:54:59 +08:00
Hanlei Qin
b2e50c3bfa fixed 2019-12-10 12:54:59 +08:00
Cloud Wu
99a7d745fb use socket_channle:changehost, this may also fix #1130 2019-12-04 15:33:01 +08:00
wudeng
b295b875c8 fix sharedata emptyslot 2019-11-29 15:11:33 +08:00
zixun
a15c64a73b fix sharetable update when match self coroutine 2019-11-29 10:13:00 +08:00
zixun
b7b595e53a fix kqueue read with eof 2019-11-28 10:20:00 +08:00
Jay Li
0e3f37f38b Call tls.closefunc 2019-11-22 16:24:11 +08:00
Cloud Wu
a6293f27cd 1.3.0 rc 2019-11-19 16:42:03 +08:00
zixun
8450e7f366 add result of accept 2019-11-19 16:25:43 +08:00
Hanlei Qin
4585da9cbd bug fixed 2019-11-19 16:25:43 +08:00
zixun
38c47b8a5d add websocket address and url param 2019-11-19 16:25:43 +08:00
zixun
21d680d5b7 triger handle close when force close 2019-11-19 16:25:43 +08:00
zixun
ec8e518abc only server websocket check frame size 2019-11-19 16:25:43 +08:00
zixun
082fb732e5 fix httpver 2019-11-19 16:25:43 +08:00
zixun
b5ea18f44b check full frame size 2019-11-19 16:25:43 +08:00
zixun
8aac2114e3 delete debug print 2019-11-19 16:25:43 +08:00
zixun
0e96c761f8 add write with masked and limit payload 2019-11-19 16:25:43 +08:00
zixun
60f4f26b85 fix closed and delete send_buf 2019-11-19 16:25:43 +08:00
zixun
7240de08a9 use sockethelper connect 2019-11-19 16:25:43 +08:00
zixun
4341106364 fix mask and close 2019-11-19 16:25:43 +08:00
zixun
81a7c44a05 add ws/wss server and client support 2019-11-19 16:25:43 +08:00
Cloud Wu
80d1082b42 bugfix 2019-11-14 10:49:25 +08:00
Cloud Wu
9d7ea09789 Add socket_sendbuffer 2019-11-14 10:49:25 +08:00
Hanlei Qin
58291a2a48 restore some styles as before. 2019-10-29 19:14:06 +08:00
Hanlei Qin
49c21916a2 format up by vscode plugin 2019-10-29 19:14:06 +08:00
Hanlei Qin
6b4050bf2c format up :
0. remove some useless multiple blank lines.
1. uniform indent as white-space.
2. add some expression white-space pad.
2019-10-29 19:14:06 +08:00
Hanlei Qin
f4d54182e9 may improve Intermediate variables. 2019-10-29 19:14:06 +08:00
Hanlei Qin
f6679a778f remove useless Intermediate variables 2019-10-29 19:14:06 +08:00
yxt945
082430147f 使用toingeger代替math.floor判断是否整数 2019-10-29 11:50:33 +08:00
yxt945
6dd47e6690 COM_STMT_EXECUTE改为'\x17',保持COM_XXX变量类型统一
整数除法改为//,不再使用math.floor
_compose_packet改为使用string.pack编码
2019-10-29 11:50:33 +08:00
yxt945
d3c4bee0c9 _compose_packet取消size参数,直接从#req读取数据大小
read_prepare_result使用string.unpack一次性读取数据
_get_datetime使用string.unpack一次性读取数据
_parse_row_data_binary计算null_count修改为 mathfloor((ncols+9)/8)
2019-10-29 11:50:33 +08:00
yxt945
15ae26b8bc 取消变量 pow_2_16,pow_2_24,改为立即数 1<<16,1<<24
取消预处理语句缓存,由用户自行管理
COM_QUERY,COM_PING,COM_STMT_PREPARE改为字符类型,避免使用时转换
2019-10-29 11:50:33 +08:00
yxt945
29e7256948 替换换行符 \r 为unix风格 \n 2019-10-29 11:50:33 +08:00
yxt945
4f050fa987 增加mysql.ping测试网络状态
增加blob数据格式支持
增加mysql.execute支持预处理语句和存储过程调用
2019-10-29 11:50:33 +08:00
yxt945
066c2c3a54 增加mysql.ping测试网络状态
增加blob数据格式支持
增加mysql.execute支持预处理语句和存储过程调用
2019-10-29 11:50:33 +08:00
Cloud Wu
41c66d1b20 add skynet.trace_timeout(on), see #1098 2019-10-22 16:11:36 +08:00
Cloud Wu
82ed7efb1b use traceback 2019-10-22 15:25:39 +08:00
zixun
f17c17b8c7 fix match intern mt and stackvalues 2019-10-21 11:41:05 +08:00
zixun
8a1d7006eb fix match thread, table key 2019-10-21 11:41:05 +08:00
wudeng
4ddc1577ef fix: coroutine leak when dispatch failed 2019-10-10 11:25:12 +08:00
Sean Feng
9c4e0d5bb7 add senders command in clusterd service 2019-09-29 08:34:43 +08:00
hong
21b1c449de luaH_set check shared table 2019-09-21 15:59:23 +08:00
Cloud Wu
e485aae55b This may fix #1080 2019-08-30 10:16:31 +08:00
Cloud Wu
5025e6887f fix #1079 2019-08-29 16:21:01 +08:00
Cloud Wu
e4224137f1 fix #1078 2019-08-28 20:19:15 +08:00
wudeng
478575436b uniqtask for gm 2019-08-27 21:58:47 +08:00
zixun
65eb351a3b fix replace mt when sharetable update 2019-08-15 19:08:06 +08:00
xjdrew
2e8659d5fc dns: remove unused variable 2019-08-15 19:07:51 +08:00
Cloud Wu
baf5987b0b fix #1062 2019-08-07 10:20:38 +08:00
Cloud Wu
7e42653f80 fix #1057 2019-07-29 16:54:49 +08:00
Cloud Wu
89f487e0a4 bugfix: init the lock of code cache at start 2019-07-02 23:08:54 +08:00
Cloud Wu
9193035767 Improve error message , see issue #1050 2019-07-01 20:26:53 +08:00
zixun
4fa1ba57cb add SSL_CTX_new error string 2019-06-27 15:37:13 +08:00
Cloud Wu
10fd5791f7 dec id would be better 2019-06-25 10:01:19 +08:00
Cloud Wu
5d26fb3f18 remove ssm and add string id 2019-06-25 10:01:19 +08:00
hong
7032f21d18 bugfix Proto is gcobject 2019-06-18 10:41:33 +08:00
Cloud Wu
c80b462412 remove l_G from Proto 2019-06-18 10:41:33 +08:00
Cloud Wu
744fbea7ee update jemalloc 5.2.0 2019-06-17 10:19:17 +08:00
Cloud Wu
5750b2d5ee Merge branch 'bugfix' 2019-06-17 09:57:11 +08:00
zixun
e9581adfc4 pass sharedtable match 2019-06-15 16:02:32 +08:00
zixun
6803f45aa1 add sharetable update 2019-06-15 16:02:32 +08:00
lwkienun
8e2facbfb8 fix crash of sharedata by incref before sharedated.monitor return cobj to client.
crash occr analise:
1.sharedated.update call many times in a short time(eg:3 times) to change a same name conf value to a->b->c->d.
2.sharedated sending 3 response  to monitoring clients。a->b and b->c and c->d.
3.if b is destroyed and it's memory is reallocated and rewrited when client process the first message a->b, client's call lbox will crash.

solution:
conf b must be keeped before message(a->b) is processed by inc it's ref.
Any return value from host to client must use incref before send to client.
2019-06-15 15:59:37 +08:00
Cloud Wu
6f0e88dc59 bugfix, See issue #1027 2019-06-15 00:37:42 +08:00
Cloud Wu
5a0f68999e fix #1032 2019-06-14 11:04:20 +08:00
Cloud Wu
24b333a5e9 add api lua_sharestring 2019-06-13 20:01:10 +08:00
Cloud Wu
b45384cc9f short string in matrix should be in fixed set 2019-06-13 17:55:45 +08:00
Cloud Wu
7fed938593 mark all short string shared, see #1027 2019-06-13 16:58:57 +08:00
Cloud Wu
ca4f549f0d free all objects in matrix 2019-06-13 14:55:57 +08:00
hong
a04e6b5b29 lua_checksig LUA_CACHELIB 2019-06-10 15:11:51 +08:00
hong
82f3e80e06 collectref的时候减少nuse 2019-06-10 15:11:51 +08:00
hong
9ffa0c6e30 markref冲突时候刷新 cache 2019-06-10 15:11:51 +08:00
hong
64d99c1bd5 nuse计数错误 2019-06-10 15:11:51 +08:00
hong
da87df6b86 有概率出现total为0的时候garbage不为0的情况 2019-06-10 15:11:51 +08:00
hong
fafc4cad34 do not makeshared to LUA_TSHRSTR 2019-06-10 15:11:51 +08:00
hong
1b60c522b0 字符串引用计数BUG 2019-06-10 15:11:51 +08:00
Cloud Wu
a8c1828786 fix #1011 2019-06-10 15:11:51 +08:00
hong
ff9b0538a4 Reserve SHAREDBIT in GC 2019-06-10 15:11:51 +08:00
hong
bed5f878dc use ttnov in shareproto 2019-06-10 15:11:51 +08:00
hong
505da68cb6 Should not link shared table to gray 2019-06-10 15:11:51 +08:00
Cloud Wu
68e94b2792 add sharetable.loadtable 2019-06-10 15:11:51 +08:00
Cloud Wu
e3c5d63a97 setmetatable raise error 2019-06-10 15:11:51 +08:00
Cloud Wu
3a0981661c don't use SSM.garbage 2019-06-10 15:11:51 +08:00
Cloud Wu
47d1047004 sweep garbage strings 2019-06-10 15:11:51 +08:00
Cloud Wu
2bcc691c4d add gc service 2019-06-10 15:11:51 +08:00
Cloud Wu
76b166f04a Add new sharetable 2019-06-10 15:11:51 +08:00
Cloud Wu
2ceb642b5d rewrite SSM and clonefunction 2019-06-10 15:11:51 +08:00
zixun
2d6d2c75a4 fix BIO_read and BIO_write return 0 2019-05-22 18:30:44 +08:00
zixun
194940822e fix SSL_read and SSL_write return 0 2019-05-22 14:52:45 +08:00
zixun
be590cfa8c #1016 bugfix SSL_read and SSL_do_handshake 2019-05-21 22:24:37 +08:00
Cloud Wu
6addb504e4 fix #1012 2019-05-15 10:49:19 +08:00
hong
db61ec376a clustersender tracetag bug 2019-05-07 10:05:06 +08:00
zixun
431feb6f16 bugfix #1007 2019-05-06 14:52:06 +08:00
zixun
2c8d373236 fix use NOUSE_JEMALLOC 2019-05-06 11:17:05 +08:00
Cloud Wu
9b69af0a4d use tinsert instead of table.insert 2019-05-06 10:29:23 +08:00
Cloud Wu
046fb69f84 bugfix 2019-05-06 10:20:15 +08:00
wudeng
6231f1c884 build jemalloc with --enable-prof 2019-05-03 18:15:07 +08:00
wudeng
35aa00fb13 Add jemalloc heap profilling in debug console 2019-05-01 20:37:48 +08:00
Cloud Wu
4159600fbc order fork, see #1000 2019-04-28 09:53:52 +08:00
hong
04e2a36c4a Update service_provider.lua
boot成功后的launch消息异常
2019-04-28 00:18:24 +08:00
wudeng
95cb848772 collectgarbage count change to lua 5.3 2019-04-19 19:09:05 +08:00
Cloud Wu
302fc580a5 bugfix 2019-04-18 15:41:24 +08:00
Cloud Wu
3048eed2aa try to fix #988 2019-04-18 15:41:24 +08:00
云风
e0729a483d Revert "bugfix:cluster初始化节点的时候有可能导致消息乱序"
This reverts commit 9ba0860c70.
2019-04-18 15:40:22 +08:00
云风
201becd3d1 Revert "避免失败卡住"
This reverts commit 77e2643728.
2019-04-18 15:40:22 +08:00
hong
77e2643728 避免失败卡住
add pcall
2019-04-18 15:39:50 +08:00
hong
9ba0860c70 bugfix:cluster初始化节点的时候有可能导致消息乱序 2019-04-18 15:39:50 +08:00
hong
4c17005c03 优化SSM查询 2019-04-17 17:46:05 +08:00
Cloud Wu
cf18b59d90 fix #981 2019-04-16 17:32:46 +08:00
Cloud Wu
fbd932e846 OOM check 2019-04-03 11:29:37 +08:00
Cloud Wu
8e8a92ca2d overflow check 2019-04-03 11:15:33 +08:00
Cloud Wu
6ab841beec turn on SSM during lua_load 2019-04-03 10:17:20 +08:00
Cloud Wu
6f40120ad8 expand SSM during loadfile 2019-04-02 20:47:27 +08:00
Cloud Wu
f8d55affba use sign n for SSM 2019-04-02 19:32:44 +08:00
Cloud Wu
56d24f46d6 overflow check 2019-04-02 19:15:35 +08:00
Cloud Wu
64e0c4daff calc variance 2019-04-02 19:15:35 +08:00
Cloud Wu
5bf635c75c SSM expanding 2019-04-02 19:15:35 +08:00
Cloud Wu
2011596de0 fix #979 2019-04-02 17:43:24 +08:00
zixun
3c6c0f7aa4 bugfix #976 long string instead of global seed 2019-03-28 21:21:44 +08:00
zixun
ea0cc1fade fix check header limit 2019-03-28 21:21:44 +08:00
xjdrew
ee1f5055ea bugfix: dns parse hosts.conf 2019-03-28 21:16:06 +08:00
drew.zxj
305a29d885 dns: parse /etc/hosts 2019-03-27 17:25:33 +08:00
CoolDesert
2651929f5b fix tls make 2019-03-27 11:05:05 +08:00
CoolDesert
1af78bc585 fix tls make 2019-03-27 11:05:05 +08:00
Cloud Wu
062f767bbf fix #967 2019-03-26 23:45:33 +08:00
zixun
0c66252cd1 fix post with https 2019-03-26 21:31:36 +08:00
Cloud Wu
45afa0fdcf fix #965 2019-03-26 18:46:31 +08:00
Cloud Wu
4c9c2ac41d Merge branch 'lvzixun-self_skynet' 2019-03-26 10:32:23 +08:00
Cloud Wu
bfbbe91efa turn off ltls by default 2019-03-26 10:31:47 +08:00
Cloud Wu
eda9f771e6 Merge branch 'self_skynet' of https://github.com/lvzixun/skynet into lvzixun-self_skynet 2019-03-26 10:08:10 +08:00
Cloud Wu
7cb4bbb960 Merge branch 'cluster' 2019-03-26 09:46:57 +08:00
Cloud Wu
2c247b511e Merge branch 'sharedk' 2019-03-26 09:46:38 +08:00
Cloud Wu
ea1affda4c fix #962 2019-03-25 09:42:53 +08:00
Cloud Wu
1c3b563ef8 add wait queue 2019-03-20 19:44:08 +08:00
Dalton
9ffdf2dbde Update skynet_daemon.c 2019-03-20 18:26:45 +08:00
Cloud Wu
000fa2be3a multi cluster sender 2019-03-20 17:56:39 +08:00
zixun
7746193b5f add https client and server support by bios 2019-03-14 10:36:02 +08:00
Cloud Wu
3f38a711ad Shared K 2019-03-14 09:54:40 +08:00
Cloud Wu
1d4308f33a Fix memory leak, See #952 2019-03-06 00:19:51 +08:00
Cloud Wu
48e5c36b5e volatile for signal, see #950 2019-03-01 16:47:29 +08:00
Cloud Wu
1422cae7fb Consider __pairs, see #942 2019-02-13 15:36:55 +08:00
Naix
9e16b04a5b dns reInit bug
recall dns.server()
false	./lualib/skynet/dns.lua:340: assertion failed!
2019-01-18 20:01:04 +08:00
Cloud Wu
0fbbd5f4d5 type can be DATA 2019-01-15 10:55:18 +08:00
Cloud Wu
6eb9b64f06 remove mysqlaux.c 2019-01-15 10:55:18 +08:00
Cloud Wu
d71c8f8b7d remove new_tab 2019-01-15 10:55:18 +08:00
Cloud Wu
68c3762abf bugfix : handshake error handle 2019-01-15 10:55:18 +08:00
Cloud Wu
304272249e fix #919 2018-11-14 11:43:23 +08:00
Oneoeigh
2102d8b9f0 Revise README.md
Slight revisions of readme to make it more concise.
2018-11-14 09:10:08 +08:00
Cloud Wu
2ee85a91f9 Release 1.2.0 2018-11-06 11:11:29 +08:00
Cloud Wu
8a3a0c1b71 register logger name in framework, see #909 2018-10-21 13:21:51 +08:00
Sean Feng
b4752f2394 multiresultset spelling mistake 2018-10-17 19:54:38 +08:00
Cloud Wu
f110b51290 add socketchannel.overload 2018-10-17 14:54:44 +08:00
Cloud Wu
e0f16b8df5 remove dead_service table, address may reused 2018-10-15 10:05:23 +08:00
Cloud Wu
08e56f4316 fix #793 2018-10-11 17:38:49 +08:00
Cloud Wu
7e57e498f6 remove dead_service table, address may reused 2018-10-08 15:44:12 +08:00
Cloud Wu
98b5c7c7c6 address 0 is reserved 2018-10-08 14:20:53 +08:00
sundream
02d5f4fbe9 rediscluster: support eval/evalshal + subscribe/publish 2018-09-27 10:00:30 +08:00
Hanlei Qin
818ff8314d remove unused code 2018-09-27 09:59:18 +08:00
Hanlei Qin
d23e6f8d8e 1. remove unused code; 2. weird indents fixed. 2018-09-20 00:31:14 +08:00
Hanlei Qin
f217a56f6e Uniform indent to tab and clear up. 2018-09-20 00:29:19 +08:00
Hanlei Qin
46b49adf9e remove useless file 2018-09-16 18:41:30 +08:00
Hanlei Qin
d9fb4d06ec remove useless local function 2018-09-16 18:41:06 +08:00
Cloud Wu
34a9979255 check launching address 2018-09-13 18:59:03 +08:00
Cloud Wu
89e7a06deb add more info when service init blocked 2018-09-13 18:27:05 +08:00
Cloud Wu
43d02ac456 update jemalloc to 5.1.0 2018-09-12 15:23:59 +08:00
Cloud Wu
c839159470 remove netpack from gate service 2018-09-12 11:45:41 +08:00
Cloud Wu
823b773051 remove unused require 2018-09-12 11:31:12 +08:00
Cloud Wu
f8434d34b6 report last accept time 2018-09-07 16:26:56 +08:00
Cloud Wu
61980c8a1f add socket.netstat 2018-09-07 16:11:27 +08:00
Cloud Wu
35176383b7 add skynet.context 2018-09-06 19:01:10 +08:00
Cloud Wu
c96e20e6c3 add skynet.context and enhance debug console command service 2018-09-06 18:59:33 +08:00
LiuYang
ce0cdc7bd3 add mongo test case: auth 2018-08-30 11:42:47 +08:00
Cloud Wu
7e63080c03 add mongo_db:auth 2018-08-30 10:50:52 +08:00
Cloud Wu
1c8ed8a46e add mongo config option: authdb, see issue #884 2018-08-30 10:50:52 +08:00
Cloud Wu
c4334be9c3 add mongo_db:auth 2018-08-30 09:51:55 +08:00
Cloud Wu
e6e69ae805 add mongo config option: authdb, see issue #884 2018-08-30 09:38:18 +08:00
LiuYang
8ce816de7f fix mongodb testcase 2018-08-29 23:33:17 +08:00
Cloud Wu
2fb52f6fce cleanup 2018-08-29 15:29:26 +08:00
Cloud Wu
c72d4d2134 support string address name, see #883 2018-08-28 15:15:38 +08:00
btt
18a36c171f debug console inject cmd support args 2018-08-23 17:02:06 +08:00
Cloud Wu
7b3c1631d1 more stable 2018-08-17 21:27:14 +08:00
Cloud Wu
4613fde654 fix #877 2018-08-17 21:16:35 +08:00
Cloud Wu
143baec319 remove duplicate code 2018-08-13 14:12:15 +08:00
fanyh
168a07d658 sleep time 1s-> 1m, sleep 1s prodcut more message 2018-08-09 19:28:59 +08:00
Cloud Wu
281acf4c71 Use fork instead of timeout 0, see #873 2018-08-07 14:55:26 +08:00
Cloud Wu
d2ab6863e3 fix #872 2018-08-07 10:49:21 +08:00
Cloud Wu
e55ad63d3c fix #873 2018-08-07 09:43:50 +08:00
Cloud Wu
ec2eaa70a4 Merge branch 'master' of https://github.com/cloudwu/skynet 2018-08-03 11:29:12 +08:00
Cloud Wu
d402619347 see #870 2018-08-03 11:28:18 +08:00
Cloud Wu
c101d9df17 see #870 2018-08-03 11:24:14 +08:00
hong
b5653a68ea runnging拼写错误 2018-08-02 21:30:03 +08:00
hong
c9942deaa9 queryname并发导致消息乱序
当有1个以上的co进入queryname,后面的协程有在第1个以后某个的co先执行(第一个已经返回),导致cluster消息乱序
2018-08-02 21:30:03 +08:00
yenshan98
2df1446c37 Rearranged sentence to be reader friendly. 2018-07-30 15:10:57 +08:00
Cloud Wu
9421815327 add posix_memalign hook 2018-07-23 15:32:35 +08:00
Cloud Wu
1a0c9997ec fix #863 2018-07-23 14:53:01 +08:00
Cloud Wu
16f060f864 hook aligned_alloc 2018-07-20 14:46:53 +08:00
Cloud Wu
ea7c6402dd update lua to 5.3.5 2018-07-10 22:11:56 +08:00
zixun
07db2580c4 fix kqueue error flag 2018-07-05 18:55:51 +08:00
zixun
1df72c0afe fix kqueue eof event 2018-07-05 18:37:50 +08:00
Cloud Wu
0e41231298 fix #857 2018-07-04 15:10:32 +08:00
Cloud Wu
8224b5a62a udp_connect may raise error 2018-06-26 09:49:18 +08:00
Cloud Wu
d8ab9dea1b fix #852 2018-06-25 14:24:04 +08:00
Cloud Wu
a8e5c31381 check udp address, see #852 2018-06-25 12:10:30 +08:00
Cloud Wu
3a1556e1fd add new debug command trace 2018-06-08 11:24:27 +08:00
Cloud Wu
4b5fbab129 recycle coroutine bugfix 2018-06-08 10:23:36 +08:00
Cloud Wu
b1ec1f4d18 token bugfix 2018-06-08 10:23:36 +08:00
Cloud Wu
16d8f4c774 cleanup 2018-06-08 10:23:36 +08:00
Cloud Wu
f8b5ec48e8 support user tag 2018-05-28 23:13:05 +08:00
Cloud Wu
7a26926965 resume trace log 2018-05-28 21:45:41 +08:00
Cloud Wu
2990fbc7cf ignore response, fix #841 2018-05-28 20:38:10 +08:00
Cloud Wu
e8e38f1682 add session log 2018-05-28 18:16:31 +08:00
Cloud Wu
35b4a09c3d unique cluster trace tag 2018-05-28 18:09:34 +08:00
Cloud Wu
9035fbe96b cluster trace 2018-05-28 16:39:04 +08:00
Cloud Wu
a41a5fadd2 ignore ret in clientagent 2018-05-28 11:24:55 +08:00
Cloud Wu
d6f265e703 call skynet.trace() in example 2018-05-26 17:37:19 +08:00
Cloud Wu
596c77afcd trace bugfix 2018-05-26 17:17:20 +08:00
Cloud Wu
e53d985c4f add skynet.trace() 2018-05-26 16:26:50 +08:00
Cloud Wu
348e53245b skynet.wait use token instead of coroutine.running() 2018-05-25 10:42:58 +08:00
Cloud Wu
2fde0a0ae4 log error when forget response a session. Add skynet.ignoreret() 2018-05-24 16:53:27 +08:00
Cloud Wu
85ec428f3f remove assert 2018-05-22 20:04:05 +08:00
Cloud Wu
a8ab809928 add __nowating flag to cluster config, see issue #803 2018-05-22 19:49:07 +08:00
caijietao
6c7cb5313d set backlog to 128 2018-05-22 13:08:00 +08:00
spin6lock
188e38198a add ipv6 host support to service_gate.c
service_gate的地址解析用strchr找到第一个':',并将后续的字符串作为
端口号解析。填ipv6地址"0:0:0:0:0:0:0:0:9999"的时候会出错,现在改成
strrchr,从右面找到的第一个':'
2018-05-22 13:07:02 +08:00
Cloud Wu
294f557268 lua 5.3.4 bug report 6 2018-05-17 12:03:03 +08:00
Cloud Wu
4dd622e180 socket channel order mode support padding, see issue #835 2018-05-09 17:38:32 +08:00
Cloud Wu
5f8e5f9be5 add random for seed 2018-05-07 11:10:45 +08:00
Cloud Wu
e561896966 Merge branch 'master' of github.com:cloudwu/skynet 2018-05-07 10:55:34 +08:00
Cloud Wu
ea25e20c88 more random seed 2018-05-07 10:55:18 +08:00
云风
003b0fdb02 Add logo 2018-05-03 23:26:53 +08:00
xjdrew
8de6500677 update mongo driver: safe_insert, safe_update, safe_delete 2018-05-02 01:36:00 +08:00
Cloud Wu
7df13e922b add testtimeout 2018-04-20 11:44:05 +08:00
Cloud Wu
182d7c7dc7 support @name, see #823 2018-04-20 10:11:16 +08:00
Cloud Wu
f4d5bc7aa4 forward fd to agent 2018-04-18 19:32:15 +08:00
Cloud Wu
d53d98b625 Merge branch 'clusteragent' 2018-04-18 19:30:24 +08:00
Cloud Wu
2bfba716ef forward fd to agent 2018-04-18 19:29:41 +08:00
Cloud Wu
4cbe33d15d remove unused sz 2018-04-17 10:47:41 +08:00
Cloud Wu
a9852273cb add addresscommand 2018-04-17 10:47:41 +08:00
Cloud Wu
eb8a2b5e65 Improve cluster package module 2018-04-17 10:47:41 +08:00
Cloud Wu
7304a990cb use clusteragent to dispatch cluster request 2018-04-17 10:47:41 +08:00
Cloud Wu
311d7c8f6a remove unused sz 2018-04-16 12:56:34 +08:00
Cloud Wu
5a3d2fdac7 add addresscommand 2018-04-14 20:30:47 +08:00
Cloud Wu
4b88f68ab8 Improve cluster package module 2018-04-14 18:14:44 +08:00
Cloud Wu
70c224c3e7 use clusteragent to dispatch cluster request 2018-04-14 16:11:26 +08:00
Cloud Wu
1932d33b41 set node = false when node is down, see #803 2018-02-24 21:26:24 +08:00
Cloud Wu
9cf4525a8f avoid error circulation 2018-02-12 18:07:16 +08:00
Cloud Wu
0846a6533d fix a legacy problem. make harbor service more stable 2018-02-12 18:07:16 +08:00
Cloud Wu
484404295e Merge branch 'hongling0-master' 2018-02-05 11:38:22 +08:00
云风
3e54becb95 Merge branch 'master' into master 2018-02-05 11:34:52 +08:00
hong
ab13305b64 monitor中不增加ref 2018-02-05 10:18:35 +08:00
Cloud Wu
6fdb123df4 bugfix, See #800 2018-02-04 21:32:41 +08:00
Cloud Wu
6cdc1cf95c collect used response, see #800 2018-02-04 16:25:19 +08:00
hong
2dd5a06616 抄写错误 2018-02-03 15:49:01 +08:00
hong
e7436bfa95 skynet.response() leak
datasheet在monitor接口里面产生的reponse在release接口里面没有释放
2018-02-03 15:43:33 +08:00
Cloud Wu
084aab4bcd dns server auto retire 2018-01-25 15:56:47 +08:00
Cloud Wu
cd99557368 udp send don't need inc/dec sending ref, see issue #794 2018-01-25 15:55:45 +08:00
Cloud Wu
04f4004934 sproto bugfix 2018-01-23 11:24:44 +08:00
Cloud Wu
bbf46f935a dec sending count asap, this may fix #794 2018-01-19 10:41:35 +08:00
Cloud Wu
b792c7144d clusterd wait for cluster.reload when the name no exist 2018-01-04 14:18:29 +08:00
Cloud Wu
5d5112257c use 32bit sending, see issue #777 2017-12-06 20:58:36 +08:00
云风
747e6c7848 Merge pull request #775 from cloudwu/tcpwriteorder
Tcpwriteorder, Fix #744
2017-12-04 11:45:49 +08:00
Cloud Wu
45d848c910 bugfix: inc sending ref, See issue #774 2017-12-04 10:55:47 +08:00
Cloud Wu
f12fa7e8f9 May fix issue #774 2017-12-03 00:26:12 +08:00
Cloud Wu
568a435e9e fix issue #773 2017-11-30 16:13:58 +08:00
Cloud Wu
c46f2633be fork may not execute when the service exit, and __gc would send message release without monitor 2017-11-16 10:47:18 +08:00
Cloud Wu
b51e28a3e0 set nodelay, see issue #763 2017-11-14 18:01:08 +08:00
云风
badfab8561 Merge pull request #761 from cloudwu/mongolimit
positive limit support
2017-11-07 10:17:04 +08:00
Cloud Wu
d5c0d687b3 positive limit support 2017-11-06 20:51:33 +08:00
Cloud Wu
57f08426ee concurrent cluster link, fix issue #757 2017-11-02 22:31:54 +08:00
Cloud Wu
ba59b879ad release v1.1 2017-10-31 11:27:14 +08:00
Cloud Wu
1e9e16f16b fix #755 2017-10-30 11:43:17 +08:00
Cloud Wu
ece075ef6e update sproto 2017-10-18 10:02:59 +08:00
Cloud Wu
c4c429b699 fix #747 2017-10-18 09:51:22 +08:00
云风
21f881910b Merge pull request #749 from chengdd1987/master
http中connect可能会连接失败,不应当将错误的fd继续传递下去
2017-10-18 09:44:43 +08:00
chengzhe
37157273ff http中connect可能会连接失败,不应当将错误的fd继续传递下去 2017-10-17 17:50:54 +08:00
云风
460ed2e9e2 Merge pull request #745 from qinhanlei/patch1
remove useless code.
2017-10-07 11:13:27 +08:00
Hanlei Qin
03ce7ab385 remove useless code. 2017-10-06 00:42:48 +08:00
Cloud Wu
1c605bed2b this may fix #744 2017-10-04 00:11:31 +08:00
Cloud Wu
55136b77ad fix issue #741 2017-09-25 15:10:21 +08:00
Cloud Wu
d8798a280a Revert "pthread may call __libc_memalign, see #731"
This reverts commit c8d6ffd393.
2017-09-06 22:21:04 +08:00
Cloud Wu
c8d6ffd393 pthread may call __libc_memalign, see #731 2017-09-06 20:19:29 +08:00
Cloud Wu
100329f09f official lua bugfix 2017-09-04 16:23:19 +08:00
Cloud Wu
553c30c6d1 sproto.default returns array type 2017-09-01 11:46:43 +08:00
云风
415459e656 Merge pull request #728 from hwangcc23/init-sigaction
Properly initialize sigaction struct
2017-09-01 10:05:08 +08:00
hwangcc23
596e8cfab2 Properly initialize sigaction struct
The code in skynet_main.c wasn't clearing the struct sigaction before passing it to sigaction().
This meant that we would block a random set of signals while executing the SIGPIPE handler, or jump to the uninitialized __sa_sigaction__ (instead of sa_handler).
Initialize properly as we do in skynet_start.c.
2017-08-31 22:38:50 +08:00
Cloud Wu
dab4419335 catch error , see #726 2017-08-28 16:06:51 +08:00
Cloud Wu
932ebfa0fd lua bugfix 2017-08-28 16:06:05 +08:00
云风
9d74307836 Merge pull request #725 from dingmingxin/master
using clock_gettime in macos(in macos_10.12 and later)
2017-08-28 12:08:41 +08:00
dmx
7be5ea0148 using clock_gettime in macos(in macos_10.12 and laster) 2017-08-28 11:26:51 +08:00
Cloud Wu
525279e9dd lua bugfix, see http://lua-users.org/lists/lua-l/2017-08/msg00065.html 2017-08-24 10:50:36 +08:00
云风
d0fbf0802f Merge pull request #722 from hwangcc23/fix-double-free
Fix double free
2017-08-24 10:05:46 +08:00
云风
fad154f474 remove this free would be better 2017-08-24 10:01:47 +08:00
hwangcc23
40543d42d5 Fix double free
In the mainloop function, calling __skynet_free__ frees the pointer which may has already been freed in __push_socket_data__.

mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
        struct harbor * h = ud;
        switch (type) {
        case PTYPE_SOCKET: {
                const struct skynet_socket_message * message = msg;
                switch(message->type) {
                case SKYNET_SOCKET_TYPE_DATA:
                        push_socket_data(h, message);
                        skynet_free(message->buffer);
                        // skip...

To fix this potential double-free bug, clear the pointer message->buffer in __push_socket_data__ after the pointer is freed.
2017-08-23 23:43:20 +08:00
Cloud Wu
fa763181c0 add \0 in dumper would be better 2017-08-22 09:41:24 +08:00
Cloud Wu
e48e6c40e7 use \0 instead of . 2017-08-21 21:49:36 +08:00
Cloud Wu
64a318a9f1 see issue #715 2017-08-19 10:20:05 +08:00
Cloud Wu
5e50aeab2b add postfix to datasheet data string 2017-08-18 14:31:25 +08:00
Cloud Wu
53fef98acf fix #718 2017-08-18 14:28:27 +08:00
Cloud Wu
f94ca6f4b3 add socket.disconnected(), used by socketchannle. see #715 2017-08-15 13:44:06 +08:00
Cloud Wu
90536e4a0d fix invalid type of generic response packets, see #712 2017-08-14 10:49:32 +08:00
Cloud Wu
9c37f5292a check direct write buffer before close, see #711 2017-08-11 17:06:01 +08:00
Cloud Wu
23ee7dd814 use skynet.pcall in init, fix #704 2017-08-09 14:34:09 +08:00
Cloud Wu
990bede9b2 can't setenv more than once 2017-08-08 20:35:45 +08:00
Cloud Wu
b8d18d198e update lua version in readme 2017-08-07 15:49:50 +08:00
Cloud Wu
6d81c2b818 use socket.shutdown where timeout 2017-08-01 09:35:16 +08:00
Cloud Wu
f966199f28 update license 2017-07-28 11:35:42 +08:00
Cloud Wu
793fa4fdeb skynet 1.1.0 rc 2017-07-18 11:55:57 +08:00
Cloud Wu
814cd31cee update jemalloc to 5.0.1 2017-07-18 11:27:28 +08:00
云风
bf9466d568 Merge pull request #685 from cloudwu/directwrite
Direct write
2017-07-18 11:08:41 +08:00
Cloud Wu
317b4fb08f merge master 2017-07-14 21:42:15 +08:00
Cloud Wu
2b5c5e3dd3 see pr #683 2017-07-14 21:38:21 +08:00
Cloud Wu
d6eb49e4eb bson dictionary's key can't be number 2017-07-04 21:32:04 +08:00
Cloud Wu
751517d7c1 spinlock can be nested, see issue #646 2017-06-27 22:59:21 +08:00
Cloud Wu
03acc7f5a9 sp_write should be lock 2017-06-27 22:09:41 +08:00
Cloud Wu
9320d8b28d Revert "add nested spinlock, see issue #646"
This reverts commit ba59ed2e6c.
2017-06-27 22:08:33 +08:00
云风
86883c7d9a Merge pull request #677 from sundream/upstream
redis-cluster: ensure port is integer
2017-06-27 19:24:12 +08:00
sundream
2553afd6c9 redis-cluster: ensure port is integer 2017-06-27 18:59:06 +08:00
云风
9fc8754369 Merge pull request #674 from RJie/master
更正connection丢失的问题
2017-06-27 18:14:18 +08:00
Cloud Wu
ba59ed2e6c add nested spinlock, see issue #646 2017-06-27 17:10:48 +08:00
Cloud Wu
14aab9085a Merge branch 'master' into directwrite 2017-06-27 16:15:45 +08:00
Cloud Wu
eb2bc91e3f negative decimal number 2017-06-26 16:32:43 +08:00
RJie
38171f3bc9 更正connection丢失的问题
根据test文件中,输入端口号为number类型,此处应该使用d%,否则只format直进来ip,容易造成同一个ip地址的connection丢失。
2017-06-22 21:18:41 +08:00
Cloud Wu
72b6039328 static const 2017-06-22 09:51:07 +08:00
Cloud Wu
c10cceb1f7 Merge branch 'master' of github.com:cloudwu/skynet 2017-06-21 19:07:16 +08:00
Cloud Wu
7dd78ec89d add crypt.hmac64_md5 2017-06-21 19:05:03 +08:00
云风
01032087ec Merge pull request #672 from Jexocn/master
hook memalign
2017-06-21 17:49:13 +08:00
Cloud Wu
933f6730b2 add comment to hmac64 2017-06-21 17:33:27 +08:00
Jexocn
2b7b51614c Merge branch 'master' of https://github.com/Jexocn/skynet 2017-06-21 17:22:52 +08:00
Jexocn
a9122a9fe1 hook memalign 2017-06-21 17:21:53 +08:00
Jexocn
78ea3d4091 hook memalign 2017-06-21 17:16:16 +08:00
Cloud Wu
b3c60d1de2 add MEMORY_CHECK macro to check double free 2017-06-21 15:41:46 +08:00
Cloud Wu
b438d5a6b0 remove typedef 2017-06-21 15:22:11 +08:00
Cloud Wu
aa42534208 use trylock in send_buffer 2017-06-21 11:50:06 +08:00
Cloud Wu
171f8eef01 Merge branch 'directwrite' of github.com:cloudwu/skynet into directwrite 2017-06-20 22:52:47 +08:00
Cloud Wu
e96b4e782d bugfix: lock bug & udp direct write 2017-06-20 22:50:09 +08:00
hongl
626ad544b7 send crash 2017-06-20 22:50:09 +08:00
Cloud Wu
c53da829d3 direct write if send queue is empty 2017-06-20 22:50:09 +08:00
Cloud Wu
eeb06014da Merge branch 'directwrite' of github.com:cloudwu/skynet into directwrite 2017-06-19 11:48:46 +08:00
Cloud Wu
cc138adda9 bugfix: lock bug & udp direct write 2017-06-19 11:48:17 +08:00
云风
5632dbeec3 Merge pull request #667 from hongling0/directwrite
send crash
2017-06-16 17:20:57 +08:00
hongl
8ca47f76bf send crash 2017-06-16 17:01:58 +08:00
云风
48e031f2fb Merge pull request #664 from hongling0/master
让service.lua可以在用一个服务中复用
2017-06-14 11:23:04 +08:00
hongl
5479848df6 service.lua可以在用一个服务中复用 2017-06-14 10:27:04 +08:00
Cloud Wu
52026eb8f2 missing file: fix #661 2017-06-13 14:35:29 +08:00
云风
af1769aa25 Merge pull request #660 from hongling0/master
skynet.profile
2017-06-13 11:12:23 +08:00
hongl
953fa2c819 skynet.profile 2017-06-13 10:54:13 +08:00
hong
6f670685e2 Merge pull request #2 from cloudwu/master
update origin
2017-06-13 10:50:17 +08:00
Cloud Wu
9618dd47ce direct write if send queue is empty 2017-06-08 20:02:39 +08:00
云风
c72a133178 Merge pull request #657 from cloudwu/datasheet
Datasheet
2017-06-06 16:05:40 +08:00
Cloud Wu
7a4189f830 PROXYCACHE key weak 2017-06-06 16:03:59 +08:00
Cloud Wu
a8b5b36737 remove datasheet.builder.diff 2017-06-06 16:03:59 +08:00
Cloud Wu
6e36cf9940 add skynet.datasheet 2017-06-06 16:03:59 +08:00
Cloud Wu
1328895ff9 copy crypt to client.crypt, see #655 2017-06-06 13:54:51 +08:00
云风
4e54a27500 Merge pull request #654 from mrvon/master
remove wrong prefix
2017-06-05 10:28:58 +08:00
dennis
a0ac8640c7 remove wrong prefix 2017-06-04 23:52:21 +08:00
云风
38e4d81fb1 Merge pull request #651 from sundream/upstream
redis cluster client
2017-06-03 13:53:50 +08:00
sundream
2798c778c7 redis cluster client 2017-06-03 12:26:19 +08:00
Cloud Wu
94374cf06f fix #648 2017-06-02 19:36:39 +08:00
Cloud Wu
624fbf6f22 fix issue #648 2017-06-02 19:16:36 +08:00
云风
5aa3ed8d8f Merge pull request #647 from cloudwu/module
Module namespace
2017-06-02 13:26:38 +08:00
Cloud Wu
c7d2e2cb0e remove debugchannel proxy 2017-06-02 13:24:24 +08:00
Cloud Wu
895c0dae3b skynet.db.mongo 2017-06-01 17:31:19 +08:00
Cloud Wu
1d364b5c22 add skynet.service 2017-06-01 16:58:51 +08:00
Cloud Wu
5a4ebe6a73 move snax to skynet 2017-06-01 12:18:42 +08:00
Cloud Wu
2be915e3c7 compat skynet 1.0 lua module 2017-06-01 12:10:14 +08:00
Cloud Wu
f9f009a4c1 add prefix skynet to c module 2017-06-01 11:56:16 +08:00
Cloud Wu
f1ed482001 move to skynet module 2017-06-01 11:29:07 +08:00
Cloud Wu
8a6243d2a0 rename socket to skynet.socket 2017-06-01 10:51:02 +08:00
Cloud Wu
24537b3001 move some module into skynet/ 2017-06-01 10:46:06 +08:00
Cloud Wu
25763fc70b consider EPOLLHUP as EPOLLIN, see #644 2017-05-31 11:00:00 +08:00
Cloud Wu
7400e51451 support error event, see #644 2017-05-27 10:41:29 +08:00
Cloud Wu
a504c5e624 lua 5.3.4 bugfix 2017-05-08 15:07:00 +08:00
Cloud Wu
648504119e bugfix: wakeup sleep 2017-05-08 11:45:50 +08:00
Cloud Wu
acb0c57844 profile.resume_co bugfix 2017-05-04 16:58:24 +08:00
Cloud Wu
ea129cd9f6 bugfix: skynet.coroutine 2017-05-04 00:59:52 +08:00
Cloud Wu
4b2efd4785 add debug info to lua 2017-05-03 13:42:13 +08:00
Cloud Wu
72e3973cf9 decode response nil 2017-05-02 16:44:43 +08:00
Cloud Wu
d4eeb1ff28 sproto support response nil 2017-05-02 15:29:48 +08:00
云风
fd427843a9 Merge pull request #631 from thomasheep/dev_socket_opt2
optimize SOCKET_WARNING msg
2017-04-28 15:18:45 +08:00
silveratom
73e61a9cc6 Update socketchannel.lua 2017-04-28 15:17:12 +08:00
Stocom
cce8f0086a optimize SOCKET_WARNING msg 2017-04-28 10:49:30 +08:00
Cloud Wu
a7be332023 don't check response, because gate use a fake session for PTYPE_CLIENT 2017-04-26 18:01:05 +08:00
Cloud Wu
3fb46241f2 raise error when you forget response the request, fix issue #625 2017-04-25 11:38:29 +08:00
Cloud Wu
1153873321 minor fix 2017-04-24 15:28:15 +08:00
云风
000b46ec37 Merge pull request #623 from t0350/sharedata
error report on sharedata newindex
2017-04-24 15:26:41 +08:00
caijietao
3b6b31266d error report on sharedata newindex 2017-04-24 15:23:12 +08:00
Cloud Wu
89d771929a add print in testmongodb 2017-04-20 18:52:02 +08:00
Cloud Wu
77ed1bd68b add check for testbson 2017-04-20 18:48:15 +08:00
云风
b7d79ff343 Merge pull request #619 from cloudwu/bsonfix
destroy bson object when encode error
2017-04-20 18:43:37 +08:00
Cloud Wu
dab5a4e308 mongo.sort 2017-04-20 18:37:27 +08:00
Cloud Wu
999a941110 destroy bson object when encode error 2017-04-20 17:57:44 +08:00
Cloud Wu
ad36be1bd7 bugfix: http://lua-users.org/lists/lua-l/2017-04/msg00045.html 2017-04-20 11:26:22 +08:00
Cloud Wu
66f8fbd1b7 see issue #615 2017-04-19 10:50:48 +08:00
云风
7b10ee8d56 Merge pull request #614 from dongjinxian/master
1、remove not used require file
2017-04-18 16:26:39 +08:00
djx
62a4bcdc71 1、remove not used require file 2017-04-18 16:03:01 +08:00
Cloud Wu
312943c6a0 connect timeout, see #611 2017-04-13 15:32:54 +08:00
Cloud Wu
61d13846cd fix a bug , issue #592 2017-04-12 17:04:58 +08:00
Cloud Wu
8e7796a672 lpeg 1.0.1 2017-04-11 13:09:24 +08:00
Cloud Wu
6fa241453c redirect support alloc session 2017-04-07 11:11:39 +08:00
Cloud Wu
1f4a84edc2 fix dns bug , see issue #605 2017-04-06 11:57:28 +08:00
Cloud Wu
6699279d53 update sproto 2017-04-05 14:16:17 +08:00
Cloud Wu
2a79d7bed9 add FAQ in comment 2017-03-31 17:51:11 +08:00
Cloud Wu
fd0291845f proto.request is the condition 2017-03-28 18:54:14 +08:00
Cloud Wu
570a8356e6 add comment 2017-03-25 15:05:39 +08:00
Cloud Wu
6289b2b8e4 complete cluster.send 2017-03-25 00:10:23 +08:00
Cloud Wu
3a4a673b43 enhance config include 2017-03-21 11:49:04 +08:00
Cloud Wu
67b055009d bugfix isse #592 2017-03-20 16:25:15 +08:00
Cloud Wu
80d9ec379f config support include 2017-03-20 14:32:05 +08:00
Cloud Wu
673ffcce00 close stdfds after write_pid, see issue #590 2017-03-19 11:38:25 +08:00
Cloud Wu
6170346da2 add LUAMOD_API 2017-03-16 15:24:11 +08:00
Cloud Wu
b00b006c4a update jemalloc 4.5.0 2017-03-14 21:01:26 +08:00
Cloud Wu
48034ae22e merge sproto 2017-03-14 20:56:49 +08:00
Cloud Wu
1cdc0d7558 add cluster.reload(config) 2017-03-13 17:24:39 +08:00
Cloud Wu
cb19ab54e9 keep skynet.wakeup order, see issue #587 2017-03-13 17:01:41 +08:00
Cloud Wu
feab147563 revert, see issue #579 2017-03-10 14:06:53 +08:00
云风
f5911342e8 Merge pull request #579 from footer/master
nice error log in skynet coroutine
2017-03-06 15:22:56 +08:00
footer
c6cbc2f6b6 nice error log in skynet coroutine 2017-03-06 14:47:03 +08:00
Cloud Wu
ca290355fa add assert 2017-03-03 10:52:25 +08:00
Cloud Wu
2b55bc57a4 do not response send, may fix issue #578 2017-03-02 14:21:56 +08:00
Cloud Wu
5c831e2465 fix issue #574 2017-02-13 11:48:31 +08:00
云风
521a387271 Merge pull request #573 from hqwrong/pr
improve snax
2017-02-10 11:43:37 +08:00
hqwrong
f25e396181 1. snax hotfix recursively patch func
2. load hotfix source with _ENV instead of empty table
2017-02-10 11:01:36 +08:00
hqwrong
6fd1072fde fix snax hotfix 2017-02-10 11:01:36 +08:00
hqwrong
d637d720db snax loader 2017-02-10 11:01:36 +08:00
hqwrong
5c508e45a7 pcall->xpcall 2017-02-10 11:01:36 +08:00
Cloud Wu
2e919505f1 bson check utf8 string 2017-02-09 17:33:30 +08:00
Cloud Wu
af6b5609de add checksig in OP_FORLOOP, see issue #568 2017-01-23 16:50:34 +08:00
Cloud Wu
9e90ee2dde update to 5.3.4 rc3 2017-01-13 10:59:10 +08:00
Cloud Wu
8bc018fe20 update to jemalloc 4.4.0 2017-01-03 10:53:56 +08:00
Cloud Wu
2dbb0129d3 update to lua 5.3.4 2017-01-03 10:44:39 +08:00
云风
f10793e99b Merge pull request #563 from dingmingxin/master
add snax.profile_info interface
2016-12-16 10:35:01 +08:00
dmx
1e51af2d62 get snax profile_table after rewriting info_func of snax service 2016-12-15 15:59:23 +08:00
Cloud Wu
7ee9cdb29b dummy session is 1 2016-12-02 21:23:12 +08:00
Cloud Wu
a3eccf5e37 trash message 2016-12-02 20:49:16 +08:00
Cloud Wu
ace41d7c22 clusterd support send 2016-12-02 20:43:06 +08:00
云风
d0a41eb494 Merge pull request #562 from wyaocn/patch-1
skynet.lua raw_dispatch_message
2016-12-02 16:04:39 +08:00
Wei Yao
060e5384f5 skynet.lua raw_dispatch_message
似乎少了个session判断
2016-12-02 11:43:14 +08:00
云风
0e6a106180 Merge pull request #557 from lipeiyuan/master
modify debug_console result string
2016-11-22 19:43:33 +08:00
lpy
bac383441e modify debug_console result string 2016-11-22 19:37:10 +08:00
云风
3498bf9329 Merge pull request #555 from lipeiyuan/master
pass the inject code error to debug_console
2016-11-22 11:36:23 +08:00
lpy
708d57a77e pass the inject code error to debug_console 2016-11-22 11:14:07 +08:00
Cloud Wu
c5fb8ef3f7 add sharedata.deepcopy 2016-11-14 13:05:01 +08:00
Cloud Wu
ffe5de468e add skynet.stat 'time' 2016-10-26 18:01:22 +08:00
Cloud Wu
249ffb9362 add skynet.stat() to get cpu cost and message count 2016-10-26 17:43:52 +08:00
Cloud Wu
07a1499886 bugfix: profile 2016-10-26 16:28:36 +08:00
Cloud Wu
9c6f8f8b82 add sharedata.flush() to collect old version immediately 2016-10-11 12:06:11 +08:00
Cloud Wu
f48eeca667 add debug command call 2016-09-26 13:07:55 +08:00
Cloud Wu
ccb0e1b24c suppot httpc.timeout 2016-09-24 12:28:57 +08:00
云风
18bc3216ae Merge pull request #536 from hanyu363/master
[bugfix] alpine linux 编译不通过。
2016-09-08 21:37:05 +08:00
张玮华
0782b355a4 [bugfix] alpine linux 编译不通过。 2016-09-08 15:18:35 +08:00
Cloud Wu
c91efa5134 debug_console support user defined ip 2016-09-01 17:53:25 +08:00
Cloud Wu
26ad20aa2b debug cmem print total memory used 2016-08-25 11:55:13 +08:00
Cloud Wu
283c3f10fe bugfix: Issue #531 2016-08-08 17:48:10 +08:00
云风
2f23367671 Merge pull request #530 from learno/master
sort support multi key
2016-08-04 13:56:11 +08:00
Learno
c082d71a56 sort support multi key 2016-08-04 12:44:11 +08:00
Cloud Wu
e2fa2a1a4d lua5.3.3 bugfix 2/3 2016-08-01 14:18:13 +08:00
云风
9882dd1cfd Merge pull request #528 from puXiaoyi/skynet_pr
fix comment for lpushbuffer
2016-07-14 15:15:12 +08:00
puXiaoyi
b278106336 fix comment for lpushbuffer
The size of first chunk ([2]) is 16 struct buffer_node, and the second
size is 32 ...
2016-07-14 13:49:06 +08:00
Cloud Wu
97538286fd 1.0.0 Released 2016-07-11 19:39:45 +08:00
Cloud Wu
fd1b230a54 1.0.0 rc5 2016-07-04 16:31:58 +08:00
Cloud Wu
33321e89a1 don't launch console service when in daemon mode 2016-06-28 18:31:12 +08:00
云风
b50e663a3a Merge pull request #525 from zxfishhack/master
auto determine primary host
2016-06-27 11:39:15 +08:00
zxfishhack
14a699cb85 auto determine primary host 2016-06-27 10:59:50 +08:00
Cloud Wu
098d44162b bson support meta array 2016-06-23 16:14:16 +08:00
Cloud Wu
16af94795e lua 5.3.3 bugfix 1 2016-06-22 22:28:54 +08:00
云风
00f41c6bc9 Merge pull request #521 from ahuang007/patch-1
Update lua-crypt.c
2016-06-21 15:37:56 +08:00
ahuang007
0465688403 Update lua-crypt.c
这个地方应该用G
2016-06-21 15:25:08 +08:00
Cloud Wu
8cd5834d28 Merge branch 'master' of github.com:cloudwu/skynet 2016-06-17 12:19:56 +08:00
Cloud Wu
040089639f memory leak bugfix in multicast, See issue #519 2016-06-17 12:17:53 +08:00
云风
81c4e47a6d Merge pull request #517 from cloudwu/mongoauth
Add mongo auth_scram_sha1 , See pr #492
2016-06-16 09:47:03 +08:00
Cloud Wu
2aef994aa4 add authmod in conf 2016-06-15 17:58:58 +08:00
Cloud Wu
ffa2bbf1e4 support mongo auth_scram_sha1 2016-06-15 16:49:58 +08:00
Cloud Wu
6a54fe8293 1.0.0 rc4 2016-06-13 15:13:17 +08:00
Cloud Wu
2020ce3c9c update jemalloc to 4.2.1 2016-06-13 15:08:33 +08:00
云风
2557559d5c Merge pull request #512 from cloudwu/createindex
add createindexes , for detail see pr #511
2016-06-13 13:12:57 +08:00
Cloud Wu
bb0143e476 add some assert 2016-06-13 12:29:01 +08:00
Cloud Wu
fd2c814fe0 default key ascending 2016-06-13 12:13:02 +08:00
Cloud Wu
bd3d9b70ec change arg name 2016-06-13 12:05:52 +08:00
Cloud Wu
ee1a218870 typo 2016-06-13 12:01:54 +08:00
Cloud Wu
84ee3da79a add mongo.createIndexs, and fix the bug in old API createIndex. For detail, see PR #511 2016-06-13 11:55:31 +08:00
云风
fdee7de36d Merge pull request #509 from dpull/master
重新设计debug.lua接口
2016-06-12 16:41:18 +08:00
dpull
bf5b74b6ca 重新设计debug.lua接口 2016-06-12 16:29:47 +08:00
Cloud Wu
d9b0347741 don't close fd twice 2016-06-12 15:07:56 +08:00
Cloud Wu
9546537256 debug console support simple http 2016-06-12 14:51:18 +08:00
Cloud Wu
f84fe84b96 update userlog 2016-06-12 13:48:53 +08:00
Cloud Wu
ea9bc53261 reopen log file when recv signal HUP 2016-06-12 13:40:23 +08:00
Cloud Wu
0edb839c95 Lua 5.3.3 released 2016-06-07 09:43:43 +08:00
Cloud Wu
b8bb327f98 make coroutine_pool weak would be better 2016-06-06 16:23:39 +08:00
cloudwu
27d69334ee Merge pull request #506 from rickone/master
Update socketchannel.lua
2016-06-05 01:07:42 +08:00
rickone
838e63ab62 Update socketchannel.lua
request的时候可能会连接失败,这时raise的不是socket_error,上层处理不太统一。
2016-06-04 16:26:07 +08:00
Cloud Wu
ba264700dc update jemalloc to 4.2.0 2016-05-31 09:36:21 +08:00
Cloud Wu
e00ad7ab79 update to lua 5.3.3 rc3 2016-05-31 09:30:21 +08:00
Cloud Wu
de176b735f update to lua 5.3.3 rc2 2016-05-19 13:16:19 +08:00
cloudwu
cc3e985834 Merge pull request #502 from pigparadise/cloudwu
lua_bson的encode方法增加对有自定义__pairs的table的支持
2016-05-19 13:19:21 +08:00
LiuYang
3b5f45eea2 lua_bson的encode方法增加对有自定义__pairs的table的支持 2016-05-19 13:10:33 +08:00
cloudwu
c3056b04c1 Merge pull request #498 from asanosoyokaze/patch-1
add vararg for INFO debug console command
2016-05-16 19:35:02 +08:00
David Feng
58755a6772 add vararg for INFO debug console command 2016-05-16 18:57:40 +08:00
Cloud Wu
1cf976c4e4 add debug console command : ping 2016-05-13 09:46:44 +08:00
Cloud Wu
5be836527c bugfix issue #494 2016-05-11 22:02:10 +08:00
Cloud Wu
e9f397945d bugfix issue #494 2016-05-10 16:59:34 +08:00
Cloud Wu
78df0b8161 refine code 2016-05-09 19:16:29 +08:00
cloudwu
db17245005 Merge pull request #493 from chenkete/master
修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败
2016-05-09 19:17:56 +08:00
chenkete
4edb586077 修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败 2016-05-09 17:16:37 +08:00
Cloud Wu
ed1a8313f4 1.0.0 rc3 2016-05-09 10:06:32 +08:00
Cloud Wu
c450b7b5d7 update jemaloc to 4.1.1 2016-05-09 09:56:30 +08:00
Cloud Wu
56846b7dda new script to check deadloop service 2016-05-09 09:47:01 +08:00
Cloud Wu
fb232cc43e update lua to 5.3.3 rc1 2016-05-09 09:45:40 +08:00
Cloud Wu
a5c79cc4bd move skynet.memlimit from skynet.manager to skynet 2016-05-07 09:23:01 +08:00
Cloud Wu
4b96ade660 support sandbox memory limit 2016-05-06 23:40:44 +08:00
Cloud Wu
76d1e6fa1f memory warning 2016-05-06 20:37:51 +08:00
Cloud Wu
a6299a0748 optimize skynet.error 2016-05-06 20:10:11 +08:00
Cloud Wu
6cc558bb82 output Exit when new service exit 2016-05-06 19:45:50 +08:00
Cloud Wu
84b08bf286 detect console fd closed 2016-05-06 19:37:16 +08:00
Cloud Wu
4ada09b93c add pcall in launcher 2016-05-06 14:06:38 +08:00
Cloud Wu
2862568eca typo in history 2016-04-29 16:25:12 +08:00
cloudwu
ed2e16a346 Merge pull request #491 from asanosoyokaze/patch-go
skynet.pcall support vararg; sharedata loader can use custom args
2016-04-27 21:44:59 +08:00
David Feng
45d46b9072 skynet.pcall support vararg; sharedata loader can use custom args 2016-04-27 20:53:05 +08:00
Cloud Wu
4924c6d30b Merge branch 'master' of github.com:cloudwu/skynet 2016-04-20 22:35:29 +08:00
Cloud Wu
6b2eb80188 fix #487 2016-04-20 22:35:01 +08:00
cloudwu
298e4baf0e Merge pull request #485 from dpull/patch-1
给dbgcmd增加扩展性
2016-04-20 10:24:54 +08:00
Cloud Wu
c5fb93823a update sproto, fix bug in sproto.default 2016-04-20 10:11:55 +08:00
Acai
f238113677 给dbgcmd增加扩展性
我们项目增加了一个dbgcmd的指令,主要用于热更新,但在升级skynet版本时,需要记得合并这个差异,感觉挺挫的。

但现有的debug.lua并不利于扩展,于是呢,我想通过给debug.lua增加一个upvalue来解决这个问题。

其实也是解决的挺挫的 :)
2016-04-19 21:11:31 +08:00
Cloud Wu
f56d777cc2 for compatible 2016-04-18 12:05:46 +08:00
Cloud Wu
b124d4c1b8 skynet.getenv can return empty string 2016-04-18 11:55:39 +08:00
cloudwu
4fe098713f Merge pull request #483 from t0350/master
bugfix, error when use lua apicheck
2016-04-08 10:34:45 +08:00
caijietao
146f8ea09d bugfix, error when use lua apicheck 2016-04-08 10:29:34 +08:00
Cloud Wu
69b5bd8c13 update sproto. support encode empty table 2016-04-07 10:12:30 +08:00
cloudwu
dd7e962c94 Merge pull request #480 from rickone/master
Update redis.lua
2016-04-01 14:33:10 +08:00
rickone
5332021086 Update redis.lua
exec执行时其中一条出错,看不到错误信息
2016-04-01 12:39:09 +08:00
Cloud Wu
8de3149485 request global name from master, see issue #476 2016-04-01 10:22:57 +08:00
cloudwu
e3fee604e1 Merge pull request #478 from xjdrew/skynet_init
skynet.init按照顺序初始化
2016-03-31 17:51:29 +08:00
xjdrew
dd152fc910 skynet.init按照顺序初始化 2016-03-31 17:33:47 +08:00
Cloud Wu
c4b45acae3 sproto: check args 2016-03-29 12:34:55 +08:00
cloudwu
cf50a582f2 Merge pull request #474 from felixonmars/patch-1
Improve some English in README
2016-03-24 17:53:00 +08:00
Felix Yan
ca5e855c34 Improve some English in README 2016-03-24 17:48:43 +08:00
Cloud Wu
13d1d9fc9d update jemalloc to 4.1.0 2016-03-24 16:29:00 +08:00
Cloud Wu
242ff32bca lua 5.3.2 bugfix 2/3 2016-03-24 16:19:06 +08:00
cloudwu
ba451c1cd2 Merge pull request #465 from mrvon/master
skynet.coroutine
2016-03-11 15:28:56 +08:00
dennis
e5490522ce this line is useless 2016-03-09 17:50:33 +08:00
dennis
ae717c3e7d Merge remote-tracking branch 'upstream/master' 2016-03-09 17:48:16 +08:00
cloudwu
1a7df9108a Merge pull request #463 from great90/master
delete unused local variable
2016-03-08 11:34:25 +08:00
great90
7771e180ec delete unused local variable
delete unused local variable table "udp_socket"
2016-03-08 11:25:59 +08:00
great90
82bbb1c944 Merge pull request #3 from cloudwu/master
release rc2
2016-03-08 11:21:18 +08:00
Cloud Wu
cbf22ac9f3 release rc2 2016-03-07 11:46:30 +08:00
great90
bacaf10f1b Merge pull request #2 from cloudwu/master
update from cloudwu
2016-03-02 09:08:40 +08:00
Cloud Wu
8f7fa6a562 merge sproto 2016-02-25 14:40:24 +08:00
cloudwu
7b96eb28eb Merge pull request #455 from niuys/patch-2
error deal for query containing multi statement
2016-02-22 16:15:51 +08:00
snail
14ccf96eb0 error deal for query containing multi statement
A query may execute multi sql statements.If an error occurs for any sql, the result should return the error info.
2016-02-22 11:23:35 +08:00
dennis
6303886b8c Merge remote-tracking branch 'upstream/master' 2016-02-15 10:12:09 +08:00
Cloud Wu
ea8557296b fix issue #450 2016-02-13 19:20:07 +08:00
cloudwu
2a821fb62a Merge pull request #445 from DavidFeng/patch
fix
2016-01-27 13:55:14 +08:00
David Feng
d982009260 fix 2016-01-27 10:35:48 +08:00
cloudwu
a3f028ee3d Merge pull request #444 from DavidFeng/patch-1
修复调试模块调试结束后定时器没有取消的问题
2016-01-22 11:05:04 +08:00
David Feng
d34b092cdd remotedebug.lua call skynet.timeout() only in debug hook
定时器在debug结束后没有取消。
2016-01-22 10:28:03 +08:00
David Feng
77f4071191 remove unused local variables 2016-01-22 10:26:13 +08:00
cloudwu
653b29145d Merge pull request #442 from DavidFeng/patch-2
change socket.write to socketdriver.send
2016-01-20 22:05:23 +08:00
David Feng
96e0a4e3cc change socket.write to socketdriver.send
这样改过之后可以直接调试使用了gate服务的模块。
因为gate服务注册了socket类型的消息,所以不能和socket模块一块使用;而debug模块只使用到了socket模块的write函数,所以这样修改后对debug的功能并没有影响,但改过之后就可以调试gate服务了。
2016-01-20 19:24:58 +08:00
Cloud Wu
1da92850a0 bugfix: dispatch local global message queue 2016-01-19 17:14:52 +08:00
Cloud Wu
9747cf9aee don't assert here 2016-01-19 16:16:18 +08:00
Cloud Wu
7f45b3fd10 correct maxsz 2016-01-13 13:13:31 +08:00
cloudwu
217ab47577 Merge pull request #435 from niuys/patch-1
reduce needless 'add_string' call
2016-01-11 15:56:52 +08:00
snail
532f47444b reduce needless 'add_string' call
Short strings in lua proto are reused most of the time. The string in SSM may be added by one service and used by other service,  there is no need to call `add_string`,which will call 'new_string' first.
2016-01-11 15:06:51 +08:00
Cloud Wu
24f9ee1560 work thread for channel may not create if you never connect 2016-01-08 18:34:45 +08:00
Cloud Wu
d7a76c7c72 If no content-length, read all. see issue #431 2016-01-07 16:01:17 +08:00
Cloud Wu
c175d66e23 remove unused function 2016-01-06 16:55:15 +08:00
dennis
30cbcfd013 Merge remote-tracking branch 'upstream/master' 2016-01-06 15:57:42 +08:00
Cloud Wu
05003e3e2a sproto.attach also need ud 2016-01-05 17:51:48 +08:00
Cloud Wu
64c2cb1b51 sproto dispatch support ud 2016-01-05 16:06:20 +08:00
cloudwu
7f0e4eac8a Merge pull request #428 from fztcjjl/master
fix comment error
2016-01-04 16:07:50 +08:00
Cloud Wu
141a4d0992 lua 5.3.2 bugfix,see http://lua-users.org/lists/lua-l/2016-01/msg00000.html 2016-01-04 16:01:03 +08:00
fztcjjl
645ce72e7e fix comment error 2016-01-04 14:55:28 +08:00
cloudwu
fca4d67a43 Merge pull request #425 from DeanHH/patch-1
Update skynet_mq.c
2016-01-01 00:08:23 +08:00
DeanHH
014cbb9676 Update skynet_mq.c
Comment error:-)
2015-12-31 17:31:08 +08:00
Dennis
a39e822184 Merge pull request #1 from cloudwu/master
update from origin
2015-12-30 09:51:58 +08:00
Cloud Wu
a3a7d129ab V1.0.0 RC 2015-12-28 13:55:01 +08:00
cloudwu
2e69370594 Merge pull request #418 from m2q1n9/master
fix a debug_console error
2015-12-28 00:15:29 +08:00
m2q1n9
bcdfcde72f fix code indent 2015-12-27 22:38:58 +08:00
Cloud Wu
0c4ea81709 EAGAIN and EWOULDBLOCK may be not the same value, see issue #420 2015-12-27 19:31:32 +08:00
m2q1n9
b9ad559992 fix a debug_console error 2015-12-25 17:24:50 +08:00
Cloud Wu
f0ac66787e socket channel connect should wait for last closing 2015-12-23 20:22:46 +08:00
Cloud Wu
5a1b2e51f7 exit dispatch_by_order when close channel 2015-12-23 19:55:42 +08:00
Cloud Wu
7acf6d8767 remove unused varargs 2015-12-18 23:28:55 +08:00
Cloud Wu
20610723a1 add debug api to show current service c memory 2015-12-17 22:13:51 +08:00
Cloud Wu
9d6bde01a3 profile support skynet coroutine 2015-12-17 20:41:02 +08:00
Cloud Wu
4a80a75fd6 skynet.coroutine.status may return blocked 2015-12-17 17:11:54 +08:00
Cloud Wu
872491e968 Add skynet.coroutine module 2015-12-17 16:25:24 +08:00
cloudwu
41252e8c21 Merge pull request #414 from DavidFeng/patch-1
fix typo
2015-12-17 16:16:38 +08:00
David Feng
a9fc577560 fix typo
fix a little mistake
2015-12-17 15:53:39 +08:00
Cloud Wu
4f8427a23f close socket when sp_add failed 2015-12-17 10:04:38 +08:00
cloudwu
8ff5bcb372 Merge pull request #410 from kezhuw/bugfix_dangling_c_pointer_to_lua_string
Fix dangling c pointer to lua string value
2015-12-15 00:56:40 +08:00
Kezhu Wang
bfe8eeb4b3 Fix dangling c pointer to lua string value
Lua string object referenced by C pointer from lua_tolstring() was
removed from stack by lua_settop(L,0).

Lua 5.3 Reference Manual says:

> Because Lua has garbage collection, there is no guarantee that the
> pointer returned by lua_tolstring will be valid after the
> corresponding Lua value is removed from the stack.

That is it.

Introduced in commit 9937081854.
2015-12-14 16:16:37 +08:00
Cloud Wu
ccb9cdbc9d update sproto schema 2015-12-14 12:25:26 +08:00
cloudwu
4006faac29 Merge pull request #407 from linse073/patch-3
loginserver.lua中的launch_slave的lua消息处理函数的return问题
2015-12-08 13:31:16 +08:00
linse073
03617f23a1 loginserver.lua中的launch_slave的lua消息处理函数的return问题
之前可能是我没有表述清楚,这两个return我猜想是不是手误加上去的,因为之前都没有见过需要在消息处理函数里面return skynet.ret调用的结果,实际去掉后测试也是没有问题的,和是不是两次pcall的调用应该是没有关系的。
2015-12-07 21:00:19 +08:00
Cloud Wu
d4d188541f add socket.close_fd 2015-12-06 16:48:28 +08:00
Cloud Wu
3a2766dd0e return results, see pr #403 2015-12-04 10:47:30 +08:00
Cloud Wu
1431f55d28 update readme 2015-12-03 15:37:43 +08:00
cloudwu
22c0d3ab73 Merge pull request #396 from niuys/patch-6
close file handle clearly
2015-12-01 21:52:38 +08:00
snail
940a7ac58c close file handle clearly
Although 'f'  would be closed after collected, maybe it's better to close it clearly
2015-12-01 20:17:03 +08:00
Cloud Wu
05605e62a9 core.querytype doesn't raise error, see issue #395 2015-12-01 17:09:32 +08:00
Cloud Wu
3a527f0a66 update lua to 5.3.2 2015-11-30 20:31:56 +08:00
Cloud Wu
e47a4921fa bugfix. remote publish first, see issue #391 2015-11-27 18:13:50 +08:00
Cloud Wu
c180036bed use async dns resolve in httpc, and dns resolve cache by ttl. see about issue #253 2015-11-25 13:09:41 +08:00
Cloud Wu
d35388581f big number in sproto 2015-11-23 16:12:57 +08:00
Cloud Wu
2c3f3ac3c6 more sproto wire protocol examples 2015-11-23 12:47:29 +08:00
cloudwu
09670ee733 Merge pull request #383 from DavidFeng/patch-1
fix typo
2015-11-22 19:39:30 +08:00
David Feng
fbbda08bb2 fix typo 2015-11-21 15:36:25 +08:00
Cloud Wu
0f454fe248 Merge branch 'master' of github.com:cloudwu/skynet 2015-11-19 22:51:55 +08:00
Cloud Wu
91c720ad6f add assert for socket fd reuse 2015-11-19 22:51:43 +08:00
Cloud Wu
3335ea11d7 dummy luaS_expandshr 2015-11-19 21:02:46 +08:00
Cloud Wu
8d83881808 use CLOCK_MONOTONIC maybe better 2015-11-18 10:19:51 +08:00
Cloud Wu
f4437948ca fix Issue #377 2015-11-16 22:42:44 +08:00
Cloud Wu
2252409eaa add skynet_now() for 64bit time 2015-11-16 19:48:38 +08:00
Cloud Wu
87bc0815f6 bugfix: add lightuserdata 2015-11-13 17:28:02 +08:00
Cloud Wu
30859a1244 make cache 2015-11-13 13:25:33 +08:00
Cloud Wu
107be7ee8c rewrite redis driver , avoid table.concat 2015-11-13 12:30:46 +08:00
Cloud Wu
86d9d52308 Merge branch 'gitfancode-master' 2015-11-13 11:05:09 +08:00
Cloud Wu
9982cb6652 Merge branch 'master' of https://github.com/gitfancode/skynet into gitfancode-master 2015-11-13 11:04:51 +08:00
Cloud Wu
ce50c47c2b socket.send support strings table 2015-11-13 11:04:02 +08:00
xiefan
34d9b5555d reds pipeline v2(support function as pipeline params)
fix a bug & add function as pipeline params
2015-11-13 08:16:47 +08:00
xiefan
85062632bb Merge remote-tracking branch 'cloudwu/master' 2015-11-13 08:14:49 +08:00
xiefan
d2396f9d20 Revert "redis pipeline"
This reverts commit 471aecd708.
2015-11-13 08:10:33 +08:00
xiefan
471aecd708 redis pipeline
redis pipeline
2015-11-12 20:45:19 +08:00
Cloud Wu
d283d7fcaa check close return value 2015-11-12 18:34:50 +08:00
Cloud Wu
b72f0921d4 remove unused local function 2015-11-12 16:21:44 +08:00
Cloud Wu
6be649c5cb Merge branch 'master' of github.com:cloudwu/skynet 2015-11-12 15:42:05 +08:00
Cloud Wu
5edde990d6 bugfix: skynet.fork use table.pack to pack table 2015-11-12 15:41:41 +08:00
cloudwu
77813b446c Merge pull request #374 from huanzai/master
Update lua-netpack.c
2015-11-12 12:08:49 +08:00
huanzai
7138144a68 Update lua-netpack.c
当长度等于0x10000时,read_size读出的值为0
2015-11-12 11:15:50 +08:00
Cloud Wu
fa729d593b lua alloc use raw allocator 2015-11-12 10:53:14 +08:00
Cloud Wu
9f3baf2ee3 fix issue #372 2015-11-11 15:06:10 +08:00
Cloud Wu
7521fe0530 socket.shutdown abandon unsend buffer now, see issue #371 2015-11-11 10:44:50 +08:00
Cloud Wu
c28ae25c70 release 1.0.0 beta 2015-11-10 12:19:04 +08:00
Cloud Wu
9382454bcd update jemalloc to 4.0.4 2015-11-10 12:12:42 +08:00
Cloud Wu
d83fc0c00f sproto support all integer representation 2015-11-02 19:50:51 +08:00
云风
31340cf346 Merge pull request #369 from kexiao8/patch-1
repeated “struct table" of line 19
2015-11-01 19:27:16 +08:00
kexiao8
d1b26a60eb repeated “struct table" of line 19 2015-10-31 17:43:33 +08:00
Cloud Wu
ac4d51b779 bugfix issue #368 2015-10-29 11:22:26 +08:00
云风
0efab15f45 Merge pull request #366 from fztcjjl/master
add a callback for mysql auth
2015-10-28 20:49:44 +08:00
Cloud Wu
0199ba1382 sharedata support filename string 2015-10-28 17:37:06 +08:00
Cloud Wu
935863f434 report connect failed reason 2015-10-28 16:12:01 +08:00
Cloud Wu
13d920e185 body may contain ascii 0, see issue #365 2015-10-27 15:40:15 +08:00
Cloud Wu
a4af35f442 fix issue #364 2015-10-27 14:00:25 +08:00
云风
b1060478f7 Merge pull request #363 from nbwk1988/master
add hmac_md5
2015-10-27 11:39:55 +08:00
nbwk1988
1999a03ff7 优化hmac 2015-10-27 10:44:23 +08:00
nbwk1988
f5740e00b1 add hmac_md5
add hmac_md5
2015-10-26 16:12:10 +08:00
fztcjjl
1653b3213a add a callback for mysql auth 2015-10-24 06:37:25 +08:00
fztcjjl
fe3954fb04 add a callback for mysql auth 2015-10-24 01:35:16 +08:00
great90
716ecccaed Merge pull request #1 from cloudwu/master
update skynet
2015-10-23 14:33:54 +08:00
Cloud Wu
26cbebfcfd verify callback overflow 2015-10-21 12:58:57 +08:00
Cloud Wu
2d27df6f46 change name 2015-10-15 14:08:01 +08:00
Cloud Wu
bab91a3067 bugfix: don't use global wait_response 2015-10-15 14:01:50 +08:00
Cloud Wu
c1c032eab4 bugfix: socketchannel order mode may blocked. (used by redis driver) 2015-10-14 20:12:30 +08:00
Cloud Wu
7486e53232 avoid circular reference while encodeing bson 2015-10-14 15:44:09 +08:00
Cloud Wu
9aaa35ef14 avoid lua stack overflow 2015-10-14 15:24:51 +08:00
Cloud Wu
d2f2e299d5 call socket.abandon while auth error, see issue #355 2015-10-12 14:40:42 +08:00
Cloud Wu
d7e4e43a1b use spinlock macro 2015-10-12 13:07:09 +08:00
Cloud Wu
878110f9f7 add codecache.mode() 2015-10-12 12:29:19 +08:00
云风
60692e58dc Merge pull request #354 from xjdrew/bugfix_warning
bugfix: remove Wformat warning
2015-10-10 15:55:14 +03:00
xjdrew
515326dadc bugfix: remove Wformat warning 2015-10-10 18:39:42 +08:00
云风
4ee59edc44 Merge pull request #352 from xjdrew/gate
gate: application could control when to start receiving data
2015-10-09 05:05:33 +03:00
xjdrew
8dd9923cf6 gate: application could control when to start receiving data 2015-10-08 16:55:29 +08:00
Cloud Wu
8c1011c503 Add sproto:exist_type and sproto:exist_proto 2015-10-08 15:30:15 +08:00
Cloud Wu
8924b86ad7 check empty group, See pr #351 2015-10-08 15:15:35 +08:00
云风
14bc029864 Merge pull request #348 from xjdrew/unused_code
removte unused code
2015-10-05 05:17:29 +03:00
Cloud Wu
79e73d907e add target update3rd 2015-10-05 10:09:22 +08:00
Cloud Wu
3a06dcf534 update jemalloc to 4.0.3 2015-10-05 10:05:36 +08:00
Cloud Wu
97fd5053c9 update lpeg to 1.0.0 2015-10-05 09:56:12 +08:00
云风
3a3159d429 Merge pull request #347 from zhengfangxin/master
delete two clear_closed_event call
2015-10-05 04:51:22 +03:00
xjdrew
97ff6afc84 removte unused code 2015-09-29 17:29:33 +08:00
zhengfangxin
cb9feb34bd delete two no need call clear_closed_event 2015-09-26 21:03:38 +08:00
云风
48f79fe6d4 Merge pull request #345 from great90/master
从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump
2015-09-22 09:37:54 +08:00
great90
63942496fd 从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump 2015-09-21 23:50:18 +08:00
云风
bf9fc0c7e9 Merge pull request #343 from bingo235/master
gateserver close
2015-09-21 12:59:30 +08:00
bingo
325452a242 Signed-off-by: bingo <heidan725@qq.com> 2015-09-21 11:21:36 +08:00
Cloud Wu
752a501f68 bugfix: remove DONTCOPY tag from type 2015-09-21 10:40:09 +08:00
Cloud Wu
008351573a raise error when DH param is 0 2015-09-18 14:13:16 +08:00
Cloud Wu
00dbf6e996 DH key exchange can't be 0 , avoid attack 2015-09-18 14:10:12 +08:00
Cloud Wu
8cc5638f14 Merge branch 'master' of github.com:cloudwu/skynet 2015-09-15 14:52:44 +08:00
Cloud Wu
b8f419eb69 more error message for socket, and close listen socket when reach limit of open files. See Issue #339 2015-09-15 14:52:30 +08:00
云风
8f284e2d7f Merge pull request #340 from sanikoyes/Pr-missing-exitshr
add missing luaS_exitshr call
2015-09-14 18:05:56 +08:00
sanikoyes
846d55eaef add missing luaS_exitshr call 2015-09-14 18:03:04 +08:00
Cloud Wu
6c33f7bc44 see pr #332 2015-09-04 12:14:09 +08:00
Cloud Wu
7797de85b4 bugfix: See PR #332 2015-08-31 16:36:57 +08:00
云风
7ec452c782 Merge pull request #332 from niuys/patch-4
'response' not released
2015-08-30 22:08:37 +08:00
snail
7f9c3c8c9a local function is better
local function is the same as " local a; a = function"
2015-08-30 18:17:41 +08:00
snail
bad3472124 'response' not released
'response' not released after src service died, and defined error.
2015-08-30 16:47:34 +08:00
Cloud Wu
4f665d2469 init global string table, See issue #331 2015-08-30 12:13:23 +08:00
Cloud Wu
633e5fbe32 fix issue #331 2015-08-29 15:24:24 +08:00
云风
c1c5cd39e5 Merge pull request #328 from cloudwu/shrtbl
global shared string table
2015-08-27 21:16:47 +08:00
云风
03f5da6bb5 Merge pull request #329 from niuys/patch-3
uncomplete buffer not free
2015-08-27 18:15:12 +08:00
snail
1bfddda435 uncomplete buffer not free
'uncomplete' buffer not freed in clear
2015-08-27 18:04:56 +08:00
Cloud Wu
9b0e496afe minor amend 2015-08-27 13:49:31 +08:00
Cloud Wu
010d1c1d4f avoid dead loop 2015-08-24 11:50:40 +08:00
Cloud Wu
eb587c63d3 fix issue #327 2015-08-21 19:42:09 +08:00
Cloud Wu
bb6d5d826e add TString struct size 2015-08-21 15:59:51 +08:00
Cloud Wu
9acce94464 disable lua apicheck 2015-08-21 13:55:43 +08:00
Cloud Wu
c0862d8445 add global share string table 2015-08-21 13:52:04 +08:00
Cloud Wu
1b53e6e28d Release alpha 10 2015-08-17 11:21:20 +08:00
云风
77bdfb2ceb Merge pull request #325 from cloudwu/pthreadlock
add pthread lock
2015-08-17 10:25:36 +08:00
Cloud Wu
2583af26d7 add cluster.register and cluster.query 2015-08-14 23:22:00 +08:00
Cloud Wu
a38a3140dd error when send to address 0 2015-08-14 17:32:59 +08:00
Cloud Wu
bf8f9b8654 add pthread lock 2015-08-13 21:00:20 +08:00
Cloud Wu
0ce9921c25 remove unused sz 2015-08-12 21:16:02 +08:00
Cloud Wu
adc39705f3 remove unused netpack c api 2015-08-12 20:56:29 +08:00
Cloud Wu
a4f827a48d use string for msgserver request 2015-08-12 14:53:36 +08:00
Cloud Wu
7547126570 bugfix: memory leak , See Issue #323 2015-08-12 12:03:52 +08:00
Cloud Wu
926b44ddf6 remove unused parm 2015-08-11 14:09:16 +08:00
Cloud Wu
d3771edc9d The cluster message never great than 64K now 2015-08-11 14:04:15 +08:00
Cloud Wu
947727e33a add new socket message WARNING 2015-08-11 13:21:24 +08:00
云风
27148981d5 Merge pull request #320 from cloudwu/multipart
Multipart
2015-08-11 11:17:22 +08:00
Cloud Wu
6fa436e8ff add core.intcommand , See Issue #321 2015-08-10 22:06:36 +08:00
Cloud Wu
2935ba3521 Release alpha9 2015-08-10 16:17:55 +08:00
云风
5c8ea6f09f Merge pull request #318 from felixdae/cloud
not work with telnet due to \r\n
2015-08-08 16:45:21 +08:00
felixdae
c16ae57639 not work with telnet due to \r\n 2015-08-07 18:52:50 +08:00
云风
1c7d44fd4d Merge pull request #316 from niuys/patch-2
'hotfix' code cannot use '_ENV'
2015-08-07 16:14:13 +08:00
云风
ca7e38137d Merge pull request #317 from chuenlungwang/multipart
Packing multipart req number first byte is 1
2015-08-07 16:07:25 +08:00
BITMAN
5936d3616c Packing multipart req number first byte is 1 2015-08-07 13:51:10 +08:00
snail
e9cfdba22a 'hotfix' code cannot use '_ENV'
If there's no global variable or function used in any interface of a snax service,the upvalue "_ENV" for 'hotfix' is not set. This modify is not  complete, it depend's on the 'collect_uv' method having upvalue '_ENV',maybe other good method to get upvalue index of '_ENV'.
2015-08-07 10:38:57 +08:00
Cloud Wu
3156661e0b bugfix: response function for socket channel 2015-08-06 20:00:48 +08:00
Cloud Wu
b4048a8eab bugfix: typo 2015-08-05 16:42:05 +08:00
Cloud Wu
aff73cbed7 Increase message size 16M(24bit) limit to 56bit on 64bit arch 2015-08-05 12:23:35 +08:00
Cloud Wu
b5244b96aa cluster rpc support large package 2015-08-04 17:56:17 +08:00
Cloud Wu
704b016f2c bugfix: inc session before get channel 2015-08-04 17:51:35 +08:00
Cloud Wu
3b48beb428 bson bugfix 2015-07-30 15:41:17 +08:00
Cloud Wu
4cbead28d5 skynet.dispatch can replace old func 2015-07-29 16:12:49 +08:00
Cloud Wu
b3f966bcaa bugfix: multicast chan gc 2015-07-29 16:10:38 +08:00
Cloud Wu
7b54e37d12 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-24 17:58:06 +08:00
Cloud Wu
e87ac18b84 expand lua stack first 2015-07-24 17:50:42 +08:00
云风
05af87ce8e Merge pull request #311 from jintiao/patch-1
fix "make cleanall" on macosx
2015-07-24 17:45:41 +08:00
jintiao
0ee61de22c skip jemalloc clean if jemalloc's makefile was missing 2015-07-24 00:48:24 +08:00
Cloud Wu
1da8a6b38d lazy init debug command 2015-07-23 18:35:29 +08:00
Cloud Wu
b2d8237363 improve unregister protocol error report 2015-07-23 18:23:47 +08:00
Cloud Wu
39f9a96b6c add cmemory.info() returns a table of c memory info 2015-07-23 16:47:35 +08:00
Cloud Wu
588c4a3508 bugfix 2015-07-22 16:49:25 +08:00
Cloud Wu
d6734890e0 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-22 15:53:19 +08:00
Cloud Wu
4ebb139c2b bugfix: free message when cluster not connected 2015-07-22 15:52:26 +08:00
云风
20476d2280 Merge pull request #308 from jsenter/patch-1
Update cdummy.lua
2015-07-21 15:20:56 +08:00
Cloud Wu
3131bca6ef Merge branch 'master' of github.com:cloudwu/skynet 2015-07-21 11:31:41 +08:00
Cloud Wu
3f91484791 user log service 2015-07-21 11:31:27 +08:00
LiBei
a0ecd51230 Update cdummy.lua
误定义全局变量
2015-07-21 11:12:55 +08:00
云风
dba1db9cc4 Merge pull request #304 from JiessieDawn/master
sharedata serialization bugfix
2015-07-13 14:13:48 +08:00
cxj
538414408d sharedata serialization bugfix 2015-07-13 13:04:09 +08:00
云风
4cf05fb2e7 Merge pull request #303 from JiessieDawn/master
sproto optimize
2015-07-11 20:36:39 +08:00
cxj
d9ad981c8c sproto optimize, malloc newchunk and return directly if sz >= CHUNK_SIZE in pool_alloc, do not replace current chunk if sz >= p->current_used in pool_alloc, more safety checking 2015-07-10 20:21:07 +08:00
云风
21c941fe63 Merge pull request #302 from sanikoyes/Pr-optimize-sproto-lunpack
Pr-optimize-sproto-unpack
2015-07-09 18:24:06 +08:00
sanikoyes
ea2437e138 lunpack optimize, do not unpack twice if r <= osz 2015-07-09 18:07:32 +08:00
Cloud Wu
86bbc9c701 off by 1 error 2015-07-07 12:11:16 +08:00
Cloud Wu
95e1d9f45f Merge branch 'master' of github.com:cloudwu/skynet 2015-07-03 10:58:53 +08:00
Cloud Wu
55cf9375fc asterisk(*) should be once or not at all 2015-07-03 10:58:40 +08:00
云风
654f732cd5 Merge pull request #300 from sanikoyes/Pr-fix-login-client
Pr-fix-login-client
2015-07-03 10:28:24 +08:00
sanikoyes
d4023c8b63 fix invalid fd after reconnected, used in unpack_f 2015-07-02 16:25:10 +08:00
云风
375f8606b4 Merge pull request #298 from JiessieDawn/master
support sharedata serialization
2015-07-02 15:04:49 +08:00
cxj
d17e6f59fe add sharedata lua serialization test 2015-07-02 15:02:11 +08:00
cxj
a77d36911d change wb_table to call wb_table_metapairs for keeping consistent style 2015-07-02 14:47:50 +08:00
cxj
4352dc4047 Merge branch 'master' of https://github.com/cloudwu/skynet 2015-07-02 13:56:55 +08:00
cxj
172356be19 fix lua-seric.c wb_table 2015-07-02 13:51:03 +08:00
Cloud Wu
08dabd51c8 fix issue #299 2015-07-02 12:17:18 +08:00
cxj
bd55a58515 support sharedata serialization 2015-07-01 16:54:20 +08:00
Cloud Wu
b646a1b8a3 fix login example 2015-07-01 12:51:20 +08:00
Cloud Wu
6b312fa09a update readme 2015-07-01 11:35:05 +08:00
Cloud Wu
dad66010cd sproto bugfix, see sproto issue 34 for detail 2015-06-30 15:05:49 +08:00
Cloud Wu
27ae0a7500 release alpha 8 2015-06-29 11:11:32 +08:00
Cloud Wu
6001d9c2eb raise error message from response function, See issue #295 2015-06-26 14:33:33 +08:00
Cloud Wu
728abeaeb8 can't write to listen fd, See issue #294 2015-06-25 19:28:42 +08:00
Cloud Wu
2fa130997f fix atom inc 2015-06-24 19:50:45 +08:00
Cloud Wu
8c57ec192a Merge branch 'master' of github.com:cloudwu/skynet 2015-06-24 18:58:24 +08:00
Cloud Wu
0fb2b21ed5 use atom inc for object id counter 2015-06-24 18:57:47 +08:00
云风
1fd2c3de81 Merge pull request #292 from leeonix/master
修改Makefile,添加lua的清理
2015-06-24 11:12:05 +08:00
Cloud Wu
f3536bfc53 not use raw api, fix Issue #293 2015-06-24 10:27:37 +08:00
leeonix
57999456ef modify Makefile and add lua clean
modify service-src/service_gate.c space to tab
2015-06-20 11:29:56 +08:00
Cloud Wu
35b35f686c bugfix: Issue #291 2015-06-19 13:22:40 +08:00
Cloud Wu
5d9142110e patch lua_clonefunction 2015-06-18 17:39:37 +08:00
Cloud Wu
2086e13a46 hack lua to support signal 2015-06-17 22:12:48 +08:00
Cloud Wu
f36b173155 update to lua 5.3.1 2015-06-17 22:06:11 +08:00
Cloud Wu
7fa1d548ed bugfix: don't call skynet_free directly when send failed 2015-06-16 10:56:28 +08:00
Cloud Wu
039235b3a3 lock before set quit flag 2015-06-09 21:46:37 +08:00
Cloud Wu
57d43a588e Check quit flag before pthread_cond_wait 2015-06-09 20:00:20 +08:00
Cloud Wu
8214c53891 release alpha7 2015-06-08 10:31:00 +08:00
Cloud Wu
5e642b15a4 Merge branch 'master' of github.com:cloudwu/skynet 2015-06-07 12:39:33 +08:00
Cloud Wu
ac093c7142 fix memory leak, see Issue #290 2015-06-07 12:38:55 +08:00
云风
01dcc45827 Merge pull request #289 from harrywong/typo-patch
typo in type of variable
2015-06-05 23:02:16 +08:00
Harry
d3ac522dc6 typo in type of variable 2015-06-05 19:04:43 +08:00
Cloud Wu
55d0d57d5c skynet.fork returns the coroutine, see Issue #287 2015-06-04 16:06:21 +08:00
Cloud Wu
1fec2e6063 sep size may greater than buffer node, See Issue #286 2015-06-03 09:42:49 +08:00
Cloud Wu
cc4756de35 fix Issue #285 2015-06-02 11:52:55 +08:00
Cloud Wu
7fb109dbb0 See Issue #284 2015-06-01 10:57:30 +08:00
Cloud Wu
7f578be649 bugfix: Issue #283 2015-06-01 10:42:29 +08:00
Cloud Wu
69946d75c5 add config.logservice for user defined log service 2015-05-30 22:17:53 +08:00
Cloud Wu
24f6994b50 close uncomplete when socket disconnect, see Issue #280 2015-05-29 21:11:02 +08:00
Cloud Wu
07dbfd8651 add underscore 2015-05-28 16:18:56 +08:00
Cloud Wu
ca50a5f518 dns support underscore 2015-05-28 16:10:19 +08:00
Cloud Wu
b8c54cbac2 skynet.kill move into skynet.manager 2015-05-27 21:17:43 +08:00
Cloud Wu
3a2c43e9e0 set nodelay in clusterd, Issue #278 2015-05-27 14:54:26 +08:00
Cloud Wu
205824ab12 use LUA_API instead of extern 2015-05-26 16:05:31 +08:00
云风
4ac047b274 Merge pull request #277 from xiyanxiyan10/master
调整格式
2015-05-23 17:02:37 +08:00
xiyanxiyan10
987a90af8b 调整格式 2015-05-23 16:35:15 +08:00
Cloud Wu
250531c9a7 bugfix: sproto.default 2015-05-22 20:51:00 +08:00
Cloud Wu
7b471ae27d snax service support cluster 2015-05-20 16:13:11 +08:00
云风
4f93054f3a Merge pull request #275 from ximenpo/master
console服务增加启动snax服务功能
2015-05-20 15:43:55 +08:00
ximenpo
65fad89794 console服务增加启动snax服务功能
输入:
svc  -> 用snlua启动svc服务
snax svc -> 用snax启动svc服务
2015-05-20 15:14:28 +08:00
云风
286c0f2c23 Merge pull request #273 from flashjay/patch-4
Update lua-crypt.c
2015-05-19 11:41:14 +08:00
HuaYang Huang
de57064b96 Update lua-crypt.c
添加 static 避免可能导致的链接冲突
2015-05-18 23:05:24 +08:00
Cloud Wu
6c43e90708 release alpha6 2015-05-18 12:02:08 +08:00
云风
1f25b79722 Merge pull request #272 from antsmallant/patch-1
Update inject.lua
2015-05-15 17:04:27 +08:00
Cloud Wu
6a9080157f need require skynet.manager 2015-05-15 16:24:01 +08:00
antsmallant
5cc2ef3ac8 Update inject.lua
免得变量i污染全局空间
2015-05-15 15:59:47 +08:00
Cloud Wu
3baeb62b0b move some api from skynet.lua to skynet/manager.lua 2015-05-13 11:04:25 +08:00
Cloud Wu
9e27f59033 remove task overload warning 2015-05-13 09:50:53 +08:00
Cloud Wu
82fa2f979c skynet.exit will call every unresponse handle 2015-05-12 23:15:03 +08:00
Cloud Wu
07d7324332 Merge branch 'master' of github.com:cloudwu/skynet 2015-05-12 22:53:16 +08:00
Cloud Wu
d92adda2c9 If skynet.wakeup a skynet.call, raise an error 2015-05-12 22:53:03 +08:00
Cloud Wu
0587400e2d update sproto: handle empty protocol 2015-05-12 10:20:16 +08:00
Cloud Wu
35c8c63793 update sproto, bugfix sproto_dump 2015-05-11 21:39:56 +08:00
Cloud Wu
c7f5145e9e update sproto , add new api sproto:default 2015-05-11 18:20:17 +08:00
Cloud Wu
9452169f0a remove unused comment 2015-05-07 18:17:46 +08:00
云风
a15f43e0f8 Merge pull request #267 from gaopan461/master
fix:udp and udp_send
2015-05-07 18:18:36 +08:00
gaopan
0eb4754b31 @fix udp_address, in big-endian machine maybe error 2015-05-07 16:52:48 +08:00
gaopan
f987ff8199 fix:udp and udp_send 2015-05-07 15:25:47 +08:00
云风
64a5d1ca24 Merge pull request #266 from xiyanxiyan10/master
错误注释更正
2015-05-06 23:27:13 +08:00
xiyanxiyan10
fa17081012 错误注释更正 2015-05-06 23:13:06 +08:00
Cloud Wu
856cb0737d Merge branch 'master' of github.com:cloudwu/skynet 2015-05-02 20:47:29 +08:00
Cloud Wu
f61e3f46e8 fix issue #265 2015-05-02 20:47:15 +08:00
云风
6b6b943b73 Merge pull request #262 from flashjay/patch-3
fix: httpc.get
2015-04-29 22:19:31 +08:00
HuaYang Huang
75d9b07158 fix: httpc.get
:-(
此错误会导致httpc.get无法找到正确的虚拟主机
2015-04-29 20:18:13 +08:00
Cloud Wu
8682f7f82f response error when return/response package is too large 2015-04-27 16:23:12 +08:00
Cloud Wu
35a5b99bed release alpha5 2015-04-27 10:45:31 +08:00
Cloud Wu
98af25d109 better error log, see pr #260 2015-04-24 14:31:18 +08:00
Cloud Wu
cd3391461c add skynet.pcall for hotfix use (call a function with require) 2015-04-22 17:01:03 +08:00
Cloud Wu
e3b7f86075 cluster reload should reset old connection to update address:port 2015-04-21 15:35:29 +08:00
Cloud Wu
86d5865457 bugfix: wunlock first, and then release context. (may dead lock) 2015-04-18 21:11:57 +08:00
Cloud Wu
7b783076e5 use hmac_hash 2015-04-16 10:41:23 +08:00
Cloud Wu
57c0ad694c add hmac_hash to simplify hmac64(hashkey(d), key) 2015-04-16 10:35:47 +08:00
Cloud Wu
f55a31c24f sproto.request_decode returns name 2015-04-15 22:01:01 +08:00
Cloud Wu
843095afc6 add snax.printf 2015-04-15 16:52:55 +08:00
Cloud Wu
a6bad52181 add sproto new api 2015-04-14 23:38:49 +08:00
Cloud Wu
012d98380d merge lua bugfix from lua offical bugs page 2015-04-13 17:14:08 +08:00
Cloud Wu
0298997d23 release alpha 4 2015-04-13 13:04:39 +08:00
Cloud Wu
678a94bf71 update license 2015-04-10 11:35:47 +08:00
Cloud Wu
03399e86a9 udp api changed, callback recv the string 2015-04-09 12:49:40 +08:00
Cloud Wu
22364bac89 bugfix: memory leak 2015-04-09 12:14:28 +08:00
Cloud Wu
9188b5451c bugfix 1 , from http://www.lua.org/bugs.html#5.3.0-1 2015-04-09 11:55:07 +08:00
Cloud Wu
c7ed527911 add const to sproto C api 2015-04-08 11:42:06 +08:00
Cloud Wu
5a1132101b share sproto C struct 2015-04-08 11:23:52 +08:00
Cloud Wu
ca33bf8b3e bugfix sproto : support empty string 2015-04-05 20:19:30 +08:00
Cloud Wu
7d8c80c9a0 fix Issue #256 2015-04-03 11:07:11 +08:00
Cloud Wu
c6f993428e bugfix #257 2015-04-03 11:03:37 +08:00
云风
f6118b858d Merge pull request #255 from flashjay/patch-1
fix: httpc.post
2015-04-03 09:35:41 +08:00
HuaYang Huang
ec1bca238e fix: httpc.post
调用httpc.post时,如果没有在header里面设置host时有问题
2015-04-01 17:54:22 +08:00
Cloud Wu
6b87f159b4 more type check 2015-04-01 13:22:09 +08:00
Cloud Wu
41b447d41a update sproto: check table 2015-04-01 12:18:49 +08:00
Cloud Wu
c512b5f59a release alpha 3 2015-03-30 11:00:51 +08:00
云风
fc9b32b4bd Merge pull request #254 from cloudwu/dev
release alpha 3
2015-03-30 11:00:18 +08:00
Cloud Wu
36ed8679b8 you can set host in httpc header 2015-03-30 09:29:22 +08:00
Cloud Wu
a9b1993686 Add async dns query 2015-03-29 14:41:28 +08:00
Cloud Wu
05b458ddb2 update sproto 2015-03-20 09:51:00 +08:00
Cloud Wu
8d8add3710 update sproto 2015-03-18 12:17:01 +08:00
Cloud Wu
65e7da9793 more sproto error message 2015-03-18 11:50:47 +08:00
Cloud Wu
7e5d9b7399 bugfix Issue #249 2015-03-18 11:07:34 +08:00
Cloud Wu
92b7b7beff use table for multi header key 2015-03-16 20:15:57 +08:00
Cloud Wu
c287f050c1 release alpha2 2015-03-16 17:39:07 +08:00
Cloud Wu
f71beb4018 sproto update 2015-03-16 17:33:24 +08:00
Cloud Wu
75bbdeb6d2 define LUA_CACHELIB 2015-03-16 17:24:02 +08:00
Cloud Wu
72c43b6614 minor fix 2015-03-15 21:20:56 +08:00
Cloud Wu
a0eddbdeca sproto:pdecode support userdata 2015-03-12 12:16:21 +08:00
Cloud Wu
03f7661a4a don't delete sproto object when share it 2015-03-11 16:48:43 +08:00
Cloud Wu
f95d8db4da Add marco detect lua version 2015-03-11 15:17:51 +08:00
Cloud Wu
a0ffff8ad6 add module signal and hack lua to support it :) 2015-03-11 15:10:53 +08:00
Cloud Wu
7ced874d7c Merge branch 'master' of github.com:cloudwu/skynet 2015-03-10 19:18:09 +08:00
Cloud Wu
a630eb796d remove wrong param, Issue #248 2015-03-10 19:17:53 +08:00
云风
f15eaee060 Merge pull request #247 from xmlzhaodj/master
use lua 5.3 in examples/login/client.lua
2015-03-10 10:13:54 +08:00
zhaodj
13cb2b79e2 change file mode 2015-03-10 05:05:39 +08:00
zhaodj
4d6d090ff2 use lua 5.3 in examples/login/client.lua 2015-03-10 05:02:12 +08:00
Cloud Wu
cbd7a2cd8b Release 1.0.0 alpha 2015-03-09 13:07:56 +08:00
Cloud Wu
e1db74da90 Merge branch 'lua53' 2015-03-09 13:01:37 +08:00
云风
612c33b92a Merge pull request #245 from DavidFeng/patch-1
remove redundant print and use skynet.error
2015-03-04 16:43:49 +08:00
Cloud Wu
77485403d7 Merge branch 'lua53' of github.com:cloudwu/skynet into lua53 2015-03-04 16:28:48 +08:00
Cloud Wu
d19d4f2443 bugfix: clear cached sub node 2015-03-04 16:27:59 +08:00
David Feng
e6d348e441 typo fix 2015-03-04 15:30:19 +08:00
David Feng
4718a12668 typo fix 2015-03-04 15:22:38 +08:00
David Feng
a7d79831e6 remove redundant print and use skynet.error 2015-03-04 15:14:35 +08:00
云风
8dd4701aa7 Merge pull request #243 from DavidFeng/patch-1
error report fix
2015-03-03 17:33:37 +08:00
云风
e6f920df9b Merge pull request #244 from learno/lua53
扩展mongo库对sort, skip, limit, count方法的支持
2015-03-03 17:04:11 +08:00
David Feng
fee96045ee fix error output format 2015-03-03 17:00:29 +08:00
Learno
5b469c0a9a 扩展mongo库对sort, skip, limit, count方法的支持 2015-03-03 16:54:34 +08:00
David Feng
cc136f996f error report fix 2015-03-02 16:31:32 +08:00
Cloud Wu
9a6e26db96 add sharemap , an example of stm 2015-02-28 16:42:47 +08:00
Cloud Wu
688cc843ce use sproto global slot 2015-02-28 13:33:56 +08:00
Cloud Wu
318ee300e3 add load/save proto for multi states use 2015-02-28 11:13:10 +08:00
Cloud Wu
7602195540 fix issue #239 2015-02-27 11:45:12 +08:00
云风
9067b9c50f Merge pull request #238 from yibiaochen/lua53
Update mysql.lua
2015-02-21 06:42:53 +08:00
billchen
e5e2771e27 Update mysql.lua
3处位操作没改
2015-02-21 01:52:34 +08:00
Cloud Wu
8645061a66 use offical patch for lua 2015-02-14 11:47:18 +08:00
Cloud Wu
76ab48df3b bugfix: watch hook begin at next call 2015-02-12 14:34:52 +08:00
Cloud Wu
bd790cbdf1 add _CO for debug coroutine 2015-02-11 17:58:52 +08:00
云风
95db7fdb5b Merge pull request #235 from cloudwu/debugger
Debugger
2015-02-11 14:56:51 +08:00
Cloud Wu
00efa6cc8a cond break point 2015-02-11 14:46:46 +08:00
Cloud Wu
8792a40845 debug step mode 2015-02-11 14:18:47 +08:00
Cloud Wu
e031a35330 support empty line 2015-02-09 23:48:45 +08:00
Cloud Wu
498f634ac5 remote debugger 2015-02-09 23:40:54 +08:00
Cloud Wu
62e70ef755 fix for lua 5.3 (PR #232) 2015-02-06 16:09:26 +08:00
Cloud Wu
d2145162bf remove bit32 2015-02-06 16:06:30 +08:00
云风
0abbe025a2 Merge pull request #231 from dpull/lua53
snax 的 G 可配置
2015-02-06 10:15:22 +08:00
dpull
0447f661e0 snax 的 G 可配置 2015-02-06 10:01:19 +08:00
Cloud Wu
72c2fad82a skynet.kill would raise error 2015-02-05 18:25:06 +08:00
Cloud Wu
7c7d63ea70 return nil to caller of newservice, while calling skynet.exit in start function 2015-02-05 18:16:26 +08:00
Cloud Wu
05ae055097 update lpeg to 0.12.1 2015-02-02 22:45:44 +08:00
云风
3404818d15 Merge pull request #228 from niuys/patch-3
needless 'string.format', accurate error info
2015-02-02 22:43:29 +08:00
snail
05c61ca2ce needless 'string.format', accurate error info
remove needless 'string.format' as param of assert, add detail error info for not exist interface.
2015-02-02 19:35:45 +08:00
Cloud Wu
6abb2dab7e Merge branch 'master' into lua53 2015-01-30 13:58:28 +08:00
云风
7399497c3a Merge pull request #226 from niuys/patch-2
remove needless 'debug.traceback' call in assert
2015-01-30 11:20:06 +08:00
snail
e2683a46c3 remove needless 'debug.traceback' call in assert
Though the result is not used, 'debug.traceback' is called when 'succ' is true
2015-01-30 11:15:43 +08:00
云风
b745ce31e1 Merge pull request #225 from niuys/patch-1
varable delcared in closure but used for global
2015-01-27 22:20:12 +08:00
Cloud Wu
5d2dc04f50 Merge branch 'master' of github.com:cloudwu/skynet into lua53 2015-01-27 22:18:51 +08:00
snail
c5c94036c3 varable delcared in closure but used for global
fork_queue is used in skynet.exit,but declared after it.
2015-01-27 22:00:24 +08:00
Cloud Wu
2de52cee4d bugfix: don't use new local var here 2015-01-27 18:03:05 +08:00
Cloud Wu
e44f589c53 unpack to table.unpack 2015-01-23 17:15:30 +08:00
Cloud Wu
40794a90b8 remove compat52 2015-01-23 11:08:49 +08:00
Cloud Wu
459347e24d use lua_clonefunction for load lua file 2015-01-22 15:23:58 +08:00
Cloud Wu
a0adbb1103 Merge remote-tracking branch 'origin/lua53' into lua53 2015-01-22 14:40:50 +08:00
Cloud Wu
b891146397 add lua_clonefunction for lua 5.3 2015-01-22 14:13:26 +08:00
Cloud Wu
a0f60db114 Merge branch 'master' into lua53 2015-01-21 20:01:41 +08:00
Cloud Wu
9f0274b5fe typo 2015-01-21 20:01:26 +08:00
Cloud Wu
93da2dbfc9 use integer for service address 2015-01-21 18:54:05 +08:00
Cloud Wu
9e8d4a453b lua 5.3 returns type for lua_rawget 2015-01-20 21:59:08 +08:00
云风
6baa04b6e1 Merge pull request #224 from apppur/lua53
Update README.md
2015-01-20 17:59:40 +08:00
apppur
72d665ca44 Update README.md 2015-01-20 16:26:18 +08:00
Cloud Wu
4156933e03 update lua 5.3 final 2015-01-13 11:09:16 +08:00
Cloud Wu
29822f14bd update to lua 5.3 rc4 2015-01-07 15:38:34 +08:00
Cloud Wu
8737531fbe remove unused line 2015-01-05 22:12:26 +08:00
Cloud Wu
309e26ba7a we don't need __ipairs in lua 5.3 2015-01-05 21:58:50 +08:00
Cloud Wu
ac85ff82a1 use lua 5.3 in examples client 2015-01-05 21:55:26 +08:00
Cloud Wu
39cf6c99a2 update sprotoparser for lua 5.3 2015-01-05 21:38:41 +08:00
Cloud Wu
cb41293320 update mysql driver for lua 5.3 2015-01-05 21:33:06 +08:00
Cloud Wu
92150dd2e9 int64 library is removed 2015-01-05 18:23:46 +08:00
Cloud Wu
d06aa9b27d support lua 5.3 lua_Integer 2015-01-05 18:17:52 +08:00
Cloud Wu
da9e8fec20 use lua 5.3 lua_isinteger 2015-01-05 17:05:41 +08:00
Cloud Wu
5c07652f6b add readme for lua 5.3.0 rc3 2015-01-05 16:29:15 +08:00
Cloud Wu
c7b5015e10 update to lua 5.3, remove lua unsigned api 2015-01-05 16:25:42 +08:00
云风
4a2b253b40 Merge pull request #221 from cloudwu/dev
release 0.9.3
2015-01-05 14:10:13 +08:00
Cloud Wu
f65ecdf767 ready for 0.9.3 2015-01-05 14:06:31 +08:00
Cloud Wu
ee3f9c6ecd Bugfix: mc.close may reference an invalid pointer. See pr #220 2015-01-05 12:17:57 +08:00
Cloud Wu
52134f9e57 check c obj dirty when len, pairs and ipairs. Fix issue #219 2014-12-28 11:39:25 +08:00
Cloud Wu
21cd5c9882 bugfix last commit 2014-12-25 17:39:59 +08:00
Cloud Wu
23587d0b0f make sproto parser result more stable 2014-12-25 13:58:32 +08:00
Cloud Wu
ce6fa906d3 remove unused macro 2014-12-15 18:08:00 +08:00
Cloud Wu
0e20fe5b4e fix typo 2014-12-15 18:05:38 +08:00
Cloud Wu
978d6af359 set utf-8 2014-12-11 11:01:02 +08:00
Cloud Wu
812088b5ab Merge branch 'master' of github.com:cloudwu/skynet into dev 2014-12-11 10:53:53 +08:00
Cloud Wu
bf54a66346 Merge branch 'master' into dev 2014-12-11 10:53:04 +08:00
云风
5fb4580108 Merge pull request #214 from dpull/dev
mongodb修改bug
2014-12-11 10:53:38 +08:00
dpull
f1c9f9b9dc 1、修改mongo_collection:createIndex的bug
2、增加mongo_collection:drop和mongo_collection:dropIndex(方便测试代码清理环境)
3、根据自己项目用到的功能,增加了测试代码
2014-12-11 10:41:59 +08:00
云风
f15cd1d458 Merge pull request #212 from cloudwu/dev
release 0.9.2
2014-12-08 10:57:23 +08:00
Cloud Wu
24a2df9383 Merge branch 'dev' of github.com:cloudwu/skynet into dev 2014-12-08 10:53:53 +08:00
Cloud Wu
176e4df90c ready for v0.9.2 2014-12-08 10:53:14 +08:00
云风
babd730d07 Merge pull request #210 from dpull/dev
扩展mongodb库功能
2014-12-05 12:07:19 +08:00
dpull
fe9640e2dd 1、mongo_collection:createIndex 创建索引
2、mongo_collection:safe_insert 可以判断返回值的insert
3、mongo_collection:findAndModify 查询并修改
2014-12-04 20:10:24 +08:00
云风
906008f667 Merge pull request #208 from xjdrew/bugfix-mq
使用spinlock,避免cas不能充分调度testdeadloop这样的用例
2014-12-04 16:31:19 +08:00
xjdrew
2da2f121c8 delete unneccessary comment 2014-12-04 16:16:17 +08:00
xjdrew
a0d2c7172c 使用spinlock,避免cas不能充分调度testdeadloop这样的用例 2014-12-04 15:50:19 +08:00
云风
463a789898 Merge pull request #207 from lmess/master
Update mongo.lua
2014-12-03 16:11:29 +08:00
lmess
175529b114 Update mongo.lua
mongo auth config
2014-12-03 15:31:32 +08:00
Cloud Wu
6f6039c136 include sys/socket.h for freebsd 2014-12-03 11:06:09 +08:00
Cloud Wu
2b13eb250d update sproto for big-endian 2014-11-26 21:18:49 +08:00
Cloud Wu
84cb4bb4c1 use explicit conversion 2014-11-25 16:04:26 +08:00
云风
784fb9fee7 Merge pull request #204 from cloudwu/dev
Dev
2014-11-20 11:38:21 +08:00
Cloud Wu
ff6c92b975 add comment 2014-11-20 11:33:16 +08:00
Cloud Wu
64801972e7 Merge branch 'dev' 2014-11-20 11:22:58 +08:00
Cloud Wu
ee61e60631 ready for 0.9.0 2014-11-17 14:55:21 +08:00
云风
c8c95f1690 Merge pull request #203 from cloudwu/dev
Ready for 0.9.0
2014-11-17 14:52:16 +08:00
Cloud Wu
50344af335 Merge branch 'udp' into dev 2014-11-17 14:47:11 +08:00
Cloud Wu
3be0f50722 use snax.newservice would be better 2014-11-15 21:33:25 +08:00
Cloud Wu
6ee014dd99 bugfix: init should be out 2014-11-15 21:28:03 +08:00
云风
2a4bee5bdd Merge pull request #202 from niuys/patch-1
ecsape char '\Z' wrong
2014-11-14 20:06:44 +08:00
snail
4f21696387 ecsape char '\Z' wrong
In mysql-connector, it's '\Z', not '\z'.Now, this bug  will change oringinal data
2014-11-14 18:11:01 +08:00
Cloud Wu
ae041c97b3 bugfix: use ai_list instead of ai_hints 2014-11-14 16:27:26 +08:00
Cloud Wu
6df72e5842 remove snax queue mode 2014-11-14 16:13:48 +08:00
Cloud Wu
b9e06dc065 add snax.self and snax.exit 2014-11-14 15:11:05 +08:00
Cloud Wu
b3cf1bc625 remove unused code 2014-11-13 12:14:02 +08:00
Cloud Wu
20b181c56d If recv one udp message, try read next immediately rather than until next epoll_wait 2014-11-13 11:44:46 +08:00
Cloud Wu
8e4a175155 use fork to dispatch more socket message 2014-11-13 11:23:15 +08:00
Cloud Wu
cfe9506a5a add UDP support, and TCP listen support ipv6 now 2014-11-12 23:00:44 +08:00
Cloud Wu
fa78623b1c support user defined send object 2014-11-11 13:54:43 +08:00
Cloud Wu
e06a9e3701 dispatch read before write, and try to dispath both 2014-11-11 11:33:57 +08:00
Cloud Wu
c87dea3d9b fix issue #200 2014-11-10 20:58:10 +08:00
Cloud Wu
929ce385a3 fprintf need cr 2014-11-10 10:53:29 +08:00
Cloud Wu
765749f608 accept may not start fd, so it can't close at last 2014-11-04 18:25:15 +08:00
Cloud Wu
5fad5d63ae socket close fd when auth failed 2014-11-04 18:12:25 +08:00
Cloud Wu
af10c59eaf release v0.8.1 2014-11-03 15:18:00 +08:00
云风
a77b71530d Merge pull request #195 from cloudwu/dev
release 0.8.1
2014-11-03 15:13:55 +08:00
Cloud Wu
803a79059a update sproto lib 2014-10-31 16:49:54 +08:00
Cloud Wu
6c9ad16077 bugfix: socket open address, and httpd bodylimit 2014-10-29 16:51:39 +08:00
Cloud Wu
2ab689f7c1 remove sha1 from lua_mysqlaux, use lua-crypt instead 2014-10-29 11:18:47 +08:00
Cloud Wu
f8a50929a8 bugfix: break when write all 2014-10-29 11:04:35 +08:00
Cloud Wu
af3ca3bb2f merge lua bugfix, read http://www.lua.org/bugs.html 2014-10-28 19:40:27 +08:00
Cloud Wu
aaf8617dd5 skynet_free(NULL) is ok 2014-10-28 17:14:30 +08:00
Cloud Wu
1d3e393fd4 Merge branch 'czlc-master' into dev 2014-10-28 17:13:35 +08:00
Cloud Wu
c3df405e33 Merge branch 'master' of github.com:czlc/skynet-1 into czlc-master 2014-10-28 17:12:16 +08:00
Cloud Wu
b1ef8a33d9 harbor can post error message back when the destination is not exist 2014-10-28 17:00:24 +08:00
Cloud Wu
954625a530 fix issue #190 2014-10-28 16:48:35 +08:00
czlc
9850ca1b94 free buffer 2014-10-28 16:43:29 +08:00
Cloud Wu
01e1a6aafa fix issue #189 2014-10-28 16:04:01 +08:00
云风
0f4a771792 Merge pull request #188 from cloudwu/dev
release v0.8.0
2014-10-27 10:46:36 +08:00
Cloud Wu
73bd788a6c ready for v0.8.0 2014-10-27 10:43:54 +08:00
云风
8cb5378df9 Merge pull request #187 from niuys/master
'queue' use xpall easy for debug
2014-10-27 10:40:41 +08:00
snail
82bddd9cb8 use xpall easy for debug
use xpall to show more debug message
2014-10-24 19:14:01 +08:00
Cloud Wu
24ff08f997 Merge branch 'master' into dev 2014-10-23 15:25:25 +08:00
Cloud Wu
fc8983227d bugfix issue #185 2014-10-22 20:32:23 +08:00
Cloud Wu
9bdc36526e close socket after request 2014-10-22 11:29:03 +08:00
Cloud Wu
24857a3d8d Merge branch 'chfg007-master' into dev 2014-10-22 11:16:31 +08:00
Cloud Wu
b221c9e84c merge mysql driver 2014-10-22 11:14:57 +08:00
云风
8d2fcef273 Merge pull request #186 from niuys/patch-1
message sequence wrong for queue
2014-10-22 10:49:51 +08:00
niuys
1d8ca31d55 message sequence wrong for queue
When the lua state yield in "more queue" proceeding, "data" comes, it should wait in queue, not immediatly do message process.
2014-10-21 16:34:25 +08:00
Cloud Wu
3b95ecd9b2 bugfix: skynet.queue 2014-10-17 11:22:49 +08:00
云风
7cc25a6238 Merge pull request #182 from cloudwu/dev
Dev
2014-10-15 10:18:29 +08:00
Cloud Wu
1ef5430e0a should not copy the ending 0 2014-10-15 10:16:28 +08:00
Cloud Wu
b39fc6ee23 update sproto for bugfix 2014-10-14 18:34:04 +08:00
Cloud Wu
a074cd79bd add nodelay option in socketchannel 2014-10-13 20:58:41 +08:00
Cloud Wu
883757b936 hotfix the bug introduce by last release 2014-10-13 18:07:34 +08:00
云风
35e5a938b0 Merge pull request #180 from cloudwu/dev
clear coroutine_pool when gc
2014-10-13 17:58:07 +08:00
Cloud Wu
31d7b648b4 bugfix: not padding 0 2014-10-13 17:55:54 +08:00
Cloud Wu
44e6693a40 clear coroutine_pool when gc 2014-10-13 16:47:40 +08:00
Cloud Wu
c458eba6b4 update history for release 2014-10-13 11:03:30 +08:00
Cloud Wu
6d51c21c06 Merge branch 'master' of github.com:cloudwu/skynet 2014-10-13 11:01:56 +08:00
云风
d2aa2069f7 Merge pull request #178 from cloudwu/dev
release 0.7.3
2014-10-13 11:03:06 +08:00
Cloud Wu
8de9c22fd7 Merge branch 'dev' 2014-10-13 10:59:59 +08:00
Cloud Wu
d649d0adf1 delete duplicate line 2014-10-13 10:59:33 +08:00
云风
0aa5274799 Merge pull request #176 from linan0827/master
fix a minor bug when unpacking string from skynet_socket_message
2014-10-12 08:50:23 +08:00
Nan Li
bfc3fd425a fix a minor bug when unpacking string from skynet_socket_message 2014-10-12 03:20:18 +08:00
Cloud Wu
05f508fb42 exit harbor before free socket 2014-10-11 13:37:40 +08:00
Cloud Wu
c8b8dc1276 CHECK ABORT every message dispatch 2014-10-11 13:11:00 +08:00
Cloud Wu
1c62785d71 CHECK ABORT every message dispatch 2014-10-11 13:10:39 +08:00
Cloud Wu
4a8bf4f39a bugfix: harbor service should not release before others 2014-10-10 20:13:53 +08:00
Cloud Wu
2f6bfe9104 add message overload warning 2014-10-08 22:42:01 +08:00
Cloud Wu
535bbc7219 add log when listen 2014-09-30 06:16:16 +08:00
changfeng
e9d4075e43 remove commented out code, improve test code 2014-06-26 07:34:16 +08:00
changfeng
fce05f0cfc no message 2014-06-26 01:04:11 +08:00
changfeng
4cce476dfc no message 2014-06-26 00:28:08 +08:00
changfeng
ad5c37200b improve mysql lib 2014-06-26 00:25:10 +08:00
changfeng
c0e1365dc2 modify error process in socket channel 2014-06-25 23:11:00 +08:00
changfeng
984f727385 imporve mysql lib test 2014-06-25 22:38:38 +08:00
changfeng
315945b2bd no message 2014-06-25 22:15:06 +08:00
changfeng
bf686da723 improve mysql lib test 2014-06-25 20:55:20 +08:00
87414772@qq.com
6733134ad4 mysql lib 2014-06-24 13:11:05 +08:00
326 changed files with 44480 additions and 15206 deletions

23
.github/ISSUE_TEMPLATE/readme-first.md vendored Normal file
View File

@@ -0,0 +1,23 @@
---
name: Readme First
about: Issues is bug report only
title: ''
labels: ''
assignees: ''
---
The **Issues** is for bug report only.
Goto **Discussions** for feature request , questions, etc.
**Update to master branch HEAD first**, and
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior.
**Additional context**
Add any other context about the problem here.

2
.gitignore vendored
View File

@@ -4,8 +4,10 @@
/skynet.pid
3rd/lua/lua
3rd/lua/luac
3rd/lua/all
/cservice
/luaclib
*.so
*.dSYM
.DS_Store
.vscode

View File

@@ -1,4 +1,23 @@
HISTORY for LPeg 0.12
HISTORY for LPeg 1.1.0
* Changes from version 1.0.2 to 1.1.0
---------------------------------
+ accumulator capture
+ UTF-8 ranges
+ Larger limit for number of rules in a grammar
+ Larger limit for number of captures in a match
+ bug fixes
+ other small improvements
* Changes from version 1.0.1 to 1.0.2
---------------------------------
+ some bugs fixed
* Changes from version 0.12 to 1.0.1
---------------------------------
+ group "names" can be any Lua value
+ some bugs fixed
+ other small improvements
* Changes from version 0.11 to 0.12
---------------------------------
@@ -7,14 +26,14 @@ HISTORY for LPeg 0.12
+ some bugs fixed
* Changes from version 0.10 to 0.11
-------------------------------
-------------------------------
+ complete reimplementation of the code generator
+ new syntax for table captures
+ new functions in module 're'
+ other small improvements
* Changes from version 0.9 to 0.10
-------------------------------
-------------------------------
+ backtrack stack has configurable size
+ better error messages
+ Notation for non-terminals in 're' back to A instead o <A>
@@ -26,34 +45,34 @@ HISTORY for LPeg 0.12
- "and" predicates do not keep captures
* Changes from version 0.8 to 0.9
-------------------------------
-------------------------------
+ The accumulator capture was replaced by a fold capture;
programs that used the old 'lpeg.Ca' will need small changes.
+ Some support for character classes from old C locales.
+ A new named-group capture.
* Changes from version 0.7 to 0.8
-------------------------------
-------------------------------
+ New "match-time" capture.
+ New "argument capture" that allows passing arguments into the pattern.
+ Better documentation for 're'.
+ Several small improvements for 're'.
+ The 're' module has an incompatibility with previous versions:
now, any use of a non-terminal must be enclosed in angle brackets
+ The 're' module has an incompatibility with previous versions:
now, any use of a non-terminal must be enclosed in angle brackets
(like <B>).
* Changes from version 0.6 to 0.7
-------------------------------
-------------------------------
+ Several improvements in module 're':
- better documentation;
- support for most captures (all but accumulator);
- limited repetitions p{n,m}.
+ Small improvements in efficiency.
+ Several small bugs corrected (special thanks to Hans Hagen
+ Several small bugs corrected (special thanks to Hans Hagen
and Taco Hoekwater).
* Changes from version 0.5 to 0.6
-------------------------------
-------------------------------
+ Support for non-numeric indices in grammars.
+ Some bug fixes (thanks to the luatex team).
+ Some new optimizations; (thanks to Mike Pall).
@@ -61,7 +80,7 @@ HISTORY for LPeg 0.12
+ Minimal documentation for module 're'.
* Changes from version 0.4 to 0.5
-------------------------------
-------------------------------
+ Several optimizations.
+ lpeg.P now accepts booleans.
+ Some new examples.
@@ -69,18 +88,18 @@ HISTORY for LPeg 0.12
+ Several small improvements.
* Changes from version 0.3 to 0.4
-------------------------------
-------------------------------
+ Static check for loops in repetitions and grammars.
+ Removed label option in captures.
+ The implementation of captures uses less memory.
* Changes from version 0.2 to 0.3
-------------------------------
-------------------------------
+ User-defined patterns in Lua.
+ Several new captures.
* Changes from version 0.1 to 0.2
-------------------------------
-------------------------------
+ Several small corrections.
+ Handles embedded zeros like any other character.
+ Capture "name" can be any Lua value.

4
3rd/lpeg/README.md Normal file
View File

@@ -0,0 +1,4 @@
# LPeg - Parsing Expression Grammars For Lua
For more information,
see [Lpeg](//www.inf.puc-rio.br/~roberto/lpeg/).

View File

@@ -1,29 +1,41 @@
/*
** $Id: lpcap.c,v 1.4 2013/03/21 20:25:12 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
#include "lua.h"
#include "lauxlib.h"
#include "lpcap.h"
#include "lpprint.h"
#include "lptypes.h"
#define captype(cap) ((cap)->kind)
#define isclosecap(cap) (captype(cap) == Cclose)
#define closeaddr(c) ((c)->s + (c)->siz - 1)
#define isfullcap(cap) ((cap)->siz != 0)
#define getfromktable(cs,v) lua_rawgeti((cs)->L, ktableidx((cs)->ptop), v)
#define pushluaval(cs) getfromktable(cs, (cs)->cap->idx)
#define skipclose(cs,head) \
if (isopencap(head)) { assert(isclosecap(cs->cap)); cs->cap++; }
/*
** Return the size of capture 'cap'. If it is an open capture, 'close'
** must be its corresponding close.
*/
static Index_t capsize (Capture *cap, Capture *close) {
if (isopencap(cap)) {
assert(isclosecap(close));
return close->index - cap->index;
}
else
return cap->siz - 1;
}
static Index_t closesize (CapState *cs, Capture *head) {
return capsize(head, cs->cap);
}
/*
** Put at the cache for Lua values the value indexed by 'v' in ktable
** of the running pattern (if it is not there yet); returns its index.
@@ -44,35 +56,40 @@ static int pushcapture (CapState *cs);
/*
** Goes back in a list of captures looking for an open capture
** corresponding to a close
** corresponding to a close one.
*/
static Capture *findopen (Capture *cap) {
int n = 0; /* number of closes waiting an open */
for (;;) {
cap--;
if (isclosecap(cap)) n++; /* one more open to skip */
else if (!isfullcap(cap))
else if (isopencap(cap))
if (n-- == 0) return cap;
}
}
/*
** Go to the next capture
** Go to the next capture at the same level.
*/
static void nextcap (CapState *cs) {
Capture *cap = cs->cap;
if (!isfullcap(cap)) { /* not a single capture? */
if (isopencap(cap)) { /* must look for a close? */
int n = 0; /* number of opens waiting a close */
for (;;) { /* look for corresponding close */
cap++;
if (isclosecap(cap)) {
if (isopencap(cap)) n++;
else if (isclosecap(cap))
if (n-- == 0) break;
}
else if (!isfullcap(cap)) n++;
}
cs->cap = cap + 1; /* + 1 to skip last close */
}
else {
Capture *next;
for (next = cap + 1; capinside(cap, next); next++)
; /* skip captures inside current one */
cs->cap = next;
}
cs->cap = cap + 1; /* + 1 to skip last close (or entire single capture) */
}
@@ -84,22 +101,17 @@ static void nextcap (CapState *cs) {
** so the function never returns zero.
*/
static int pushnestedvalues (CapState *cs, int addextra) {
Capture *co = cs->cap;
if (isfullcap(cs->cap++)) { /* no nested captures? */
lua_pushlstring(cs->L, co->s, co->siz - 1); /* push whole match */
return 1; /* that is it */
}
else {
int n = 0;
while (!isclosecap(cs->cap)) /* repeat for all nested patterns */
n += pushcapture(cs);
if (addextra || n == 0) { /* need extra? */
lua_pushlstring(cs->L, co->s, cs->cap->s - co->s); /* push whole match */
n++;
}
cs->cap++; /* skip close entry */
return n;
Capture *head = cs->cap++; /* original capture */
int n = 0; /* number of pushed subvalues */
/* repeat for all nested patterns */
while (capinside(head, cs->cap))
n += pushcapture(cs);
if (addextra || n == 0) { /* need extra? */
lua_pushlstring(cs->L, cs->s + head->index, closesize(cs, head));
n++;
}
skipclose(cs, head);
return n;
}
@@ -114,19 +126,45 @@ static void pushonenestedvalue (CapState *cs) {
/*
** Try to find a named group capture with the name given at the top of
** the stack; goes backward from 'cap'.
** Checks whether group 'grp' is visible to 'ref', that is, 'grp' is
** not nested inside a full capture that does not contain 'ref'. (We
** only need to care for full captures because the search at 'findback'
** skips open-end blocks; so, if 'grp' is nested in a non-full capture,
** 'ref' is also inside it.) To check this, we search backward for the
** inner full capture enclosing 'grp'. A full capture cannot contain
** non-full captures, so a close capture means we cannot be inside a
** full capture anymore.
*/
static Capture *findback (CapState *cs, Capture *cap) {
static int capvisible (CapState *cs, Capture *grp, Capture *ref) {
Capture *cap = grp;
int i = MAXLOP; /* maximum distance for an 'open' */
while (i-- > 0 && cap-- > cs->ocap) {
if (isclosecap(cap))
return 1; /* can stop the search */
else if (grp->index - cap->index >= UCHAR_MAX)
return 1; /* can stop the search */
else if (capinside(cap, grp)) /* is 'grp' inside cap? */
return capinside(cap, ref); /* ok iff cap also contains 'ref' */
}
return 1; /* 'grp' is not inside any capture */
}
/*
** Try to find a named group capture with the name given at the top of
** the stack; goes backward from 'ref'.
*/
static Capture *findback (CapState *cs, Capture *ref) {
lua_State *L = cs->L;
Capture *cap = ref;
while (cap-- > cs->ocap) { /* repeat until end of list */
if (isclosecap(cap))
cap = findopen(cap); /* skip nested captures */
else if (!isfullcap(cap))
continue; /* opening an enclosing capture: skip and get previous */
if (captype(cap) == Cgroup) {
else if (capinside(cap, ref))
continue; /* enclosing captures are not visible to 'ref' */
if (captype(cap) == Cgroup && capvisible(cs, cap, ref)) {
getfromktable(cs, cap->idx); /* get group name */
if (lua_equal(L, -2, -1)) { /* right group? */
if (lp_equal(L, -2, -1)) { /* right group? */
lua_pop(L, 2); /* remove reference name and group name */
return cap;
}
@@ -158,11 +196,10 @@ static int backrefcap (CapState *cs) {
*/
static int tablecap (CapState *cs) {
lua_State *L = cs->L;
Capture *head = cs->cap++;
int n = 0;
lua_newtable(L);
if (isfullcap(cs->cap++))
return 1; /* table is empty */
while (!isclosecap(cs->cap)) {
while (capinside(head, cs->cap)) {
if (captype(cs->cap) == Cgroup && cs->cap->idx != 0) { /* named group? */
pushluaval(cs); /* push group name */
pushonenestedvalue(cs);
@@ -176,7 +213,7 @@ static int tablecap (CapState *cs) {
n += k;
}
}
cs->cap++; /* skip close entry */
skipclose(cs, head);
return 1; /* number of values pushed (only the table) */
}
@@ -203,20 +240,20 @@ static int querycap (CapState *cs) {
static int foldcap (CapState *cs) {
int n;
lua_State *L = cs->L;
int idx = cs->cap->idx;
if (isfullcap(cs->cap++) || /* no nested captures? */
isclosecap(cs->cap) || /* no nested captures (large subject)? */
Capture *head = cs->cap++;
int idx = head->idx;
if (isclosecap(cs->cap) || /* no nested captures (large subject)? */
(n = pushcapture(cs)) == 0) /* nested captures with no values? */
return luaL_error(L, "no initial value for fold capture");
if (n > 1)
lua_pop(L, n - 1); /* leave only one result for accumulator */
while (!isclosecap(cs->cap)) {
while (capinside(head, cs->cap)) {
lua_pushvalue(L, updatecache(cs, idx)); /* get folding function */
lua_insert(L, -2); /* put it before accumulator */
n = pushcapture(cs); /* get next capture's values */
lua_call(L, n + 1, 1); /* call folding function */
}
cs->cap++; /* skip close entry */
skipclose(cs, head);
return 1; /* only accumulator left on the stack */
}
@@ -234,6 +271,22 @@ static int functioncap (CapState *cs) {
}
/*
** Accumulator capture
*/
static int accumulatorcap (CapState *cs) {
lua_State *L = cs->L;
int n;
if (lua_gettop(L) < cs->firstcap)
luaL_error(L, "no previous value for accumulator capture");
pushluaval(cs); /* push function */
lua_insert(L, -2); /* previous value becomes first argument */
n = pushnestedvalues(cs, 0); /* push nested captures */
lua_call(L, n + 1, 1); /* call function */
return 0; /* did not add any extra value */
}
/*
** Select capture
*/
@@ -271,19 +324,19 @@ int finddyncap (Capture *cap, Capture *last) {
/*
** Calls a runtime capture. Returns number of captures removed by
** the call, including the initial Cgroup. (Captures to be added are
** on the Lua stack.)
** Calls a runtime capture. Returns number of captures "removed" by the
** call, that is, those inside the group capture. Captures to be added
** are on the Lua stack.
*/
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
int n, id;
lua_State *L = cs->L;
int otop = lua_gettop(L);
Capture *open = findopen(close);
Capture *open = findopen(close); /* get open group capture */
assert(captype(open) == Cgroup);
id = finddyncap(open, close); /* get first dynamic capture argument */
close->kind = Cclose; /* closes the group */
close->s = s;
close->index = s - cs->s;
cs->cap = open; cs->valuecached = 0; /* prepare capture state */
luaL_checkstack(L, 4, "too many runtime captures");
pushluaval(cs); /* push function to be called */
@@ -299,7 +352,7 @@ int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
}
else
*rem = 0; /* no dynamic captures removed */
return close - open; /* number of captures of all kinds removed */
return close - open - 1; /* number of captures to be removed */
}
@@ -313,8 +366,8 @@ typedef struct StrAux {
union {
Capture *cp; /* if not a string, respective capture */
struct { /* if it is a string... */
const char *s; /* ... starts here */
const char *e; /* ... ends here */
Index_t idx; /* starts here */
Index_t siz; /* with this size */
} s;
} u;
} StrAux;
@@ -329,24 +382,23 @@ typedef struct StrAux {
*/
static int getstrcaps (CapState *cs, StrAux *cps, int n) {
int k = n++;
Capture *head = cs->cap++;
cps[k].isstring = 1; /* get string value */
cps[k].u.s.s = cs->cap->s; /* starts here */
if (!isfullcap(cs->cap++)) { /* nested captures? */
while (!isclosecap(cs->cap)) { /* traverse them */
if (n >= MAXSTRCAPS) /* too many captures? */
nextcap(cs); /* skip extra captures (will not need them) */
else if (captype(cs->cap) == Csimple) /* string? */
n = getstrcaps(cs, cps, n); /* put info. into array */
else {
cps[n].isstring = 0; /* not a string */
cps[n].u.cp = cs->cap; /* keep original capture */
nextcap(cs);
n++;
}
cps[k].u.s.idx = head->index; /* starts here */
while (capinside(head, cs->cap)) {
if (n >= MAXSTRCAPS) /* too many captures? */
nextcap(cs); /* skip extra captures (will not need them) */
else if (captype(cs->cap) == Csimple) /* string? */
n = getstrcaps(cs, cps, n); /* put info. into array */
else {
cps[n].isstring = 0; /* not a string */
cps[n].u.cp = cs->cap; /* keep original capture */
nextcap(cs);
n++;
}
cs->cap++; /* skip close */
}
cps[k].u.s.e = closeaddr(cs->cap - 1); /* ends here */
cps[k].u.s.siz = closesize(cs, head);
skipclose(cs, head);
return n;
}
@@ -368,7 +420,7 @@ static void stringcap (luaL_Buffer *b, CapState *cs) {
const char *fmt; /* format string */
fmt = lua_tolstring(cs->L, updatecache(cs, cs->cap->idx), &len);
n = getstrcaps(cs, cps, 0) - 1; /* collect nested captures */
for (i = 0; i < len; i++) { /* traverse them */
for (i = 0; i < len; i++) { /* traverse format string */
if (fmt[i] != '%') /* not an escape? */
luaL_addchar(b, fmt[i]); /* add it to buffer */
else if (fmt[++i] < '0' || fmt[i] > '9') /* not followed by a digit? */
@@ -378,7 +430,7 @@ static void stringcap (luaL_Buffer *b, CapState *cs) {
if (l > n)
luaL_error(cs->L, "invalid capture index (%d)", l);
else if (cps[l].isstring)
luaL_addlstring(b, cps[l].u.s.s, cps[l].u.s.e - cps[l].u.s.s);
luaL_addlstring(b, cs->s + cps[l].u.s.idx, cps[l].u.s.siz);
else {
Capture *curr = cs->cap;
cs->cap = cps[l].u.cp; /* go back to evaluate that nested capture */
@@ -395,22 +447,20 @@ static void stringcap (luaL_Buffer *b, CapState *cs) {
** Substitution capture: add result to buffer 'b'
*/
static void substcap (luaL_Buffer *b, CapState *cs) {
const char *curr = cs->cap->s;
if (isfullcap(cs->cap)) /* no nested captures? */
luaL_addlstring(b, curr, cs->cap->siz - 1); /* keep original text */
else {
cs->cap++; /* skip open entry */
while (!isclosecap(cs->cap)) { /* traverse nested captures */
const char *next = cs->cap->s;
luaL_addlstring(b, curr, next - curr); /* add text up to capture */
if (addonestring(b, cs, "replacement"))
curr = closeaddr(cs->cap - 1); /* continue after match */
else /* no capture value */
curr = next; /* keep original text in final result */
}
luaL_addlstring(b, curr, cs->cap->s - curr); /* add last piece of text */
const char *curr = cs->s + cs->cap->index;
Capture *head = cs->cap++;
while (capinside(head, cs->cap)) {
Capture *cap = cs->cap;
const char *caps = cs->s + cap->index;
luaL_addlstring(b, curr, caps - curr); /* add text up to capture */
if (addonestring(b, cs, "replacement"))
curr = caps + capsize(cap, cs->cap - 1); /* continue after match */
else /* no capture value */
curr = caps; /* keep original text in final result */
}
cs->cap++; /* go to next capture */
/* add last piece of text */
luaL_addlstring(b, curr, cs->s + head->index + closesize(cs, head) - curr);
skipclose(cs, head);
}
@@ -426,13 +476,16 @@ static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
case Csubst:
substcap(b, cs); /* add capture directly to buffer */
return 1;
case Cacc: /* accumulator capture? */
return luaL_error(cs->L, "invalid context for an accumulator capture");
default: {
lua_State *L = cs->L;
int n = pushcapture(cs);
if (n > 0) {
if (n > 1) lua_pop(L, n - 1); /* only one result */
if (!lua_isstring(L, -1))
luaL_error(L, "invalid %s value (a %s)", what, luaL_typename(L, -1));
return luaL_error(L, "invalid %s value (a %s)",
what, luaL_typename(L, -1));
luaL_addvalue(b);
}
return n;
@@ -441,77 +494,96 @@ static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
}
#if !defined(MAXRECLEVEL)
#define MAXRECLEVEL 200
#endif
/*
** Push all values of the current capture into the stack; returns
** number of values pushed
*/
static int pushcapture (CapState *cs) {
lua_State *L = cs->L;
int res;
luaL_checkstack(L, 4, "too many captures");
if (cs->reclevel++ > MAXRECLEVEL)
return luaL_error(L, "subcapture nesting too deep");
switch (captype(cs->cap)) {
case Cposition: {
lua_pushinteger(L, cs->cap->s - cs->s + 1);
lua_pushinteger(L, cs->cap->index + 1);
cs->cap++;
return 1;
res = 1;
break;
}
case Cconst: {
pushluaval(cs);
cs->cap++;
return 1;
res = 1;
break;
}
case Carg: {
int arg = (cs->cap++)->idx;
if (arg + FIXEDARGS > cs->ptop)
return luaL_error(L, "reference to absent argument #%d", arg);
return luaL_error(L, "reference to absent extra argument #%d", arg);
lua_pushvalue(L, arg + FIXEDARGS);
return 1;
res = 1;
break;
}
case Csimple: {
int k = pushnestedvalues(cs, 1);
lua_insert(L, -k); /* make whole match be first result */
return k;
res = k;
break;
}
case Cruntime: {
lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */
return 1;
res = 1;
break;
}
case Cstring: {
luaL_Buffer b;
luaL_buffinit(L, &b);
stringcap(&b, cs);
luaL_pushresult(&b);
return 1;
res = 1;
break;
}
case Csubst: {
luaL_Buffer b;
luaL_buffinit(L, &b);
substcap(&b, cs);
luaL_pushresult(&b);
return 1;
res = 1;
break;
}
case Cgroup: {
if (cs->cap->idx == 0) /* anonymous group? */
return pushnestedvalues(cs, 0); /* add all nested values */
res = pushnestedvalues(cs, 0); /* add all nested values */
else { /* named group: add no values */
nextcap(cs); /* skip capture */
return 0;
res = 0;
}
break;
}
case Cbackref: return backrefcap(cs);
case Ctable: return tablecap(cs);
case Cfunction: return functioncap(cs);
case Cnum: return numcap(cs);
case Cquery: return querycap(cs);
case Cfold: return foldcap(cs);
default: assert(0); return 0;
case Cbackref: res = backrefcap(cs); break;
case Ctable: res = tablecap(cs); break;
case Cfunction: res = functioncap(cs); break;
case Cacc: res = accumulatorcap(cs); break;
case Cnum: res = numcap(cs); break;
case Cquery: res = querycap(cs); break;
case Cfold: res = foldcap(cs); break;
default: assert(0); res = 0;
}
cs->reclevel--;
return res;
}
/*
** Prepare a CapState structure and traverse the entire list of
** captures in the stack pushing its results. 's' is the subject
** string, 'r' is the final position of the match, and 'ptop'
** string, 'r' is the final position of the match, and 'ptop'
** the index in the stack where some useful values were pushed.
** Returns the number of results pushed. (If the list produces no
** results, push the final position of the match.)
@@ -519,13 +591,16 @@ static int pushcapture (CapState *cs) {
int getcaptures (lua_State *L, const char *s, const char *r, int ptop) {
Capture *capture = (Capture *)lua_touserdata(L, caplistidx(ptop));
int n = 0;
/* printcaplist(capture); */
if (!isclosecap(capture)) { /* is there any capture? */
CapState cs;
cs.ocap = cs.cap = capture; cs.L = L;
cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0;
cs.s = s; cs.valuecached = 0; cs.ptop = ptop;
cs.firstcap = lua_gettop(L) + 1; /* where first value (if any) will go */
do { /* collect their values */
n += pushcapture(&cs);
} while (!isclosecap(cs.cap));
assert(lua_gettop(L) - cs.firstcap == n - 1);
}
if (n == 0) { /* no capture values? */
lua_pushinteger(L, r - s + 1); /* return only end position */

View File

@@ -1,6 +1,3 @@
/*
** $Id: lpcap.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
*/
#if !defined(lpcap_h)
#define lpcap_h
@@ -11,14 +8,40 @@
/* kinds of captures */
typedef enum CapKind {
Cclose, Cposition, Cconst, Cbackref, Carg, Csimple, Ctable, Cfunction,
Cquery, Cstring, Cnum, Csubst, Cfold, Cruntime, Cgroup
Cclose, /* not used in trees */
Cposition,
Cconst, /* ktable[key] is Lua constant */
Cbackref, /* ktable[key] is "name" of group to get capture */
Carg, /* 'key' is arg's number */
Csimple, /* next node is pattern */
Ctable, /* next node is pattern */
Cfunction, /* ktable[key] is function; next node is pattern */
Cacc, /* ktable[key] is function; next node is pattern */
Cquery, /* ktable[key] is table; next node is pattern */
Cstring, /* ktable[key] is string; next node is pattern */
Cnum, /* numbered capture; 'key' is number of value to return */
Csubst, /* substitution capture; next node is pattern */
Cfold, /* ktable[key] is function; next node is pattern */
Cruntime, /* not used in trees (is uses another type for tree) */
Cgroup /* ktable[key] is group's "name" */
} CapKind;
/*
** An unsigned integer large enough to index any subject entirely.
** It can be size_t, but that will double the size of the array
** of captures in a 64-bit machine.
*/
#if !defined(Index_t)
typedef uint Index_t;
#endif
#define MAXINDT (~(Index_t)0)
typedef struct Capture {
const char *s; /* subject position */
short idx; /* extra info about capture (group name, arg index, etc.) */
Index_t index; /* subject position */
unsigned short idx; /* extra info (group name, arg index, etc.) */
byte kind; /* kind of capture */
byte siz; /* size of full capture + 1 (0 = not a full capture) */
} Capture;
@@ -28,12 +51,32 @@ typedef struct CapState {
Capture *cap; /* current capture */
Capture *ocap; /* (original) capture list */
lua_State *L;
int ptop; /* index of last argument to 'match' */
int ptop; /* stack index of last argument to 'match' */
int firstcap; /* stack index of first capture pushed in the stack */
const char *s; /* original string */
int valuecached; /* value stored in cache slot */
int reclevel; /* recursion level */
} CapState;
#define captype(cap) ((cap)->kind)
#define isclosecap(cap) (captype(cap) == Cclose)
#define isopencap(cap) ((cap)->siz == 0)
/* true if c2 is (any number of levels) inside c1 */
#define capinside(c1,c2) \
(isopencap(c1) ? !isclosecap(c2) \
: (c2)->index < (c1)->index + (c1)->siz - 1)
/**
** Maximum number of captures to visit when looking for an 'open'.
*/
#define MAXLOP 20
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem);
int getcaptures (lua_State *L, const char *s, const char *r, int ptop);
int finddyncap (Capture *cap, Capture *last);

View File

@@ -1,7 +1,3 @@
/*
** $Id: lpcode.c,v 1.18 2013/04/12 16:30:33 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
#include <limits.h>
@@ -11,6 +7,7 @@
#include "lptypes.h"
#include "lpcode.h"
#include "lpcset.h"
/* signals a "no-instruction */
@@ -26,56 +23,13 @@ static const Charset fullset_ =
static const Charset *fullset = &fullset_;
/*
** {======================================================
** Analysis and some optimizations
** =======================================================
*/
/*
** Check whether a charset is empty (IFail), singleton (IChar),
** full (IAny), or none of those (ISet).
*/
static Opcode charsettype (const byte *cs, int *c) {
int count = 0;
int i;
int candidate = -1; /* candidate position for a char */
for (i = 0; i < CHARSETSIZE; i++) {
int b = cs[i];
if (b == 0) {
if (count > 1) return ISet; /* else set is still empty */
}
else if (b == 0xFF) {
if (count < (i * BITSPERCHAR))
return ISet;
else count += BITSPERCHAR; /* set is still full */
}
else if ((b & (b - 1)) == 0) { /* byte has only one bit? */
if (count > 0)
return ISet; /* set is neither full nor empty */
else { /* set has only one char till now; track it */
count++;
candidate = i;
}
}
else return ISet; /* byte is neither empty, full, nor singleton */
}
switch (count) {
case 0: return IFail; /* empty set */
case 1: { /* singleton; find character bit inside byte */
int b = cs[candidate];
*c = candidate * BITSPERCHAR;
if ((b & 0xF0) != 0) { *c += 4; b >>= 4; }
if ((b & 0x0C) != 0) { *c += 2; b >>= 2; }
if ((b & 0x02) != 0) { *c += 1; }
return IChar;
}
default: {
assert(count == CHARSETSIZE * BITSPERCHAR); /* full set */
return IAny;
}
}
}
/*
** A few basic operations on Charsets
@@ -84,16 +38,6 @@ static void cs_complement (Charset *cs) {
loopset(i, cs->cs[i] = ~cs->cs[i]);
}
static int cs_equal (const byte *cs1, const byte *cs2) {
loopset(i, if (cs1[i] != cs2[i]) return 0);
return 1;
}
/*
** computes whether sets cs1 and cs2 are disjoint
*/
static int cs_disjoint (const Charset *cs1, const Charset *cs2) {
loopset(i, if ((cs1->cs[i] & cs2->cs[i]) != 0) return 0;)
return 1;
@@ -101,43 +45,46 @@ static int cs_disjoint (const Charset *cs1, const Charset *cs2) {
/*
** Convert a 'char' pattern (TSet, TChar, TAny) to a charset
** Visit a TCall node taking care to stop recursion. If node not yet
** visited, return 'f(sib2(tree))', otherwise return 'def' (default
** value)
*/
int tocharset (TTree *tree, Charset *cs) {
switch (tree->tag) {
case TSet: { /* copy set */
loopset(i, cs->cs[i] = treebuffer(tree)[i]);
return 1;
}
case TChar: { /* only one char */
assert(0 <= tree->u.n && tree->u.n <= UCHAR_MAX);
loopset(i, cs->cs[i] = 0); /* erase all chars */
setchar(cs->cs, tree->u.n); /* add that one */
return 1;
}
case TAny: {
loopset(i, cs->cs[i] = 0xFF); /* add all to the set */
return 1;
}
default: return 0;
static int callrecursive (TTree *tree, int f (TTree *t), int def) {
int key = tree->key;
assert(tree->tag == TCall);
assert(sib2(tree)->tag == TRule);
if (key == 0) /* node already visited? */
return def; /* return default value */
else { /* first visit */
int result;
tree->key = 0; /* mark call as already visited */
result = f(sib2(tree)); /* go to called rule */
tree->key = key; /* restore tree */
return result;
}
}
/*
** Checks whether a pattern has captures
** Check whether a pattern tree has captures
*/
int hascaptures (TTree *tree) {
tailcall:
switch (tree->tag) {
case TCapture: case TRunTime:
return 1;
case TCall:
return callrecursive(tree, hascaptures, 0);
case TRule: /* do not follow siblings */
tree = sib1(tree); goto tailcall;
case TOpenCall: assert(0);
default: {
switch (numsiblings[tree->tag]) {
case 1: /* return hascaptures(sib1(tree)); */
tree = sib1(tree); goto tailcall;
case 2:
if (hascaptures(sib1(tree))) return 1;
if (hascaptures(sib1(tree)))
return 1;
/* else return hascaptures(sib2(tree)); */
tree = sib2(tree); goto tailcall;
default: assert(numsiblings[tree->tag] == 0); return 0;
@@ -161,14 +108,14 @@ int hascaptures (TTree *tree) {
** p is nullable => nullable(p)
** nofail(p) => p cannot fail
** The function assumes that TOpenCall is not nullable;
** this will be checked again when the grammar is fixed.)
** this will be checked again when the grammar is fixed.
** Run-time captures can do whatever they want, so the result
** is conservative.
*/
int checkaux (TTree *tree, int pred) {
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny:
case TChar: case TSet: case TAny: case TUTFR:
case TFalse: case TOpenCall:
return 0; /* not nullable */
case TRep: case TTrue:
@@ -192,50 +139,55 @@ int checkaux (TTree *tree, int pred) {
if (checkaux(sib2(tree), pred)) return 1;
/* else return checkaux(sib1(tree), pred); */
tree = sib1(tree); goto tailcall;
case TCapture: case TGrammar: case TRule:
case TCapture: case TGrammar: case TRule: case TXInfo:
/* return checkaux(sib1(tree), pred); */
tree = sib1(tree); goto tailcall;
case TCall: /* return checkaux(sib2(tree), pred); */
tree = sib2(tree); goto tailcall;
default: assert(0); return 0;
};
}
}
/*
** number of characters to match a pattern (or -1 if variable)
** ('count' avoids infinite loops for grammars)
*/
int fixedlenx (TTree *tree, int count, int len) {
int fixedlen (TTree *tree) {
int len = 0; /* to accumulate in tail calls */
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny:
return len + 1;
case TUTFR:
return (tree->cap == sib1(tree)->cap) ? len + tree->cap : -1;
case TFalse: case TTrue: case TNot: case TAnd: case TBehind:
return len;
case TRep: case TRunTime: case TOpenCall:
return -1;
case TCapture: case TRule: case TGrammar:
/* return fixedlenx(sib1(tree), count); */
case TCapture: case TRule: case TGrammar: case TXInfo:
/* return fixedlen(sib1(tree)); */
tree = sib1(tree); goto tailcall;
case TCall:
if (count++ >= MAXRULES)
return -1; /* may be a loop */
/* else return fixedlenx(sib2(tree), count); */
tree = sib2(tree); goto tailcall;
case TCall: {
int n1 = callrecursive(tree, fixedlen, -1);
if (n1 < 0)
return -1;
else
return len + n1;
}
case TSeq: {
len = fixedlenx(sib1(tree), count, len);
if (len < 0) return -1;
/* else return fixedlenx(sib2(tree), count, len); */
tree = sib2(tree); goto tailcall;
int n1 = fixedlen(sib1(tree));
if (n1 < 0)
return -1;
/* else return fixedlen(sib2(tree)) + len; */
len += n1; tree = sib2(tree); goto tailcall;
}
case TChoice: {
int n1, n2;
n1 = fixedlenx(sib1(tree), count, len);
if (n1 < 0) return -1;
n2 = fixedlenx(sib2(tree), count, len);
if (n1 == n2) return n1;
else return -1;
int n1 = fixedlen(sib1(tree));
int n2 = fixedlen(sib2(tree));
if (n1 != n2 || n1 < 0)
return -1;
else
return len + n1;
}
default: assert(0); return 0;
};
@@ -245,31 +197,38 @@ int fixedlenx (TTree *tree, int count, int len) {
/*
** Computes the 'first set' of a pattern.
** The result is a conservative aproximation:
** match p ax -> x' for some x ==> a in first(p).
** match p ax -> x (for some x) ==> a belongs to first(p)
** or
** a not in first(p) ==> match p ax -> fail (for all x)
**
** The set 'follow' is the first set of what follows the
** pattern (full set if nothing follows it).
** The function returns 0 when this set can be used for
** tests that avoid the pattern altogether.
**
** The function returns 0 when this resulting set can be used for
** test instructions that avoid the pattern altogether.
** A non-zero return can happen for two reasons:
** 1) match p '' -> '' ==> returns 1.
** (tests cannot be used because they always fail for an empty input)
** 2) there is a match-time capture ==> returns 2.
** (match-time captures should not be avoided by optimizations)
** 1) match p '' -> '' ==> return has bit 1 set
** (tests cannot be used because they would always fail for an empty input);
** 2) there is a match-time capture ==> return has bit 2 set
** (optimizations should not bypass match-time captures).
*/
static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny: {
case TChar: case TSet: case TAny: case TFalse: {
tocharset(tree, firstset);
return 0;
}
case TUTFR: {
int c;
clearset(firstset->cs); /* erase all chars */
for (c = tree->key; c <= sib1(tree)->key; c++)
setchar(firstset->cs, c);
return 0;
}
case TTrue: {
loopset(i, firstset->cs[i] = follow->cs[i]);
return 1;
}
case TFalse: {
loopset(i, firstset->cs[i] = 0);
return 0;
return 1; /* accepts the empty string */
}
case TChoice: {
Charset csaux;
@@ -280,7 +239,8 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
}
case TSeq: {
if (!nullable(sib1(tree))) {
/* return getfirst(sib1(tree), fullset, firstset); */
/* when p1 is not nullable, p2 has nothing to contribute;
return getfirst(sib1(tree), fullset, firstset); */
tree = sib1(tree); follow = fullset; goto tailcall;
}
else { /* FIRST(p1 p2, fl) = FIRST(p1, FIRST(p2, fl)) */
@@ -298,7 +258,7 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
loopset(i, firstset->cs[i] |= follow->cs[i]);
return 1; /* accept the empty string */
}
case TCapture: case TGrammar: case TRule: {
case TCapture: case TGrammar: case TRule: case TXInfo: {
/* return getfirst(sib1(tree), follow, firstset); */
tree = sib1(tree); goto tailcall;
}
@@ -320,11 +280,10 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
if (tocharset(sib1(tree), firstset)) {
cs_complement(firstset);
return 1;
}
/* else go through */
}
} /* else */
} /* FALLTHROUGH */
case TBehind: { /* instruction gives no new information */
/* call 'getfirst' to check for math-time captures */
/* call 'getfirst' only to check for math-time captures */
int e = getfirst(sib1(tree), follow, firstset);
loopset(i, firstset->cs[i] = follow->cs[i]); /* uses follow */
return e | 1; /* always can accept the empty string */
@@ -335,8 +294,8 @@ static int getfirst (TTree *tree, const Charset *follow, Charset *firstset) {
/*
** If it returns true, then pattern can fail only depending on the next
** character of the subject
** If 'headfail(tree)' true, then 'tree' can fail only depending on the
** next character of the subject.
*/
static int headfail (TTree *tree) {
tailcall:
@@ -344,9 +303,9 @@ static int headfail (TTree *tree) {
case TChar: case TSet: case TAny: case TFalse:
return 1;
case TTrue: case TRep: case TRunTime: case TNot:
case TBehind:
case TBehind: case TUTFR:
return 0;
case TCapture: case TGrammar: case TRule: case TAnd:
case TCapture: case TGrammar: case TRule: case TXInfo: case TAnd:
tree = sib1(tree); goto tailcall; /* return headfail(sib1(tree)); */
case TCall:
tree = sib2(tree); goto tailcall; /* return headfail(sib2(tree)); */
@@ -371,7 +330,7 @@ static int headfail (TTree *tree) {
static int needfollow (TTree *tree) {
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny:
case TChar: case TSet: case TAny: case TUTFR:
case TFalse: case TTrue: case TAnd: case TNot:
case TRunTime: case TGrammar: case TCall: case TBehind:
return 0;
@@ -382,7 +341,7 @@ static int needfollow (TTree *tree) {
case TSeq:
tree = sib2(tree); goto tailcall;
default: assert(0); return 0;
}
}
}
/* }====================================================== */
@@ -401,11 +360,12 @@ static int needfollow (TTree *tree) {
*/
int sizei (const Instruction *i) {
switch((Opcode)i->i.code) {
case ISet: case ISpan: return CHARSETINSTSIZE;
case ITestSet: return CHARSETINSTSIZE + 1;
case ITestChar: case ITestAny: case IChoice: case IJmp:
case ICall: case IOpenCall: case ICommit: case IPartialCommit:
case IBackCommit: return 2;
case ISet: case ISpan: return 1 + i->i.aux2.set.size;
case ITestSet: return 2 + i->i.aux2.set.size;
case ITestChar: case ITestAny: case IChoice: case IJmp: case ICall:
case IOpenCall: case ICommit: case IPartialCommit: case IBackCommit:
case IUTFR:
return 2;
default: return 1;
}
}
@@ -422,32 +382,77 @@ typedef struct CompileState {
/*
** code generation is recursive; 'opt' indicates that the code is
** being generated under a 'IChoice' operator jumping to its end.
** 'tt' points to a previous test protecting this code. 'fl' is
** the follow set of the pattern.
** code generation is recursive; 'opt' indicates that the code is being
** generated as the last thing inside an optional pattern (so, if that
** code is optional too, it can reuse the 'IChoice' already in place for
** the outer pattern). 'tt' points to a previous test protecting this
** code (or NOINST). 'fl' is the follow set of the pattern.
*/
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
const Charset *fl);
void reallocprog (lua_State *L, Pattern *p, int nsize) {
void *ud;
lua_Alloc f = lua_getallocf(L, &ud);
void *newblock = f(ud, p->code, p->codesize * sizeof(Instruction),
nsize * sizeof(Instruction));
if (newblock == NULL && nsize > 0)
static void finishrelcode (lua_State *L, Pattern *p, Instruction *block,
int size) {
if (block == NULL)
luaL_error(L, "not enough memory");
p->code = (Instruction *)newblock;
p->codesize = nsize;
block->codesize = size;
p->code = (Instruction *)block + 1;
}
static int nextinstruction (CompileState *compst) {
int size = compst->p->codesize;
if (compst->ncode >= size)
reallocprog(compst->L, compst->p, size * 2);
return compst->ncode++;
/*
** Initialize array 'p->code'
*/
static void newcode (lua_State *L, Pattern *p, int size) {
void *ud;
Instruction *block;
lua_Alloc f = lua_getallocf(L, &ud);
size++; /* slot for 'codesize' */
block = (Instruction*) f(ud, NULL, 0, size * sizeof(Instruction));
finishrelcode(L, p, block, size);
}
void freecode (lua_State *L, Pattern *p) {
if (p->code != NULL) {
void *ud;
lua_Alloc f = lua_getallocf(L, &ud);
uint osize = p->code[-1].codesize;
f(ud, p->code - 1, osize * sizeof(Instruction), 0); /* free block */
}
}
/*
** Assume that 'nsize' is not zero and that 'p->code' already exists.
*/
static void realloccode (lua_State *L, Pattern *p, int nsize) {
void *ud;
lua_Alloc f = lua_getallocf(L, &ud);
Instruction *block = p->code - 1;
uint osize = block->codesize;
nsize++; /* add the 'codesize' slot to size */
block = (Instruction*) f(ud, block, osize * sizeof(Instruction),
nsize * sizeof(Instruction));
finishrelcode(L, p, block, nsize);
}
/*
** Add space for an instruction with 'n' slots and return its index.
*/
static int nextinstruction (CompileState *compst, int n) {
int size = compst->p->code[-1].codesize - 1;
int ncode = compst->ncode;
if (ncode > size - n) {
uint nsize = size + (size >> 1) + n;
if (nsize >= INT_MAX)
luaL_error(compst->L, "pattern code too large");
realloccode(compst->L, compst->p, nsize);
}
compst->ncode = ncode + n;
return ncode;
}
@@ -455,13 +460,16 @@ static int nextinstruction (CompileState *compst) {
static int addinstruction (CompileState *compst, Opcode op, int aux) {
int i = nextinstruction(compst);
int i = nextinstruction(compst, 1);
getinstr(compst, i).i.code = op;
getinstr(compst, i).i.aux = aux;
getinstr(compst, i).i.aux1 = aux;
return i;
}
/*
** Add an instruction followed by space for an offset (to be set later)
*/
static int addoffsetinst (CompileState *compst, Opcode op) {
int i = addinstruction(compst, op, 0); /* instruction */
addinstruction(compst, (Opcode)0, 0); /* open space for offset */
@@ -470,21 +478,34 @@ static int addoffsetinst (CompileState *compst, Opcode op) {
}
/*
** Set the offset of an instruction
*/
static void setoffset (CompileState *compst, int instruction, int offset) {
getinstr(compst, instruction + 1).offset = offset;
}
static void codeutfr (CompileState *compst, TTree *tree) {
int i = addoffsetinst(compst, IUTFR);
int to = sib1(tree)->u.n;
assert(sib1(tree)->tag == TXInfo);
getinstr(compst, i + 1).offset = tree->u.n;
getinstr(compst, i).i.aux1 = to & 0xff;
getinstr(compst, i).i.aux2.key = to >> 8;
}
/*
** Add a capture instruction:
** 'op' is the capture instruction; 'cap' the capture kind;
** 'key' the key into ktable; 'aux' is optional offset
** 'key' the key into ktable; 'aux' is the optional capture offset
**
*/
static int addinstcap (CompileState *compst, Opcode op, int cap, int key,
int aux) {
int i = addinstruction(compst, op, joinkindoff(cap, aux));
getinstr(compst, i).i.key = key;
getinstr(compst, i).i.aux2.key = key;
return i;
}
@@ -494,12 +515,18 @@ static int addinstcap (CompileState *compst, Opcode op, int cap, int key,
#define target(code,i) ((i) + code[i + 1].offset)
/*
** Patch 'instruction' to jump to 'target'
*/
static void jumptothere (CompileState *compst, int instruction, int target) {
if (instruction >= 0)
setoffset(compst, instruction, target - instruction);
}
/*
** Patch 'instruction' to jump to current position
*/
static void jumptohere (CompileState *compst, int instruction) {
jumptothere(compst, instruction, gethere(compst));
}
@@ -511,7 +538,7 @@ static void jumptohere (CompileState *compst, int instruction) {
*/
static void codechar (CompileState *compst, int c, int tt) {
if (tt >= 0 && getinstr(compst, tt).i.code == ITestChar &&
getinstr(compst, tt).i.aux == c)
getinstr(compst, tt).i.aux1 == c)
addinstruction(compst, IAny, 0);
else
addinstruction(compst, IChar, c);
@@ -519,45 +546,63 @@ static void codechar (CompileState *compst, int c, int tt) {
/*
** Add a charset posfix to an instruction
** Add a charset posfix to an instruction.
*/
static void addcharset (CompileState *compst, const byte *cs) {
int p = gethere(compst);
static void addcharset (CompileState *compst, int inst, charsetinfo *info) {
int p;
Instruction *I = &getinstr(compst, inst);
byte *charset;
int isize = instsize(info->size); /* size in instructions */
int i;
for (i = 0; i < (int)CHARSETINSTSIZE - 1; i++)
nextinstruction(compst); /* space for buffer */
/* fill buffer with charset */
loopset(j, getinstr(compst, p).buff[j] = cs[j]);
I->i.aux2.set.offset = info->offset * 8; /* offset in bits */
I->i.aux2.set.size = isize;
I->i.aux1 = info->deflt;
p = nextinstruction(compst, isize); /* space for charset */
charset = getinstr(compst, p).buff; /* charset buffer */
for (i = 0; i < isize * (int)sizeof(Instruction); i++)
charset[i] = getbytefromcharset(info, i); /* copy the buffer */
}
/*
** code a char set, optimizing unit sets for IChar, "complete"
** sets for IAny, and empty sets for IFail; also use an IAny
** when instruction is dominated by an equivalent test.
** Check whether charset 'info' is dominated by instruction 'p'
*/
static void codecharset (CompileState *compst, const byte *cs, int tt) {
int c = 0; /* (=) to avoid warnings */
Opcode op = charsettype(cs, &c);
switch (op) {
case IChar: codechar(compst, c, tt); break;
case ISet: { /* non-trivial set? */
if (tt >= 0 && getinstr(compst, tt).i.code == ITestSet &&
cs_equal(cs, getinstr(compst, tt + 2).buff))
addinstruction(compst, IAny, 0);
else {
addinstruction(compst, ISet, 0);
addcharset(compst, cs);
}
break;
static int cs_equal (Instruction *p, charsetinfo *info) {
if (p->i.code != ITestSet)
return 0;
else if (p->i.aux2.set.offset != info->offset * 8 ||
p->i.aux2.set.size != instsize(info->size) ||
p->i.aux1 != info->deflt)
return 0;
else {
int i;
for (i = 0; i < instsize(info->size) * (int)sizeof(Instruction); i++) {
if ((p + 2)->buff[i] != getbytefromcharset(info, i))
return 0;
}
default: addinstruction(compst, op, c); break;
}
return 1;
}
/*
** Code a char set, using IAny when instruction is dominated by an
** equivalent test.
*/
static void codecharset (CompileState *compst, TTree *tree, int tt) {
charsetinfo info;
tree2cset(tree, &info);
if (tt >= 0 && cs_equal(&getinstr(compst, tt), &info))
addinstruction(compst, IAny, 0);
else {
int i = addinstruction(compst, ISet, 0);
addcharset(compst, i, &info);
}
}
/*
** code a test set, optimizing unit sets for ITestChar, "complete"
** Code a test set, optimizing unit sets for ITestChar, "complete"
** sets for ITestAny, and empty sets for IJmp (always fails).
** 'e' is true iff test should accept the empty string. (Test
** instructions in the current VM never accept the empty string.)
@@ -565,22 +610,22 @@ static void codecharset (CompileState *compst, const byte *cs, int tt) {
static int codetestset (CompileState *compst, Charset *cs, int e) {
if (e) return NOINST; /* no test */
else {
int c = 0;
Opcode op = charsettype(cs->cs, &c);
charsetinfo info;
Opcode op = charsettype(cs->cs, &info);
switch (op) {
case IFail: return addoffsetinst(compst, IJmp); /* always jump */
case IAny: return addoffsetinst(compst, ITestAny);
case IChar: {
int i = addoffsetinst(compst, ITestChar);
getinstr(compst, i).i.aux = c;
getinstr(compst, i).i.aux1 = info.offset;
return i;
}
case ISet: {
default: { /* regular set */
int i = addoffsetinst(compst, ITestSet);
addcharset(compst, cs->cs);
addcharset(compst, i, &info);
assert(op == ISet);
return i;
}
default: assert(0); return 0;
}
}
}
@@ -616,13 +661,13 @@ static void codebehind (CompileState *compst, TTree *tree) {
/*
** Choice; optimizations:
** - when p1 is headfail
** - when first(p1) and first(p2) are disjoint; than
** a character not in first(p1) cannot go to p1, and a character
** in first(p1) cannot go to p2 (at it is not in first(p2)).
** (The optimization is not valid if p1 accepts the empty string,
** - when p1 is headfail or when first(p1) and first(p2) are disjoint,
** than a character not in first(p1) cannot go to p1 and a character
** in first(p1) cannot go to p2, either because p1 will accept
** (headfail) or because it is not in first(p2) (disjoint).
** (The second case is not valid if p1 accepts the empty string,
** as then there is no character at all...)
** - when p2 is empty and opt is true; a IPartialCommit can resuse
** - when p2 is empty and opt is true; a IPartialCommit can reuse
** the Choice already active in the stack.
*/
static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
@@ -637,7 +682,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
int jmp = NOINST;
codegen(compst, p1, 0, test, fl);
if (!emptyp2)
jmp = addoffsetinst(compst, IJmp);
jmp = addoffsetinst(compst, IJmp);
jumptohere(compst, test);
codegen(compst, p2, opt, NOINST, fl);
jumptohere(compst, jmp);
@@ -648,8 +693,8 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
codegen(compst, p1, 1, NOINST, fullset);
}
else {
/* <p1 / p2> ==
test(fail(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
/* <p1 / p2> ==
test(first(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
int pcommit;
int test = codetestset(compst, &cs1, e1);
int pchoice = addoffsetinst(compst, IChoice);
@@ -688,9 +733,10 @@ static void codeand (CompileState *compst, TTree *tree, int tt) {
/*
** Captures: if pattern has fixed (and not too big) length, use
** a single IFullCapture instruction after the match; otherwise,
** enclose the pattern with OpenCapture - CloseCapture.
** Captures: if pattern has fixed (and not too big) length, and it
** has no nested captures, use a single IFullCapture instruction
** after the match; otherwise, enclose the pattern with OpenCapture -
** CloseCapture.
*/
static void codecapture (CompileState *compst, TTree *tree, int tt,
const Charset *fl) {
@@ -714,9 +760,53 @@ static void coderuntime (CompileState *compst, TTree *tree, int tt) {
}
/*
** Create a jump to 'test' and fix 'test' to jump to next instruction
*/
static void closeloop (CompileState *compst, int test) {
int jmp = addoffsetinst(compst, IJmp);
jumptohere(compst, test);
jumptothere(compst, jmp, test);
}
/*
** Try repetition of charsets:
** For an empty set, repetition of fail is a no-op;
** For any or char, code a tight loop;
** For generic charset, use a span instruction.
*/
static int coderepcharset (CompileState *compst, TTree *tree) {
switch (tree->tag) {
case TFalse: return 1; /* 'fail*' is a no-op */
case TAny: { /* L1: testany -> L2; any; jmp L1; L2: */
int test = addoffsetinst(compst, ITestAny);
addinstruction(compst, IAny, 0);
closeloop(compst, test);
return 1;
}
case TChar: { /* L1: testchar c -> L2; any; jmp L1; L2: */
int test = addoffsetinst(compst, ITestChar);
getinstr(compst, test).i.aux1 = tree->u.n;
addinstruction(compst, IAny, 0);
closeloop(compst, test);
return 1;
}
case TSet: { /* regular set */
charsetinfo info;
int i = addinstruction(compst, ISpan, 0);
tree2cset(tree, &info);
addcharset(compst, i, &info);
return 1;
}
default: return 0; /* not a charset */
}
}
/*
** Repetion; optimizations:
** When pattern is a charset, can use special instruction ISpan.
** When pattern is a charset, use special code.
** When pattern is head fail, or if it starts with characters that
** are disjoint from what follows the repetions, a simple test
** is enough (a fail inside the repetition would backtrack to fail
@@ -726,21 +816,14 @@ static void coderuntime (CompileState *compst, TTree *tree, int tt) {
*/
static void coderep (CompileState *compst, TTree *tree, int opt,
const Charset *fl) {
Charset st;
if (tocharset(tree, &st)) {
addinstruction(compst, ISpan, 0);
addcharset(compst, st.cs);
}
else {
if (!coderepcharset(compst, tree)) {
Charset st;
int e1 = getfirst(tree, fullset, &st);
if (headfail(tree) || (!e1 && cs_disjoint(&st, fl))) {
/* L1: test (fail(p1)) -> L2; <p>; jmp L1; L2: */
int jmp;
int test = codetestset(compst, &st, 0);
codegen(compst, tree, opt, test, fullset);
jmp = addoffsetinst(compst, IJmp);
jumptohere(compst, test);
jumptothere(compst, jmp, test);
codegen(compst, tree, 0, test, fullset);
closeloop(compst, test);
}
else {
/* test(fail(p1)) -> L2; choice L2; L1: <p>; partialcommit L1; L2: */
@@ -797,7 +880,7 @@ static void correctcalls (CompileState *compst, int *positions,
Instruction *code = compst->p->code;
for (i = from; i < to; i += sizei(&code[i])) {
if (code[i].i.code == IOpenCall) {
int n = code[i].i.key; /* rule number */
int n = code[i].i.aux2.key; /* rule number */
int rule = positions[n]; /* rule position */
assert(rule == from || code[rule - 1].i.code == IRet);
if (code[finaltarget(code, i + 2)].i.code == IRet) /* call; ret ? */
@@ -824,8 +907,10 @@ static void codegrammar (CompileState *compst, TTree *grammar) {
int start = gethere(compst); /* here starts the initial rule */
jumptohere(compst, firstcall);
for (rule = sib1(grammar); rule->tag == TRule; rule = sib2(rule)) {
TTree *r = sib1(rule);
assert(r->tag == TXInfo);
positions[rulenumber++] = gethere(compst); /* save rule position */
codegen(compst, sib1(rule), 0, NOINST, fullset); /* code rule */
codegen(compst, sib1(r), 0, NOINST, fullset); /* code rule */
addinstruction(compst, IRet, 0);
}
assert(rule->tag == TTrue);
@@ -836,8 +921,8 @@ static void codegrammar (CompileState *compst, TTree *grammar) {
static void codecall (CompileState *compst, TTree *call) {
int c = addoffsetinst(compst, IOpenCall); /* to be corrected later */
getinstr(compst, c).i.key = sib2(call)->cap; /* rule number */
assert(sib2(call)->tag == TRule);
assert(sib1(sib2(call))->tag == TXInfo);
getinstr(compst, c).i.aux2.key = sib1(sib2(call))->u.n; /* rule number */
}
@@ -863,7 +948,8 @@ static int codeseq1 (CompileState *compst, TTree *p1, TTree *p2,
/*
** Main code-generation function: dispatch to auxiliar functions
** according to kind of tree
** according to kind of tree. ('needfollow' should return true
** only for consructions that use 'fl'.)
*/
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
const Charset *fl) {
@@ -871,9 +957,10 @@ static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
switch (tree->tag) {
case TChar: codechar(compst, tree->u.n, tt); break;
case TAny: addinstruction(compst, IAny, 0); break;
case TSet: codecharset(compst, treebuffer(tree), tt); break;
case TSet: codecharset(compst, tree, tt); break;
case TTrue: break;
case TFalse: addinstruction(compst, IFail, 0); break;
case TUTFR: codeutfr(compst, tree); break;
case TChoice: codechoice(compst, sib1(tree), sib2(tree), opt, fl); break;
case TRep: coderep(compst, sib1(tree), opt, fl); break;
case TBehind: codebehind(compst, tree); break;
@@ -906,6 +993,7 @@ static void peephole (CompileState *compst) {
Instruction *code = compst->p->code;
int i;
for (i = 0; i < compst->ncode; i += sizei(&code[i])) {
redo:
switch (code[i].i.code) {
case IChoice: case ICall: case ICommit: case IPartialCommit:
case IBackCommit: case ITestChar: case ITestSet:
@@ -919,7 +1007,7 @@ static void peephole (CompileState *compst) {
case IRet: case IFail: case IFailTwice:
case IEnd: { /* instructions with unconditional implicit jumps */
code[i] = code[ft]; /* jump becomes that instruction */
code[i + 1].i.code = IAny; /* 'no-op' for target position */
code[i + 1].i.code = IEmpty; /* 'no-op' for target position */
break;
}
case ICommit: case IPartialCommit:
@@ -927,8 +1015,7 @@ static void peephole (CompileState *compst) {
int fft = finallabel(code, ft);
code[i] = code[ft]; /* jump becomes that instruction... */
jumptothere(compst, i, fft); /* but must correct its offset */
i--; /* reoptimize its label */
break;
goto redo; /* reoptimize its label */
}
default: {
jumptothere(compst, i, ft); /* optimize label */
@@ -945,15 +1032,16 @@ static void peephole (CompileState *compst) {
/*
** Compile a pattern
** Compile a pattern. 'size' is the size of the pattern's tree,
** which gives a hint for the size of the final code.
*/
Instruction *compile (lua_State *L, Pattern *p) {
Instruction *compile (lua_State *L, Pattern *p, uint size) {
CompileState compst;
compst.p = p; compst.ncode = 0; compst.L = L;
reallocprog(L, p, 2); /* minimum initial size */
newcode(L, p, size/2u + 2); /* set initial size */
codegen(&compst, p->tree, 0, NOINST, fullset);
addinstruction(&compst, IEnd, 0);
reallocprog(L, p, compst.ncode); /* set final size */
realloccode(L, p, compst.ncode); /* set final size */
peephole(&compst);
return p->code;
}

View File

@@ -1,6 +1,3 @@
/*
** $Id: lpcode.h,v 1.5 2013/04/04 21:24:45 roberto Exp $
*/
#if !defined(lpcode_h)
#define lpcode_h
@@ -11,23 +8,28 @@
#include "lptree.h"
#include "lpvm.h"
int tocharset (TTree *tree, Charset *cs);
int checkaux (TTree *tree, int pred);
int fixedlenx (TTree *tree, int count, int len);
int fixedlen (TTree *tree);
int hascaptures (TTree *tree);
int lp_gc (lua_State *L);
Instruction *compile (lua_State *L, Pattern *p);
void reallocprog (lua_State *L, Pattern *p, int nsize);
Instruction *compile (lua_State *L, Pattern *p, uint size);
void freecode (lua_State *L, Pattern *p);
int sizei (const Instruction *i);
#define PEnullable 0
#define PEnofail 1
/*
** nofail(t) implies that 't' cannot fail with any input
*/
#define nofail(t) checkaux(t, PEnofail)
#define nullable(t) checkaux(t, PEnullable)
#define fixedlen(t) fixedlenx(t, 0, 0)
/*
** (not nullable(t)) implies 't' cannot match without consuming
** something
*/
#define nullable(t) checkaux(t, PEnullable)

110
3rd/lpeg/lpcset.c Normal file
View File

@@ -0,0 +1,110 @@
#include "lptypes.h"
#include "lpcset.h"
/*
** Add to 'c' the index of the (only) bit set in byte 'b'
*/
static int onlybit (int c, int b) {
if ((b & 0xF0) != 0) { c += 4; b >>= 4; }
if ((b & 0x0C) != 0) { c += 2; b >>= 2; }
if ((b & 0x02) != 0) { c += 1; }
return c;
}
/*
** Check whether a charset is empty (returns IFail), singleton (IChar),
** full (IAny), or none of those (ISet). When singleton, 'info.offset'
** returns which character it is. When generic set, 'info' returns
** information about its range.
*/
Opcode charsettype (const byte *cs, charsetinfo *info) {
int low0, low1, high0, high1;
for (low1 = 0; low1 < CHARSETSIZE && cs[low1] == 0; low1++)
/* find lowest byte with a 1-bit */;
if (low1 == CHARSETSIZE)
return IFail; /* no characters in set */
for (high1 = CHARSETSIZE - 1; cs[high1] == 0; high1--)
/* find highest byte with a 1-bit; low1 is a sentinel */;
if (low1 == high1) { /* only one byte with 1-bits? */
int b = cs[low1];
if ((b & (b - 1)) == 0) { /* does byte has only one 1-bit? */
info->offset = onlybit(low1 * BITSPERCHAR, b); /* get that bit */
return IChar; /* single character */
}
}
for (low0 = 0; low0 < CHARSETSIZE && cs[low0] == 0xFF; low0++)
/* find lowest byte with a 0-bit */;
if (low0 == CHARSETSIZE)
return IAny; /* set has all bits set */
for (high0 = CHARSETSIZE - 1; cs[high0] == 0xFF; high0--)
/* find highest byte with a 0-bit; low0 is a sentinel */;
if (high1 - low1 <= high0 - low0) { /* range of 1s smaller than of 0s? */
info->offset = low1;
info->size = high1 - low1 + 1;
info->deflt = 0; /* all discharged bits were 0 */
}
else {
info->offset = low0;
info->size = high0 - low0 + 1;
info->deflt = 0xFF; /* all discharged bits were 1 */
}
info->cs = cs + info->offset;
return ISet;
}
/*
** Get a byte from a compact charset. If index is inside the charset
** range, get the byte from the supporting charset (correcting it
** by the offset). Otherwise, return the default for the set.
*/
byte getbytefromcharset (const charsetinfo *info, int index) {
if (index < info->size)
return info->cs[index];
else return info->deflt;
}
/*
** If 'tree' is a 'char' pattern (TSet, TChar, TAny, TFalse), convert it
** into a charset and return 1; else return 0.
*/
int tocharset (TTree *tree, Charset *cs) {
switch (tree->tag) {
case TChar: { /* only one char */
assert(0 <= tree->u.n && tree->u.n <= UCHAR_MAX);
clearset(cs->cs); /* erase all chars */
setchar(cs->cs, tree->u.n); /* add that one */
return 1;
}
case TAny: {
fillset(cs->cs, 0xFF); /* add all characters to the set */
return 1;
}
case TFalse: {
clearset(cs->cs); /* empty set */
return 1;
}
case TSet: { /* fill set */
int i;
fillset(cs->cs, tree->u.set.deflt);
for (i = 0; i < tree->u.set.size; i++)
cs->cs[tree->u.set.offset + i] = treebuffer(tree)[i];
return 1;
}
default: return 0;
}
}
void tree2cset (TTree *tree, charsetinfo *info) {
assert(tree->tag == TSet);
info->offset = tree->u.set.offset;
info->size = tree->u.set.size;
info->deflt = tree->u.set.deflt;
info->cs = treebuffer(tree);
}

30
3rd/lpeg/lpcset.h Normal file
View File

@@ -0,0 +1,30 @@
#if !defined(lpset_h)
#define lpset_h
#include "lpcset.h"
#include "lpcode.h"
#include "lptree.h"
/*
** Extra information for the result of 'charsettype'. When result is
** IChar, 'offset' is the character. When result is ISet, 'cs' is the
** supporting bit array (with offset included), 'offset' is the offset
** (in bytes), 'size' is the size (in bytes), and 'delt' is the default
** value for bytes outside the set.
*/
typedef struct {
const byte *cs;
int offset;
int size;
int deflt;
} charsetinfo;
int tocharset (TTree *tree, Charset *cs);
Opcode charsettype (const byte *cs, charsetinfo *info);
byte getbytefromcharset (const charsetinfo *info, int index);
void tree2cset (TTree *tree, charsetinfo *info);
#endif

View File

@@ -1,28 +1,27 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
"//www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="//www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>LPeg - Parsing Expression Grammars For Lua</title>
<link rel="stylesheet"
href="http://www.inf.puc-rio.br/~roberto/lpeg/doc.css"
href="//www.inf.puc-rio.br/~roberto/lpeg/doc.css"
type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<!-- $Id: lpeg.html,v 1.71 2013/04/11 19:17:41 roberto Exp $ -->
<div id="container">
<div id="product">
<div id="product_logo">
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/">
<a href="//www.inf.puc-rio.br/~roberto/lpeg/">
<img alt="LPeg logo" src="lpeg-128.gif"/></a>
</div>
<div id="product_name"><big><strong>LPeg</strong></big></div>
<div id="product_description">
Parsing Expression Grammars For Lua, version 0.12
Parsing Expression Grammars For Lua, version 1.1
</div>
</div> <!-- id="product" -->
@@ -56,16 +55,16 @@
<p>
<em>LPeg</em> is a new pattern-matching library for Lua,
based on
<a href="http://pdos.csail.mit.edu/%7Ebaford/packrat/">
<a href="//bford.info/packrat/">
Parsing Expression Grammars</a> (PEGs).
This text is a reference manual for the library.
For a more formal treatment of LPeg,
as well as some discussion about its implementation,
see
<a href="http://www.inf.puc-rio.br/~roberto/docs/peg.pdf">
<a href="//www.inf.puc-rio.br/~roberto/docs/peg.pdf">
A Text Pattern-Matching Tool based on Parsing Expression Grammars</a>.
(You may also be interested in my
<a href="http://vimeo.com/1485123">talk about LPeg</a>
<a href="//vimeo.com/1485123">talk about LPeg</a>
given at the III Lua Workshop.)
</p>
@@ -107,6 +106,9 @@ for creating patterns:
<td>Matches any character in <code>string</code> (Set)</td></tr>
<tr><td><a href="#op-r"><code>lpeg.R("<em>xy</em>")</code></a></td>
<td>Matches any character between <em>x</em> and <em>y</em> (Range)</td></tr>
<tr><td><a href="#op-utfR"><code>lpeg.utfR(cp1, cp2)</code></a></td>
<td>Matches an UTF-8 code point between <code>cp1</code> and
<code>cp2</code></td></tr>
<tr><td><a href="#op-pow"><code>patt^n</code></a></td>
<td>Matches at least <code>n</code> repetitions of <code>patt</code></td></tr>
<tr><td><a href="#op-pow"><code>patt^-n</code></a></td>
@@ -142,7 +144,7 @@ so, it succeeds only at the end of the subject.
LPeg also offers the <a href="re.html"><code>re</code> module</a>,
which implements patterns following a regular-expression style
(e.g., <code>[09]+</code>).
(This module is 260 lines of Lua code,
(This module is 270 lines of Lua code,
and of course it uses LPeg to parse regular expressions and
translate them to regular LPeg patterns.)
</p>
@@ -164,7 +166,7 @@ or the <a href="#captures">captured values</a>
<p>
An optional numeric argument <code>init</code> makes the match
start at that position in the subject string.
As usual in Lua libraries,
As in the Lua standard libraries,
a negative value counts from the end.
</p>
@@ -188,20 +190,23 @@ returns the string <code>"pattern"</code>.
Otherwise returns nil.
</p>
<h3><a name="f-version"></a><code>lpeg.version ()</code></h3>
<h3><a name="f-version"></a><code>lpeg.version</code></h3>
<p>
Returns a string with the running version of LPeg.
A string (not a function) with the running version of LPeg.
</p>
<h3><a name="f-setstack"></a><code>lpeg.setmaxstack (max)</code></h3>
<p>
Sets the maximum size for the backtrack stack used by LPeg to
Sets a limit for the size of the backtrack stack used by LPeg to
track calls and choices.
(The default limit is 400.)
Most well-written patterns need little backtrack levels and
therefore you seldom need to change this maximum;
but a few useful patterns may need more space.
Before changing this maximum you should try to rewrite your
therefore you seldom need to change this limit;
before changing it you should try to rewrite your
pattern to avoid the need for extra space.
Nevertheless, a few useful patterns may overflow.
Also, with recursive grammars,
subjects with deep recursion may also need larger limits.
</p>
@@ -326,6 +331,15 @@ are patterns that always fail.
</p>
<h3><a name="op-utfR"></a><code>lpeg.utfR (cp1, cp2)</code></h3>
<p>
Returns a pattern that matches a valid UTF-8 byte sequence
representing a code point in the range <code>[cp1, cp2]</code>.
The range is limited by the natural Unicode limit of 0x10FFFF,
but may include surrogates.
</p>
<h3><a name="op-v"></a><code>lpeg.V (v)</code></h3>
<p>
This operation creates a non-terminal (a <em>variable</em>)
@@ -430,7 +444,8 @@ letter = lower + upper
<h3><a name="op-sub"></a><code>patt1 - patt2</code></h3>
<p>
Returns a pattern equivalent to <em>!patt2 patt1</em>.
Returns a pattern equivalent to <em>!patt2 patt1</em>
in the origial PEG notation.
This pattern asserts that the input does not match
<code>patt2</code> and then matches <code>patt1</code>.
</p>
@@ -574,8 +589,9 @@ It is equivalent to the following grammar in standard PEG notation:
<h2><a name="captures">Captures</a></h2>
<p>
A <em>capture</em> is a pattern that creates values
(the so called <em>semantic information</em>) when it matches.
A <em>capture</em> is a pattern that produces values
(the so called <em>semantic information</em>)
according to what it matches.
LPeg offers several kinds of captures,
which produces values based on matches and combine these values to
produce new values.
@@ -593,17 +609,17 @@ The following table summarizes the basic captures:
<tr><td><a href="#cap-arg"><code>lpeg.Carg(n)</code></a></td>
<td>the value of the n<sup>th</sup> extra argument to
<code>lpeg.match</code> (matches the empty string)</td></tr>
<tr><td><a href="#cap-b"><code>lpeg.Cb(name)</code></a></td>
<tr><td><a href="#cap-b"><code>lpeg.Cb(key)</code></a></td>
<td>the values produced by the previous
group capture named <code>name</code>
group capture named <code>key</code>
(matches the empty string)</td></tr>
<tr><td><a href="#cap-cc"><code>lpeg.Cc(values)</code></a></td>
<td>the given values (matches the empty string)</td></tr>
<tr><td><a href="#cap-f"><code>lpeg.Cf(patt, func)</code></a></td>
<td>a <em>folding</em> of the captures from <code>patt</code></td></tr>
<tr><td><a href="#cap-g"><code>lpeg.Cg(patt [, name])</code></a></td>
<td>folding capture (<em>deprecated</em>)</td></tr>
<tr><td><a href="#cap-g"><code>lpeg.Cg(patt [, key])</code></a></td>
<td>the values produced by <code>patt</code>,
optionally tagged with <code>name</code></td></tr>
optionally tagged with <code>key</code></td></tr>
<tr><td><a href="#cap-p"><code>lpeg.Cp()</code></a></td>
<td>the current position (matches the empty string)</td></tr>
<tr><td><a href="#cap-s"><code>lpeg.Cs(patt)</code></a></td>
@@ -623,16 +639,18 @@ or no value when <code>number</code> is zero.</td></tr>
<tr><td><a href="#cap-func"><code>patt / function</code></a></td>
<td>the returns of <code>function</code> applied to the captures
of <code>patt</code></td></tr>
<tr><td><a href="#cap-acc"><code>patt % function</code></a></td>
<td>produces no value;
it <em>accummulates</em> the captures from <code>patt</code>
into the previous capture through <code>function</code>
</td></tr>
<tr><td><a href="#matchtime"><code>lpeg.Cmt(patt, function)</code></a></td>
<td>the returns of <code>function</code> applied to the captures
of <code>patt</code>; the application is done at match time</td></tr>
</tbody></table>
<p>
A capture pattern produces its values every time it succeeds.
For instance,
a capture inside a loop produces as many values as matched by the loop.
A capture produces a value only when it succeeds.
A capture pattern produces its values only when it succeeds.
For instance,
the pattern <code>lpeg.C(lpeg.P"a"^-1)</code>
produces the empty string when there is no <code>"a"</code>
@@ -640,15 +658,21 @@ produces the empty string when there is no <code>"a"</code>
while the pattern <code>lpeg.C("a")^-1</code>
does not produce any value when there is no <code>"a"</code>
(because the pattern <code>"a"</code> fails).
A pattern inside a loop or inside a recursive structure
produces values for each match.
</p>
<p>
Usually,
LPeg evaluates all captures only after (and if) the entire match succeeds.
During <em>match time</em> it only gathers enough information
to produce the capture values later.
As a particularly important consequence,
most captures cannot affect the way a pattern matches a subject.
LPeg does not specify when (and if) it evaluates its captures.
(As an example,
consider the pattern <code>lpeg.P"a" / func / 0</code>.
Because the "division" by 0 instructs LPeg to throw away the
results from the pattern,
it is not specified whether LPeg will call <code>func</code>.)
Therefore, captures should avoid side effects.
Moreover,
captures cannot affect the way a pattern matches a subject.
The only exception to this rule is the
so-called <a href="#matchtime"><em>match-time capture</em></a>.
When a match-time capture matches,
@@ -677,25 +701,33 @@ argument given in the call to <code>lpeg.match</code>.
</p>
<h3><a name="cap-b"></a><code>lpeg.Cb (name)</code></h3>
<h3><a name="cap-b"></a><code>lpeg.Cb (key)</code></h3>
<p>
Creates a <em>back capture</em>.
This pattern matches the empty string and
produces the values produced by the <em>most recent</em>
<a href="#cap-g">group capture</a> named <code>name</code>.
<a href="#cap-g">group capture</a> named <code>key</code>
(where <code>key</code> can be any Lua value).
</p>
<p>
<em>Most recent</em> means the last
<em>complete</em>
<em>outermost</em>
group capture with the given name.
group capture with the given key.
A <em>Complete</em> capture means that the entire pattern
corresponding to the capture has matched.
corresponding to the capture has matched;
in other words, the back capture is not nested inside the group.
An <em>Outermost</em> capture means that the capture is not inside
another complete capture.
another complete capture that does not contain the back capture itself.
</p>
<p>
In the same way that LPeg does not specify when it evaluates captures,
it does not specify whether it reuses
values previously produced by the group
or re-evaluates them.
</p>
<h3><a name="cap-cc"></a><code>lpeg.Cc ([value, ...])</code></h3>
<p>
@@ -708,61 +740,22 @@ produces all given values as its captured values.
<h3><a name="cap-f"></a><code>lpeg.Cf (patt, func)</code></h3>
<p>
Creates a <em>fold capture</em>.
If <code>patt</code> produces a list of captures
<em>C<sub>1</sub> C<sub>2</sub> ... C<sub>n</sub></em>,
this capture will produce the value
<em>func(...func(func(C<sub>1</sub>, C<sub>2</sub>), C<sub>3</sub>)...,
C<sub>n</sub>)</em>,
that is, it will <em>fold</em>
(or <em>accumulate</em>, or <em>reduce</em>)
the captures from <code>patt</code> using function <code>func</code>.
</p>
<p>
This capture assumes that <code>patt</code> should produce
at least one capture with at least one value (of any type),
which becomes the initial value of an <em>accumulator</em>.
(If you need a specific initial value,
you may prefix a <a href="#cap-cc">constant capture</a> to <code>patt</code>.)
For each subsequent capture,
LPeg calls <code>func</code>
with this accumulator as the first argument and all values produced
by the capture as extra arguments;
the first result from this call
becomes the new value for the accumulator.
The final value of the accumulator becomes the captured value.
</p>
<p>
As an example,
the following pattern matches a list of numbers separated
by commas and returns their addition:
</p>
<pre class="example">
-- matches a numeral and captures its numerical value
number = lpeg.R"09"^1 / tonumber
-- matches a list of numbers, capturing their values
list = number * ("," * number)^0
-- auxiliary function to add two numbers
function add (acc, newvalue) return acc + newvalue end
-- folds the list of numbers adding them
sum = lpeg.Cf(list, add)
-- example of use
print(sum:match("10,30,43")) --&gt; 83
</pre>
This construction is deprecated;
use an <a href="#cap-acc">accumulator pattern</a> instead.
In general, a fold like
<code>lpeg.Cf(p1 * p2^0, func)</code>
can be translated to
<code>(p1 * (p2 % func)^0)</code>.
<h3><a name="cap-g"></a><code>lpeg.Cg (patt [, name])</code></h3>
<h3><a name="cap-g"></a><code>lpeg.Cg (patt [, key])</code></h3>
<p>
Creates a <em>group capture</em>.
It groups all values returned by <code>patt</code>
into a single capture.
The group may be anonymous (if no name is given)
or named with the given name.
The group may be anonymous (if no key is given)
or named with the given key
(which can be any non-nil Lua value).
</p>
<p>
@@ -801,13 +794,13 @@ all replacements.
<h3><a name="cap-t"></a><code>lpeg.Ct (patt)</code></h3>
<p>
Creates a <em>table capture</em>.
This capture creates a table and puts all values from all anonymous captures
This capture returns a table with all values from all anonymous captures
made by <code>patt</code> inside this table in successive integer keys,
starting at 1.
Moreover,
for each named capture group created by <code>patt</code>,
the first value of the group is put into the table
with the group name as its key.
with the group key as its key.
The captured value is only the table.
</p>
@@ -863,11 +856,104 @@ there is no captured value.
</p>
<h3><a name="cap-acc"></a><code>patt % function</code></h3>
<p>
Creates an <em>accumulator capture</em>.
This pattern behaves similarly to a
<a href="#cap-func">function capture</a>,
with the following differences:
The last captured value before <code>patt</code>
is added as a first argument to the call;
the return of the function is adjusted to one single value;
that value replaces the last captured value.
Note that the capture itself produces no values;
it only changes the value of its previous capture.
</p>
<p>
As an example,
let us consider the problem of adding a list of numbers.
</p>
<pre class="example">
-- matches a numeral and captures its numerical value
number = lpeg.R"09"^1 / tonumber
-- auxiliary function to add two numbers
function add (acc, newvalue) return acc + newvalue end
-- matches a list of numbers, adding their values
sum = number * ("," * number % add)^0
-- example of use
print(sum:match("10,30,43")) --&gt; 83
</pre>
<p>
First, the initial <code>number</code> captures a number;
that first capture will play the role of an accumulator.
Then, each time the sequence <code>comma-number</code>
matches inside the loop there is an accumulator capture:
It calls <code>add</code> with the current value of the
accumulator&mdash;which is the last captured value, created by the
first <code>number</code>&mdash; and the value of the new number,
and the result of the call (the sum of the two numbers)
replaces the value of the accumulator.
At the end of the match,
the accumulator with all sums is the final value.
</p>
<p>
As another example,
consider the following code fragment:
</p>
<pre class="example">
local name = lpeg.C(lpeg.R("az")^1)
local p = name * (lpeg.P("^") % string.upper)^-1
print(p:match("count")) --&gt; count
print(p:match("count^")) --&gt; COUNT
</pre>
<p>
In the match against <code>"count"</code>,
as there is no <code>"^"</code>,
the optional accumulator capture does not match;
so, the match results in its sole capture, a name.
In the match against <code>"count^"</code>,
the accumulator capture matches,
so the function <code>string.upper</code>
is called with the previous captured value (created by <code>name</code>)
plus the string <code>"^"</code>;
the function ignores its second argument and returns the first argument
changed to upper case;
that value then becomes the first and only
capture value created by the match.
</p>
<p>
Due to the nature of this capture,
you should avoid using it in places where it is not clear
what is the "previous" capture,
such as directly nested in a <a href="#cap-string">string capture</a>
or a <a href="#cap-num">numbered capture</a>.
(Note that these captures may not need to evaluate
all their subcaptures to compute their results.)
Moreover, due to implementation details,
you should not use this capture directly nested in a
<a href="#cap-s">substitution capture</a>.
You should also avoid a direct nesting of this capture inside
a <a href="#cap-f">folding capture</a> (deprecated),
as the folding will try to fold each individual accumulator capture.
A simple and effective way to avoid all these issues is
to enclose the whole accumulation composition
(including the capture that generates the initial value)
into an anonymous <a href="#cap-g">group capture</a>.
</p>
<h3><a name="matchtime"></a><code>lpeg.Cmt(patt, function)</code></h3>
<p>
Creates a <em>match-time capture</em>.
Unlike all other captures,
this one is evaluated immediately when a match occurs.
this one is evaluated immediately when a match occurs
(even if it is part of a larger pattern that fails later).
It forces the immediate evaluation of all its nested captures
and then calls <code>function</code>.
</p>
@@ -914,9 +1000,9 @@ local lpeg = require "lpeg"
-- matches a word followed by end-of-string
p = lpeg.R"az"^1 * -1
print(p:match("hello")) --> 6
print(lpeg.match(p, "hello")) --> 6
print(p:match("1 hello")) --> nil
print(p:match("hello")) --&gt; 6
print(lpeg.match(p, "hello")) --&gt; 6
print(p:match("1 hello")) --&gt; nil
</pre>
<p>
The pattern is simply a sequence of one or more lower-case letters
@@ -941,19 +1027,18 @@ lpeg.locale(lpeg) -- adds locale entries into 'lpeg' table
local space = lpeg.space^0
local name = lpeg.C(lpeg.alpha^1) * space
local sep = lpeg.S(",;") * space
local pair = lpeg.Cg(name * "=" * space * name) * sep^-1
local list = lpeg.Cf(lpeg.Ct("") * pair^0, rawset)
t = list:match("a=b, c = hi; next = pi") --> { a = "b", c = "hi", next = "pi" }
local pair = name * "=" * space * name * sep^-1
local list = lpeg.Ct("") * (pair % rawset)^0
t = list:match("a=b, c = hi; next = pi")
--&gt; { a = "b", c = "hi", next = "pi" }
</pre>
<p>
Each pair has the format <code>name = name</code> followed by
an optional separator (a comma or a semicolon).
The <code>pair</code> pattern encloses the pair in a group pattern,
so that the names become the values of a single capture.
The <code>list</code> pattern then folds these captures.
The <code>list</code> pattern then <em>folds</em> these captures.
It starts with an empty table,
created by a table capture matching an empty string;
then for each capture (a pair of names) it applies <code>rawset</code>
then for each a pair of names it applies <code>rawset</code>
over the accumulator (the table) and the capture values (the pair of names).
<code>rawset</code> returns the table itself,
so the accumulator is always the table.
@@ -987,7 +1072,7 @@ by <code>sep</code>.
If the split results in too many values,
it may overflow the maximum number of values
that can be returned by a Lua function.
In this case,
To avoid this problem,
we can collect these values in a table:
</p>
<pre class="example">
@@ -1023,7 +1108,7 @@ end
</pre>
<p>
This grammar has a straight reading:
it matches <code>p</code> or skips one character and tries again.
its sole rule matches <code>p</code> or skips one character and tries again.
</p>
<p>
@@ -1032,27 +1117,27 @@ If we want to know where the pattern is in the string
we can add position captures to the pattern:
</p>
<pre class="example">
local I = lpeg.Cp()
local Cp = lpeg.Cp()
function anywhere (p)
return lpeg.P{ I * p * I + 1 * lpeg.V(1) }
return lpeg.P{ Cp * p * Cp + 1 * lpeg.V(1) }
end
print(anywhere("world"):match("hello world!")) -> 7 12
print(anywhere("world"):match("hello world!")) --&gt; 7 12
</pre>
<p>
Another option for the search is like this:
</p>
<pre class="example">
local I = lpeg.Cp()
local Cp = lpeg.Cp()
function anywhere (p)
return (1 - lpeg.P(p))^0 * I * p * I
return (1 - lpeg.P(p))^0 * Cp * p * Cp
end
</pre>
<p>
Again the pattern has a straight reading:
it skips as many characters as possible while not matching <code>p</code>,
and then matches <code>p</code> (plus appropriate captures).
and then matches <code>p</code> plus appropriate captures.
</p>
<p>
@@ -1147,91 +1232,6 @@ local record = lpeg.Ct(field * (',' * field)^0) * (lpeg.P'\n' + -1)
</pre>
<h3>UTF-8 and Latin 1</h3>
<p>
It is not difficult to use LPeg to convert a string from
UTF-8 encoding to Latin 1 (ISO 8859-1):
</p>
<pre class="example">
-- convert a two-byte UTF-8 sequence to a Latin 1 character
local function f2 (s)
local c1, c2 = string.byte(s, 1, 2)
return string.char(c1 * 64 + c2 - 12416)
end
local utf8 = lpeg.R("\0\127")
+ lpeg.R("\194\195") * lpeg.R("\128\191") / f2
local decode_pattern = lpeg.Cs(utf8^0) * -1
</pre>
<p>
In this code,
the definition of UTF-8 is already restricted to the
Latin 1 range (from 0 to 255).
Any encoding outside this range (as well as any invalid encoding)
will not match that pattern.
</p>
<p>
As the definition of <code>decode_pattern</code> demands that
the pattern matches the whole input (because of the -1 at its end),
any invalid string will simply fail to match,
without any useful information about the problem.
We can improve this situation redefining <code>decode_pattern</code>
as follows:
</p>
<pre class="example">
local function er (_, i) error("invalid encoding at position " .. i) end
local decode_pattern = lpeg.Cs(utf8^0) * (-1 + lpeg.P(er))
</pre>
<p>
Now, if the pattern <code>utf8^0</code> stops
before the end of the string,
an appropriate error function is called.
</p>
<h3>UTF-8 and Unicode</h3>
<p>
We can extend the previous patterns to handle all Unicode code points.
Of course,
we cannot translate them to Latin 1 or any other one-byte encoding.
Instead, our translation results in a array with the code points
represented as numbers.
The full code is here:
</p>
<pre class="example">
-- decode a two-byte UTF-8 sequence
local function f2 (s)
local c1, c2 = string.byte(s, 1, 2)
return c1 * 64 + c2 - 12416
end
-- decode a three-byte UTF-8 sequence
local function f3 (s)
local c1, c2, c3 = string.byte(s, 1, 3)
return (c1 * 64 + c2) * 64 + c3 - 925824
end
-- decode a four-byte UTF-8 sequence
local function f4 (s)
local c1, c2, c3, c4 = string.byte(s, 1, 4)
return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168
end
local cont = lpeg.R("\128\191") -- continuation byte
local utf8 = lpeg.R("\0\127") / string.byte
+ lpeg.R("\194\223") * cont / f2
+ lpeg.R("\224\239") * cont * cont / f3
+ lpeg.R("\240\244") * cont * cont * cont / f4
local decode_pattern = lpeg.Ct(utf8^0) * -1
</pre>
<h3>Lua's long strings</h3>
<p>
A long string in Lua starts with the pattern <code>[=*[</code>
@@ -1331,7 +1331,7 @@ function evalExp (s)
end
-- small example
print(evalExp"3 + 5*9 / (1+1) - 12") --> 13.5
print(evalExp"3 + 5*9 / (1+1) - 12") --&gt; 13.5
</pre>
<p>
@@ -1353,16 +1353,16 @@ end
-- Grammar
local V = lpeg.V
G = lpeg.P{ "Exp",
Exp = lpeg.Cf(V"Term" * lpeg.Cg(TermOp * V"Term")^0, eval);
Term = lpeg.Cf(V"Factor" * lpeg.Cg(FactorOp * V"Factor")^0, eval);
Exp = V"Term" * (TermOp * V"Term" % eval)^0;
Term = V"Factor" * (FactorOp * V"Factor" % eval)^0;
Factor = Number / tonumber + Open * V"Exp" * Close;
}
-- small example
print(lpeg.match(G, "3 + 5*9 / (1+1) - 12")) --> 13.5
print(lpeg.match(G, "3 + 5*9 / (1+1) - 12")) --&gt; 13.5
</pre>
<p>
Note the use of the fold (accumulator) capture.
Note the use of the accumulator capture.
To compute the value of an expression,
the accumulator starts with the value of the first term,
and then applies <code>eval</code> over
@@ -1375,13 +1375,20 @@ and the new term for each repetition.
<h2><a name="download"></a>Download</h2>
<p>LPeg
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-0.12.tar.gz">source code</a>.</p>
<a href="//www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.1.0.tar.gz">source code</a>.</p>
<p>
Probably, the easiest way to install LPeg is with
<a href="//luarocks.org/">LuaRocks</a>.
If you have LuaRocks installed,
the following command is all you need to install LPeg:
<pre>$ luarocks install lpeg</pre>
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2013 Lua.org, PUC-Rio.
Copyright &copy; 2007-2023 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
@@ -1417,12 +1424,6 @@ THE SOFTWARE.
</div> <!-- id="main" -->
<div id="about">
<p><small>
$Id: lpeg.html,v 1.71 2013/04/11 19:17:41 roberto Exp $
</small></p>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -1,7 +1,3 @@
/*
** $Id: lpprint.c,v 1.7 2013/04/12 16:29:49 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
#include <ctype.h>
#include <limits.h>
@@ -27,7 +23,7 @@ void printcharset (const byte *st) {
printf("[");
for (i = 0; i <= UCHAR_MAX; i++) {
int first = i;
while (testchar(st, i) && i <= UCHAR_MAX) i++;
while (i <= UCHAR_MAX && testchar(st, i)) i++;
if (i - 1 == first) /* unary range? */
printf("(%02x)", first);
else if (i - 1 > first) /* non-empty range? */
@@ -37,13 +33,37 @@ void printcharset (const byte *st) {
}
static void printcapkind (int kind) {
static void printIcharset (const Instruction *inst, const byte *buff) {
byte cs[CHARSETSIZE];
int i;
printf("(%02x-%d) ", inst->i.aux2.set.offset, inst->i.aux2.set.size);
clearset(cs);
for (i = 0; i < CHARSETSIZE * 8; i++) {
if (charinset(inst, buff, i))
setchar(cs, i);
}
printcharset(cs);
}
static void printTcharset (TTree *tree) {
byte cs[CHARSETSIZE];
int i;
printf("(%02x-%d) ", tree->u.set.offset, tree->u.set.size);
fillset(cs, tree->u.set.deflt);
for (i = 0; i < tree->u.set.size; i++)
cs[tree->u.set.offset + i] = treebuffer(tree)[i];
printcharset(cs);
}
static const char *capkind (int kind) {
const char *const modes[] = {
"close", "position", "constant", "backref",
"argument", "simple", "table", "function",
"argument", "simple", "table", "function", "accumulator",
"query", "string", "num", "substitution", "fold",
"runtime", "group"};
printf("%s", modes[kind]);
return modes[kind];
}
@@ -52,46 +72,50 @@ static void printjmp (const Instruction *op, const Instruction *p) {
}
static void printinst (const Instruction *op, const Instruction *p) {
void printinst (const Instruction *op, const Instruction *p) {
const char *const names[] = {
"any", "char", "set",
"testany", "testchar", "testset",
"span", "behind",
"span", "utf-range", "behind",
"ret", "end",
"choice", "jmp", "call", "open_call",
"commit", "partial_commit", "back_commit", "failtwice", "fail", "giveup",
"fullcapture", "opencapture", "closecapture", "closeruntime"
"fullcapture", "opencapture", "closecapture", "closeruntime",
"--"
};
printf("%02ld: %s ", (long)(p - op), names[p->i.code]);
switch ((Opcode)p->i.code) {
case IChar: {
printf("'%c'", p->i.aux);
printf("'%c' (%02x)", p->i.aux1, p->i.aux1);
break;
}
case ITestChar: {
printf("'%c'", p->i.aux); printjmp(op, p);
printf("'%c' (%02x)", p->i.aux1, p->i.aux1); printjmp(op, p);
break;
}
case IUTFR: {
printf("%d - %d", p[1].offset, utf_to(p));
break;
}
case IFullCapture: {
printcapkind(getkind(p));
printf(" (size = %d) (idx = %d)", getoff(p), p->i.key);
printf("%s (size = %d) (idx = %d)",
capkind(getkind(p)), getoff(p), p->i.aux2.key);
break;
}
case IOpenCapture: {
printcapkind(getkind(p));
printf(" (idx = %d)", p->i.key);
printf("%s (idx = %d)", capkind(getkind(p)), p->i.aux2.key);
break;
}
case ISet: {
printcharset((p+1)->buff);
printIcharset(p, (p+1)->buff);
break;
}
case ITestSet: {
printcharset((p+2)->buff); printjmp(op, p);
printIcharset(p, (p+2)->buff); printjmp(op, p);
break;
}
case ISpan: {
printcharset((p+1)->buff);
printIcharset(p, (p+1)->buff);
break;
}
case IOpenCall: {
@@ -99,7 +123,7 @@ static void printinst (const Instruction *op, const Instruction *p) {
break;
}
case IBehind: {
printf("%d", p->i.aux);
printf("%d", p->i.aux1);
break;
}
case IJmp: case ICall: case ICommit: case IChoice:
@@ -113,8 +137,9 @@ static void printinst (const Instruction *op, const Instruction *p) {
}
void printpatt (Instruction *p, int n) {
void printpatt (Instruction *p) {
Instruction *op = p;
uint n = op[-1].codesize - 1;
while (p < op + n) {
printinst(op, p);
p += sizei(p);
@@ -122,20 +147,39 @@ void printpatt (Instruction *p, int n) {
}
#if defined(LPEG_DEBUG)
static void printcap (Capture *cap) {
printcapkind(cap->kind);
printf(" (idx: %d - size: %d) -> %p\n", cap->idx, cap->siz, cap->s);
static void printcap (Capture *cap, int ident) {
while (ident--) printf(" ");
printf("%s (idx: %d - size: %d) -> %lu (%p)\n",
capkind(cap->kind), cap->idx, cap->siz, (long)cap->index, (void*)cap);
}
void printcaplist (Capture *cap, Capture *limit) {
/*
** Print a capture and its nested captures
*/
static Capture *printcap2close (Capture *cap, int ident) {
Capture *head = cap++;
printcap(head, ident); /* print head capture */
while (capinside(head, cap))
cap = printcap2close(cap, ident + 2); /* print nested captures */
if (isopencap(head)) {
assert(isclosecap(cap));
printcap(cap++, ident); /* print and skip close capture */
}
return cap;
}
void printcaplist (Capture *cap) {
{ /* for debugging, print first a raw list of captures */
Capture *c = cap;
while (c->index != MAXINDT) { printcap(c, 0); c++; }
}
printf(">======\n");
for (; cap->s && (limit == NULL || cap < limit); cap++)
printcap(cap);
while (!isclosecap(cap))
cap = printcap2close(cap, 0);
printf("=======\n");
}
#endif
/* }====================================================== */
@@ -148,11 +192,11 @@ void printcaplist (Capture *cap, Capture *limit) {
static const char *tagnames[] = {
"char", "set", "any",
"true", "false",
"true", "false", "utf8.range",
"rep",
"seq", "choice",
"not", "and",
"call", "opencall", "rule", "grammar",
"call", "opencall", "rule", "xinfo", "grammar",
"behind",
"capture", "run-time"
};
@@ -160,6 +204,7 @@ static const char *tagnames[] = {
void printtree (TTree *tree, int ident) {
int i;
int sibs = numsiblings[tree->tag];
for (i = 0; i < ident; i++) printf(" ");
printf("%s", tagnames[tree->tag]);
switch (tree->tag) {
@@ -172,28 +217,38 @@ void printtree (TTree *tree, int ident) {
break;
}
case TSet: {
printcharset(treebuffer(tree));
printTcharset(tree);
printf("\n");
break;
}
case TUTFR: {
assert(sib1(tree)->tag == TXInfo);
printf(" %d (%02x %d) - %d (%02x %d) \n",
tree->u.n, tree->key, tree->cap,
sib1(tree)->u.n, sib1(tree)->key, sib1(tree)->cap);
break;
}
case TOpenCall: case TCall: {
printf(" key: %d\n", tree->key);
assert(sib1(sib2(tree))->tag == TXInfo);
printf(" key: %d (rule: %d)\n", tree->key, sib1(sib2(tree))->u.n);
break;
}
case TBehind: {
printf(" %d\n", tree->u.n);
printtree(sib1(tree), ident + 2);
break;
}
case TCapture: {
printf(" cap: %d key: %d n: %d\n", tree->cap, tree->key, tree->u.n);
printtree(sib1(tree), ident + 2);
printf(" kind: '%s' key: %d\n", capkind(tree->cap), tree->key);
break;
}
case TRule: {
printf(" n: %d key: %d\n", tree->cap, tree->key);
printtree(sib1(tree), ident + 2);
break; /* do not print next rule as a sibling */
printf(" key: %d\n", tree->key);
sibs = 1; /* do not print 'sib2' (next rule) as a sibling */
break;
}
case TXInfo: {
printf(" n: %d\n", tree->u.n);
break;
}
case TGrammar: {
TTree *rule = sib1(tree);
@@ -203,28 +258,27 @@ void printtree (TTree *tree, int ident) {
rule = sib2(rule);
}
assert(rule->tag == TTrue); /* sentinel */
sibs = 0; /* siblings already handled */
break;
}
default: {
int sibs = numsiblings[tree->tag];
default:
printf("\n");
if (sibs >= 1) {
printtree(sib1(tree), ident + 2);
if (sibs >= 2)
printtree(sib2(tree), ident + 2);
}
break;
}
}
if (sibs >= 1) {
printtree(sib1(tree), ident + 2);
if (sibs >= 2)
printtree(sib2(tree), ident + 2);
}
}
void printktable (lua_State *L, int idx) {
int n, i;
lua_getfenv(L, idx);
lua_getuservalue(L, idx);
if (lua_isnil(L, -1)) /* no ktable? */
return;
n = lua_objlen(L, -1);
n = lua_rawlen(L, -1);
printf("[");
for (i = 1; i <= n; i++) {
printf("%d = ", i);

View File

@@ -1,7 +1,3 @@
/*
** $Id: lpprint.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
*/
#if !defined(lpprint_h)
#define lpprint_h
@@ -13,11 +9,12 @@
#if defined(LPEG_DEBUG)
void printpatt (Instruction *p, int n);
void printpatt (Instruction *p);
void printtree (TTree *tree, int ident);
void printktable (lua_State *L, int idx);
void printcharset (const byte *st);
void printcaplist (Capture *cap, Capture *limit);
void printcaplist (Capture *cap);
void printinst (const Instruction *op, const Instruction *p);
#else
@@ -25,7 +22,7 @@ void printcaplist (Capture *cap, Capture *limit);
luaL_error(L, "function only implemented in debug mode")
#define printtree(tree,i) \
luaL_error(L, "function only implemented in debug mode")
#define printpatt(p,n) \
#define printpatt(p) \
luaL_error(L, "function only implemented in debug mode")
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,70 +1,85 @@
/*
** $Id: lptree.h,v 1.2 2013/03/24 13:51:12 roberto Exp $
*/
#if !defined(lptree_h)
#define lptree_h
#include "lptypes.h"
#include "lptypes.h"
/*
** types of trees
*/
typedef enum TTag {
TChar = 0, TSet, TAny, /* standard PEG elements */
TTrue, TFalse,
TRep,
TSeq, TChoice,
TNot, TAnd,
TCall,
TOpenCall,
TRule, /* sib1 is rule's pattern, sib2 is 'next' rule */
TGrammar, /* sib1 is initial (and first) rule */
TBehind, /* match behind */
TCapture, /* regular capture */
TRunTime /* run-time capture */
TChar = 0, /* 'n' = char */
TSet, /* the set is encoded in 'u.set' and the next 'u.set.size' bytes */
TAny,
TTrue,
TFalse,
TUTFR, /* range of UTF-8 codepoints; 'n' has initial codepoint;
'cap' has length; 'key' has first byte;
extra info is similar for end codepoint */
TRep, /* 'sib1'* */
TSeq, /* 'sib1' 'sib2' */
TChoice, /* 'sib1' / 'sib2' */
TNot, /* !'sib1' */
TAnd, /* &'sib1' */
TCall, /* ktable[key] is rule's key; 'sib2' is rule being called */
TOpenCall, /* ktable[key] is rule's key */
TRule, /* ktable[key] is rule's key (but key == 0 for unused rules);
'sib1' is rule's pattern pre-rule; 'sib2' is next rule;
extra info 'n' is rule's sequential number */
TXInfo, /* extra info */
TGrammar, /* 'sib1' is initial (and first) rule */
TBehind, /* 'sib1' is pattern, 'n' is how much to go back */
TCapture, /* captures: 'cap' is kind of capture (enum 'CapKind');
ktable[key] is Lua value associated with capture;
'sib1' is capture body */
TRunTime /* run-time capture: 'key' is Lua function;
'sib1' is capture body */
} TTag;
/* number of siblings for each tree */
extern const byte numsiblings[];
/*
** Tree trees
** The first sibling of a tree (if there is one) is immediately after
** the tree. A reference to a second sibling (ps) is its position
** relative to the position of the tree itself. A key in ktable
** uses the (unique) address of the original tree that created that
** entry. NULL means no data.
** The first child of a tree (if there is one) is immediately after
** the tree. A reference to a second child (ps) is its position
** relative to the position of the tree itself.
*/
typedef struct TTree {
byte tag;
byte cap; /* kind of capture (if it is a capture) */
unsigned short key; /* key in ktable for Lua data (0 if no key) */
union {
int ps; /* occasional second sibling */
int ps; /* occasional second child */
int n; /* occasional counter */
struct {
byte offset; /* compact set offset (in bytes) */
byte size; /* compact set size (in bytes) */
byte deflt; /* default value */
byte bitmap[1]; /* bitmap (open array) */
} set; /* for compact sets */
} u;
} TTree;
/* access to charset */
#define treebuffer(t) ((t)->u.set.bitmap)
/*
** A complete pattern has its tree plus, if already compiled,
** its corresponding code
*/
typedef struct Pattern {
union Instruction *code;
int codesize;
TTree tree[1];
} Pattern;
/* number of siblings for each tree */
/* number of children for each tree */
extern const byte numsiblings[];
/* access to siblings */
/* access to children */
#define sib1(t) ((t) + 1)
#define sib2(t) ((t) + (t)->u.ps)

View File

@@ -1,7 +1,6 @@
/*
** $Id: lptypes.h,v 1.8 2013/04/12 16:26:38 roberto Exp $
** LPeg - PEG pattern matching for Lua
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** Copyright 2007-2023, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy
*/
@@ -9,17 +8,14 @@
#define lptypes_h
#if !defined(LPEG_DEBUG)
#define NDEBUG
#endif
#include <assert.h>
#include <limits.h>
#include <string.h>
#include "lua.h"
#define VERSION "0.12"
#define VERSION "1.1.0"
#define PATTERN_T "lpeg-pattern"
@@ -27,36 +23,40 @@
/*
** compatibility with Lua 5.2
** compatibility with Lua 5.1
*/
#if (LUA_VERSION_NUM == 502)
#if (LUA_VERSION_NUM == 501)
#undef lua_equal
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lp_equal lua_equal
#undef lua_getfenv
#define lua_getfenv lua_getuservalue
#undef lua_setfenv
#define lua_setfenv lua_setuservalue
#define lua_getuservalue lua_getfenv
#define lua_setuservalue lua_setfenv
#undef lua_objlen
#define lua_objlen lua_rawlen
#define lua_rawlen lua_objlen
#undef luaL_register
#define luaL_register(L,n,f) \
{ if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f)
#define luaL_newlib(L,f) luaL_register(L,"lpeg",f)
typedef size_t lua_Unsigned;
#endif
#if !defined(lp_equal)
#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#endif
/* default maximum size for call/backtrack stack */
#if !defined(MAXBACK)
#define MAXBACK 100
#define MAXBACK 400
#endif
/* maximum number of rules in a grammar */
#define MAXRULES 200
/* maximum number of rules in a grammar (limited by 'unsigned short') */
#if !defined(MAXRULES)
#define MAXRULES 1000
#endif
@@ -83,6 +83,8 @@
typedef unsigned char byte;
typedef unsigned int uint;
#define BITSPERCHAR 8
@@ -98,11 +100,11 @@ typedef struct Charset {
#define loopset(v,b) { int v; for (v = 0; v < CHARSETSIZE; v++) {b;} }
/* access to charset */
#define treebuffer(t) ((byte *)((t) + 1))
#define fillset(s,c) memset(s,c,CHARSETSIZE)
#define clearset(s) fillset(s,0)
/* number of slots needed for 'n' bytes */
#define bytes2slots(n) (((n) - 1) / sizeof(TTree) + 1)
#define bytes2slots(n) (((n) - 1u) / (uint)sizeof(TTree) + 1u)
/* set 'b' bit in charset 'cs' */
#define setchar(cs,b) ((cs)[(b) >> 3] |= (1 << ((b) & 7)))
@@ -112,8 +114,8 @@ typedef struct Charset {
** in capture instructions, 'kind' of capture and its offset are
** packed in field 'aux', 4 bits for each
*/
#define getkind(op) ((op)->i.aux & 0xF)
#define getoff(op) (((op)->i.aux >> 4) & 0xF)
#define getkind(op) ((op)->i.aux1 & 0xF)
#define getoff(op) (((op)->i.aux1 >> 4) & 0xF)
#define joinkindoff(k,o) ((k) | ((o) << 4))
#define MAXOFF 0xF
@@ -128,19 +130,20 @@ typedef struct Charset {
#define MAXPATTSIZE (SHRT_MAX - 10)
/* size (in elements) for an instruction plus extra l bytes */
#define instsize(l) (((l) + sizeof(Instruction) - 1)/sizeof(Instruction) + 1)
/* size (in instructions) for l bytes (l > 0) */
#define instsize(l) ((int)(((l) + (uint)sizeof(Instruction) - 1u) \
/ (uint)sizeof(Instruction)))
/* size (in elements) for a ISet instruction */
#define CHARSETINSTSIZE instsize(CHARSETSIZE)
#define CHARSETINSTSIZE (1 + instsize(CHARSETSIZE))
/* size (in elements) for a IFunc instruction */
#define funcinstsize(p) ((p)->i.aux + 2)
#define testchar(st,c) (((int)(st)[((c) >> 3)] & (1 << ((c) & 7))))
#define testchar(st,c) ((((uint)(st)[((c) >> 3)]) >> ((c) & 7)) & 1)
#endif

View File

@@ -1,7 +1,3 @@
/*
** $Id: lpvm.c,v 1.5 2013/04/12 16:29:49 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
#include <limits.h>
#include <string.h>
@@ -18,13 +14,52 @@
/* initial size for call/backtrack stack */
#if !defined(INITBACK)
#define INITBACK 100
#define INITBACK MAXBACK
#endif
#define getoffset(p) (((p) + 1)->offset)
static const Instruction giveup = {{IGiveup, 0, 0}};
static const Instruction giveup = {{IGiveup, 0, {0}}};
int charinset (const Instruction *i, const byte *buff, uint c) {
c -= i->i.aux2.set.offset;
if (c >= ((uint)i->i.aux2.set.size /* size in instructions... */
* (uint)sizeof(Instruction) /* in bytes... */
* 8u)) /* in bits */
return i->i.aux1; /* out of range; return default value */
return testchar(buff, c);
}
/*
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
*/
static const char *utf8_decode (const char *o, int *val) {
static const uint limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFFu};
const unsigned char *s = (const unsigned char *)o;
uint c = s[0]; /* first byte */
uint res = 0; /* final result */
if (c < 0x80) /* ascii? */
res = c;
else {
int count = 0; /* to count number of continuation bytes */
while (c & 0x40) { /* still have continuation bytes? */
int cc = s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
c <<= 1; /* to test next bit */
}
res |= (c & 0x7F) << (count * 5); /* add first byte */
if (count > 3 || res > 0x10FFFFu || res <= limits[count])
return NULL; /* invalid byte sequence */
s += count; /* skip continuation bytes read */
}
*val = res;
return (const char *)s + 1; /* +1 to include first byte */
}
/*
@@ -45,16 +80,38 @@ typedef struct Stack {
/*
** Double the size of the array of captures
** Ensures the size of array 'capture' (with size '*capsize' and
** 'captop' elements being used) is enough to accomodate 'n' extra
** elements plus one. (Because several opcodes add stuff to the capture
** array, it is simpler to ensure the array always has at least one free
** slot upfront and check its size later.)
*/
static Capture *doublecap (lua_State *L, Capture *cap, int captop, int ptop) {
Capture *newc;
if (captop >= INT_MAX/((int)sizeof(Capture) * 2))
luaL_error(L, "too many captures");
newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture));
memcpy(newc, cap, captop * sizeof(Capture));
lua_replace(L, caplistidx(ptop));
return newc;
/* new size in number of elements cannot overflow integers, and new
size in bytes cannot overflow size_t. */
#define MAXNEWSIZE \
(((size_t)INT_MAX) <= (~(size_t)0 / sizeof(Capture)) ? \
((size_t)INT_MAX) : (~(size_t)0 / sizeof(Capture)))
static Capture *growcap (lua_State *L, Capture *capture, int *capsize,
int captop, int n, int ptop) {
if (*capsize - captop > n)
return capture; /* no need to grow array */
else { /* must grow */
Capture *newc;
uint newsize = captop + n + 1; /* minimum size needed */
if (newsize < (MAXNEWSIZE / 3) * 2)
newsize += newsize / 2; /* 1.5 that size, if not too big */
else if (newsize < (MAXNEWSIZE / 9) * 8)
newsize += newsize / 8; /* else, try 9/8 that size */
else
luaL_error(L, "too many captures");
newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture));
memcpy(newc, capture, captop * sizeof(Capture));
*capsize = newsize;
lua_replace(L, caplistidx(ptop));
return newc;
}
}
@@ -70,7 +127,7 @@ static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) {
max = lua_tointeger(L, -1); /* maximum allowed size */
lua_pop(L, 1);
if (n >= max) /* already at maximum size? */
luaL_error(L, "too many pending calls/choices");
luaL_error(L, "backtrack stack overflow (current limit is %d)", max);
newn = 2 * n; /* new size */
if (newn > max) newn = max;
newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack));
@@ -107,24 +164,24 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) {
/*
** Add capture values returned by a dynamic capture to the capture list
** 'base', nested inside a group capture. 'fd' indexes the first capture
** value, 'n' is the number of values (at least 1).
** Add capture values returned by a dynamic capture to the list
** 'capture', nested inside a group. 'fd' indexes the first capture
** value, 'n' is the number of values (at least 1). The open group
** capture is already in 'capture', before the place for the new entries.
*/
static void adddyncaptures (const char *s, Capture *base, int n, int fd) {
static void adddyncaptures (Index_t index, Capture *capture, int n, int fd) {
int i;
/* Cgroup capture is already there */
assert(base[0].kind == Cgroup && base[0].siz == 0);
base[0].idx = 0; /* make it an anonymous group */
for (i = 1; i <= n; i++) { /* add runtime captures */
base[i].kind = Cruntime;
base[i].siz = 1; /* mark it as closed */
base[i].idx = fd + i - 1; /* stack index of capture value */
base[i].s = s;
assert(capture[-1].kind == Cgroup && capture[-1].siz == 0);
capture[-1].idx = 0; /* make group capture an anonymous group */
for (i = 0; i < n; i++) { /* add runtime captures */
capture[i].kind = Cruntime;
capture[i].siz = 1; /* mark it as closed */
capture[i].idx = fd + i; /* stack index of capture value */
capture[i].index = index;
}
base[i].kind = Cclose; /* close group */
base[i].siz = 1;
base[i].s = s;
capture[n].kind = Cclose; /* close group */
capture[n].siz = 1;
capture[n].index = index;
}
@@ -141,6 +198,32 @@ static int removedyncap (lua_State *L, Capture *capture,
}
/*
** Find the corresponding 'open' capture before 'cap', when that capture
** can become a full capture. If a full capture c1 is followed by an
** empty capture c2, there is no way to know whether c2 is inside
** c1. So, full captures can enclose only captures that start *before*
** its end.
*/
static Capture *findopen (Capture *cap, Index_t currindex) {
int i;
cap--; /* check last capture */
/* Must it be inside current one, but starts where current one ends? */
if (!isopencap(cap) && cap->index == currindex)
return NULL; /* current one cannot be a full capture */
/* else, look for an 'open' capture */
for (i = 0; i < MAXLOP; i++, cap--) {
if (currindex - cap->index >= UCHAR_MAX)
return NULL; /* capture too long for a full capture */
else if (isopencap(cap)) /* open capture? */
return cap; /* that's the one to be closed */
else if (cap->kind == Cclose)
return NULL; /* a full capture should not nest a non-full one */
}
return NULL; /* not found within allowed search limit */
}
/*
** Opcode interpreter
*/
@@ -157,17 +240,18 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
lua_pushlightuserdata(L, stackbase);
for (;;) {
#if defined(DEBUG)
printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ",
s, stack - getstackbase(L, ptop), ndyncap, captop);
printinst(op, p);
printf("-------------------------------------\n");
printcaplist(capture, capture + captop);
printf("s: |%s| stck:%d, dyncaps:%d, caps:%d ",
s, (int)(stack - getstackbase(L, ptop)), ndyncap, captop);
printinst(op, p);
#endif
assert(stackidx(ptop) + ndyncap == lua_gettop(L) && ndyncap <= captop);
switch ((Opcode)p->i.code) {
case IEnd: {
assert(stack == getstackbase(L, ptop) + 1);
capture[captop].kind = Cclose;
capture[captop].s = NULL;
capture[captop].index = MAXINDT;
return s;
}
case IGiveup: {
@@ -184,47 +268,58 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
else goto fail;
continue;
}
case IUTFR: {
int codepoint;
if (s >= e)
goto fail;
s = utf8_decode (s, &codepoint);
if (s && p[1].offset <= codepoint && codepoint <= utf_to(p))
p += 2;
else
goto fail;
continue;
}
case ITestAny: {
if (s < e) p += 2;
else p += getoffset(p);
continue;
}
case IChar: {
if ((byte)*s == p->i.aux && s < e) { p++; s++; }
if ((byte)*s == p->i.aux1 && s < e) { p++; s++; }
else goto fail;
continue;
}
case ITestChar: {
if ((byte)*s == p->i.aux && s < e) p += 2;
if ((byte)*s == p->i.aux1 && s < e) p += 2;
else p += getoffset(p);
continue;
}
case ISet: {
int c = (byte)*s;
if (testchar((p+1)->buff, c) && s < e)
{ p += CHARSETINSTSIZE; s++; }
uint c = (byte)*s;
if (charinset(p, (p+1)->buff, c) && s < e)
{ p += 1 + p->i.aux2.set.size; s++; }
else goto fail;
continue;
}
case ITestSet: {
int c = (byte)*s;
if (testchar((p + 2)->buff, c) && s < e)
p += 1 + CHARSETINSTSIZE;
uint c = (byte)*s;
if (charinset(p, (p + 2)->buff, c) && s < e)
p += 2 + p->i.aux2.set.size;
else p += getoffset(p);
continue;
}
case IBehind: {
int n = p->i.aux;
int n = p->i.aux1;
if (n > s - o) goto fail;
s -= n; p++;
continue;
}
case ISpan: {
for (; s < e; s++) {
int c = (byte)*s;
if (!testchar((p+1)->buff, c)) break;
uint c = (byte)*s;
if (!charinset(p, (p+1)->buff, c)) break;
}
p += CHARSETINSTSIZE;
p += 1 + p->i.aux2.set.size;
continue;
}
case IJmp: {
@@ -266,6 +361,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
case IBackCommit: {
assert(stack > getstackbase(L, ptop) && (stack - 1)->s != NULL);
s = (--stack)->s;
if (ndyncap > 0) /* are there matchtime captures? */
ndyncap -= removedyncap(L, capture, stack->caplevel, captop);
captop = stack->caplevel;
p += getoffset(p);
continue;
@@ -273,7 +370,7 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
case IFailTwice:
assert(stack > getstackbase(L, ptop));
stack--;
/* go through */
/* FALLTHROUGH */
case IFail:
fail: { /* pattern failed: try to backtrack */
do { /* remove pending calls */
@@ -284,64 +381,67 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
ndyncap -= removedyncap(L, capture, stack->caplevel, captop);
captop = stack->caplevel;
p = stack->p;
#if defined(DEBUG)
printf("**FAIL**\n");
#endif
continue;
}
case ICloseRunTime: {
CapState cs;
int rem, res, n;
int fr = lua_gettop(L) + 1; /* stack index of first result */
cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop;
cs.reclevel = 0; cs.L = L;
cs.s = o; cs.ocap = capture; cs.ptop = ptop;
n = runtimecap(&cs, capture + captop, s, &rem); /* call function */
captop -= n; /* remove nested captures */
ndyncap -= rem; /* update number of dynamic captures */
fr -= rem; /* 'rem' items were popped from Lua stack */
res = resdyncaptures(L, fr, s - o, e - o); /* get result */
if (res == -1) /* fail? */
goto fail;
s = o + res; /* else update current position */
n = lua_gettop(L) - fr + 1; /* number of new captures */
ndyncap += n - rem; /* update number of dynamic captures */
if (n > 0) { /* any new capture? */
if ((captop += n + 2) >= capsize) {
capture = doublecap(L, capture, captop, ptop);
capsize = 2 * captop;
}
/* add new captures to 'capture' list */
adddyncaptures(s, capture + captop - n - 2, n, fr);
ndyncap += n; /* update number of dynamic captures */
if (n == 0) /* no new captures? */
captop--; /* remove open group */
else { /* new captures; keep original open group */
if (fr + n >= SHRT_MAX)
luaL_error(L, "too many results in match-time capture");
/* add new captures + close group to 'capture' list */
capture = growcap(L, capture, &capsize, captop, n + 1, ptop);
adddyncaptures(s - o, capture + captop, n, fr);
captop += n + 1; /* new captures + close group */
}
p++;
continue;
}
case ICloseCapture: {
const char *s1 = s;
Capture *open = findopen(capture + captop, s - o);
assert(captop > 0);
/* if possible, turn capture into a full capture */
if (capture[captop - 1].siz == 0 &&
s1 - capture[captop - 1].s < UCHAR_MAX) {
capture[captop - 1].siz = s1 - capture[captop - 1].s + 1;
if (open) { /* if possible, turn capture into a full capture */
open->siz = (s - o) - open->index + 1;
p++;
continue;
}
else {
else { /* must create a close capture */
capture[captop].siz = 1; /* mark entry as closed */
capture[captop].s = s;
capture[captop].index = s - o;
goto pushcapture;
}
}
case IOpenCapture:
capture[captop].siz = 0; /* mark entry as open */
capture[captop].s = s;
capture[captop].index = s - o;
goto pushcapture;
case IFullCapture:
capture[captop].siz = getoff(p) + 1; /* save capture size */
capture[captop].s = s - getoff(p);
capture[captop].index = s - o - getoff(p);
/* goto pushcapture; */
pushcapture: {
capture[captop].idx = p->i.key;
capture[captop].idx = p->i.aux2.key;
capture[captop].kind = getkind(p);
if (++captop >= capsize) {
capture = doublecap(L, capture, captop, ptop);
capsize = 2 * captop;
}
captop++;
capture = growcap(L, capture, &capsize, captop, 0, ptop);
p++;
continue;
}

View File

@@ -1,6 +1,3 @@
/*
** $Id: lpvm.h,v 1.2 2013/04/03 20:37:18 roberto Exp $
*/
#if !defined(lpvm_h)
#define lpvm_h
@@ -8,16 +5,24 @@
#include "lpcap.h"
/*
** About Character sets in instructions: a set is a bit map with an
** initial offset, in bits, and a size, in number of instructions.
** aux1 has the default value for the bits outsize that range.
*/
/* Virtual Machine's instructions */
typedef enum Opcode {
IAny, /* if no char, fail */
IChar, /* if char != aux, fail */
ISet, /* if char not in buff, fail */
IChar, /* if char != aux1, fail */
ISet, /* if char not in set, fail */
ITestAny, /* in no char, jump to 'offset' */
ITestChar, /* if char != aux, jump to 'offset' */
ITestSet, /* if char not in buff, jump to 'offset' */
ISpan, /* read a span of chars in buff */
IBehind, /* walk back 'aux' characters (fail if not possible) */
ITestChar, /* if char != aux1, jump to 'offset' */
ITestSet, /* if char not in set, jump to 'offset' */
ISpan, /* read a span of chars in set */
IUTFR, /* if codepoint not in range [offset, utf_to], fail */
IBehind, /* walk back 'aux1' characters (fail if not possible) */
IRet, /* return from a rule */
IEnd, /* end of pattern */
IChoice, /* stack a choice; next fail will jump to 'offset' */
@@ -26,37 +31,48 @@ typedef enum Opcode {
IOpenCall, /* call rule number 'key' (must be closed to a ICall) */
ICommit, /* pop choice and jump to 'offset' */
IPartialCommit, /* update top choice to current position and jump */
IBackCommit, /* "fails" but jump to its own 'offset' */
IBackCommit, /* backtrack like "fail" but jump to its own 'offset' */
IFailTwice, /* pop one choice and then fail */
IFail, /* go back to saved state on choice and jump to saved offset */
IGiveup, /* internal use */
IFullCapture, /* complete capture of last 'off' chars */
IOpenCapture, /* start a capture */
ICloseCapture,
ICloseRunTime
ICloseRunTime,
IEmpty /* to fill empty slots left by optimizations */
} Opcode;
/*
** All array of instructions has a 'codesize' as its first element
** and is referred by a pointer to its second element, which is the
** first actual opcode.
*/
typedef union Instruction {
struct Inst {
byte code;
byte aux;
short key;
byte aux1;
union {
short key;
struct {
byte offset;
byte size;
} set;
} aux2;
} i;
int offset;
uint codesize;
byte buff[1];
} Instruction;
int getposition (lua_State *L, int t, int i);
void printpatt (Instruction *p, int n);
/* extract 24-bit value from an instruction */
#define utf_to(inst) (((inst)->i.aux2.key << 8) | (inst)->i.aux1)
int charinset (const Instruction *i, const byte *buff, uint c);
const char *match (lua_State *L, const char *o, const char *s, const char *e,
Instruction *op, Capture *capture, int ptop);
int verify (lua_State *L, Instruction *op, const Instruction *p,
Instruction *e, int postable, int rule);
void checkrule (lua_State *L, Instruction *op, int from, int to,
int postable, int rule);
#endif

View File

@@ -1,8 +1,8 @@
LIBNAME = lpeg
LUADIR = /usr/include/lua5.1/
LUADIR = ../lua/
COPT = -O2
# COPT = -DLPEG_DEBUG -g
COPT = -O2 -DNDEBUG
# COPT = -O0 -DLPEG_DEBUG -g
CWARNS = -Wall -Wextra -pedantic \
-Waggregate-return \
@@ -11,29 +11,32 @@ CWARNS = -Wall -Wextra -pedantic \
-Wdisabled-optimization \
-Wpointer-arith \
-Wshadow \
-Wredundant-decls \
-Wsign-compare \
-Wundef \
-Wwrite-strings \
-Wbad-function-cast \
-Wdeclaration-after-statement \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wnested-externs \
-Wstrict-prototypes \
-Wc++-compat \
# -Wunreachable-code \
CFLAGS = $(CWARNS) $(COPT) -ansi -I$(LUADIR) -fPIC
CFLAGS = $(CWARNS) $(COPT) -std=c99 -I$(LUADIR) -fPIC
CC = gcc
FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o
FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o lpcset.o
# For Linux
linux:
make lpeg.so "DLLFLAGS = -shared -fPIC"
$(MAKE) lpeg.so "DLLFLAGS = -shared -fPIC"
# For Mac OS
macosx:
make lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup"
$(MAKE) lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup"
lpeg.so: $(FILES)
env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so
@@ -48,8 +51,9 @@ clean:
lpcap.o: lpcap.c lpcap.h lptypes.h
lpcode.o: lpcode.c lptypes.h lpcode.h lptree.h lpvm.h lpcap.h
lpprint.o: lpprint.c lptypes.h lpprint.h lptree.h lpvm.h lpcap.h
lptree.o: lptree.c lptypes.h lpcap.h lpcode.h lptree.h lpvm.h lpprint.h
lpcode.o: lpcode.c lptypes.h lpcode.h lptree.h lpvm.h lpcap.h lpcset.h
lpcset.o: lpcset.c lptypes.h lpcset.h lpcode.h lptree.h lpvm.h lpcap.h
lpprint.o: lpprint.c lptypes.h lpprint.h lptree.h lpvm.h lpcap.h lpcode.h
lptree.o: lptree.c lptypes.h lpcap.h lpcode.h lptree.h lpvm.h lpprint.h \
lpcset.h
lpvm.o: lpvm.c lpcap.h lptypes.h lpvm.h lpprint.h lptree.h

View File

@@ -1,22 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
"//www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>LPeg.re - Regex syntax for LPEG</title>
<link rel="stylesheet"
href="http://www.inf.puc-rio.br/~roberto/lpeg/doc.css"
href="//www.inf.puc-rio.br/~roberto/lpeg/doc.css"
type="text/css"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<!-- $Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $ -->
<div id="container">
<div id="product">
<div id="product_logo">
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/">
<a href="//www.inf.puc-rio.br/~roberto/lpeg/">
<img alt="LPeg logo" src="lpeg-128.gif"/>
</a>
</div>
@@ -62,6 +61,20 @@ Constructions are listed in order of decreasing precedence.
<table border="1">
<tbody><tr><td><b>Syntax</b></td><td><b>Description</b></td></tr>
<tr><td><code>( p )</code></td> <td>grouping</td></tr>
<tr><td><code>&amp; p</code></td> <td>and predicate</td></tr>
<tr><td><code>! p</code></td> <td>not predicate</td></tr>
<tr><td><code>p1 p2</code></td> <td>concatenation</td></tr>
<tr><td><code>p1 / p2</code></td> <td>ordered choice</td></tr>
<tr><td><code>p ?</code></td> <td>optional match</td></tr>
<tr><td><code>p *</code></td> <td>zero or more repetitions</td></tr>
<tr><td><code>p +</code></td> <td>one or more repetitions</td></tr>
<tr><td><code>p^num</code></td>
<td>exactly <code>num</code> repetitions</td></tr>
<tr><td><code>p^+num</code></td>
<td>at least <code>num</code> repetitions</td></tr>
<tr><td><code>p^-num</code></td>
<td>at most <code>num</code> repetitions</td></tr>
<tr><td>(<code>name &lt;- p</code>)<sup>+</sup></td> <td>grammar</td></tr>
<tr><td><code>'string'</code></td> <td>literal string</td></tr>
<tr><td><code>"string"</code></td> <td>literal string</td></tr>
<tr><td><code>[class]</code></td> <td>character class</td></tr>
@@ -70,22 +83,15 @@ Constructions are listed in order of decreasing precedence.
<td>pattern <code>defs[name]</code> or a pre-defined pattern</td></tr>
<tr><td><code>name</code></td><td>non terminal</td></tr>
<tr><td><code>&lt;name&gt;</code></td><td>non terminal</td></tr>
<tr><td><code>{}</code></td> <td>position capture</td></tr>
<tr><td><code>{ p }</code></td> <td>simple capture</td></tr>
<tr><td><code>{: p :}</code></td> <td>anonymous group capture</td></tr>
<tr><td><code>{:name: p :}</code></td> <td>named group capture</td></tr>
<tr><td><code>{~ p ~}</code></td> <td>substitution capture</td></tr>
<tr><td><code>{| p |}</code></td> <td>table capture</td></tr>
<tr><td><code>=name</code></td> <td>back reference
</td></tr>
<tr><td><code>p ?</code></td> <td>optional match</td></tr>
<tr><td><code>p *</code></td> <td>zero or more repetitions</td></tr>
<tr><td><code>p +</code></td> <td>one or more repetitions</td></tr>
<tr><td><code>p^num</code></td> <td>exactly <code>n</code> repetitions</td></tr>
<tr><td><code>p^+num</code></td>
<td>at least <code>n</code> repetitions</td></tr>
<tr><td><code>p^-num</code></td>
<td>at most <code>n</code> repetitions</td></tr>
<tr><td><code>=name</code></td> <td>back reference</td></tr>
<tr><td><code>p -&gt; 'string'</code></td> <td>string capture</td></tr>
<tr><td><code>p -&gt; "string"</code></td> <td>string capture</td></tr>
<tr><td><code>p -&gt; num</code></td> <td>numbered capture</td></tr>
@@ -93,15 +99,14 @@ Constructions are listed in order of decreasing precedence.
equivalent to <code>p / defs[name]</code></td></tr>
<tr><td><code>p =&gt; name</code></td> <td>match-time capture
equivalent to <code>lpeg.Cmt(p, defs[name])</code></td></tr>
<tr><td><code>& p</code></td> <td>and predicate</td></tr>
<tr><td><code>! p</code></td> <td>not predicate</td></tr>
<tr><td><code>p1 p2</code></td> <td>concatenation</td></tr>
<tr><td><code>p1 / p2</code></td> <td>ordered choice</td></tr>
<tr><td>(<code>name &lt;- p</code>)<sup>+</sup></td> <td>grammar</td></tr>
<tr><td><code>p ~&gt; name</code></td> <td>fold capture
(deprecated)</td></tr>
<tr><td><code>p &gt;&gt; name</code></td> <td>accumulator capture
equivalent to <code>(p % defs[name])</code></td></tr>
</tbody></table>
<p>
Any space appearing in a syntax description can be
replaced by zero or more space characters and Lua-style comments
replaced by zero or more space characters and Lua-style short comments
(<code>--</code> until end of line).
</p>
@@ -198,9 +203,10 @@ print(re.match("the number 423 is odd", "({%a+} / .)*"))
--&gt; the number is odd
-- returns the first numeral in a string
print(re.match("the number 423 is odd", "s <- {%d+} / . s"))
print(re.match("the number 423 is odd", "s &lt;- {%d+} / . s"))
--&gt; 423
-- substitutes a dot for each vowel in a string
print(re.gsub("hello World", "[aeiou]", "."))
--&gt; h.ll. W.rld
</pre>
@@ -296,7 +302,7 @@ it would be useful if each table had
a <code>tag</code> field telling what non terminal
that table represents.
We can add such a tag using
<a href="lpeg.html/#cap-g">named group captures</a>:
<a href="lpeg.html#cap-g">named group captures</a>:
</p>
<pre class="example">
x = re.compile[[
@@ -327,7 +333,7 @@ respecting the indentation:
<pre class="example">
p = re.compile[[
block &lt;- {| {:ident:' '*:} line
((=ident !' ' line) / &(=ident ' ') block)* |}
((=ident !' ' line) / &amp;(=ident ' ') block)* |}
line &lt;- {[^%nl]*} %nl
]]
</pre>
@@ -406,7 +412,7 @@ of patterns accepted by <code>re</code>.
p = [=[
pattern &lt;- exp !.
exp &lt;- S (alternative / grammar)
exp &lt;- S (grammar / alternative)
alternative &lt;- seq ('/' S seq)*
seq &lt;- prefix*
@@ -414,6 +420,7 @@ prefix &lt;- '&amp;' S prefix / '!' S prefix / suffix
suffix &lt;- primary S (([+*?]
/ '^' [+-]? num
/ '-&gt;' S (string / '{}' / name)
/ '&gt&gt;' S name
/ '=&gt;' S name) S)*
primary &lt;- '(' exp ')' / string / class / defined
@@ -421,6 +428,7 @@ primary &lt;- '(' exp ')' / string / class / defined
/ '=' name
/ '{}'
/ '{~' exp '~}'
/ '{|' exp '|}'
/ '{' exp '}'
/ '.'
/ name S !arrow
@@ -434,7 +442,7 @@ item &lt;- defined / range / .
range &lt;- . '-' [^]]
S &lt;- (%s / '--' [^%nl]*)* -- spaces and comments
name &lt;- [A-Za-z][A-Za-z0-9_]*
name &lt;- [A-Za-z_][A-Za-z0-9_]*
arrow &lt;- '&lt;-'
num &lt;- [0-9]+
string &lt;- '"' [^"]* '"' / "'" [^']* "'"
@@ -450,48 +458,14 @@ print(re.match(p, p)) -- a self description must match itself
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2008-2010 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and
associated documentation files (the "Software"),
to deal in the Software without restriction,
including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software,
and to permit persons to whom the Software is
furnished to do so,
subject to the following conditions:
</p>
This module is part of the <a href="lpeg.html">LPeg</a> package and shares
its <a href="lpeg.html#license">license</a>.
<p>
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</p>
</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<p><small>
$Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $
</small></p>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -1,4 +1,7 @@
-- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $
--
-- Copyright 2007-2023, Lua.org & PUC-Rio (see 'lpeg.html' for license)
-- written by Roberto Ierusalimschy
--
-- imported functions and modules
local tonumber, type, print, error = tonumber, type, print, error
@@ -10,14 +13,14 @@ local m = require"lpeg"
-- on 'mm'
local mm = m
-- pattern's metatable
-- patterns' metatable
local mt = getmetatable(mm.P(0))
local version = _VERSION
-- No more global accesses after this point
local version = _VERSION
if version == "Lua 5.2" then _ENV = nil end
_ENV = nil -- does no harm in Lua 5.1
local any = m.P(1)
@@ -71,13 +74,6 @@ updatelocale()
local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
local function getdef (id, defs)
local c = defs and defs[id]
if not c then error("undefined name: " .. id) end
return c
end
local function patt_error (s, i)
local msg = (#s < i + 20) and s:sub(i)
or s:sub(i,i+20) .. "..."
@@ -116,6 +112,20 @@ name = m.C(name)
-- a defined name only have meaning in a given environment
local Def = name * m.Carg(1)
local function getdef (id, defs)
local c = defs and defs[id]
if not c then error("undefined name: " .. id) end
return c
end
-- match a name and return a group of its corresponding definition
-- and 'f' (to be folded in 'Suffix')
local function defwithfunc (f)
return m.Cg(Def / getdef * m.Cc(f))
end
local num = m.C(m.R"09"^1) * S / tonumber
local String = "'" * m.C((any - "'")^0) * "'" +
@@ -130,12 +140,12 @@ end
local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
local item = defined + Range + m.C(any)
local item = (defined + Range + m.C(any)) / m.P
local Class =
"["
* (m.C(m.P"^"^-1)) -- optional complement symbol
* m.Cf(item * (item - "]")^0, mt.__add) /
* (item * ((item % mt.__add) - "]")^0) /
function (c, p) return c == "^" and any - p or p end
* "]"
@@ -161,13 +171,13 @@ end
local exp = m.P{ "Exp",
Exp = S * ( m.V"Grammar"
+ m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) );
Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul)
+ m.V"Seq" * ("/" * S * m.V"Seq" % mt.__add)^0 );
Seq = (m.Cc(m.P"") * (m.V"Prefix" % mt.__mul)^0)
* (#seq_follow + patt_error);
Prefix = "&" * S * m.V"Prefix" / mt.__len
+ "!" * S * m.V"Prefix" / mt.__unm
+ m.V"Suffix";
Suffix = m.Cf(m.V"Primary" * S *
Suffix = m.V"Primary" * S *
( ( m.P"+" * m.Cc(1, mt.__pow)
+ m.P"*" * m.Cc(0, mt.__pow)
+ m.P"?" * m.Cc(-1, mt.__pow)
@@ -176,11 +186,13 @@ local exp = m.P{ "Exp",
)
+ "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div))
+ m.P"{}" * m.Cc(nil, m.Ct)
+ m.Cg(Def / getdef * m.Cc(mt.__div))
+ defwithfunc(mt.__div)
)
+ "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt))
) * S
)^0, function (a,b,f) return f(a,b) end );
+ "=>" * S * defwithfunc(mm.Cmt)
+ ">>" * S * defwithfunc(mt.__mod)
+ "~>" * S * defwithfunc(mm.Cf)
) % function (a,b,f) return f(a,b) end * S
)^0;
Primary = "(" * m.V"Exp" * ")"
+ String / mm.P
+ Class
@@ -196,8 +208,7 @@ local exp = m.P{ "Exp",
+ (name * -arrow + "<" * name * ">") * m.Cb("G") / NT;
Definition = name * arrow * m.V"Exp";
Grammar = m.Cg(m.Cc(true), "G") *
m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0,
adddef) / mm.P
((m.V"Definition" / firstdef) * (m.V"Definition" % adddef)^0) / mm.P
}
local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error)

View File

@@ -1,6 +1,4 @@
#!/usr/bin/env lua5.1
-- $Id: test.lua,v 1.101 2013/04/12 16:30:33 roberto Exp $
#!/usr/bin/env lua
-- require"strict" -- just to be pedantic
@@ -16,9 +14,6 @@ local unpack = rawget(table, "unpack") or unpack
local loadstring = rawget(_G, "loadstring") or load
-- most tests here do not need much stack space
m.setmaxstack(5)
local any = m.P(1)
local space = m.S" \t\n"^0
@@ -51,8 +46,8 @@ end
print"General tests for LPeg library"
assert(type(m.version()) == "string")
print("version " .. m.version())
assert(type(m.version) == "string")
print(m.version)
assert(m.type("alo") ~= "pattern")
assert(m.type(io.input) ~= "pattern")
assert(m.type(m.P"alo") == "pattern")
@@ -73,6 +68,8 @@ assert(m.match(#m.P(true) * "a", "a") == 2)
assert(m.match("a" * #m.P(false), "a") == nil)
assert(m.match("a" * #m.P(true), "a") == 2)
assert(m.match(m.P(1)^0, "abcd") == 5)
assert(m.match(m.S("")^0, "abcd") == 1)
-- tests for locale
do
@@ -122,6 +119,8 @@ eqcharset(m.S"\1\0\2", m.R"\0\2")
eqcharset(m.S"\1\0\2", m.R"\1\2" + "\0")
eqcharset(m.S"\1\0\2" - "\0", m.R"\1\2")
eqcharset(m.S("\0\255"), m.P"\0" + "\255") -- charset extremes
local word = alpha^1 * (1 - alpha)^0
assert((word^0 * -1):match"alo alo")
@@ -170,8 +169,8 @@ assert(m.match( basiclookfor((#m.P(b) * 1) * m.Cp()), " ( (a)") == 7)
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "123")}
checkeq(a, {"123", "d"})
a = {m.match(m.C(digit^1) * "d" * -1 + m.C(letter^1 * m.Cc"l"), "123d")}
checkeq(a, {"123"})
-- bug in LPeg 0.12 (nil value does not create a 'ktable')
assert(m.match(m.Cc(nil), "") == nil)
a = {m.match(m.C(digit^1 * m.Cc"d") + m.C(letter^1 * m.Cc"l"), "abcd")}
checkeq(a, {"abcd", "l"})
@@ -194,6 +193,24 @@ checkeq(a, {1, 5})
t = {m.match({[1] = m.C(m.C(1) * m.V(1) + -1)}, "abc")}
checkeq(t, {"abc", "a", "bc", "b", "c", "c", ""})
-- bug in 0.12 ('hascapture' did not check for captures inside a rule)
do
local pat = m.P{
'S';
S1 = m.C('abc') + 3,
S = #m.V('S1') -- rule has capture, but '#' must ignore it
}
assert(pat:match'abc' == 1)
end
-- bug: loop in 'hascaptures'
do
local p = m.C(-m.P{m.P'x' * m.V(1) + m.P'y'})
assert(p:match("xxx") == "")
end
-- test for small capture boundary
for i = 250,260 do
@@ -201,9 +218,8 @@ for i = 250,260 do
assert(#m.match(m.C(m.C(i)), string.rep('a', i)) == i)
end
-- tests for any*n and any*-n
for n = 1, 550 do
for n = 1, 550, 13 do
local x_1 = string.rep('x', n - 1)
local x = x_1 .. 'a'
assert(not m.P(n):match(x_1))
@@ -282,6 +298,13 @@ assert(m.match(m.P"ab"^-1 - "c", "abcd") == 3)
p = ('Aa' * ('Bb' * ('Cc' * m.P'Dd'^0)^0)^0)^-1
assert(p:match("AaBbCcDdBbCcDdDdDdBb") == 21)
-- bug in 0.12.2
-- p = { ('ab' ('c' 'ef'?)*)? }
p = m.C(('ab' * ('c' * m.P'ef'^-1)^0)^-1)
s = "abcefccefc"
assert(s == p:match(s))
pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510"
@@ -343,10 +366,16 @@ checkeq(t, {hi = 10, ho = 20})
t = p:match'abc'
checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'})
-- non-string group names
p = m.Ct(m.Cg(1, print) * m.Cg(1, 23.5) * m.Cg(1, io))
t = p:match('abcdefghij')
assert(t[print] == 'a' and t[23.5] == 'b' and t[io] == 'c')
-- test for error messages
local function checkerr (msg, ...)
assert(m.match({ m.P(msg) + 1 * m.V(1) }, select(2, pcall(...))))
local function checkerr (msg, f, ...)
local st, err = pcall(f, ...)
assert(not st and m.match({ m.P(msg) + 1 * m.V(1) }, err))
end
checkerr("rule '1' may be left recursive", m.match, { m.V(1) * 'a' }, "a")
@@ -370,6 +399,42 @@ p = {'a',
}
checkerr("rule 'a' may be left recursive", m.match, p, "a")
-- Bug in peephole optimization of LPeg 0.12 (IJmp -> ICommit)
-- the next grammar has an original sequence IJmp -> ICommit -> IJmp L1
-- that is optimized to ICommit L1
p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' }
assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc')
do
print "testing large dynamic Cc"
local lim = 2^16 - 1
local c = 0
local function seq (n)
if n == 1 then c = c + 1; return m.Cc(c)
else
local m = math.floor(n / 2)
return seq(m) * seq(n - m)
end
end
p = m.Ct(seq(lim))
t = p:match('')
assert(t[lim] == lim)
checkerr("too many", function () p = p / print end)
checkerr("too many", seq, lim + 1)
end
do
-- nesting of captures too deep
local p = m.C(1)
for i = 1, 300 do
p = m.Ct(p)
end
checkerr("too deep", p.match, p, "x")
end
-- tests for non-pattern as arguments to pattern functions
@@ -428,8 +493,8 @@ local function f_term (v1, op, v2, d)
end
G = m.P{ "Exp",
Exp = m.Cf(V"Factor" * m.Cg(FactorOp * V"Factor")^0, f_factor);
Factor = m.Cf(V"Term" * m.Cg(TermOp * V"Term")^0, f_term);
Exp = V"Factor" * (FactorOp * V"Factor" % f_factor)^0;
Factor = V"Term" * (TermOp * V"Term" % f_term)^0;
Term = Number / tonumber + Open * V"Exp" * Close;
}
@@ -472,6 +537,27 @@ assert(m.match(m.Cs((#((#m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
assert(m.match(m.Cs((- -m.P("a") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
assert(m.match(m.Cs((-((-m.P"a")/"") * 1 + m.P(1)/".")^0), "aloal") == "a..a.")
-- fixed length
do
-- 'and' predicate using fixed length
local p = m.C(#("a" * (m.P("bd") + "cd")) * 2)
assert(p:match("acd") == "ac")
p = #m.P{ "a" * m.V(2), m.P"b" } * 2
assert(p:match("abc") == 3)
p = #(m.P"abc" * m.B"c")
assert(p:match("abc") == 1 and not p:match("ab"))
p = m.P{ "a" * m.V(2), m.P"b"^1 }
checkerr("pattern may not have fixed length", m.B, p)
p = "abc" * (m.P"b"^1 + m.P"a"^0)
checkerr("pattern may not have fixed length", m.B, p)
end
p = -m.P'a' * m.Cc(1) + -m.P'b' * m.Cc(2) + -m.P'c' * m.Cc(3)
assert(p:match('a') == 2 and p:match('') == 1 and p:match('b') == 1)
@@ -488,7 +574,10 @@ assert(m.match(1 * m.B(1), 'a') == 2)
assert(m.match(-m.B(1), 'a') == 1)
assert(m.match(m.B(250), string.rep('a', 250)) == nil)
assert(m.match(250 * m.B(250), string.rep('a', 250)) == 251)
assert(not pcall(m.B, 260))
-- look-behind with an open call
checkerr("pattern may not have fixed length", m.B, m.V'S1')
checkerr("too long to look behind", m.B, 260)
B = #letter * -m.B(letter) + -letter * m.B(letter)
x = m.Ct({ (B * m.Cp())^-1 * (1 * m.V(1) + m.P(true)) })
@@ -555,18 +644,18 @@ assert(not p:match(string.rep("011", 10001)))
-- this grammar does need backtracking info.
local lim = 10000
p = m.P{ '0' * m.V(1) + '0' }
assert(not pcall(m.match, p, string.rep("0", lim)))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim)
assert(not pcall(m.match, p, string.rep("0", lim)))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim + 4)
assert(pcall(m.match, p, string.rep("0", lim)))
assert(m.match(p, string.rep("0", lim)) == lim + 1)
-- this repetition should not need stack space (only the call does)
p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' }
m.setmaxstack(200)
assert(p:match(string.rep('a', 180) .. 'c' .. string.rep('b', 180)) == 362)
m.setmaxstack(5) -- restore original limit
m.setmaxstack(100) -- restore low limit
-- tests for optional start position
assert(m.match("a", "abc", 1))
@@ -588,10 +677,10 @@ print("+")
-- tests for argument captures
assert(not pcall(m.Carg, 0))
assert(not pcall(m.Carg, -1))
assert(not pcall(m.Carg, 2^18))
assert(not pcall(m.match, m.Carg(1), 'a', 1))
checkerr("invalid argument", m.Carg, 0)
checkerr("invalid argument", m.Carg, -1)
checkerr("invalid argument", m.Carg, 2^18)
checkerr("absent extra argument #1", m.match, m.Carg(1), 'a', 1)
assert(m.match(m.Carg(1), 'a', 1, print) == print)
x = {m.match(m.Carg(1) * m.Carg(2), '', 1, 10, 20)}
checkeq(x, {10, 20})
@@ -644,14 +733,16 @@ assert(m.match(p, "aaaa") == 5)
assert(m.match(p, "abaa") == 2)
assert(not m.match(p, "baaa"))
assert(not pcall(m.match, function () return 2^20 end, s))
assert(not pcall(m.match, function () return 0 end, s))
assert(not pcall(m.match, function (s, i) return i - 1 end, s))
assert(not pcall(m.match, m.P(1)^0 * function (_, i) return i - 1 end, s))
checkerr("invalid position", m.match, function () return 2^20 end, s)
checkerr("invalid position", m.match, function () return 0 end, s)
checkerr("invalid position", m.match, function (s, i) return i - 1 end, s)
checkerr("invalid position", m.match,
m.P(1)^0 * function (_, i) return i - 1 end, s)
assert(m.match(m.P(1)^0 * function (_, i) return i end * -1, s))
assert(not pcall(m.match, m.P(1)^0 * function (_, i) return i + 1 end, s))
checkerr("invalid position", m.match,
m.P(1)^0 * function (_, i) return i + 1 end, s)
assert(m.match(m.P(function (s, i) return s:len() + 1 end) * -1, s))
assert(not pcall(m.match, m.P(function (s, i) return s:len() + 2 end) * -1, s))
checkerr("invalid position", m.match, m.P(function (s, i) return s:len() + 2 end) * -1, s)
assert(not m.match(m.P(function (s, i) return s:len() end) * -1, s))
assert(m.match(m.P(1)^0 * function (_, i) return true end, s) ==
string.len(s) + 1)
@@ -696,6 +787,10 @@ t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")}
t1 = {1,1,nil,nil,4,nil,3,nil,nil}
for i=1,10 do assert(t[i] == t1[i]) end
-- bug in 0.12.2: ktable with only nil could be eliminated when joining
-- with a pattern without ktable
assert((m.P"aaa" * m.Cc(nil)):match"aaa" == nil)
t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")}
checkeq(t, {"a", "ax", "b", "bx", "c", "cx"})
@@ -734,9 +829,9 @@ assert(m.match(m.Cs((m.P(1) / ".xx")^0), "abcd") == ".xx.xx.xx.xx")
assert(m.match(m.Cp() * m.P(3) * m.Cp()/"%2%1%1 - %0 ", "abcde") ==
"411 - abc ")
assert(pcall(m.match, m.P(1)/"%0", "abc"))
assert(not pcall(m.match, m.P(1)/"%1", "abc")) -- out of range
assert(not pcall(m.match, m.P(1)/"%9", "abc")) -- out of range
assert(m.match(m.P(1)/"%0", "abc") == "a")
checkerr("invalid capture index", m.match, m.P(1)/"%1", "abc")
checkerr("invalid capture index", m.match, m.P(1)/"%9", "abc")
p = m.C(1)
p = p * p; p = p * p; p = p * p * m.C(1) / "%9 - %1"
@@ -754,7 +849,7 @@ assert(m.match(m.C(1)^0 / "%9-%1-%0-%3", s) == "9-1-" .. s .. "-3")
p = m.Cc('alo') * m.C(1) / "%1 - %2 - %1"
assert(p:match'x' == 'alo - x - alo')
assert(not pcall(m.match, m.Cc(true) / "%1", "a"))
checkerr("invalid capture value (a boolean)", m.match, m.Cc(true) / "%1", "a")
-- long strings for string capture
l = 10000
@@ -771,6 +866,7 @@ print"+"
-- accumulator capture
function f (x) return x + 1 end
assert(m.match(m.Cf(m.Cc(0) * m.C(1)^0, f), "alo alo") == 7)
assert(m.match(m.Cc(0) * (m.C(1) % f)^0, "alo alo") == 7)
t = {m.match(m.Cf(m.Cc(1,2,3), error), "")}
checkeq(t, {1})
@@ -780,37 +876,45 @@ t = p:match("a=b;c=du;xux=yuy;")
checkeq(t, {a="b", c="du", xux="yuy"})
-- errors in fold capture
-- no initial capture
checkerr("no initial value", m.match, m.Cf(m.P(5), print), 'aaaaaa')
-- no initial capture (very long match forces fold to be a pair open-close)
checkerr("no initial value", m.match, m.Cf(m.P(500), print),
string.rep('a', 600))
-- errors in accumulator capture
-- very long match (forces fold to be a pair open-close) producing with
-- no initial capture
assert(not pcall(m.match, m.Cf(m.P(500), print), string.rep('a', 600)))
-- nested capture produces no initial value
assert(not pcall(m.match, m.Cf(m.P(1) / {}, print), "alo"))
checkerr("no previous value", m.match, m.P(5) % print, 'aaaaaa')
-- no initial capture (very long match forces fold to be a pair open-close)
checkerr("no previous value", m.match, m.P(500) % print,
string.rep('a', 600))
-- tests for loop checker
local function haveloop (p)
assert(not pcall(function (p) return p^0 end, m.P(p)))
local function isnullable (p)
checkerr("may accept empty string", function (p) return p^0 end, m.P(p))
end
haveloop(m.P("x")^-4)
isnullable(m.P("x")^-4)
assert(m.match(((m.P(0) + 1) * m.S"al")^0, "alo") == 3)
assert(m.match((("x" + #m.P(1))^-4 * m.S"al")^0, "alo") == 3)
haveloop("")
haveloop(m.P("x")^0)
haveloop(m.P("x")^-1)
haveloop(m.P("x") + 1 + 2 + m.P("a")^-1)
haveloop(-m.P("ab"))
haveloop(- -m.P("ab"))
haveloop(# #(m.P("ab") + "xy"))
haveloop(- #m.P("ab")^0)
haveloop(# -m.P("ab")^1)
haveloop(#m.V(3))
haveloop(m.V(3) + m.V(1) + m.P('a')^-1)
haveloop({[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(0)})
isnullable("")
isnullable(m.P("x")^0)
isnullable(m.P("x")^-1)
isnullable(m.P("x") + 1 + 2 + m.P("a")^-1)
isnullable(-m.P("ab"))
isnullable(- -m.P("ab"))
isnullable(# #(m.P("ab") + "xy"))
isnullable(- #m.P("ab")^0)
isnullable(# -m.P("ab")^1)
isnullable(#m.V(3))
isnullable(m.V(3) + m.V(1) + m.P('a')^-1)
isnullable({[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(0)})
assert(m.match(m.P{[1] = m.V(2) * m.V(3), [2] = m.V(3), [3] = m.P(1)}^0, "abc")
== 3)
assert(m.match(m.P""^-3, "a") == 1)
@@ -890,18 +994,54 @@ for i = 1, 10 do
assert(p:match("aaaaaaaaaaa") == 11 - i + 1)
end
print"+"
-- tests for back references
assert(not pcall(m.match, m.Cb('x'), ''))
assert(not pcall(m.match, m.Cg(1, 'a') * m.Cb('b'), 'a'))
print "testing back references"
checkerr("back reference 'x' not found", m.match, m.Cb('x'), '')
checkerr("back reference 'b' not found", m.match, m.Cg(1, 'a') * m.Cb('b'), 'a')
p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k"))
t = p:match("ab")
checkeq(t, {"a", "b"})
do
-- some basic cases
assert(m.match(m.Cg(m.Cc(3), "a") * m.Cb("a"), "a") == 3)
assert(m.match(m.Cg(m.C(1), 133) * m.Cb(133), "X") == "X")
-- first reference to 'x' should not see the group enclosing it
local p = m.Cg(m.Cb('x'), 'x') * m.Cb('x')
checkerr("back reference 'x' not found", m.match, p, '')
local p = m.Cg(m.Cb('x') * m.C(1), 'x') * m.Cb('x')
checkerr("back reference 'x' not found", m.match, p, 'abc')
-- reference to 'x' should not see the group enclosed in another capture
local s = string.rep("a", 30)
local p = (m.C(1)^-4 * m.Cg(m.C(1), 'x')) / {} * m.Cb('x')
checkerr("back reference 'x' not found", m.match, p, s)
local p = (m.C(1)^-20 * m.Cg(m.C(1), 'x')) / {} * m.Cb('x')
checkerr("back reference 'x' not found", m.match, p, s)
-- second reference 'k' should refer to 10 and first ref. 'k'
p = m.Cg(m.Cc(20), 'k') * m.Cg(m.Cc(10) * m.Cb('k') * m.C(1), 'k')
* (m.Cb('k') / function (a,b,c) return a*10 + b + tonumber(c) end)
-- 10 * 10 (Cc) + 20 (Cb) + 7 (C) == 127
assert(p:match("756") == 127)
end
p = m.P(true)
for i = 1, 10 do p = p * m.Cg(1, i) end
for i = 1, 10 do
local p = p * m.Cb(i)
assert(p:match('abcdefghij') == string.sub('abcdefghij', i, i))
end
t = {}
function foo (p) t[#t + 1] = p; return p .. "x" end
@@ -930,6 +1070,17 @@ local function id (s, i, ...)
return true, ...
end
do -- run-time capture in an end predicate (should discard its value)
local x = 0
function foo (s, i)
x = x + 1
return true, x
end
local p = #(m.Cmt("", foo) * "xx") * m.Cmt("", foo)
assert(p:match("xx") == 2)
end
assert(m.Cmt(m.Cs((m.Cmt(m.S'abc' / { a = 'x', c = 'y' }, id) +
m.R'09'^1 / string.char +
m.P(1))^0), id):match"acb98+68c" == "xyb\98+\68y")
@@ -1035,6 +1186,32 @@ do
assert(c == 11)
end
-- Return a match-time capture that returns 'n' captures
local function manyCmt (n)
return m.Cmt("a", function ()
local a = {}; for i = 1, n do a[i] = n - i end
return true, unpack(a)
end)
end
-- bug in 1.0: failed match-time that used previous match-time results
do
local x
local function aux (...) x = #{...}; return false end
local res = {m.match(m.Cmt(manyCmt(20), aux) + manyCmt(10), "a")}
assert(#res == 10 and res[1] == 9 and res[10] == 0)
end
-- bug in 1.0: problems with math-times returning too many captures
if _VERSION >= "Lua 5.2" then
local lim = 2^11 - 10
local res = {m.match(manyCmt(lim), "a")}
assert(#res == lim and res[1] == lim - 1 and res[lim] == 0)
checkerr("too many", m.match, manyCmt(2^15), "a")
end
p = (m.P(function () return true, "a" end) * 'a'
+ m.P(function (s, i) return i, "aa", 20 end) * 'b'
+ m.P(function (s,i) if i <= #s then return i, "aaa" end end) * 1)^0
@@ -1043,9 +1220,91 @@ t = {p:match('abacc')}
checkeq(t, {'a', 'aa', 20, 'a', 'aaa', 'aaa'})
do print"testing large grammars"
local lim = 1000 -- number of rules
local t = {}
for i = 3, lim do
t[i] = m.V(i - 1) -- each rule calls previous one
end
t[1] = m.V(lim) -- start on last rule
t[2] = m.C("alo") -- final rule
local P = m.P(t) -- build grammar
assert(P:match("alo") == "alo")
t[#t + 1] = m.P("x") -- one more rule...
checkerr("too many rules", m.P, t)
end
print "testing UTF-8 ranges"
do -- a few typical UTF-8 ranges
local p = m.utfR(0x410, 0x44f)^1 / "cyr: %0"
+ m.utfR(0x4e00, 0x9fff)^1 / "cjk: %0"
+ m.utfR(0x1F600, 0x1F64F)^1 / "emot: %0"
+ m.utfR(0, 0x7f)^1 / "ascii: %0"
+ m.utfR(0, 0x10ffff) / "other: %0"
p = m.Ct(p^0) * -m.P(1)
local cyr = "ждюя"
local emot = "\240\159\152\128\240\159\153\128" -- 😀🙀
local cjk = "专举乸"
local ascii = "alo"
local last = "\244\143\191\191" -- U+10FFFF
local s = cyr .. "" .. emot .. "" .. cjk .. "" .. ascii .. last
t = (p:match(s))
assert(t[1] == "cyr: " .. cyr and t[2] == "other: —" and
t[3] == "emot: " .. emot and t[4] == "other: —" and
t[5] == "cjk: " .. cjk and t[6] == "other: —" and
t[7] == "ascii: " .. ascii and t[8] == "other: " .. last and
t[9] == nil)
-- failing UTF-8 matches and borders
assert(not m.match(m.utfR(10, 0x2000), "\9"))
assert(not m.match(m.utfR(10, 0x2000), "\226\128\129"))
assert(m.match(m.utfR(10, 0x2000), "\10") == 2)
assert(m.match(m.utfR(10, 0x2000), "\226\128\128") == 4)
end
do -- valid and invalid code points
local p = m.utfR(0, 0x10ffff)^0
assert(p:match("汉字\128") == #"汉字" + 1)
assert(p:match("\244\159\191") == 1)
assert(p:match("\244\159\191\191") == 1)
assert(p:match("\255") == 1)
-- basic errors
checkerr("empty range", m.utfR, 1, 0)
checkerr("invalid code point", m.utfR, 1, 0x10ffff + 1)
end
do -- back references (fixed width)
-- match a byte after a CJK point
local p = m.B(m.utfR(0x4e00, 0x9fff)) * m.C(1)
p = m.P{ p + m.P(1) * m.V(1) } -- search for 'p'
assert(p:match("ab д 专X x") == "X")
-- match a byte after a hebrew point
local p = m.B(m.utfR(0x5d0, 0x5ea)) * m.C(1)
p = m.P(#"ש") * p
assert(p:match("שX") == "X")
checkerr("fixed length", m.B, m.utfR(0, 0x10ffff))
end
-------------------------------------------------------------------
-- Tests for 're' module
-------------------------------------------------------------------
print"testing 're' module"
local re = require "re"
@@ -1068,6 +1327,9 @@ assert(not match("abbcde", " [b-z] + "))
assert(match("abb\"de", '"abb"["]"de"') == 7)
assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee")
assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8)
assert(re.match("aaand", "[a]^2") == 3)
local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")}
checkeq(t, {4, 5, 7})
local t = {match("abceefe", "((&&'e' {})? .)*")}
@@ -1176,6 +1438,12 @@ e = compile([[
e = compile("{[0-9]+'.'?[0-9]*} -> sin", math)
assert(e:match("2.34") == math.sin(2.34))
e = compile("'pi' -> math", _G)
assert(e:match("pi") == math.pi)
e = compile("[ ]* 'version' -> _VERSION", _G)
assert(e:match(" version") == _VERSION)
function eq (_, _, a, b) return a == b end
@@ -1242,6 +1510,20 @@ checkeq(x, {tag='x', 'hi', {tag = 'b', 'hello'}, 'but',
{'totheend'}})
-- test for folding captures
c = re.compile([[
S <- (number (%s+ number)*) ~> add
number <- %d+ -> tonumber
]], {tonumber = tonumber, add = function (a,b) return a + b end})
assert(c:match("3 401 50") == 3 + 401 + 50)
-- test for accumulator captures
c = re.compile([[
S <- number (%s+ number >> add)*
number <- %d+ -> tonumber
]], {tonumber = tonumber, add = function (a,b) return a + b end})
assert(c:match("3 401 50") == 3 + 401 + 50)
-- tests for look-ahead captures
x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")}
checkeq(x, {"", "alo", ""})
@@ -1370,8 +1652,7 @@ assert(rev:match"0123456789" == "9876543210")
-- testing error messages in re
local function errmsg (p, err)
local s, msg = pcall(re.compile, p)
assert(not s and string.find(msg, err))
checkerr(err, re.compile, p)
end
errmsg('aaaa', "rule 'aaaa'")

View File

@@ -1,6 +0,0 @@
install :
gcc -g -Wall -fPIC --shared -o int64.so int64.c
clean :
rm int64.so

View File

@@ -1,2 +0,0 @@
See https://github.com/cloudwu/lua-int64
It will remove when Lua upgrade to 5.3 .

View File

@@ -1,317 +0,0 @@
#include <lua.h>
#include <lauxlib.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
static int64_t
_int64(lua_State *L, int index) {
int type = lua_type(L,index);
int64_t n = 0;
switch(type) {
case LUA_TNUMBER: {
lua_Number d = lua_tonumber(L,index);
n = (int64_t)d;
break;
}
case LUA_TSTRING: {
size_t len = 0;
const uint8_t * str = (const uint8_t *)lua_tolstring(L, index, &len);
if (len>8) {
return luaL_error(L, "The string (length = %d) is not an int64 string", len);
}
int i = 0;
uint64_t n64 = 0;
for (i=0;i<(int)len;i++) {
n64 |= (uint64_t)str[i] << (i*8);
}
n = (int64_t)n64;
break;
}
case LUA_TLIGHTUSERDATA: {
void * p = lua_touserdata(L,index);
n = (intptr_t)p;
break;
}
default:
return luaL_error(L, "argument %d error type %s", index, lua_typename(L,type));
}
return n;
}
static inline void
_pushint64(lua_State *L, int64_t n) {
void * p = (void *)(intptr_t)n;
lua_pushlightuserdata(L,p);
}
static int
int64_add(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
_pushint64(L, a+b);
return 1;
}
static int
int64_sub(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
_pushint64(L, a-b);
return 1;
}
static int
int64_mul(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
_pushint64(L, a * b);
return 1;
}
static int
int64_div(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
if (b == 0) {
return luaL_error(L, "div by zero");
}
_pushint64(L, a / b);
return 1;
}
static int
int64_mod(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
if (b == 0) {
return luaL_error(L, "mod by zero");
}
_pushint64(L, a % b);
return 1;
}
static int64_t
_pow64(int64_t a, int64_t b) {
if (b == 1) {
return a;
}
int64_t a2 = a * a;
if (b % 2 == 1) {
return _pow64(a2, b/2) * a;
} else {
return _pow64(a2, b/2);
}
}
static int
int64_pow(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
int64_t p;
if (b > 0) {
p = _pow64(a,b);
} else if (b == 0) {
p = 1;
} else {
return luaL_error(L, "pow by nagtive number %d",(int)b);
}
_pushint64(L, p);
return 1;
}
static int
int64_unm(lua_State *L) {
int64_t a = _int64(L,1);
_pushint64(L, -a);
return 1;
}
static int
int64_new(lua_State *L) {
int top = lua_gettop(L);
int64_t n;
switch(top) {
case 0 :
lua_pushlightuserdata(L,NULL);
break;
case 1 :
n = _int64(L,1);
_pushint64(L,n);
break;
default: {
int base = luaL_checkinteger(L,2);
if (base < 2) {
luaL_error(L, "base must be >= 2");
}
const char * str = luaL_checkstring(L, 1);
n = strtoll(str, NULL, base);
_pushint64(L,n);
break;
}
}
return 1;
}
static int
int64_eq(lua_State *L) {
// __eq metamethod can't be invoke by lightuserdata
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
lua_pushboolean(L,a == b);
return 1;
}
static int
int64_lt(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
lua_pushboolean(L,a < b);
return 1;
}
static int
int64_le(lua_State *L) {
int64_t a = _int64(L,1);
int64_t b = _int64(L,2);
lua_pushboolean(L,a <= b);
return 1;
}
static int
int64_len(lua_State *L) {
int64_t a = _int64(L,1);
lua_pushnumber(L,(lua_Number)a);
return 1;
}
static int
tostring(lua_State *L) {
static char hex[16] = "0123456789ABCDEF";
uintptr_t n = (uintptr_t)lua_touserdata(L,1);
if (lua_gettop(L) == 1) {
luaL_Buffer b;
luaL_buffinit(L , &b);
luaL_addstring(&b, "int64: 0x");
int i;
bool strip = true;
for (i=15;i>=0;i--) {
int c = (n >> (i*4)) & 0xf;
if (strip && c ==0) {
continue;
}
strip = false;
luaL_addchar(&b, hex[c]);
}
if (strip) {
luaL_addchar(&b , '0');
}
luaL_pushresult(&b);
} else {
int base = luaL_checkinteger(L,2);
int shift =0, mask =0;
switch(base) {
case 0: {
unsigned char buffer[8];
int i;
for (i=0;i<8;i++) {
buffer[i] = (n >> (i*8)) & 0xff;
}
lua_pushlstring(L,(const char *)buffer, 8);
return 1;
}
case 10: {
int64_t dec = (int64_t)n;
luaL_Buffer b;
luaL_buffinit(L , &b);
if (dec<0) {
luaL_addchar(&b, '-');
dec = -dec;
}
int buffer[32];
int i;
for (i=0;i<32;i++) {
buffer[i] = dec%10;
dec /= 10;
if (dec == 0)
break;
}
while (i>=0) {
luaL_addchar(&b, hex[buffer[i]]);
--i;
}
luaL_pushresult(&b);
return 1;
}
case 2:
shift = 1;
mask = 1;
break;
case 8:
shift = 3;
mask = 7;
break;
case 16:
shift = 4;
mask = 0xf;
break;
default:
luaL_error(L, "Unsupport base %d",base);
break;
}
int i;
char buffer[64];
for (i=0;i<64;i+=shift) {
buffer[i/shift] = hex[(n>>(64-shift-i)) & mask];
}
lua_pushlstring(L, buffer, 64 / shift);
}
return 1;
}
static void
make_mt(lua_State *L) {
luaL_Reg lib[] = {
{ "__add", int64_add },
{ "__sub", int64_sub },
{ "__mul", int64_mul },
{ "__div", int64_div },
{ "__mod", int64_mod },
{ "__unm", int64_unm },
{ "__pow", int64_pow },
{ "__eq", int64_eq },
{ "__lt", int64_lt },
{ "__le", int64_le },
{ "__len", int64_len },
{ "__tostring", tostring },
{ NULL, NULL },
};
luaL_newlib(L,lib);
}
int
luaopen_int64(lua_State *L) {
if (sizeof(intptr_t)!=sizeof(int64_t)) {
return luaL_error(L, "Only support 64bit architecture");
}
lua_pushlightuserdata(L,NULL);
make_mt(L);
lua_setmetatable(L,-2);
lua_pop(L,1);
lua_newtable(L);
lua_pushcfunction(L, int64_new);
lua_setfield(L, -2, "new");
lua_pushcfunction(L, tostring);
lua_setfield(L, -2, "tostring");
return 1;
}

View File

@@ -1,17 +0,0 @@
lib = require "int64"
local int64 = lib.new
print(lib.tostring(int64 "\1\2\3\4\5\6\7\8"))
a = 1 + int64(1)
b = int64 "\16" + int64("9",10)
print(lib.tostring(a,10), lib.tostring(b,2))
print("+", a+b)
print("-", lib.tostring(a-b,10))
print("*", a*b)
print("/", a/b)
print("%", a%b)
print("^", a^b)
print("==", a == b)
print(">", a > b)
print("#", #a)

View File

@@ -1,187 +0,0 @@
# Makefile for building Lua
# See ../doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= none
CC= gcc
CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
AR= ar rcu
RANLIB= ranlib
RM= rm -f
SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYLDFLAGS=
MYLIBS=
MYOBJS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \
lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \
ltm.o lundump.o lvm.o lzio.o
LIB_O= lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \
lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= lua
LUA_O= lua.o
LUAC_T= luac
LUAC_O= luac.o
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
ALL_A= $(LUA_A)
# Targets start here.
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(BASE_O)
$(AR) $@ $(BASE_O)
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
$(LUAC_T): $(LUAC_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM l*.c
echo:
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(SYSLDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
@echo "RM= $(RM)"
# Convenience targets for popular platforms
ALL= all
none:
@echo "Please do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
aix:
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
ansi:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_ANSI"
bsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
freebsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline"
generic: $(ALL)
linux:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
macosx:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc
mingw:
$(MAKE) "LUA_A=lua52.dll" "LUA_T=lua.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
$(MAKE) "LUAC_T=luac.exe" luac.exe
posix:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
solaris:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl"
# list targets that do not create files (but not all makes understand .PHONY)
.PHONY: all $(PLATS) default o a clean depend echo none
# DO NOT DELETE
lapi.o: lapi.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h ltable.h lundump.h \
lvm.h
lauxlib.o: lauxlib.c lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lgc.h \
lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h ldebug.h ldo.h \
lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h ltm.h \
lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h lparser.h \
lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h \
lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lua.h luaconf.h lfunc.h lobject.h llimits.h lgc.h \
lstate.h ltm.h lzio.h lmem.h
lgc.o: lgc.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lua.h luaconf.h lctype.h llimits.h ldo.h lobject.h \
lstate.h ltm.h lzio.h lmem.h llex.h lparser.h lstring.h lgc.h ltable.h
lmathlib.o: lmathlib.c lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lua.h luaconf.h lctype.h llimits.h ldebug.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lvm.h
lopcodes.o: lopcodes.c lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lua.h luaconf.h lcode.h llex.h lobject.h llimits.h \
lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \
lstring.h lgc.h ltable.h
lstate.o: lstate.c lua.h luaconf.h lapi.h llimits.h lstate.h lobject.h \
ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h lstring.h \
ltable.h
lstring.o: lstring.c lua.h luaconf.h lmem.h llimits.h lobject.h lstate.h \
ltm.h lzio.h lstring.h lgc.h
lstrlib.o: lstrlib.c lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h \
ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lua.h luaconf.h lobject.h llimits.h lstate.h ltm.h lzio.h \
lmem.h lstring.h lgc.h ltable.h
lua.o: lua.c lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lua.h luaconf.h lauxlib.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h lundump.h
lvm.o: lvm.c lua.h luaconf.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
lzio.o: lzio.c lua.h luaconf.h llimits.h lmem.h lstate.h lobject.h ltm.h \
lzio.h

View File

@@ -1,3 +1,6 @@
This is a modify version of lua 5.2.3 (http://www.lua.org/ftp/lua-5.2.3.tar.gz) .
This is a modify version of lua 5.4.3 .
For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
For detail ,
Shared Proto : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
Shared short string table : http://blog.codingnow.com/2015/08/lua_vm_share_string.html
Signal for debug use : http://blog.codingnow.com/2015/03/skynet_signal.html

7
3rd/lua/README.md Normal file
View File

@@ -0,0 +1,7 @@
# Lua
This is the repository of Lua development code, as seen by the Lua team. It contains the full history of all commits but is mirrored irregularly. For complete information about Lua, visit [Lua.org](https://www.lua.org/).
Please **do not** send pull requests. To report issues, post a message to the [Lua mailing list](https://www.lua.org/lua-l.html).
Download official Lua releases from [Lua.org](https://www.lua.org/download.html).

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lapi.h $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
@@ -11,14 +11,42 @@
#include "llimits.h"
#include "lstate.h"
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
/* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
/* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack")
/*
** To reduce the overhead of returning from C functions, the presence of
** to-be-closed variables in these functions is coded in the CallInfo's
** field 'nresults', in a way that functions with no to-be-closed variables
** with zero, one, or "all" wanted results have no overhead. Functions
** with other number of wanted results, as well as functions with
** variables to be closed, have an extra check.
*/
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
#define codeNresults(n) (-(n) - 3)
#define decodeNresults(n) (-(n) - 3)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lauxlib.h $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -12,44 +12,60 @@
#include <stddef.h>
#include <stdio.h>
#include "luaconf.h"
#include "lua.h"
/* global table */
#define LUA_GNAME "_G"
/* extra error code for `luaL_load' */
typedef struct luaL_Buffer luaL_Buffer;
/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM)
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
#define luaL_checkversion(L) \
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
lua_Integer def);
LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg);
LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg,
lua_Unsigned def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
@@ -59,13 +75,14 @@ LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* pre-defined references */
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
@@ -74,6 +91,8 @@ LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
LUALIB_API int (luaL_loadfilex_) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
@@ -83,10 +102,12 @@ LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API int (luaL_len) (lua_State *L, int idx);
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
const char *p, const char *r);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
const char *p, const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
@@ -108,16 +129,17 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_newlib(L,l) \
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,arg,extramsg) \
((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_argexpected(L,cond,arg,tname) \
((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
@@ -134,19 +156,54 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** Perform arithmetic operations on lua_Integer values with wrap-around
** semantics, as the Lua core does.
*/
#define luaL_intop(op,v1,v2) \
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
/* push the value used to represent failure/error */
#define luaL_pushfail(L) lua_pushnil(L)
/*
** Internal assertions for in-house debugging
*/
#if !defined(lua_assert)
#if defined LUAI_ASSERT
#include <assert.h>
#define lua_assert(c) assert(c)
#else
#define lua_assert(c) ((void)0)
#endif
#endif
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
union {
LUAI_MAXALIGN; /* ensure maximum alignment for buffer */
char b[LUAL_BUFFERSIZE]; /* initial buffer */
} init;
};
#define luaL_bufflen(bf) ((bf)->n)
#define luaL_buffaddr(bf) ((bf)->b)
#define luaL_addchar(B,c) \
@@ -155,6 +212,8 @@ typedef struct luaL_Buffer {
#define luaL_addsize(B,s) ((B)->n += (s))
#define luaL_buffsub(B,s) ((B)->n -= (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
@@ -192,19 +251,51 @@ typedef struct luaL_Stream {
/* }====================================================== */
/*
** {==================================================================
** "Abstraction Layer" for basic report of messages and errors
** ===================================================================
*/
/* print a string */
#if !defined(lua_writestring)
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
#endif
/* print a newline and flush the output */
#if !defined(lua_writeline)
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
#endif
/* print an error message */
#if !defined(lua_writestringerror)
#define lua_writestringerror(s,p) \
(fprintf(stderr, (s), (p)), fflush(stderr))
#endif
/* }================================================================== */
/* compatibility with old module system */
#if defined(LUA_COMPAT_MODULE)
/*
** {============================================================
** Compatibility with deprecated conversions
** =============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
#define luaL_optunsigned(L,a,d) \
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#endif
/* }============================================================ */
#endif

View File

@@ -1,9 +1,13 @@
/*
** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lbaselib.c $
** Basic library
** See Copyright Notice in lua.h
*/
#define lbaselib_c
#define LUA_LIB
#include "lprefix.h"
#include <ctype.h>
@@ -11,9 +15,6 @@
#include <stdlib.h>
#include <string.h>
#define lbaselib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
@@ -23,74 +24,98 @@
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
for (i = 1; i <= n; i++) { /* for each argument */
size_t l;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &l); /* get result */
if (s == NULL)
return luaL_error(L,
LUA_QL("tostring") " must return a string to " LUA_QL("print"));
if (i>1) luai_writestring("\t", 1);
luai_writestring(s, l);
const char *s = luaL_tolstring(L, i, &l); /* convert it to string */
if (i > 1) /* not the first element? */
lua_writestring("\t", 1); /* add a tab before it */
lua_writestring(s, l); /* print it */
lua_pop(L, 1); /* pop result */
}
luai_writeline();
lua_writeline();
return 0;
}
/*
** Creates a warning with all given arguments.
** Check first for errors; otherwise an error may interrupt
** the composition of a warning, leaving it unfinished.
*/
static int luaB_warn (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
luaL_checkstring(L, 1); /* at least one argument */
for (i = 2; i <= n; i++)
luaL_checkstring(L, i); /* make sure all arguments are strings */
for (i = 1; i < n; i++) /* compose warning */
lua_warning(L, lua_tostring(L, i), 1);
lua_warning(L, lua_tostring(L, n), 0); /* close warning */
return 0;
}
#define SPACECHARS " \f\n\r\t\v"
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
lua_Unsigned n = 0;
int neg = 0;
s += strspn(s, SPACECHARS); /* skip initial spaces */
if (*s == '-') { s++; neg = 1; } /* handle sign */
else if (*s == '+') s++;
if (!isalnum((unsigned char)*s)) /* no digit? */
return NULL;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: (toupper((unsigned char)*s) - 'A') + 10;
if (digit >= base) return NULL; /* invalid numeral */
n = n * base + digit;
s++;
} while (isalnum((unsigned char)*s));
s += strspn(s, SPACECHARS); /* skip trailing spaces */
*pn = (lua_Integer)((neg) ? (0u - n) : n);
return s;
}
static int luaB_tonumber (lua_State *L) {
if (lua_isnoneornil(L, 2)) { /* standard conversion */
int isnum;
lua_Number n = lua_tonumberx(L, 1, &isnum);
if (isnum) {
lua_pushnumber(L, n);
if (lua_isnoneornil(L, 2)) { /* standard conversion? */
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
lua_settop(L, 1); /* yes; return it */
return 1;
} /* else not a number; must be something */
luaL_checkany(L, 1);
}
else {
size_t l;
const char *s = lua_tolstring(L, 1, &l);
if (s != NULL && lua_stringtonumber(L, s) == l + 1)
return 1; /* successful conversion to number */
/* else not a number */
luaL_checkany(L, 1); /* (but there must be some parameter) */
}
}
else {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
const char *e = s + l; /* end point for 's' */
int base = luaL_checkint(L, 2);
int neg = 0;
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
s += strspn(s, SPACECHARS); /* skip initial spaces */
if (*s == '-') { s++; neg = 1; } /* handle signal */
else if (*s == '+') s++;
if (isalnum((unsigned char)*s)) {
lua_Number n = 0;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: toupper((unsigned char)*s) - 'A' + 10;
if (digit >= base) break; /* invalid numeral; force a fail */
n = n * (lua_Number)base + (lua_Number)digit;
s++;
} while (isalnum((unsigned char)*s));
s += strspn(s, SPACECHARS); /* skip trailing spaces */
if (s == e) { /* no invalid trailing characters? */
lua_pushnumber(L, (neg) ? -n : n);
return 1;
} /* else not a number */
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
return 1;
} /* else not a number */
}
lua_pushnil(L); /* not a number */
} /* else not a number */
luaL_pushfail(L); /* not a number */
return 1;
}
static int luaB_error (lua_State *L) {
int level = luaL_optint(L, 2, 1);
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -112,9 +137,8 @@ static int luaB_getmetatable (lua_State *L) {
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
return luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
@@ -132,8 +156,8 @@ static int luaB_rawequal (lua_State *L) {
static int luaB_rawlen (lua_State *L) {
int t = lua_type(L, 1);
luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
"table or string expected");
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
"table or string");
lua_pushinteger(L, lua_rawlen(L, 1));
return 1;
}
@@ -157,56 +181,86 @@ static int luaB_rawset (lua_State *L) {
}
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"setmajorinc", "isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = luaL_optint(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
lua_pushnumber(L, res + ((lua_Number)b/1024));
lua_pushinteger(L, b);
return 2;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
lua_pushboolean(L, res);
return 1;
}
default: {
lua_pushinteger(L, res);
return 1;
}
}
}
static int luaB_type (lua_State *L) {
luaL_checkany(L, 1);
lua_pushstring(L, luaL_typename(L, 1));
static int pushmode (lua_State *L, int oldmode) {
if (oldmode == -1)
luaL_pushfail(L); /* invalid call to 'lua_gc' */
else
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
: "generational");
return 1;
}
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
else lua_pushnil(L);
/*
** check whether call to 'lua_gc' was valid (not inside a finalizer)
*/
#define checkvalres(res) { if (res == -1) break; }
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
switch (o) {
case LUA_GCCOUNT: {
int k = lua_gc(L, o);
int b = lua_gc(L, LUA_GCCOUNTB);
checkvalres(k);
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
return 1;
}
case LUA_GCSTEP: {
int step = (int)luaL_optinteger(L, 2, 0);
int res = lua_gc(L, o, step);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCSETPAUSE:
case LUA_GCSETSTEPMUL: {
int p = (int)luaL_optinteger(L, 2, 0);
int previous = lua_gc(L, o, p);
checkvalres(previous);
lua_pushinteger(L, previous);
return 1;
}
case LUA_GCISRUNNING: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushboolean(L, res);
return 1;
}
case LUA_GCGEN: {
int minormul = (int)luaL_optinteger(L, 2, 0);
int majormul = (int)luaL_optinteger(L, 3, 0);
return pushmode(L, lua_gc(L, o, minormul, majormul));
}
case LUA_GCINC: {
int pause = (int)luaL_optinteger(L, 2, 0);
int stepmul = (int)luaL_optinteger(L, 3, 0);
int stepsize = (int)luaL_optinteger(L, 4, 0);
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
}
default: {
int res = lua_gc(L, o);
checkvalres(res);
lua_pushinteger(L, res);
return 1;
}
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_call(L, 1, 3); /* get 3 values from metamethod */
}
return 3;
luaL_pushfail(L); /* invalid call (inside a finalizer) */
return 1;
}
static int luaB_type (lua_State *L) {
int t = lua_type(L, 1);
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
lua_pushstring(L, lua_typename(L, t));
return 1;
}
@@ -222,28 +276,52 @@ static int luaB_next (lua_State *L) {
}
static int pairscont (lua_State *L, int status, lua_KContext k) {
(void)L; (void)status; (void)k; /* unused */
return 3;
}
static int luaB_pairs (lua_State *L) {
return pairsmeta(L, "__pairs", 0, luaB_next);
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
lua_pushcfunction(L, luaB_next); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
}
return 3;
}
/*
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
int i = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
i++; /* next value */
lua_Integer i = luaL_checkinteger(L, 2);
i = luaL_intop(+, i, 1);
lua_pushinteger(L, i);
lua_rawgeti(L, 1, i);
return (lua_isnil(L, -1)) ? 1 : 2;
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
/*
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
return pairsmeta(L, "__ipairs", 1, ipairsaux);
luaL_checkany(L, 1);
lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
}
static int load_aux (lua_State *L, int status, int envidx) {
if (status == LUA_OK) {
if (l_likely(status == LUA_OK)) {
if (envidx != 0) { /* 'env' parameter? */
lua_pushvalue(L, envidx); /* environment for loaded function */
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
@@ -252,9 +330,9 @@ static int load_aux (lua_State *L, int status, int envidx) {
return 1;
}
else { /* error (message is on top of the stack) */
lua_pushnil(L);
luaL_pushfail(L);
lua_insert(L, -2); /* put before error message */
return 2; /* return nil plus error message */
return 2; /* return fail plus error message */
}
}
@@ -284,7 +362,7 @@ static int luaB_loadfile (lua_State *L) {
/*
** Reader for generic `load' function: `lua_load' uses the
** Reader for generic 'load' function: 'lua_load' uses the
** stack for internal stuff, so the reader cannot change the
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
@@ -299,7 +377,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
*size = 0;
return NULL;
}
else if (!lua_isstring(L, -1))
else if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size);
@@ -328,7 +406,8 @@ static int luaB_load (lua_State *L) {
/* }====================================================== */
static int dofilecont (lua_State *L) {
static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
(void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */
return lua_gettop(L) - 1;
}
@@ -336,17 +415,23 @@ static int dofilecont (lua_State *L) {
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
if (luaL_loadfile(L, fname) != LUA_OK)
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L);
return dofilecont(L, 0, 0);
}
static int luaB_assert (lua_State *L) {
if (!lua_toboolean(L, 1))
return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
return lua_gettop(L);
if (l_likely(lua_toboolean(L, 1))) /* condition is true? */
return lua_gettop(L); /* return all arguments */
else { /* error */
luaL_checkany(L, 1); /* there must be a condition */
lua_remove(L, 1); /* remove it */
lua_pushliteral(L, "assertion failed!"); /* default message */
lua_settop(L, 1); /* leave only message (default if no other one) */
return luaB_error(L); /* call 'error' */
}
}
@@ -357,53 +442,57 @@ static int luaB_select (lua_State *L) {
return 1;
}
else {
int i = luaL_checkint(L, 1);
lua_Integer i = luaL_checkinteger(L, 1);
if (i < 0) i = n + i;
else if (i > n) i = n;
luaL_argcheck(L, 1 <= i, 1, "index out of range");
return n - i;
return n - (int)i;
}
}
static int finishpcall (lua_State *L, int status) {
if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */
lua_settop(L, 0); /* create space for return values */
lua_pushboolean(L, 0);
lua_pushstring(L, "stack overflow");
/*
** Continuation function for 'pcall' and 'xpcall'. Both functions
** already pushed a 'true' before doing the call, so in case of success
** 'finishpcall' only has to return everything in the stack minus
** 'extra' values (where 'extra' is exactly the number of items to be
** ignored).
*/
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */
lua_pushboolean(L, 0); /* first result (false) */
lua_pushvalue(L, -2); /* error message */
return 2; /* return false, msg */
}
lua_pushboolean(L, status); /* first result (status) */
lua_replace(L, 1); /* put first result in first slot */
return lua_gettop(L);
}
static int pcallcont (lua_State *L) {
int status = lua_getctx(L, NULL);
return finishpcall(L, (status == LUA_YIELD));
else
return lua_gettop(L) - (int)extra; /* return all results */
}
static int luaB_pcall (lua_State *L) {
int status;
luaL_checkany(L, 1);
lua_pushnil(L);
lua_insert(L, 1); /* create space for status result */
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
lua_pushboolean(L, 1); /* first result if no errors */
lua_insert(L, 1); /* put it in place */
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
return finishpcall(L, status, 0);
}
/*
** Do a protected call with error handling. After 'lua_rotate', the
** stack will have <f, err, true, f, [args...]>; so, the function passes
** 2 to 'finishpcall' to skip the 2 first values when returning results.
*/
static int luaB_xpcall (lua_State *L) {
int status;
int n = lua_gettop(L);
luaL_argcheck(L, n >= 2, 2, "value expected");
lua_pushvalue(L, 1); /* exchange function... */
lua_copy(L, 2, 1); /* ...and error handler */
lua_replace(L, 2);
status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
lua_pushboolean(L, 1); /* first result */
lua_pushvalue(L, 1); /* function */
lua_rotate(L, 3, 2); /* move them below function's arguments */
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
return finishpcall(L, status, 2);
}
@@ -423,13 +512,11 @@ static const luaL_Reg base_funcs[] = {
{"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
#if defined(LUA_COMPAT_LOADSTRING)
{"loadstring", luaB_load},
#endif
{"next", luaB_next},
{"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"warn", luaB_warn},
{"rawequal", luaB_rawequal},
{"rawlen", luaB_rawlen},
{"rawget", luaB_rawget},
@@ -440,19 +527,23 @@ static const luaL_Reg base_funcs[] = {
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
{LUA_GNAME, NULL},
{"_VERSION", NULL},
{NULL, NULL}
};
LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _G */
lua_pushglobaltable(L);
lua_pushglobaltable(L);
lua_setfield(L, -2, "_G");
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
/* set global _G */
lua_pushvalue(L, -1);
lua_setfield(L, -2, LUA_GNAME);
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
lua_setfield(L, -2, "_VERSION");
return 1;
}

View File

@@ -1,212 +0,0 @@
/*
** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
#define lbitlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
#endif
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
/* macro to trim extra bits */
#define trim(x) ((x) & ALLONES)
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
typedef lua_Unsigned b_uint;
static b_uint andaux (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = ~(b_uint)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
b_uint r = andaux(L);
lua_pushunsigned(L, r);
return 1;
}
static int b_test (lua_State *L) {
b_uint r = andaux(L);
lua_pushboolean(L, r != 0);
return 1;
}
static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
b_uint r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_shift (lua_State *L, b_uint r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
if (i >= LUA_NBITS) r = 0;
else r >>= i;
}
else { /* shift left */
if (i >= LUA_NBITS) r = 0;
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
}
static int b_arshift (lua_State *L) {
b_uint r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */
lua_pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, int i) {
b_uint r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_lrot (lua_State *L) {
return b_rot(L, luaL_checkint(L, 2));
}
static int b_rrot (lua_State *L) {
return b_rot(L, -luaL_checkint(L, 2));
}
/*
** get field and width arguments for field-manipulation functions,
** checking whether they are valid.
** ('luaL_error' called without 'return' to avoid later warnings about
** 'width' being used uninitialized.)
*/
static int fieldargs (lua_State *L, int farg, int *width) {
int f = luaL_checkint(L, farg);
int w = luaL_optint(L, farg + 1, 1);
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
if (f + w > LUA_NBITS)
luaL_error(L, "trying to access non-existent bits");
*width = w;
return f;
}
static int b_extract (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
b_uint v = luaL_checkunsigned(L, 2);
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
return 1;
}
static const luaL_Reg bitlib[] = {
{"arshift", b_arshift},
{"band", b_and},
{"bnot", b_not},
{"bor", b_or},
{"bxor", b_xor},
{"btest", b_test},
{"extract", b_extract},
{"lrotate", b_lrot},
{"lshift", b_lshift},
{"replace", b_replace},
{"rrotate", b_rrot},
{"rshift", b_rshift},
{NULL, NULL}
};
LUAMOD_API int luaopen_bit32 (lua_State *L) {
luaL_newlib(L, bitlib);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lcode.h $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -24,35 +24,53 @@
** grep "ORDER OPR" if you change these enums (ORDER OP)
*/
typedef enum BinOpr {
OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
/* arithmetic operators */
OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
OPR_DIV, OPR_IDIV,
/* bitwise operators */
OPR_BAND, OPR_BOR, OPR_BXOR,
OPR_SHL, OPR_SHR,
/* string operator */
OPR_CONCAT,
/* comparison operators */
OPR_EQ, OPR_LT, OPR_LE,
OPR_NE, OPR_GT, OPR_GE,
/* logical operators */
OPR_AND, OPR_OR,
OPR_NOBINOPR
} BinOpr;
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
/* true if operation is foldable (that is, it is arithmetic or bitwise) */
#define foldbinop(op) ((op) <= OPR_SHR)
#define getcode(fs,e) ((fs)->f->sp->code[(e)->u.info])
#define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0)
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
int B, int C, int k);
LUAI_FUNC int luaK_isKint (expdesc *e);
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
@@ -70,14 +88,17 @@ LUAI_FUNC int luaK_jump (FuncState *fs);
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
expdesc *v2, int line);
LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
int ra, int asize, int hsize);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
LUAI_FUNC void luaK_finish (FuncState *fs);
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
#endif

View File

@@ -1,37 +1,44 @@
/*
** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lcorolib.c $
** Coroutine Library
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#define lcorolib_c
#define LUA_LIB
#include "lprefix.h"
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static lua_State *getco (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argexpected(L, co, 1, "thread");
return co;
}
/*
** Resumes a coroutine. Returns the number of results for non-error
** cases or -1 for errors.
*/
static int auxresume (lua_State *L, lua_State *co, int narg) {
int status;
if (!lua_checkstack(co, narg)) {
int status, nres;
if (l_unlikely(!lua_checkstack(co, narg))) {
lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */
}
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
lua_pushliteral(L, "cannot resume dead coroutine");
return -1; /* error flag */
}
lua_xmove(L, co, narg);
status = lua_resume(co, L, narg);
if (status == LUA_OK || status == LUA_YIELD) {
int nres = lua_gettop(co);
if (!lua_checkstack(L, nres + 1)) {
status = lua_resume(co, L, narg, &nres);
if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
if (l_unlikely(!lua_checkstack(L, nres + 1))) {
lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */
@@ -47,11 +54,10 @@ static int auxresume (lua_State *L, lua_State *co, int narg) {
static int luaB_coresume (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
lua_State *co = getco(L);
int r;
luaL_argcheck(L, co, 1, "coroutine expected");
r = auxresume(L, co, lua_gettop(L) - 1);
if (r < 0) {
if (l_unlikely(r < 0)) {
lua_pushboolean(L, 0);
lua_insert(L, -2);
return 2; /* return false + error message */
@@ -59,7 +65,7 @@ static int luaB_coresume (lua_State *L) {
else {
lua_pushboolean(L, 1);
lua_insert(L, -(r + 1));
return r + 1; /* return true + `resume' returns */
return r + 1; /* return true + 'resume' returns */
}
}
@@ -67,9 +73,16 @@ static int luaB_coresume (lua_State *L) {
static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
if (stat != LUA_ERRMEM && /* not a memory error and ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
luaL_where(L, 1); /* add extra info, if available */
lua_insert(L, -2);
lua_concat(L, 2);
}
@@ -101,30 +114,48 @@ static int luaB_yield (lua_State *L) {
}
static int luaB_costatus (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argcheck(L, co, 1, "coroutine expected");
if (L == co) lua_pushliteral(L, "running");
#define COS_RUN 0
#define COS_DEAD 1
#define COS_YIELD 2
#define COS_NORM 3
static const char *const statname[] =
{"running", "dead", "suspended", "normal"};
static int auxstatus (lua_State *L, lua_State *co) {
if (L == co) return COS_RUN;
else {
switch (lua_status(co)) {
case LUA_YIELD:
lua_pushliteral(L, "suspended");
break;
return COS_YIELD;
case LUA_OK: {
lua_Debug ar;
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
lua_pushliteral(L, "normal"); /* it is running */
if (lua_getstack(co, 0, &ar)) /* does it have frames? */
return COS_NORM; /* it is running */
else if (lua_gettop(co) == 0)
lua_pushliteral(L, "dead");
return COS_DEAD;
else
lua_pushliteral(L, "suspended"); /* initial state */
break;
return COS_YIELD; /* initial state */
}
default: /* some error occurred */
lua_pushliteral(L, "dead");
break;
return COS_DEAD;
}
}
}
static int luaB_costatus (lua_State *L) {
lua_State *co = getco(L);
lua_pushstring(L, statname[auxstatus(L, co)]);
return 1;
}
static int luaB_yieldable (lua_State *L) {
lua_State *co = lua_isnone(L, 1) ? L : getco(L);
lua_pushboolean(L, lua_isyieldable(co));
return 1;
}
@@ -136,6 +167,28 @@ static int luaB_corunning (lua_State *L) {
}
static int luaB_close (lua_State *L) {
lua_State *co = getco(L);
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushboolean(L, 0);
lua_xmove(co, L, 1); /* move error message */
return 2;
}
}
default: /* normal or running coroutine */
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
}
}
static const luaL_Reg co_funcs[] = {
{"create", luaB_cocreate},
{"resume", luaB_coresume},
@@ -143,6 +196,8 @@ static const luaL_Reg co_funcs[] = {
{"status", luaB_costatus},
{"wrap", luaB_cowrap},
{"yield", luaB_yield},
{"isyieldable", luaB_yieldable},
{"close", luaB_close},
{NULL, NULL}
};

View File

@@ -1,5 +1,5 @@
/*
** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lctype.c $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
@@ -7,12 +7,24 @@
#define lctype_c
#define LUA_CORE
#include "lprefix.h"
#include "lctype.h"
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
/* consider all non-ascii codepoints to be alphabetic */
#define NONA 0x01
#else
#define NONA 0x00 /* default */
#endif
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
0x00, /* EOZ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
@@ -31,22 +43,22 @@ LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif /* } */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lctype.h $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,7 @@
/*
** WARNING: the functions defined here do not necessarily correspond
** to the similar functions in the standard C ctype.h. They are
** optimized for the specific needs of Lua
** optimized for the specific needs of Lua.
*/
#if !defined(LUA_USE_CTYPE)
@@ -61,14 +61,20 @@
#define lisprint(c) testprop(c, MASK(PRINTBIT))
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
/*
** this 'ltolower' only works for alphabetic characters
** In ASCII, this 'ltolower' is correct for alphabetic characters and
** for '.'. That is enough for Lua needs. ('check_exp' ensures that
** the character either is an upper-case letter or is unchanged by
** the transformation, which holds for lower-case letters and '.'.)
*/
#define ltolower(c) ((c) | ('A' ^ 'a'))
#define ltolower(c) \
check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
(c) | ('A' ^ 'a'))
/* two more entries for 0 and -1 (EOZ) */
LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
/* one entry for each character and for -1 (EOZ) */
LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
#else /* }{ */

View File

@@ -1,26 +1,42 @@
/*
** $Id: ldblib.c,v 1.132.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ldblib.c $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
#define ldblib_c
#define LUA_LIB
#include "lprefix.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ldblib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define HOOKKEY "_HKEY"
/*
** The hook table at registry[HOOKKEY] maps threads to their current
** hook function.
*/
static const char *const HOOKKEY = "_HOOKKEY";
/*
** If L1 != L, L1 can be in any state, and therefore there are no
** guarantees about its stack space; any push in L1 must be
** checked.
*/
static void checkstack (lua_State *L, lua_State *L1, int n) {
if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
luaL_error(L, "stack overflow");
}
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
@@ -39,8 +55,7 @@ static int db_getmetatable (lua_State *L) {
static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1; /* return 1st argument */
@@ -48,44 +63,34 @@ static int db_setmetatable (lua_State *L) {
static int db_getuservalue (lua_State *L) {
int n = (int)luaL_optinteger(L, 2, 1);
if (lua_type(L, 1) != LUA_TUSERDATA)
lua_pushnil(L);
else
lua_getuservalue(L, 1);
luaL_pushfail(L);
else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) {
lua_pushboolean(L, 1);
return 2;
}
return 1;
}
static int db_setuservalue (lua_State *L) {
if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
luaL_argerror(L, 1, "full userdata expected, got light userdata");
int n = (int)luaL_optinteger(L, 3, 1);
luaL_checktype(L, 1, LUA_TUSERDATA);
if (!lua_isnoneornil(L, 2))
luaL_checktype(L, 2, LUA_TTABLE);
luaL_checkany(L, 2);
lua_settop(L, 2);
lua_setuservalue(L, 1);
if (!lua_setiuservalue(L, 1, n))
luaL_pushfail(L);
return 1;
}
static void settabss (lua_State *L, const char *i, const char *v) {
lua_pushstring(L, v);
lua_setfield(L, -2, i);
}
static void settabsi (lua_State *L, const char *i, int v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, i);
}
static void settabsb (lua_State *L, const char *i, int v) {
lua_pushboolean(L, v);
lua_setfield(L, -2, i);
}
/*
** Auxiliary function used by several library functions: check for
** an optional thread as function's first argument and set 'arg' with
** 1 if this argument is present (so that functions can skip it to
** access their other arguments)
*/
static lua_State *getthread (lua_State *L, int *arg) {
if (lua_isthread(L, 1)) {
*arg = 1;
@@ -93,46 +98,78 @@ static lua_State *getthread (lua_State *L, int *arg) {
}
else {
*arg = 0;
return L;
return L; /* function will operate over current thread */
}
}
/*
** Variations of 'lua_settable', used by 'db_getinfo' to put results
** from 'lua_getinfo' into result table. Key is always a string;
** value can be a string, an int, or a boolean.
*/
static void settabss (lua_State *L, const char *k, const char *v) {
lua_pushstring(L, v);
lua_setfield(L, -2, k);
}
static void settabsi (lua_State *L, const char *k, int v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, k);
}
static void settabsb (lua_State *L, const char *k, int v) {
lua_pushboolean(L, v);
lua_setfield(L, -2, k);
}
/*
** In function 'db_getinfo', the call to 'lua_getinfo' may push
** results on the stack; later it creates the result table to put
** these objects. Function 'treatstackoption' puts the result from
** 'lua_getinfo' on top of the result table so that it can call
** 'lua_setfield'.
*/
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
if (L == L1) {
lua_pushvalue(L, -2);
lua_remove(L, -3);
}
if (L == L1)
lua_rotate(L, -2, 1); /* exchange object and table */
else
lua_xmove(L1, L, 1);
lua_setfield(L, -2, fname);
lua_xmove(L1, L, 1); /* move object to the "main" stack */
lua_setfield(L, -2, fname); /* put object into table */
}
/*
** Calls 'lua_getinfo' and collects all results in a new table.
** L1 needs stack space for an optional input (function) plus
** two optional outputs (function and line table) from function
** 'lua_getinfo'.
*/
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnStu");
if (lua_isnumber(L, arg+1)) {
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
lua_pushnil(L); /* level out of range */
const char *options = luaL_optstring(L, arg+2, "flnSrtu");
checkstack(L, L1, 3);
luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
lua_xmove(L, L1, 1);
}
else { /* stack level */
if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
luaL_pushfail(L); /* level out of range */
return 1;
}
}
else if (lua_isfunction(L, arg+1)) {
lua_pushfstring(L, ">%s", options);
options = lua_tostring(L, -1);
lua_pushvalue(L, arg+1);
lua_xmove(L, L1, 1);
}
else
return luaL_argerror(L, arg+1, "function or level expected");
if (!lua_getinfo(L1, options, &ar))
return luaL_argerror(L, arg+2, "invalid option");
lua_createtable(L, 0, 2);
lua_newtable(L); /* table to collect results */
if (strchr(options, 'S')) {
settabss(L, "source", ar.source);
lua_pushlstring(L, ar.source, ar.srclen);
lua_setfield(L, -2, "source");
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
@@ -149,6 +186,10 @@ static int db_getinfo (lua_State *L) {
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
}
if (strchr(options, 'r')) {
settabsi(L, "ftransfer", ar.ftransfer);
settabsi(L, "ntransfer", ar.ntransfer);
}
if (strchr(options, 't'))
settabsb(L, "istailcall", ar.istailcall);
if (strchr(options, 'L'))
@@ -162,26 +203,28 @@ static int db_getinfo (lua_State *L) {
static int db_getlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
int nvar = luaL_checkint(L, arg+2); /* local-variable index */
int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
if (lua_isfunction(L, arg + 1)) { /* function argument? */
lua_pushvalue(L, arg + 1); /* push function */
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
return 1;
return 1; /* return only name (there is no value) */
}
else { /* stack-level argument */
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
lua_Debug ar;
const char *name;
int level = (int)luaL_checkinteger(L, arg + 1);
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* push local value */
lua_xmove(L1, L, 1); /* move local value */
lua_pushstring(L, name); /* push name */
lua_pushvalue(L, -2); /* re-order */
lua_rotate(L, -2, 1); /* re-order */
return 2;
}
else {
lua_pushnil(L); /* no name (nor value) */
luaL_pushfail(L); /* no name (nor value) */
return 1;
}
}
@@ -190,26 +233,36 @@ static int db_getlocal (lua_State *L) {
static int db_setlocal (lua_State *L) {
int arg;
const char *name;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
int level = (int)luaL_checkinteger(L, arg + 1);
int nvar = (int)luaL_checkinteger(L, arg + 2);
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
name = lua_setlocal(L1, &ar, nvar);
if (name == NULL)
lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
lua_pushstring(L, name);
return 1;
}
/*
** get (if 'get' is true) or set an upvalue from a closure
*/
static int auxupvalue (lua_State *L, int get) {
const char *name;
int n = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TFUNCTION);
int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name == NULL) return 0;
lua_pushstring(L, name);
lua_insert(L, -(get+1));
lua_insert(L, -(get+1)); /* no-op if get is false */
return get + 1;
}
@@ -225,27 +278,37 @@ static int db_setupvalue (lua_State *L) {
}
static int checkupval (lua_State *L, int argf, int argnup) {
lua_Debug ar;
int nup = luaL_checkint(L, argnup);
luaL_checktype(L, argf, LUA_TFUNCTION);
lua_pushvalue(L, argf);
lua_getinfo(L, ">u", &ar);
luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
return nup;
/*
** Check whether a given upvalue from a given closure exists and
** returns its index
*/
static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) {
void *id;
int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
id = lua_upvalueid(L, argf, nup);
if (pnup) {
luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index");
*pnup = nup;
}
return id;
}
static int db_upvalueid (lua_State *L) {
int n = checkupval(L, 1, 2);
lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
void *id = checkupval(L, 1, 2, NULL);
if (id != NULL)
lua_pushlightuserdata(L, id);
else
luaL_pushfail(L);
return 1;
}
static int db_upvaluejoin (lua_State *L) {
int n1 = checkupval(L, 1, 2);
int n2 = checkupval(L, 3, 4);
int n1, n2;
checkupval(L, 1, 2, &n1);
checkupval(L, 3, 4, &n2);
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
lua_upvaluejoin(L, 1, n1, 3, n2);
@@ -253,26 +316,29 @@ static int db_upvaluejoin (lua_State *L) {
}
#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
/*
** Call hook function registered at hook table for the current
** thread (if there is one)
*/
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
gethooktable(L);
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
lua_pushthread(L);
lua_rawget(L, -2);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
lua_pushinteger(L, ar->currentline); /* push current line */
else lua_pushnil(L);
lua_assert(lua_getinfo(L, "lS", ar));
lua_call(L, 2, 0);
lua_call(L, 2, 0); /* call hook function */
}
}
/*
** Convert a string mask (for 'sethook') into a bit mask
*/
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
@@ -283,6 +349,9 @@ static int makemask (const char *smask, int count) {
}
/*
** Convert a bit mask (for 'gethook') into a string mask
*/
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
@@ -297,26 +366,28 @@ static int db_sethook (lua_State *L) {
int arg, mask, count;
lua_Hook func;
lua_State *L1 = getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) {
if (lua_isnoneornil(L, arg+1)) { /* no hook? */
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
}
else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = luaL_optint(L, arg+3, 0);
count = (int)luaL_optinteger(L, arg + 3, 0);
func = hookf; mask = makemask(smask, count);
}
if (gethooktable(L) == 0) { /* creating hook table? */
lua_pushstring(L, "k");
if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
/* table just created; initialize it */
lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */
}
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_pushvalue(L, arg+1);
lua_rawset(L, -3); /* set new hook */
lua_sethook(L1, func, mask, count); /* set hooks */
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
lua_pushvalue(L, arg + 1); /* value (hook function) */
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
lua_sethook(L1, func, mask, count);
return 0;
}
@@ -327,16 +398,21 @@ static int db_gethook (lua_State *L) {
char buff[5];
int mask = lua_gethookmask(L1);
lua_Hook hook = lua_gethook(L1);
if (hook != NULL && hook != hookf) /* external hook? */
if (hook == NULL) { /* no hook? */
luaL_pushfail(L);
return 1;
}
else if (hook != hookf) /* external hook? */
lua_pushliteral(L, "external hook");
else {
gethooktable(L);
else { /* hook table must exist */
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* get hook */
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
lua_remove(L, -2); /* remove hook table */
}
lua_pushstring(L, unmakemask(mask, buff));
lua_pushinteger(L, lua_gethookcount(L1));
lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
return 3;
}
@@ -344,13 +420,13 @@ static int db_gethook (lua_State *L) {
static int db_debug (lua_State *L) {
for (;;) {
char buffer[250];
luai_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
lua_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0))
luai_writestringerror("%s\n", lua_tostring(L, -1));
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
lua_settop(L, 0); /* remove eventual returns */
}
}
@@ -363,13 +439,21 @@ static int db_traceback (lua_State *L) {
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
lua_pushvalue(L, arg + 1); /* return it untouched */
else {
int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
luaL_traceback(L, L1, msg, level);
}
return 1;
}
static int db_setcstacklimit (lua_State *L) {
int limit = (int)luaL_checkinteger(L, 1);
int res = lua_setcstacklimit(L, limit);
lua_pushinteger(L, res);
return 1;
}
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getuservalue", db_getuservalue},
@@ -387,6 +471,7 @@ static const luaL_Reg dblib[] = {
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_traceback},
{"setcstacklimit", db_setcstacklimit},
{NULL, NULL}
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ldebug.h $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -11,24 +11,53 @@
#include "lstate.h"
#define pcRel(pc, p) (cast(int, (pc) - (p)->sp->code) - 1)
#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define getfuncline(f,pc) (((f)->sp->lineinfo) ? (f)->sp->lineinfo[pc] : 0)
#define resethookcount(L) (L->hookcount = L->basehookcount)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue((ci)->func))
/*
** mark for entries in 'lineinfo' array that has absolute information in
** 'abslineinfo' array
*/
#define ABSLINEINFO (-0x80)
/*
** MAXimum number of successive Instructions WiTHout ABSolute line
** information. (A power of two allows fast divisions.)
*/
#if !defined(MAXIWTHABS)
#define MAXIWTHABS 128
#endif
LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos);
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2);
LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1,
LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
const char *what);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,
const TValue *p2,
const char *msg);
LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ldo.h $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -8,36 +8,78 @@
#define ldo_h
#include "llimits.h"
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
luaD_growstack(L, n); else condmovestack(L);
/*
** Macro to check stack size and grow stack if needed. Parameters
** 'pre'/'pos' allow the macro to preserve a pointer into the
** stack across reallocations, doing the work only when needed.
** It also allows the running of one GC step when the stack is
** reallocated.
** 'condmovestack' is used in heavy tests to force a stack reallocation
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* type of protected functions, to be ran by `runprotected' */
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC */
#define checkstackGC(L,fsize) \
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
/* type of protected functions, to be ran by 'runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud);
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
int allowyield);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);

View File

@@ -1,174 +1,230 @@
/*
** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ldump.c $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define ldump_c
#define LUA_CORE
#include "lprefix.h"
#include <limits.h>
#include <stddef.h>
#include "lua.h"
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
typedef struct {
lua_State* L;
lua_Writer writer;
void* data;
int strip;
int status;
lua_State *L;
lua_Writer writer;
void *data;
int strip;
int status;
} DumpState;
#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
static void DumpBlock(const void* b, size_t size, DumpState* D)
{
if (D->status==0)
{
lua_unlock(D->L);
D->status=(*D->writer)(D->L,b,size,D->data);
lua_lock(D->L);
}
}
/*
** All high-level dumps go through dumpVector; you can change it to
** change the endianness of the result
*/
#define dumpVector(D,v,n) dumpBlock(D,v,(n)*sizeof((v)[0]))
static void DumpChar(int y, DumpState* D)
{
char x=(char)y;
DumpVar(x,D);
}
#define dumpLiteral(D, s) dumpBlock(D,s,sizeof(s) - sizeof(char))
static void DumpInt(int x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpNumber(lua_Number x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpVector(const void* b, int n, size_t size, DumpState* D)
{
DumpInt(n,D);
DumpMem(b,n,size,D);
}
static void DumpString(const TString* s, DumpState* D)
{
if (s==NULL)
{
size_t size=0;
DumpVar(size,D);
}
else
{
size_t size=s->tsv.len+1; /* include trailing '\0' */
DumpVar(size,D);
DumpBlock(getstr(s),size*sizeof(char),D);
}
}
#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
static void DumpFunction(const Proto* f, DumpState* D);
static void DumpConstants(const Proto* f, DumpState* D)
{
int i,n=f->sp->sizek;
DumpInt(n,D);
for (i=0; i<n; i++)
{
const TValue* o=&f->k[i];
DumpChar(ttypenv(o),D);
switch (ttypenv(o))
{
case LUA_TNIL:
break;
case LUA_TBOOLEAN:
DumpChar(bvalue(o),D);
break;
case LUA_TNUMBER:
DumpNumber(nvalue(o),D);
break;
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
default: lua_assert(0);
static void dumpBlock (DumpState *D, const void *b, size_t size) {
if (D->status == 0 && size > 0) {
lua_unlock(D->L);
D->status = (*D->writer)(D->L, b, size, D->data);
lua_lock(D->L);
}
}
n=f->sp->sizep;
DumpInt(n,D);
for (i=0; i<n; i++) DumpFunction(f->p[i],D);
}
static void DumpUpvalues(const Proto* f, DumpState* D)
{
int i,n=f->sp->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpChar(f->sp->upvalues[i].instack,D);
DumpChar(f->sp->upvalues[i].idx,D);
}
#define dumpVar(D,x) dumpVector(D,&x,1)
static void dumpByte (DumpState *D, int y) {
lu_byte x = (lu_byte)y;
dumpVar(D, x);
}
static void DumpDebug(const SharedProto* f, DumpState* D)
{
int i,n;
DumpString((D->strip) ? NULL : f->source,D);
n= (D->strip) ? 0 : f->sizelineinfo;
DumpVector(f->lineinfo,n,sizeof(int),D);
n= (D->strip) ? 0 : f->sizelocvars;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpString(f->locvars[i].varname,D);
DumpInt(f->locvars[i].startpc,D);
DumpInt(f->locvars[i].endpc,D);
}
n= (D->strip) ? 0 : f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
/*
** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];
int n = 0;
do {
buff[DIBS - (++n)] = x & 0x7f; /* fill buffer in reverse order */
x >>= 7;
} while (x != 0);
buff[DIBS - 1] |= 0x80; /* mark last byte */
dumpVector(D, buff + DIBS - n, n);
}
static void DumpFunction(const Proto* f, DumpState* D)
{
const SharedProto *sp = f->sp;
DumpInt(sp->linedefined,D);
DumpInt(sp->lastlinedefined,D);
DumpChar(sp->numparams,D);
DumpChar(sp->is_vararg,D);
DumpChar(sp->maxstacksize,D);
DumpCode(sp,D);
DumpConstants(f,D);
DumpUpvalues(f,D);
DumpDebug(sp,D);
static void dumpInt (DumpState *D, int x) {
dumpSize(D, x);
}
static void DumpHeader(DumpState* D)
{
lu_byte h[LUAC_HEADERSIZE];
luaU_header(h);
DumpBlock(h,LUAC_HEADERSIZE,D);
static void dumpNumber (DumpState *D, lua_Number x) {
dumpVar(D, x);
}
static void dumpInteger (DumpState *D, lua_Integer x) {
dumpVar(D, x);
}
static void dumpString (DumpState *D, const TString *s) {
if (s == NULL)
dumpSize(D, 0);
else {
size_t size = tsslen(s);
const char *str = getstr(s);
dumpSize(D, size + 1);
dumpVector(D, str, size);
}
}
static void dumpCode (DumpState *D, const Proto *f) {
dumpInt(D, f->sizecode);
dumpVector(D, f->code, f->sizecode);
}
static void dumpFunction(DumpState *D, const Proto *f, TString *psource);
static void dumpConstants (DumpState *D, const Proto *f) {
int i;
int n = f->sizek;
dumpInt(D, n);
for (i = 0; i < n; i++) {
const TValue *o = &f->k[i];
int tt = ttypetag(o);
dumpByte(D, tt);
switch (tt) {
case LUA_VNUMFLT:
dumpNumber(D, fltvalue(o));
break;
case LUA_VNUMINT:
dumpInteger(D, ivalue(o));
break;
case LUA_VSHRSTR:
case LUA_VLNGSTR:
dumpString(D, tsvalue(o));
break;
default:
lua_assert(tt == LUA_VNIL || tt == LUA_VFALSE || tt == LUA_VTRUE);
}
}
}
static void dumpProtos (DumpState *D, const Proto *f) {
int i;
int n = f->sizep;
dumpInt(D, n);
for (i = 0; i < n; i++)
dumpFunction(D, f->p[i], f->source);
}
static void dumpUpvalues (DumpState *D, const Proto *f) {
int i, n = f->sizeupvalues;
dumpInt(D, n);
for (i = 0; i < n; i++) {
dumpByte(D, f->upvalues[i].instack);
dumpByte(D, f->upvalues[i].idx);
dumpByte(D, f->upvalues[i].kind);
}
}
static void dumpDebug (DumpState *D, const Proto *f) {
int i, n;
n = (D->strip) ? 0 : f->sizelineinfo;
dumpInt(D, n);
dumpVector(D, f->lineinfo, n);
n = (D->strip) ? 0 : f->sizeabslineinfo;
dumpInt(D, n);
for (i = 0; i < n; i++) {
dumpInt(D, f->abslineinfo[i].pc);
dumpInt(D, f->abslineinfo[i].line);
}
n = (D->strip) ? 0 : f->sizelocvars;
dumpInt(D, n);
for (i = 0; i < n; i++) {
dumpString(D, f->locvars[i].varname);
dumpInt(D, f->locvars[i].startpc);
dumpInt(D, f->locvars[i].endpc);
}
n = (D->strip) ? 0 : f->sizeupvalues;
dumpInt(D, n);
for (i = 0; i < n; i++)
dumpString(D, f->upvalues[i].name);
}
static void dumpFunction (DumpState *D, const Proto *f, TString *psource) {
if (D->strip || f->source == psource)
dumpString(D, NULL); /* no debug info or same source as its parent */
else
dumpString(D, f->source);
dumpInt(D, f->linedefined);
dumpInt(D, f->lastlinedefined);
dumpByte(D, f->numparams);
dumpByte(D, f->is_vararg);
dumpByte(D, f->maxstacksize);
dumpCode(D, f);
dumpConstants(D, f);
dumpUpvalues(D, f);
dumpProtos(D, f);
dumpDebug(D, f);
}
static void dumpHeader (DumpState *D) {
dumpLiteral(D, LUA_SIGNATURE);
dumpByte(D, LUAC_VERSION);
dumpByte(D, LUAC_FORMAT);
dumpLiteral(D, LUAC_DATA);
dumpByte(D, sizeof(Instruction));
dumpByte(D, sizeof(lua_Integer));
dumpByte(D, sizeof(lua_Number));
dumpInteger(D, LUAC_INT);
dumpNumber(D, LUAC_NUM);
}
/*
** dump Lua function as precompiled chunk
*/
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
{
DumpState D;
D.L=L;
D.writer=w;
D.data=data;
D.strip=strip;
D.status=0;
DumpHeader(&D);
DumpFunction(f,&D);
return D.status;
int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
int strip) {
DumpState D;
D.L = L;
D.writer = w;
D.data = data;
D.strip = strip;
D.status = 0;
dumpHeader(&D);
dumpByte(&D, f->sizeupvalues);
dumpFunction(&D, f, NULL);
return D.status;
}

View File

@@ -1,170 +1,288 @@
/*
** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lfunc.c $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define lfunc_c
#define LUA_CORE
#include "lprefix.h"
#include <stddef.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
Closure *luaF_newCclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
c->c.nupvalues = cast_byte(n);
CClosure *luaF_newCclosure (lua_State *L, int nupvals) {
GCObject *o = luaC_newobj(L, LUA_VCCL, sizeCclosure(nupvals));
CClosure *c = gco2ccl(o);
c->nupvalues = cast_byte(nupvals);
return c;
}
Closure *luaF_newLclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
c->l.p = NULL;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
LClosure *luaF_newLclosure (lua_State *L, int nupvals) {
GCObject *o = luaC_newobj(L, LUA_VLCL, sizeLclosure(nupvals));
LClosure *c = gco2lcl(o);
c->p = NULL;
c->nupvalues = cast_byte(nupvals);
while (nupvals--) c->upvals[nupvals] = NULL;
return c;
}
UpVal *luaF_newupval (lua_State *L) {
UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
uv->v = &uv->u.value;
setnilvalue(uv->v);
/*
** fill a closure with new closed upvalues
*/
void luaF_initupvals (lua_State *L, LClosure *cl) {
int i;
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
}
/*
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
next->u.open.previous = &uv->u.open.next;
*prev = uv;
if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
L->twups = G(L)->twups; /* link it to the list */
G(L)->twups = L;
}
return uv;
}
/*
** Find and reuse, or create if it does not exist, an upvalue
** at the given level.
*/
UpVal *luaF_findupval (lua_State *L, StkId level) {
global_State *g = G(L);
GCObject **pp = &L->openupval;
UpVal **pp = &L->openupval;
UpVal *p;
UpVal *uv;
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
GCObject *o = obj2gco(p);
lua_assert(p->v != &p->u.value);
lua_assert(!isold(o) || isold(obj2gco(L)));
if (p->v == level) { /* found a corresponding upvalue? */
if (isdead(g, o)) /* is it dead? */
changewhite(o); /* resurrect it */
return p;
}
pp = &p->next;
lua_assert(isintwups(L) || L->openupval == NULL);
while ((p = *pp) != NULL && uplevel(p) >= level) { /* search for it */
lua_assert(!isdead(G(L), p));
if (uplevel(p) == level) /* corresponding upvalue? */
return p; /* return it */
pp = &p->u.open.next;
}
/* not found: create a new one */
uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
uv->v = level; /* current value lives in the stack */
uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
uv->u.l.next = g->uvhead.u.l.next;
uv->u.l.next->u.l.prev = uv;
g->uvhead.u.l.next = uv;
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
return uv;
/* not found: create a new upvalue after 'pp' */
return newupval(L, level, pp);
}
static void unlinkupval (UpVal *uv) {
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
uv->u.l.prev->u.l.next = uv->u.l.next;
/*
** Call closing method for object 'obj' with error message 'err'. The
** boolean 'yy' controls whether the call is yieldable.
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
luaD_callnoyield(L, top, 0);
}
void luaF_freeupval (lua_State *L, UpVal *uv) {
if (uv->v != &uv->u.value) /* is it open? */
unlinkupval(uv); /* remove from open list */
luaM_free(L, uv); /* free upvalue */
/*
** Check whether object at given level has a close metamethod and raise
** an error if not.
*/
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
}
}
void luaF_close (lua_State *L, StkId level) {
/*
** Prepare and call a closing method.
** If status is CLOSEKTOP, the call to the closing method will be pushed
** at the top of the stack. Otherwise, values can be pushed right after
** the 'level' of the upvalue being closed, as everything after that
** won't be used again.
*/
static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
TValue *uv = s2v(level); /* value being closed */
TValue *errobj;
if (status == CLOSEKTOP)
errobj = &G(L)->nilvalue; /* error object is nil */
else { /* 'luaD_seterrorobj' will set top to level + 2 */
errobj = s2v(level + 1); /* error object goes after 'uv' */
luaD_seterrorobj(L, status, level + 1); /* set error object */
}
callclosemethod(L, uv, errobj, yy);
}
/*
** Maximum value for deltas in 'tbclist', dependent on the type
** of delta. (This macro assumes that an 'L' is in scope where it
** is used.)
*/
#define MAXDELTA \
((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist.p->tbclist.delta = 0;
}
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist.p = level;
}
void luaF_unlinkupval (UpVal *uv) {
lua_assert(upisopen(uv));
*uv->u.open.previous = uv->u.open.next;
if (uv->u.open.next)
uv->u.open.next->u.open.previous = uv->u.open.previous;
}
/*
** Close all upvalues up to the given stack level.
*/
void luaF_closeupval (lua_State *L, StkId level) {
UpVal *uv;
global_State *g = G(L);
while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
GCObject *o = obj2gco(uv);
lua_assert(!isblack(o) && uv->v != &uv->u.value);
L->openupval = uv->next; /* remove from `open' list */
if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
else {
unlinkupval(uv); /* remove upvalue from 'uvhead' list */
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
g->allgc = o;
luaC_checkupvalcolor(g, uv);
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
}
}
}
Proto *luaF_newproto (lua_State *L, SharedProto *sp) {
Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
/*
** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
** level. Return restored 'level'.
*/
StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
return level;
}
Proto *luaF_newproto (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_VPROTO, sizeof(Proto));
Proto *f = gco2p(o);
f->k = NULL;
f->sp = NULL;
f->sizek = 0;
f->p = NULL;
f->cache = NULL;
if (sp == NULL) {
sp = luaM_new(L, SharedProto);
sp->l_G = G(L);
sp->sizek = 0;
sp->sizep = 0;
sp->code = NULL;
sp->sizecode = 0;
sp->lineinfo = NULL;
sp->sizelineinfo = 0;
sp->upvalues = NULL;
sp->sizeupvalues = 0;
sp->numparams = 0;
sp->is_vararg = 0;
sp->maxstacksize = 0;
sp->locvars = NULL;
sp->sizelocvars = 0;
sp->linedefined = 0;
sp->lastlinedefined = 0;
sp->source = NULL;
}
f->sp = sp;
f->sizep = 0;
f->code = NULL;
f->sizecode = 0;
f->lineinfo = NULL;
f->sizelineinfo = 0;
f->abslineinfo = NULL;
f->sizeabslineinfo = 0;
f->upvalues = NULL;
f->sizeupvalues = 0;
f->numparams = 0;
f->is_vararg = 0;
f->maxstacksize = 0;
f->locvars = NULL;
f->sizelocvars = 0;
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
return f;
}
static void
luaF_freesharedproto (lua_State *L, SharedProto *f) {
if (f == NULL || G(L) != f->l_G)
return;
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode);
luaM_freearray(L, f->p, f->sizep);
luaM_freearray(L, f->k, f->sizek);
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
luaM_freearray(L, f->abslineinfo, f->sizeabslineinfo);
luaM_freearray(L, f->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
}
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->k, f->sp->sizek);
luaM_freearray(L, f->p, f->sp->sizep);
luaF_freesharedproto(L, f->sp);
luaM_free(L, f);
}
/*
** Look for n-th local variable at line `line' in function `func'.
** Look for n-th local variable at line 'line' in function 'func'.
** Returns NULL if not found.
*/
const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
int i;
const SharedProto *f = fp->sp;
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
if (pc < f->locvars[i].endpc) { /* is variable active? */
local_number--;
@@ -175,3 +293,20 @@ const char *luaF_getlocalname (const Proto *fp, int local_number, int pc) {
return NULL; /* not found */
}
void luaF_shareproto (Proto *f) {
int i;
if (f == NULL || isshared(f))
return;
makeshared(f);
luaS_share(f->source);
for (i = 0; i < f->sizek; i++) {
if (ttype(&f->k[i]) == LUA_TSTRING)
luaS_share(tsvalue(&f->k[i]));
}
for (i = 0; i < f->sizeupvalues; i++)
luaS_share(f->upvalues[i].name);
for (i = 0; i < f->sizelocvars; i++)
luaS_share(f->locvars[i].varname);
for (i = 0; i < f->sizep; i++)
luaF_shareproto(f->p[i]);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lfunc.h $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -11,23 +11,54 @@
#include "lobject.h"
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
cast(int, sizeof(TValue)*((n)-1)))
#define sizeCclosure(n) (cast_int(offsetof(CClosure, upvalue)) + \
cast_int(sizeof(TValue)) * (n))
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
cast(int, sizeof(TValue *)*((n)-1)))
#define sizeLclosure(n) (cast_int(offsetof(LClosure, upvals)) + \
cast_int(sizeof(TValue *)) * (n))
LUAI_FUNC Proto *luaF_newproto (lua_State *L, SharedProto *sp);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
/* test whether thread is in 'twups' list */
#define isintwups(L) (L->twups != L)
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in a VM register.)
*/
#define MAXUPVAL 255
#define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
** maximum number of misses before giving up the cache of closures
** in prototypes
*/
#define MAXMISS 10
/* special status to close upvalues preserving the top of the stack */
#define CLOSEKTOP (-1)
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nupvals);
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
LUAI_FUNC void luaF_shareproto (Proto *func);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lgc.h $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -12,68 +12,52 @@
#include "lstate.h"
/*
** Collectable objects may have one of three colors: white, which
** means the object is not marked; gray, which means the
** object is marked, but its references may be not marked; and
** black, which means that the object and all its references are marked.
** The main invariant of the garbage collector, while marking objects,
** is that a black object can never point to a white one. Moreover,
** any gray object must be in a "gray list" (gray, grayagain, weak,
** allweak, ephemeron) so that it can be visited again before finishing
** the collection cycle. These lists have no meaning when the invariant
** is not being enforced (e.g., sweep phase).
** Collectable objects may have one of three colors: white, which means
** the object is not marked; gray, which means the object is marked, but
** its references may be not marked; and black, which means that the
** object and all its references are marked. The main invariant of the
** garbage collector, while marking objects, is that a black object can
** never point to a white one. Moreover, any gray object must be in a
** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
** can be visited again before finishing the collection cycle. (Open
** upvalues are an exception to this rule.) These lists have no meaning
** when the invariant is not being enforced (e.g., sweep phase).
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSsweepstring 2
#define GCSsweepudata 3
#define GCSsweep 4
#define GCSpause 5
#define GCSenteratomic 1
#define GCSatomic 2
#define GCSswpallgc 3
#define GCSswpfinobj 4
#define GCSswptobefnz 5
#define GCSswpend 6
#define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \
(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
(GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend)
#define isgenerational(g) ((g)->gckind == KGC_GEN)
/*
** macros to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep
** macro to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a collection, the sweep
** phase may break the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the
** invariant must be kept all times.
** all objects are white again.
*/
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
/*
** Outside the collector, the state in generational mode is kept in
** 'propagate', so 'keepinvariant' is always true.
*/
#define keepinvariantout(g) \
check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \
g->gcstate <= GCSatomic)
#define keepinvariant(g) ((g)->gcstate <= GCSatomic)
/*
** some useful bit tricks
*/
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
#define resetbits(x,m) ((x) &= cast_byte(~(m)))
#define setbits(x,m) ((x) |= (m))
#define testbits(x,m) ((x) & (m))
#define bitmask(b) (1<<(b))
@@ -83,75 +67,141 @@
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in `marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been separated for finalization */
#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */
#define FIXEDBIT 5 /* object is fixed (should not be collected) */
#define OLDBIT 6 /* object is old (only in generational mode) */
/* bit 7 is currently used by tests (luaL_checkmemory) */
/*
** Layout for bit use in 'marked' field. First three bits are
** used for object "age" in generational mode. Last bit is used
** by tests.
*/
#define WHITE0BIT 3 /* object is white (type 0) */
#define WHITE1BIT 4 /* object is white (type 1) */
#define BLACKBIT 5 /* object is black */
#define FINALIZEDBIT 6 /* object has been marked for finalization */
#define TESTBIT 7
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
#define iswhite(x) testbits((x)->gch.marked, WHITEBITS)
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
#define iswhite(x) testbits((x)->marked, WHITEBITS)
#define isblack(x) testbit((x)->marked, BLACKBIT)
#define isgray(x) /* neither white nor black */ \
(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
(!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT)))
#define isold(x) testbit((x)->gch.marked, OLDBIT)
#define tofinalize(x) testbit((x)->marked, FINALIZEDBIT)
/* MOVE OLD rule: whenever an object is moved to the beginning of
a GC list, its old bit must be cleared */
#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT)
#define otherwhite(g) ((g)->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) ((m) & (ow))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked)
#define changewhite(x) ((x)->marked ^= WHITEBITS)
#define nw2black(x) \
check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
#define luaC_condGC(L,c) \
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
/* object age in generational mode */
#define G_NEW 0 /* created in current cycle */
#define G_SURVIVAL 1 /* created in previous cycle */
#define G_OLD0 2 /* marked old by frw. barrier in this cycle */
#define G_OLD1 3 /* first full cycle as old */
#define G_OLD 4 /* really old object (not to be visited) */
#define G_TOUCHED1 5 /* old object touched this cycle */
#define G_TOUCHED2 6 /* old object touched in previous cycle */
#define G_SHARED 7 /* object is shared */
#define AGEBITS 7 /* all age bits (111) */
#define getage(o) ((o)->marked & AGEBITS)
#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a))
#define isold(o) (getage(o) > G_SURVIVAL)
#define isshared(x) (getage(x) == G_SHARED)
#define makeshared(x) setage(x, G_SHARED)
#define ispurewhite(x) (iswhite(x) && !isshared(x))
#define changeage(o,f,t) \
check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
/* Default Values for GC parameters */
#define LUAI_GENMAJORMUL 100
#define LUAI_GENMINORMUL 20
#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrierback_(L,p); }
/* wait memory to double before starting new cycle */
#define LUAI_GCPAUSE 200
#define luaC_objbarrier(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
/*
** some gc parameters are stored divided by 4 to allow a maximum value
** up to 1023 in a 'lu_byte'.
*/
#define getgcparam(p) ((p) * 4)
#define setgcparam(p,v) ((p) = (v) / 4)
#define luaC_objbarrierback(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
#define LUAI_GCMUL 100
#define luaC_barrierproto(L,p,c) \
{ if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
/* how much to allocate before next GC step (log2) */
#define LUAI_GCSTEPSIZE 13 /* 8 KB */
/*
** Check whether the declared GC mode is generational. While in
** generational mode, the collector can go temporarily to incremental
** mode to improve performance. This is signaled by 'g->lastatomic != 0'.
*/
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
/*
** Control when GC is running:
*/
#define GCSTPUSR 1 /* bit true when GC stopped by user */
#define GCSTPGC 2 /* bit true when GC stopped by itself */
#define GCSTPCLS 4 /* bit true when closing Lua state */
#define gcrunning(g) ((g)->gcstp == 0)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
** 'condchangemem' is used only for heavy tests (forcing a full
** GC cycle on every opportunity)
*/
#define luaC_condGC(L,pre,pos) \
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && ispurewhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && ispurewhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_forcestep (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
GCObject **list, int offset);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#endif

View File

@@ -1,20 +1,33 @@
/*
** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: linit.c $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
#define linit_c
#define LUA_LIB
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
**
** You can also *preload* libraries, so that a later 'require' can
** open the library, which is already linked to the application.
** For that, do the following code:
**
** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname);
** lua_pop(L, 1); // remove PRELOAD table
*/
#include "lprefix.h"
#define linit_c
#define LUA_LIB
#include <stddef.h>
#include "lua.h"
@@ -27,41 +40,26 @@
** program
*/
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_GNAME, luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_UTF8LIBNAME, luaopen_utf8},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
/*
** these libs are preloaded and must be required before used
*/
static const luaL_Reg preloadedlibs[] = {
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' and set results to global table */
/* "require" functions from 'loadedlibs' and set results to global table */
for (lib = loadedlibs; lib->func; lib++) {
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
for (lib = preloadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1); /* remove _PRELOAD table */
}

View File

@@ -1,120 +1,153 @@
/*
** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: liolib.c $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
#define liolib_c
#define LUA_LIB
/*
** This definition must come before the inclusion of 'stdio.h'; it
** should not affect non-POSIX systems
*/
#if !defined(_FILE_OFFSET_BITS)
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
#endif
#include "lprefix.h"
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define liolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#if !defined(lua_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
#define lua_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
(*mode == '\0'))
#if !defined(l_checkmode)
/* accepted extensions to 'mode' in 'fopen' */
#if !defined(L_MODEEXT)
#define L_MODEEXT "b"
#endif
/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
static int l_checkmode (const char *mode) {
return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
(*mode != '+' || ((void)(++mode), 1)) && /* skip if char is '+' */
(strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
}
#endif
/*
** {======================================================
** lua_popen spawns a new process connected to the current
** l_popen spawns a new process connected to the current
** one through the file streams.
** =======================================================
*/
#if !defined(lua_popen) /* { */
#if !defined(l_popen) /* { */
#if defined(LUA_USE_POPEN) /* { */
#if defined(LUA_USE_POSIX) /* { */
#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
#define lua_pclose(L,file) ((void)L, pclose(file))
#define l_popen(L,c,m) (fflush(NULL), popen(c,m))
#define l_pclose(L,file) (pclose(file))
#elif defined(LUA_WIN) /* }{ */
#elif defined(LUA_USE_WINDOWS) /* }{ */
#define lua_popen(L,c,m) ((void)L, _popen(c,m))
#define lua_pclose(L,file) ((void)L, _pclose(file))
#define l_popen(L,c,m) (_popen(c,m))
#define l_pclose(L,file) (_pclose(file))
#if !defined(l_checkmodep)
/* Windows accepts "[rw][bt]?" as valid modes */
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \
(m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0')))
#endif
#else /* }{ */
#define lua_popen(L,c,m) ((void)((void)c, m), \
luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
#define lua_pclose(L,file) ((void)((void)L, file), -1)
/* ISO C definitions */
#define l_popen(L,c,m) \
((void)c, (void)m, \
luaL_error(L, "'popen' not supported"), \
(FILE*)0)
#define l_pclose(L,file) ((void)L, (void)file, -1)
#endif /* } */
#endif /* } */
#endif /* } */
#if !defined(l_checkmodep)
/* By default, Lua accepts only "r" or "w" as valid modes */
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
#endif
/* }====================================================== */
#if !defined(l_getc) /* { */
#if defined(LUA_USE_POSIX)
#define l_getc(f) getc_unlocked(f)
#define l_lockfile(f) flockfile(f)
#define l_unlockfile(f) funlockfile(f)
#else
#define l_getc(f) getc(f)
#define l_lockfile(f) ((void)0)
#define l_unlockfile(f) ((void)0)
#endif
#endif /* } */
/*
** {======================================================
** lua_fseek: configuration for longer offsets
** l_fseek: configuration for longer offsets
** =======================================================
*/
#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */
#if !defined(l_fseek) /* { */
#if defined(LUA_USE_POSIX) /* { */
#include <sys/types.h>
#define l_fseek(f,o,w) fseeko(f,o,w)
#define l_ftell(f) ftello(f)
#define l_seeknum off_t
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
#elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
/* Windows (but not DDK) and Visual C++ 2005 or higher */
/* Windows (but not DDK) and Visual C++ 2005 or higher */
#define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64
#endif /* } */
#else /* }{ */
#endif /* } */
#if !defined(l_fseek) /* default definitions */
/* ISO C definitions */
#define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f)
#define l_seeknum long
#endif
#endif /* } */
#endif /* } */
/* }====================================================== */
#define IO_PREFIX "_IO_"
#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1)
#define IO_INPUT (IO_PREFIX "input")
#define IO_OUTPUT (IO_PREFIX "output")
@@ -132,7 +165,7 @@ static int io_type (lua_State *L) {
luaL_checkany(L, 1);
p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
if (p == NULL)
lua_pushnil(L); /* not a file */
luaL_pushfail(L); /* not a file */
else if (isclosed(p))
lua_pushliteral(L, "closed file");
else
@@ -153,7 +186,7 @@ static int f_tostring (lua_State *L) {
static FILE *tofile (lua_State *L) {
LStream *p = tolstream(L);
if (isclosed(p))
if (l_unlikely(isclosed(p)))
luaL_error(L, "attempt to use a closed file");
lua_assert(p->f);
return p->f;
@@ -161,34 +194,44 @@ static FILE *tofile (lua_State *L) {
/*
** When creating file handles, always creates a `closed' file handle
** When creating file handles, always creates a 'closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
** handle is in a consistent state.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
LStream *p = (LStream *)lua_newuserdatauv(L, sizeof(LStream), 0);
p->closef = NULL; /* mark file handle as 'closed' */
luaL_setmetatable(L, LUA_FILEHANDLE);
return p;
}
/*
** Calls the 'close' function from a file handle. The 'volatile' avoids
** a bug in some versions of the Clang compiler (e.g., clang 3.0 for
** 32 bits).
*/
static int aux_close (lua_State *L) {
LStream *p = tolstream(L);
lua_CFunction cf = p->closef;
volatile lua_CFunction cf = p->closef;
p->closef = NULL; /* mark stream as closed */
return (*cf)(L); /* close it */
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
static int f_close (lua_State *L) {
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use default output */
return f_close(L);
}
static int f_gc (lua_State *L) {
LStream *p = tolstream(L);
if (!isclosed(p) && p->f != NULL)
@@ -218,8 +261,8 @@ static LStream *newfile (lua_State *L) {
static void opencheck (lua_State *L, const char *fname, const char *mode) {
LStream *p = newfile(L);
p->f = fopen(fname, mode);
if (p->f == NULL)
luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
if (l_unlikely(p->f == NULL))
luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
}
@@ -228,7 +271,7 @@ static int io_open (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
luaL_argcheck(L, l_checkmode(md), 2, "invalid mode");
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -239,7 +282,8 @@ static int io_open (lua_State *L) {
*/
static int io_pclose (lua_State *L) {
LStream *p = tolstream(L);
return luaL_execresult(L, lua_pclose(L, p->f));
errno = 0;
return luaL_execresult(L, l_pclose(L, p->f));
}
@@ -247,7 +291,8 @@ static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
p->f = lua_popen(L, filename, mode);
luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
p->f = l_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
@@ -264,8 +309,8 @@ static FILE *getiofile (lua_State *L, const char *findex) {
LStream *p;
lua_getfield(L, LUA_REGISTRYINDEX, findex);
p = (LStream *)lua_touserdata(L, -1);
if (isclosed(p))
luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX));
if (l_unlikely(isclosed(p)))
luaL_error(L, "default %s file is closed", findex + IOPREF_LEN);
return p->f;
}
@@ -300,15 +345,28 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
/*
** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
** in the limit for upvalues of a closure)
*/
#define MAXARGLINE 250
/*
** Auxiliary function to create the iteration function for 'lines'.
** The iteration function is a closure over 'io_readline', with
** the following upvalues:
** 1) The file being read (first value in the stack)
** 2) the number of arguments to read
** 3) a boolean, true iff file has to be closed when finished ('toclose')
** *) a variable number of format arguments (rest of the stack)
*/
static void aux_lines (lua_State *L, int toclose) {
int i;
int n = lua_gettop(L) - 1; /* number of arguments to read */
/* ensure that arguments will fit here and into 'io_readline' stack */
luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
lua_pushvalue(L, 1); /* file handle */
luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
lua_pushvalue(L, 1); /* file */
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */
lua_rotate(L, 2, 3); /* move the three values to their positions */
lua_pushcclosure(L, io_readline, 3 + n);
}
@@ -320,6 +378,11 @@ static int f_lines (lua_State *L) {
}
/*
** Return an iteration function for 'io.lines'. If file has to be
** closed, also returns the file itself as a second result (to be
** closed as the state at the exit of a generic for).
*/
static int io_lines (lua_State *L) {
int toclose;
if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
@@ -335,8 +398,15 @@ static int io_lines (lua_State *L) {
lua_replace(L, 1); /* put file at index 1 */
toclose = 1; /* close it after iteration */
}
aux_lines(L, toclose);
return 1;
aux_lines(L, toclose); /* push iteration function */
if (toclose) {
lua_pushnil(L); /* state */
lua_pushnil(L); /* control */
lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */
return 4;
}
else
return 1;
}
@@ -347,13 +417,91 @@ static int io_lines (lua_State *L) {
*/
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
/* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
/*
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
else {
rn->buff[rn->n++] = rn->c; /* save current char */
rn->c = l_getc(rn->f); /* read next one */
return 1;
}
}
/*
** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
/*
** Read a sequence of (hex)digits
*/
static int readdigits (RN *rn, int hex) {
int count = 0;
while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn))
count++;
return count;
}
/*
** Read a number: first reads a valid prefix of a numeral into a buffer.
** Then it calls 'lua_stringtonumber' to check whether the format is
** correct and to convert it to a Lua number.
*/
static int read_number (lua_State *L, FILE *f) {
RN rn;
int count = 0;
int hex = 0;
char decp[2];
rn.f = f; rn.n = 0;
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional sign */
if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}
count += readdigits(&rn, hex); /* integral part */
if (test2(&rn, decp)) /* decimal point? */
count += readdigits(&rn, hex); /* fractional part */
if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */
test2(&rn, "-+"); /* exponent sign */
readdigits(&rn, 0); /* exponent digits */
}
ungetc(rn.c, rn.f); /* unread look-ahead char */
l_unlockfile(rn.f);
rn.buff[rn.n] = '\0'; /* finish string */
if (l_likely(lua_stringtonumber(L, rn.buff)))
return 1; /* ok, it is a valid number */
else { /* invalid format */
lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */
}
@@ -362,48 +510,42 @@ static int read_number (lua_State *L, FILE *f) {
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f);
lua_pushlstring(L, NULL, 0);
ungetc(c, f); /* no-op when c == EOF */
lua_pushliteral(L, "");
return (c != EOF);
}
static int read_line (lua_State *L, FILE *f, int chop) {
luaL_Buffer b;
int c;
luaL_buffinit(L, &b);
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_rawlen(L, -1) > 0); /* check whether read something */
}
l = strlen(p);
if (l == 0 || p[l-1] != '\n')
luaL_addsize(&b, l);
else {
luaL_addsize(&b, l - chop); /* chop 'eol' if needed */
luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */
}
}
do { /* may need to read several chunks to get whole line */
char *buff = luaL_prepbuffer(&b); /* preallocate buffer space */
int i = 0;
l_lockfile(f); /* no memory errors can happen inside the lock */
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
buff[i++] = c; /* read up to end of line or buffer limit */
l_unlockfile(f);
luaL_addsize(&b, i);
} while (c != EOF && c != '\n'); /* repeat until end of line */
if (!chop && c == '\n') /* want a newline and have one? */
luaL_addchar(&b, c); /* add ending newline to result */
luaL_pushresult(&b); /* close buffer */
/* return ok if read something (either a newline or something else) */
return (c == '\n' || lua_rawlen(L, -1) > 0);
}
#define MAX_SIZE_T (~(size_t)0)
static void read_all (lua_State *L, FILE *f) {
size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */
size_t nr;
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
char *p = luaL_prepbuffsize(&b, rlen);
size_t nr = fread(p, sizeof(char), rlen, f);
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
char *p = luaL_prepbuffer(&b);
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
if (nr < rlen) break; /* eof? */
else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */
rlen *= 2; /* double buffer size at each iteration */
}
} while (nr == LUAL_BUFFERSIZE);
luaL_pushresult(&b); /* close buffer */
}
@@ -423,25 +565,25 @@ static int read_chars (lua_State *L, FILE *f, size_t n) {
static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
int n, success;
clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1);
n = first+1; /* to return 1 result */
n = first + 1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
else {
/* ensure stack space for all results and for auxlib's buffer */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
size_t l = (size_t)luaL_checkinteger(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
const char *p = luaL_checkstring(L, n);
if (*p == '*') p++; /* skip optional '*' (for compatibility) */
switch (*p) {
case 'n': /* number */
success = read_number(L, f);
break;
@@ -465,7 +607,7 @@ static int g_read (lua_State *L, FILE *f, int first) {
return luaL_fileresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
luaL_pushfail(L); /* push nil instead */
}
return n - first;
}
@@ -481,6 +623,9 @@ static int f_read (lua_State *L) {
}
/*
** Iteration function for 'lines'.
*/
static int io_readline (lua_State *L) {
LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
int i;
@@ -488,20 +633,21 @@ static int io_readline (lua_State *L) {
if (isclosed(p)) /* file is already closed? */
return luaL_error(L, "file is already closed");
lua_settop(L , 1);
luaL_checkstack(L, n, "too many arguments");
for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
lua_pushvalue(L, lua_upvalueindex(3 + i));
n = g_read(L, p->f, 2); /* 'n' is number of results */
lua_assert(n > 0); /* should return at least a nil */
if (!lua_isnil(L, -n)) /* read at least one value? */
if (lua_toboolean(L, -n)) /* read at least one value? */
return n; /* return them */
else { /* first result is nil: EOF or error */
else { /* first result is false: EOF or error */
if (n > 1) { /* is there error information? */
/* 2nd result is error message */
return luaL_error(L, "%s", lua_tostring(L, -n + 1));
}
if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
lua_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(1));
lua_settop(L, 0); /* clear stack */
lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */
aux_close(L); /* close it */
}
return 0;
@@ -517,8 +663,12 @@ static int g_write (lua_State *L, FILE *f, int arg) {
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
int len = lua_isinteger(L, arg)
? fprintf(f, LUA_INTEGER_FMT,
(LUAI_UACINT)lua_tointeger(L, arg))
: fprintf(f, LUA_NUMBER_FMT,
(LUAI_UACNUMBER)lua_tonumber(L, arg));
status = status && (len > 0);
}
else {
size_t l;
@@ -526,7 +676,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
status = status && (fwrite(s, sizeof(char), l, f) == l);
}
}
if (status) return 1; /* file handle already on stack top */
if (l_likely(status))
return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL);
}
@@ -548,15 +699,15 @@ static int f_seek (lua_State *L) {
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
lua_Number p3 = luaL_optnumber(L, 3, 0);
lua_Integer p3 = luaL_optinteger(L, 3, 0);
l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Number)offset == p3, 3,
luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range");
op = l_fseek(f, offset, mode[op]);
if (op)
if (l_unlikely(op))
return luaL_fileresult(L, 0, NULL); /* error */
else {
lua_pushnumber(L, (lua_Number)l_ftell(f));
lua_pushinteger(L, (lua_Integer)l_ftell(f));
return 1;
}
}
@@ -568,7 +719,7 @@ static int f_setvbuf (lua_State *L) {
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
int res = setvbuf(f, NULL, mode[op], (size_t)sz);
return luaL_fileresult(L, res == 0, NULL);
}
@@ -606,26 +757,37 @@ static const luaL_Reg iolib[] = {
/*
** methods for file handles
*/
static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
static const luaL_Reg meth[] = {
{"read", f_read},
{"seek", f_seek},
{"setvbuf", f_setvbuf},
{"write", f_write},
{"lines", f_lines},
{"flush", f_flush},
{"seek", f_seek},
{"close", f_close},
{"setvbuf", f_setvbuf},
{NULL, NULL}
};
/*
** metamethods for file handles
*/
static const luaL_Reg metameth[] = {
{"__index", NULL}, /* place holder */
{"__gc", f_gc},
{"__close", f_gc},
{"__tostring", f_tostring},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */
lua_pop(L, 1); /* pop new metatable */
luaL_newmetatable(L, LUA_FILEHANDLE); /* metatable for file handles */
luaL_setfuncs(L, metameth, 0); /* add metamethods to new metatable */
luaL_newlibtable(L, meth); /* create method table */
luaL_setfuncs(L, meth, 0); /* add file methods to method table */
lua_setfield(L, -2, "__index"); /* metatable.__index = method table */
lua_pop(L, 1); /* pop metatable */
}
@@ -635,7 +797,7 @@ static void createmeta (lua_State *L) {
static int io_noclose (lua_State *L) {
LStream *p = tolstream(L);
p->closef = &io_noclose; /* keep file opened */
lua_pushnil(L);
luaL_pushfail(L);
lua_pushliteral(L, "cannot close standard file");
return 2;
}

112
3rd/lua/ljumptab.h Normal file
View File

@@ -0,0 +1,112 @@
/*
** $Id: ljumptab.h $
** Jump Table for the Lua interpreter
** See Copyright Notice in lua.h
*/
#undef vmdispatch
#undef vmcase
#undef vmbreak
#define vmdispatch(x) goto *disptab[x];
#define vmcase(l) L_##l:
#define vmbreak vmfetch(); vmdispatch(GET_OPCODE(i));
static const void *const disptab[NUM_OPCODES] = {
#if 0
** you can update the following list with this command:
**
** sed -n '/^OP_/\!d; s/OP_/\&\&L_OP_/ ; s/,.*/,/ ; s/\/.*// ; p' lopcodes.h
**
#endif
&&L_OP_MOVE,
&&L_OP_LOADI,
&&L_OP_LOADF,
&&L_OP_LOADK,
&&L_OP_LOADKX,
&&L_OP_LOADFALSE,
&&L_OP_LFALSESKIP,
&&L_OP_LOADTRUE,
&&L_OP_LOADNIL,
&&L_OP_GETUPVAL,
&&L_OP_SETUPVAL,
&&L_OP_GETTABUP,
&&L_OP_GETTABLE,
&&L_OP_GETI,
&&L_OP_GETFIELD,
&&L_OP_SETTABUP,
&&L_OP_SETTABLE,
&&L_OP_SETI,
&&L_OP_SETFIELD,
&&L_OP_NEWTABLE,
&&L_OP_SELF,
&&L_OP_ADDI,
&&L_OP_ADDK,
&&L_OP_SUBK,
&&L_OP_MULK,
&&L_OP_MODK,
&&L_OP_POWK,
&&L_OP_DIVK,
&&L_OP_IDIVK,
&&L_OP_BANDK,
&&L_OP_BORK,
&&L_OP_BXORK,
&&L_OP_SHRI,
&&L_OP_SHLI,
&&L_OP_ADD,
&&L_OP_SUB,
&&L_OP_MUL,
&&L_OP_MOD,
&&L_OP_POW,
&&L_OP_DIV,
&&L_OP_IDIV,
&&L_OP_BAND,
&&L_OP_BOR,
&&L_OP_BXOR,
&&L_OP_SHL,
&&L_OP_SHR,
&&L_OP_MMBIN,
&&L_OP_MMBINI,
&&L_OP_MMBINK,
&&L_OP_UNM,
&&L_OP_BNOT,
&&L_OP_NOT,
&&L_OP_LEN,
&&L_OP_CONCAT,
&&L_OP_CLOSE,
&&L_OP_TBC,
&&L_OP_JMP,
&&L_OP_EQ,
&&L_OP_LT,
&&L_OP_LE,
&&L_OP_EQK,
&&L_OP_EQI,
&&L_OP_LTI,
&&L_OP_LEI,
&&L_OP_GTI,
&&L_OP_GEI,
&&L_OP_TEST,
&&L_OP_TESTSET,
&&L_OP_CALL,
&&L_OP_TAILCALL,
&&L_OP_RETURN,
&&L_OP_RETURN0,
&&L_OP_RETURN1,
&&L_OP_FORLOOP,
&&L_OP_FORPREP,
&&L_OP_TFORPREP,
&&L_OP_TFORCALL,
&&L_OP_TFORLOOP,
&&L_OP_SETLIST,
&&L_OP_CLOSURE,
&&L_OP_VARARG,
&&L_OP_VARARGPREP,
&&L_OP_EXTRAARG
};

View File

@@ -1,20 +1,24 @@
/*
** $Id: llex.c,v 2.63.1.2 2013/08/30 15:49:41 roberto Exp $
** $Id: llex.c $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#define llex_c
#define LUA_CORE
#include "lprefix.h"
#include <locale.h>
#include <string.h>
#define llex_c
#define LUA_CORE
#include "lua.h"
#include "lctype.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lobject.h"
#include "lparser.h"
@@ -25,7 +29,7 @@
#define next(ls) (ls->current = zgetc(ls->z))
#define next(ls) (ls->current = zgetc(ls->z))
@@ -38,8 +42,9 @@ static const char *const luaX_tokens [] = {
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "::", "<eof>",
"<number>", "<name>", "<string>"
"//", "..", "...", "==", ">=", "<=", "~=",
"<<", ">>", "::", "<eof>",
"<number>", "<integer>", "<name>", "<string>"
};
@@ -53,35 +58,38 @@ static void save (LexState *ls, int c) {
Mbuffer *b = ls->buff;
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
size_t newsize;
if (luaZ_sizebuffer(b) >= MAX_SIZET/2)
if (luaZ_sizebuffer(b) >= MAX_SIZE/2)
lexerror(ls, "lexical element too long", 0);
newsize = luaZ_sizebuffer(b) * 2;
luaZ_resizebuffer(ls->L, b, newsize);
}
b->buffer[luaZ_bufflen(b)++] = cast(char, c);
b->buffer[luaZ_bufflen(b)++] = cast_char(c);
}
void luaX_init (lua_State *L) {
int i;
TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
luaS_fix(ts); /* reserved words are never collected */
ts->tsv.extra = cast_byte(i+1); /* reserved word */
luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */
ts->extra = cast_byte(i+1); /* reserved word */
}
}
const char *luaX_token2str (LexState *ls, int token) {
if (token < FIRST_RESERVED) { /* single-byte symbols? */
lua_assert(token == cast(unsigned char, token));
return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
luaO_pushfstring(ls->L, "char(%d)", token);
if (lisprint(token))
return luaO_pushfstring(ls->L, "'%c'", token);
else /* control character */
return luaO_pushfstring(ls->L, "'<\\%d>'", token);
}
else {
const char *s = luaX_tokens[token - FIRST_RESERVED];
if (token < TK_EOS) /* fixed format (symbols and reserved words)? */
return luaO_pushfstring(ls->L, LUA_QS, s);
return luaO_pushfstring(ls->L, "'%s'", s);
else /* names, strings, and numerals */
return s;
}
@@ -90,11 +98,10 @@ const char *luaX_token2str (LexState *ls, int token) {
static const char *txtToken (LexState *ls, int token) {
switch (token) {
case TK_NAME:
case TK_STRING:
case TK_NUMBER:
case TK_NAME: case TK_STRING:
case TK_FLT: case TK_INT:
save(ls, '\0');
return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff));
return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff));
default:
return luaX_token2str(ls, token);
}
@@ -102,9 +109,7 @@ static const char *txtToken (LexState *ls, int token) {
static l_noret lexerror (LexState *ls, const char *msg, int token) {
char buff[LUA_IDSIZE];
luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
@@ -117,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
/*
** creates a new string and anchors it in function's table so that
** it will not be collected until the end of the function's compilation
** (by that time it should be anchored in function's prototype)
** Creates a new string and anchors it in scanner's table so that it
** will not be collected until the end of the compilation; by that time
** it should be anchored somewhere. It also internalizes long strings,
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TValue *o; /* entry for `str' */
TString *ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, ls->fs->h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? (see 'addK') */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
const TValue *o = luaH_getstr(ls->h, ts);
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
L->top.p--; /* remove string from stack */
}
else { /* string already present */
ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;
}
@@ -148,17 +156,17 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
static void inclinenumber (LexState *ls) {
int old = ls->current;
lua_assert(currIsNewline(ls));
next(ls); /* skip `\n' or `\r' */
next(ls); /* skip '\n' or '\r' */
if (currIsNewline(ls) && ls->current != old)
next(ls); /* skip `\n\r' or `\r\n' */
next(ls); /* skip '\n\r' or '\r\n' */
if (++ls->linenumber >= MAX_INT)
luaX_syntaxerror(ls, "chunk has too many lines");
lexerror(ls, "chunk has too many lines", 0);
}
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->decpoint = '.';
ls->t.token = 0;
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -167,8 +175,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
ls->envn = luaS_new(L, LUA_ENV); /* create env name */
luaS_fix(ls->envn); /* never collect this name */
ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
@@ -181,81 +188,82 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
*/
static int check_next (LexState *ls, const char *set) {
if (ls->current == '\0' || !strchr(set, ls->current))
return 0;
save_and_next(ls);
return 1;
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
#if !defined(getlocaledecpoint)
#define getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e)
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
char old = ls->decpoint;
ls->decpoint = getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!buff2d(ls->buff, &seminfo->r)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_NUMBER);
static int check_next1 (LexState *ls, int c) {
if (ls->current == c) {
next(ls);
return 1;
}
else return 0;
}
/*
** Check whether current char is in set 'set' (with two chars) and
** saves it
*/
static int check_next2 (LexState *ls, const char *set) {
lua_assert(set[2] == '\0');
if (ls->current == set[0] || ls->current == set[1]) {
save_and_next(ls);
return 1;
}
else return 0;
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2d'
** will reject ill-formed numerals.
** This function is quite liberal in what it accepts, as 'luaO_str2num'
** will reject ill-formed numerals. Roughly, it accepts the following
** pattern:
**
** %d(%x|%.|([Ee][+-]?))* | 0[Xx](%x|%.|([Pp][+-]?))*
**
** The only tricky part is to accept [+-] only after a valid exponent
** mark, to avoid reading '3-4' or '0xe+1' as a single number.
**
** The caller might have already read an initial dot.
*/
static void read_numeral (LexState *ls, SemInfo *seminfo) {
static int read_numeral (LexState *ls, SemInfo *seminfo) {
TValue obj;
const char *expo = "Ee";
int first = ls->current;
lua_assert(lisdigit(ls->current));
save_and_next(ls);
if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */
if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */
expo = "Pp";
for (;;) {
if (check_next(ls, expo)) /* exponent part? */
check_next(ls, "+-"); /* optional exponent sign */
if (lisxdigit(ls->current) || ls->current == '.')
if (check_next2(ls, expo)) /* exponent mark? */
check_next2(ls, "-+"); /* optional exponent sign */
else if (lisxdigit(ls->current) || ls->current == '.') /* '%x|%.' */
save_and_next(ls);
else break;
else break;
}
if (lislalpha(ls->current)) /* is numeral touching a letter? */
save_and_next(ls); /* force an error */
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
trydecpoint(ls, seminfo); /* try to update decimal point separator */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;
}
else {
lua_assert(ttisfloat(&obj));
seminfo->r = fltvalue(&obj);
return TK_FLT;
}
}
/*
** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
** -1 if sequence is malformed
** read a sequence '[=*[' or ']=*]', leaving the last bracket. If
** sequence is well formed, return its number of '='s + 2; otherwise,
** return 1 if it is a single bracket (no '='s and no 2nd bracket);
** otherwise (an unfinished '[==...') return 0.
*/
static int skip_sep (LexState *ls) {
int count = 0;
static size_t skip_sep (LexState *ls) {
size_t count = 0;
int s = ls->current;
lua_assert(s == '[' || s == ']');
save_and_next(ls);
@@ -263,23 +271,29 @@ static int skip_sep (LexState *ls) {
save_and_next(ls);
count++;
}
return (ls->current == s) ? count : (-count) - 1;
return (ls->current == s) ? count + 2
: (count == 0) ? 1
: 0;
}
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
save_and_next(ls); /* skip 2nd `[' */
static void read_long_string (LexState *ls, SemInfo *seminfo, size_t sep) {
int line = ls->linenumber; /* initial line (for error message) */
save_and_next(ls); /* skip 2nd '[' */
if (currIsNewline(ls)) /* string starts with a newline? */
inclinenumber(ls); /* skip it */
for (;;) {
switch (ls->current) {
case EOZ:
lexerror(ls, (seminfo) ? "unfinished long string" :
"unfinished long comment", TK_EOS);
case EOZ: { /* error */
const char *what = (seminfo ? "string" : "comment");
const char *msg = luaO_pushfstring(ls->L,
"unfinished long %s (starting at line %d)", what, line);
lexerror(ls, msg, TK_EOS);
break; /* to avoid warnings */
}
case ']': {
if (skip_sep(ls) == sep) {
save_and_next(ls); /* skip 2nd `]' */
save_and_next(ls); /* skip 2nd ']' */
goto endloop;
}
break;
@@ -297,45 +311,70 @@ static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
}
} endloop:
if (seminfo)
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
luaZ_bufflen(ls->buff) - 2*(2 + sep));
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + sep,
luaZ_bufflen(ls->buff) - 2 * sep);
}
static void escerror (LexState *ls, int *c, int n, const char *msg) {
int i;
luaZ_resetbuffer(ls->buff); /* prepare error message */
save(ls, '\\');
for (i = 0; i < n && c[i] != EOZ; i++)
save(ls, c[i]);
lexerror(ls, msg, TK_STRING);
static void esccheck (LexState *ls, int c, const char *msg) {
if (!c) {
if (ls->current != EOZ)
save_and_next(ls); /* add current to buffer for error message */
lexerror(ls, msg, TK_STRING);
}
}
static int gethexa (LexState *ls) {
save_and_next(ls);
esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected");
return luaO_hexavalue(ls->current);
}
static int readhexaesc (LexState *ls) {
int c[3], i; /* keep input for error message */
int r = 0; /* result accumulator */
c[0] = 'x'; /* for error message */
for (i = 1; i < 3; i++) { /* read two hexadecimal digits */
c[i] = next(ls);
if (!lisxdigit(c[i]))
escerror(ls, c, i + 1, "hexadecimal digit expected");
r = (r << 4) + luaO_hexavalue(c[i]);
}
int r = gethexa(ls);
r = (r << 4) + gethexa(ls);
luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */
return r;
}
static unsigned long readutf8esc (LexState *ls) {
unsigned long r;
int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */
save_and_next(ls); /* skip 'u' */
esccheck(ls, ls->current == '{', "missing '{'");
r = gethexa(ls); /* must have at least one digit */
while (cast_void(save_and_next(ls)), lisxdigit(ls->current)) {
i++;
esccheck(ls, r <= (0x7FFFFFFFu >> 4), "UTF-8 value too large");
r = (r << 4) + luaO_hexavalue(ls->current);
}
esccheck(ls, ls->current == '}', "missing '}'");
next(ls); /* skip '}' */
luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */
return r;
}
static void utf8esc (LexState *ls) {
char buff[UTF8BUFFSZ];
int n = luaO_utf8esc(buff, readutf8esc(ls));
for (; n > 0; n--) /* add 'buff' to string */
save(ls, buff[UTF8BUFFSZ - n]);
}
static int readdecesc (LexState *ls) {
int c[3], i;
int i;
int r = 0; /* result accumulator */
for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */
c[i] = ls->current;
r = 10*r + c[i] - '0';
next(ls);
r = 10*r + ls->current - '0';
save_and_next(ls);
}
if (r > UCHAR_MAX)
escerror(ls, c, i, "decimal escape too large");
esccheck(ls, r <= UCHAR_MAX, "decimal escape too large");
luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */
return r;
}
@@ -353,7 +392,7 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
break; /* to avoid warnings */
case '\\': { /* escape sequences */
int c; /* final character to be saved */
next(ls); /* do not save the `\' */
save_and_next(ls); /* keep '\\' for error messages */
switch (ls->current) {
case 'a': c = '\a'; goto read_save;
case 'b': c = '\b'; goto read_save;
@@ -363,12 +402,14 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
case 't': c = '\t'; goto read_save;
case 'v': c = '\v'; goto read_save;
case 'x': c = readhexaesc(ls); goto read_save;
case 'u': utf8esc(ls); goto no_save;
case '\n': case '\r':
inclinenumber(ls); c = '\n'; goto only_save;
case '\\': case '\"': case '\'':
c = ls->current; goto read_save;
case EOZ: goto no_save; /* will raise an error next loop */
case 'z': { /* zap following span of spaces */
luaZ_buffremove(ls->buff, 1); /* remove '\\' */
next(ls); /* skip the 'z' */
while (lisspace(ls->current)) {
if (currIsNewline(ls)) inclinenumber(ls);
@@ -377,15 +418,18 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) {
goto no_save;
}
default: {
if (!lisdigit(ls->current))
escerror(ls, &ls->current, 1, "invalid escape sequence");
/* digital escape \ddd */
c = readdecesc(ls);
esccheck(ls, lisdigit(ls->current), "invalid escape sequence");
c = readdecesc(ls); /* digital escape '\ddd' */
goto only_save;
}
}
read_save: next(ls); /* read next character */
only_save: save(ls, c); /* save 'c' */
read_save:
next(ls);
/* go through */
only_save:
luaZ_buffremove(ls->buff, 1); /* remove '\\' */
save(ls, c);
/* go through */
no_save: break;
}
default:
@@ -416,9 +460,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
/* else is a comment */
next(ls);
if (ls->current == '[') { /* long comment? */
int sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
if (sep >= 0) {
size_t sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */
if (sep >= 2) {
read_long_string(ls, NULL, sep); /* skip long comment */
luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
break;
@@ -430,38 +474,46 @@ static int llex (LexState *ls, SemInfo *seminfo) {
break;
}
case '[': { /* long string or simply '[' */
int sep = skip_sep(ls);
if (sep >= 0) {
size_t sep = skip_sep(ls);
if (sep >= 2) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
else if (sep == -1) return '[';
else lexerror(ls, "invalid long string delimiter", TK_STRING);
else if (sep == 0) /* '[=...' missing second bracket? */
lexerror(ls, "invalid long string delimiter", TK_STRING);
return '[';
}
case '=': {
next(ls);
if (ls->current != '=') return '=';
else { next(ls); return TK_EQ; }
if (check_next1(ls, '=')) return TK_EQ; /* '==' */
else return '=';
}
case '<': {
next(ls);
if (ls->current != '=') return '<';
else { next(ls); return TK_LE; }
if (check_next1(ls, '=')) return TK_LE; /* '<=' */
else if (check_next1(ls, '<')) return TK_SHL; /* '<<' */
else return '<';
}
case '>': {
next(ls);
if (ls->current != '=') return '>';
else { next(ls); return TK_GE; }
if (check_next1(ls, '=')) return TK_GE; /* '>=' */
else if (check_next1(ls, '>')) return TK_SHR; /* '>>' */
else return '>';
}
case '/': {
next(ls);
if (check_next1(ls, '/')) return TK_IDIV; /* '//' */
else return '/';
}
case '~': {
next(ls);
if (ls->current != '=') return '~';
else { next(ls); return TK_NE; }
if (check_next1(ls, '=')) return TK_NE; /* '~=' */
else return '~';
}
case ':': {
next(ls);
if (ls->current != ':') return ':';
else { next(ls); return TK_DBCOLON; }
if (check_next1(ls, ':')) return TK_DBCOLON; /* '::' */
else return ':';
}
case '"': case '\'': { /* short literal strings */
read_string(ls, ls->current, seminfo);
@@ -469,18 +521,17 @@ static int llex (LexState *ls, SemInfo *seminfo) {
}
case '.': { /* '.', '..', '...', or number */
save_and_next(ls);
if (check_next(ls, ".")) {
if (check_next(ls, "."))
if (check_next1(ls, '.')) {
if (check_next1(ls, '.'))
return TK_DOTS; /* '...' */
else return TK_CONCAT; /* '..' */
}
else if (!lisdigit(ls->current)) return '.';
/* else go through */
else return read_numeral(ls, seminfo);
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
read_numeral(ls, seminfo);
return TK_NUMBER;
return read_numeral(ls, seminfo);
}
case EOZ: {
return TK_EOS;
@@ -495,12 +546,12 @@ static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_bufflen(ls->buff));
seminfo->ts = ts;
if (isreserved(ts)) /* reserved word? */
return ts->tsv.extra - 1 + FIRST_RESERVED;
return ts->extra - 1 + FIRST_RESERVED;
else {
return TK_NAME;
}
}
else { /* single-char tokens (+ - / ...) */
else { /* single-char tokens ('+', '*', '%', '{', '}', ...) */
int c = ls->current;
next(ls);
return c;

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: llex.h $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -7,13 +7,23 @@
#ifndef llex_h
#define llex_h
#include <limits.h>
#include "lobject.h"
#include "lzio.h"
#define FIRST_RESERVED 257
/*
** Single-char tokens (terminal symbols) are represented by their own
** numeric code. Other tokens start at the following value.
*/
#define FIRST_RESERVED (UCHAR_MAX + 1)
#if !defined(LUA_ENV)
#define LUA_ENV "_ENV"
#endif
/*
* WARNING: if you change the order of this enumeration,
@@ -26,16 +36,19 @@ enum RESERVED {
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS,
TK_NUMBER, TK_NAME, TK_STRING
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
TK_SHL, TK_SHR,
TK_DBCOLON, TK_EOS,
TK_FLT, TK_INT, TK_NAME, TK_STRING
};
/* number of reserved words */
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
#define NUM_RESERVED (cast_int(TK_WHILE-FIRST_RESERVED + 1))
typedef union {
lua_Number r;
lua_Integer i;
TString *ts;
} SemInfo; /* semantics information */
@@ -51,17 +64,17 @@ typedef struct Token {
typedef struct LexState {
int current; /* current character (charint) */
int linenumber; /* input line counter */
int lastline; /* line of last token `consumed' */
int lastline; /* line of last token 'consumed' */
Token t; /* current token */
Token lookahead; /* look ahead token */
struct FuncState *fs; /* current function (parser) */
struct lua_State *L;
ZIO *z; /* input stream */
Mbuffer *buff; /* buffer for tokens */
Table *h; /* to avoid collection/reuse strings */
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;

View File

@@ -1,6 +1,6 @@
/*
** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** $Id: llimits.h $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -15,53 +15,101 @@
#include "lua.h"
typedef unsigned LUA_INT32 lu_int32;
/*
** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count
** the total memory used by Lua (in bytes). Usually, 'size_t' and
** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines.
*/
#if defined(LUAI_MEM) /* { external definitions? */
typedef LUAI_UMEM lu_mem;
typedef LUAI_MEM l_mem;
#elif LUAI_IS32INT /* }{ */
typedef size_t lu_mem;
typedef ptrdiff_t l_mem;
#else /* 16-bit ints */ /* }{ */
typedef unsigned long lu_mem;
typedef long l_mem;
#endif /* } */
/* chars used as small naturals (so that `char' is reserved for characters) */
/* chars used as small naturals (so that 'char' is reserved for characters) */
typedef unsigned char lu_byte;
typedef signed char ls_byte;
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
/* maximum value for size_t */
#define MAX_SIZET ((size_t)(~(size_t)0))
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2))
/* maximum size visible for Lua (must be representable in a lua_Integer) */
#define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \
: (size_t)(LUA_MAXINTEGER))
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0))
#define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1))
#define MAX_INT INT_MAX /* maximum value of an int */
/*
** conversion of pointer to integer
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
** floor of the log2 of the maximum signed value for integral type 't'.
** (That is, maximum 'n' such that '2^n' fits in the given signed type.)
*/
#define IntPoint(p) ((unsigned int)(lu_mem)(p))
#define log2maxs(t) (sizeof(t) * 8 - 2)
/*
** test whether an unsigned value is a power of 2 (or zero)
*/
#define ispow2(x) (((x) & ((x) - 1)) == 0)
/* type to ensure maximum alignment */
#if !defined(LUAI_USER_ALIGNMENT_T)
#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
/* number of chars of a literal string without the ending \0 */
#define LL(x) (sizeof(x)/sizeof(char) - 1)
/*
** conversion of pointer to unsigned integer: this is for hashing only;
** there is no problem if the integer cannot hold the whole pointer
** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
/* result of a `usual argument conversion' over lua_Number */
/* types of 'usual argument conversions' for lua_Number and lua_Integer */
typedef LUAI_UACNUMBER l_uacNumber;
typedef LUAI_UACINT l_uacInt;
/* internal assertions for in-house debugging */
/*
** Internal assertions for in-house debugging
*/
#if defined LUAI_ASSERT
#undef NDEBUG
#include <assert.h>
#define lua_assert(c) assert(c)
#endif
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
@@ -72,76 +120,122 @@ typedef LUAI_UACNUMBER l_uacNumber;
** assertion for checking API calls
*/
#if !defined(luai_apicheck)
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(L,e) assert(e)
#else
#define luai_apicheck(L,e) lua_assert(e)
#endif
#define luai_apicheck(l,e) ((void)l, lua_assert(e))
#endif
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
/* macro to avoid warnings about unused variables */
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#define UNUSED(x) ((void)(x))
#endif
/* type casts (a macro highlights casts in the code) */
#define cast(t, exp) ((t)(exp))
#define cast_byte(i) cast(lu_byte, (i))
#define cast_void(i) cast(void, (i))
#define cast_voidp(i) cast(void *, (i))
#define cast_num(i) cast(lua_Number, (i))
#define cast_int(i) cast(int, (i))
#define cast_uint(i) cast(unsigned int, (i))
#define cast_byte(i) cast(lu_byte, (i))
#define cast_uchar(i) cast(unsigned char, (i))
#define cast_char(i) cast(char, (i))
#define cast_charp(i) cast(char *, (i))
#define cast_sizet(i) cast(size_t, (i))
/* cast a signed lua_Integer to lua_Unsigned */
#if !defined(l_castS2U)
#define l_castS2U(i) ((lua_Unsigned)(i))
#endif
/*
** cast a lua_Unsigned to a signed lua_Integer; this cast is
** not strict ISO C, but two-complement architectures should
** work fine.
*/
#if !defined(l_castU2S)
#define l_castU2S(i) ((lua_Integer)(i))
#endif
/*
** non-return type
*/
#if !defined(l_noret)
#if defined(__GNUC__)
#define l_noret void __attribute__((noreturn))
#elif defined(_MSC_VER)
#elif defined(_MSC_VER) && _MSC_VER >= 1200
#define l_noret void __declspec(noreturn)
#else
#define l_noret void
#endif
/*
** maximum depth for nested C calls and syntactical nested non-terminals
** in a program. (Value must fit in an unsigned short int.)
*/
#if !defined(LUAI_MAXCCALLS)
#define LUAI_MAXCCALLS 200
#endif
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in an unsigned char.)
** Inline functions
*/
#define MAXUPVAL UCHAR_MAX
#if !defined(LUA_USE_C89)
#define l_inline inline
#elif defined(__GNUC__)
#define l_inline __inline__
#else
#define l_inline /* empty */
#endif
#define l_sinline static l_inline
/*
** type for virtual-machine instructions
** type for virtual-machine instructions;
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
*/
typedef lu_int32 Instruction;
#if LUAI_IS32INT
typedef unsigned int l_uint32;
#else
typedef unsigned long l_uint32;
#endif
typedef l_uint32 Instruction;
/* maximum stack for a Lua function */
#define MAXSTACK 250
/*
** Maximum length for short strings, that is, strings that are
** internalized. (Cannot be smaller than reserved words or tags for
** metamethods, as these strings must be internalized;
** #("function") = 8, #("__newindex") = 10.)
*/
#if !defined(LUAI_MAXSHORTLEN)
#define LUAI_MAXSHORTLEN 40
#endif
/* minimum size for the string table (must be power of 2) */
/*
** Initial size for the string table (must be power of 2).
** The Lua core alone registers ~50 strings (reserved words +
** metaevent keys + a few others). Libraries would typically add
** a few dozens more.
*/
#if !defined(MINSTRTABSIZE)
#define MINSTRTABSIZE 32
#define MINSTRTABSIZE 128
#endif
/*
** Size of cache for strings in the API. 'N' is the number of
** sets (better be a prime) and "M" is the size of each set (M == 1
** makes a direct cache.)
*/
#if !defined(STRCACHE_N)
#define STRCACHE_N 53
#define STRCACHE_M 2
#endif
@@ -151,19 +245,37 @@ typedef lu_int32 Instruction;
#endif
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
/*
** Maximum depth for nested C calls, syntactical nested non-terminals,
** and other features implemented through recursion in C. (Value must
** fit in a 16-bit unsigned integer. It must also be compatible with
** the size of the C stack.)
*/
#if !defined(LUAI_MAXCCALLS)
#define LUAI_MAXCCALLS 200
#endif
/*
** these macros allow user-specific actions on threads when you defined
** LUAI_EXTRASPACE and need to do something extra when a thread is
** macros that are executed whenever program enters the Lua core
** ('lua_lock') and leaves the core ('lua_unlock')
*/
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
/*
** macro executed during Lua functions at points where the
** function can yield.
*/
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
/*
** these macros allow user-specific actions when a thread is
** created/deleted/resumed/yielded.
*/
#if !defined(luai_userstateopen)
@@ -183,127 +295,86 @@ typedef lu_int32 Instruction;
#endif
#if !defined(luai_userstateresume)
#define luai_userstateresume(L,n) ((void)L)
#define luai_userstateresume(L,n) ((void)L)
#endif
#if !defined(luai_userstateyield)
#define luai_userstateyield(L,n) ((void)L)
#define luai_userstateyield(L,n) ((void)L)
#endif
/*
** The luai_num* macros define the primitive operations over numbers.
*/
/* floor division (defined as 'floor(a/b)') */
#if !defined(luai_numidiv)
#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
#endif
/* float division */
#if !defined(luai_numdiv)
#define luai_numdiv(L,a,b) ((a)/(b))
#endif
/*
** lua_number2int is a macro to convert lua_Number to int.
** lua_number2integer is a macro to convert lua_Number to lua_Integer.
** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
** luai_hashnum is a macro to hash a lua_Number value into an integer.
** The hash must be deterministic and give reasonable values for
** both small and large values (outside the range of integers).
** modulo: defined as 'a - floor(a/b)*b'; the direct computation
** using this definition has several problems with rounding errors,
** so it is better to use 'fmod'. 'fmod' gives the result of
** 'a - trunc(a/b)*b', and therefore must be corrected when
** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
** non-integer negative result: non-integer result is equivalent to
** a non-zero remainder 'm'; negative result is equivalent to 'a' and
** 'b' with different signs, or 'm' and 'b' with different signs
** (as the result 'm' of 'fmod' has the same sign of 'a').
*/
#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */
/* trick with Microsoft assembler for X86 */
#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
#define lua_number2integer(i,n) lua_number2int(i, n)
#define lua_number2unsigned(i,n) \
{__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
#elif defined(LUA_IEEE754TRICK) /* }{ */
/* the next trick should work on any machine using IEEE754 with
a 32-bit int type */
union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#if !defined(LUA_IEEEENDIAN) /* { */
#define LUAI_EXTRAIEEE \
static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
#else
#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
#define LUAI_EXTRAIEEE /* empty */
#endif /* } */
#define lua_number2int32(i,n,t) \
{ LUAI_EXTRAIEEE \
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
(i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
#define luai_hashnum(i,n) \
{ volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
(i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */
#define lua_number2int(i,n) lua_number2int32(i, n, int)
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
/* the trick can be expanded to lua_Integer when it is a 32-bit value */
#if defined(LUA_IEEELL)
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
#if !defined(luai_nummod)
#define luai_nummod(L,a,b,m) \
{ (void)L; (m) = l_mathop(fmod)(a,b); \
if (((m) > 0) ? (b) < 0 : ((m) < 0 && (b) > 0)) (m) += (b); }
#endif
#endif /* } */
/* the following definitions always work, but may be slow */
#if !defined(lua_number2int)
#define lua_number2int(i,n) ((i)=(int)(n))
/* exponentiation */
#if !defined(luai_numpow)
#define luai_numpow(L,a,b) \
((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b))
#endif
#if !defined(lua_number2integer)
#define lua_number2integer(i,n) ((i)=(lua_Integer)(n))
#endif
#if !defined(lua_number2unsigned) /* { */
/* the following definition assures proper modulo behavior */
#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
#include <math.h>
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
#define lua_number2unsigned(i,n) \
((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
#else
#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n))
#endif
#endif /* } */
#if !defined(lua_unsigned2number)
/* on several machines, coercion from unsigned to double is slow,
so it may be worth to avoid */
#define lua_unsigned2number(u) \
(((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
/* the others are quite standard operations */
#if !defined(luai_numadd)
#define luai_numadd(L,a,b) ((a)+(b))
#define luai_numsub(L,a,b) ((a)-(b))
#define luai_nummul(L,a,b) ((a)*(b))
#define luai_numunm(L,a) (-(a))
#define luai_numeq(a,b) ((a)==(b))
#define luai_numlt(a,b) ((a)<(b))
#define luai_numle(a,b) ((a)<=(b))
#define luai_numgt(a,b) ((a)>(b))
#define luai_numge(a,b) ((a)>=(b))
#define luai_numisnan(a) (!luai_numeq((a), (a)))
#endif
#if defined(ltable_c) && !defined(luai_hashnum)
#include <float.h>
#include <math.h>
#define luai_hashnum(i,n) { int e; \
n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
lua_number2int(i, n); i += e; }
#endif
/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
#define condmovestack(L) ((void)0)
#define condmovestack(L,pre,pos) ((void)0)
#else
/* realloc stack keeping its size */
#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
#define condmovestack(L,pre,pos) \
{ int sz_ = stacksize(L); pre; luaD_reallocstack((L), sz_, 0); pos; }
#endif
#if !defined(HARDMEMTESTS)
#define condchangemem(L) condmovestack(L)
#define condchangemem(L,pre,pos) ((void)0)
#else
#define condchangemem(L) \
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#define condchangemem(L,pre,pos) \
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif

View File

@@ -1,16 +1,21 @@
/*
** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lmathlib.c $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#include <math.h>
#define lmathlib_c
#define LUA_LIB
#include "lprefix.h"
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include "lua.h"
#include "lauxlib.h"
@@ -18,13 +23,17 @@
#undef PI
#define PI ((lua_Number)(3.1415926535897932384626433832795))
#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0))
#define PI (l_mathop(3.141592653589793238462643383279502884))
static int math_abs (lua_State *L) {
lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
if (lua_isinteger(L, 1)) {
lua_Integer n = lua_tointeger(L, 1);
if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
lua_pushinteger(L, n);
}
else
lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
return 1;
}
@@ -33,31 +42,16 @@ static int math_sin (lua_State *L) {
return 1;
}
static int math_sinh (lua_State *L) {
lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_cos (lua_State *L) {
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
return 1;
}
static int math_cosh (lua_State *L) {
lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_tan (lua_State *L) {
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
return 1;
}
static int math_tanh (lua_State *L) {
lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_asin (lua_State *L) {
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
return 1;
@@ -69,49 +63,106 @@ static int math_acos (lua_State *L) {
}
static int math_atan (lua_State *L) {
lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1)));
lua_Number y = luaL_checknumber(L, 1);
lua_Number x = luaL_optnumber(L, 2, 1);
lua_pushnumber(L, l_mathop(atan2)(y, x));
return 1;
}
static int math_atan2 (lua_State *L) {
lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2)));
static int math_toint (lua_State *L) {
int valid;
lua_Integer n = lua_tointegerx(L, 1, &valid);
if (l_likely(valid))
lua_pushinteger(L, n);
else {
luaL_checkany(L, 1);
luaL_pushfail(L); /* value is not convertible to integer */
}
return 1;
}
static int math_ceil (lua_State *L) {
lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1)));
return 1;
static void pushnumint (lua_State *L, lua_Number d) {
lua_Integer n;
if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */
lua_pushinteger(L, n); /* result is integer */
else
lua_pushnumber(L, d); /* result is float */
}
static int math_floor (lua_State *L) {
lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1)));
if (lua_isinteger(L, 1))
lua_settop(L, 1); /* integer is its own floor */
else {
lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1));
pushnumint(L, d);
}
return 1;
}
static int math_ceil (lua_State *L) {
if (lua_isinteger(L, 1))
lua_settop(L, 1); /* integer is its own ceil */
else {
lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1));
pushnumint(L, d);
}
return 1;
}
static int math_fmod (lua_State *L) {
lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2)));
if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) {
lua_Integer d = lua_tointeger(L, 2);
if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */
luaL_argcheck(L, d != 0, 2, "zero");
lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */
}
else
lua_pushinteger(L, lua_tointeger(L, 1) % d);
}
else
lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2)));
return 1;
}
/*
** next function does not use 'modf', avoiding problems with 'double*'
** (which is not compatible with 'float*') when lua_Number is not
** 'double'.
*/
static int math_modf (lua_State *L) {
lua_Number ip;
lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip);
lua_pushnumber(L, ip);
lua_pushnumber(L, fp);
if (lua_isinteger(L ,1)) {
lua_settop(L, 1); /* number is its own integer part */
lua_pushnumber(L, 0); /* no fractional part */
}
else {
lua_Number n = luaL_checknumber(L, 1);
/* integer part (rounds toward zero) */
lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n);
pushnumint(L, ip);
/* fractional part (test needed for inf/-inf) */
lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip));
}
return 2;
}
static int math_sqrt (lua_State *L) {
lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
return 1;
}
static int math_pow (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
lua_Number y = luaL_checknumber(L, 2);
lua_pushnumber(L, l_mathop(pow)(x, y));
static int math_ult (lua_State *L) {
lua_Integer a = luaL_checkinteger(L, 1);
lua_Integer b = luaL_checkinteger(L, 2);
lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b);
return 1;
}
@@ -122,32 +173,508 @@ static int math_log (lua_State *L) {
res = l_mathop(log)(x);
else {
lua_Number base = luaL_checknumber(L, 2);
if (base == (lua_Number)10.0) res = l_mathop(log10)(x);
else res = l_mathop(log)(x)/l_mathop(log)(base);
#if !defined(LUA_USE_C89)
if (base == l_mathop(2.0))
res = l_mathop(log2)(x);
else
#endif
if (base == l_mathop(10.0))
res = l_mathop(log10)(x);
else
res = l_mathop(log)(x)/l_mathop(log)(base);
}
lua_pushnumber(L, res);
return 1;
}
#if defined(LUA_COMPAT_LOG10)
static int math_log10 (lua_State *L) {
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
return 1;
}
#endif
static int math_exp (lua_State *L) {
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
return 1;
}
static int math_deg (lua_State *L) {
lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI));
return 1;
}
static int math_rad (lua_State *L) {
lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0)));
return 1;
}
static int math_min (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int imin = 1; /* index of current minimum value */
int i;
luaL_argcheck(L, n >= 1, 1, "value expected");
for (i = 2; i <= n; i++) {
if (lua_compare(L, i, imin, LUA_OPLT))
imin = i;
}
lua_pushvalue(L, imin);
return 1;
}
static int math_max (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int imax = 1; /* index of current maximum value */
int i;
luaL_argcheck(L, n >= 1, 1, "value expected");
for (i = 2; i <= n; i++) {
if (lua_compare(L, imax, i, LUA_OPLT))
imax = i;
}
lua_pushvalue(L, imax);
return 1;
}
static int math_type (lua_State *L) {
if (lua_type(L, 1) == LUA_TNUMBER)
lua_pushstring(L, (lua_isinteger(L, 1)) ? "integer" : "float");
else {
luaL_checkany(L, 1);
luaL_pushfail(L);
}
return 1;
}
/*
** {==================================================================
** Pseudo-Random Number Generator based on 'xoshiro256**'.
** ===================================================================
*/
/* number of binary digits in the mantissa of a float */
#define FIGS l_floatatt(MANT_DIG)
#if FIGS > 64
/* there are only 64 random bits; use them all */
#undef FIGS
#define FIGS 64
#endif
/*
** LUA_RAND32 forces the use of 32-bit integers in the implementation
** of the PRN generator (mainly for testing).
*/
#if !defined(LUA_RAND32) && !defined(Rand64)
/* try to find an integer type with at least 64 bits */
#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
#elif !defined(LUA_USE_C89) && defined(LLONG_MAX)
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
#endif
#if defined(Rand64) /* { */
/*
** Standard implementation, using 64-bit integers.
** If 'Rand64' has more than 64 bits, the extra bits do not interfere
** with the 64 initial bits, except in a right shift. Moreover, the
** final result has to discard the extra bits.
*/
/* avoid using extra bits when needed */
#define trim64(x) ((x) & 0xffffffffffffffffu)
/* rotate left 'x' by 'n' bits */
static Rand64 rotl (Rand64 x, int n) {
return (x << n) | (trim64(x) >> (64 - n));
}
static Rand64 nextrand (Rand64 *state) {
Rand64 state0 = state[0];
Rand64 state1 = state[1];
Rand64 state2 = state[2] ^ state0;
Rand64 state3 = state[3] ^ state1;
Rand64 res = rotl(state1 * 5, 7) * 9;
state[0] = state0 ^ state3;
state[1] = state1 ^ state2;
state[2] = state2 ^ (state1 << 17);
state[3] = rotl(state3, 45);
return res;
}
/* must take care to not shift stuff by more than 63 slots */
/*
** Convert bits from a random integer into a float in the
** interval [0,1), getting the higher FIG bits from the
** random unsigned integer and converting that to a float.
*/
/* must throw out the extra (64 - FIGS) bits */
#define shift64_FIG (64 - FIGS)
/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */
#define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1)))
static lua_Number I2d (Rand64 x) {
return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG;
}
/* convert a 'Rand64' to a 'lua_Unsigned' */
#define I2UInt(x) ((lua_Unsigned)trim64(x))
/* convert a 'lua_Unsigned' to a 'Rand64' */
#define Int2I(x) ((Rand64)(x))
#else /* no 'Rand64' }{ */
/* get an integer with at least 32 bits */
#if LUAI_IS32INT
typedef unsigned int lu_int32;
#else
typedef unsigned long lu_int32;
#endif
/*
** Use two 32-bit integers to represent a 64-bit quantity.
*/
typedef struct Rand64 {
lu_int32 h; /* higher half */
lu_int32 l; /* lower half */
} Rand64;
/*
** If 'lu_int32' has more than 32 bits, the extra bits do not interfere
** with the 32 initial bits, except in a right shift and comparisons.
** Moreover, the final result has to discard the extra bits.
*/
/* avoid using extra bits when needed */
#define trim32(x) ((x) & 0xffffffffu)
/*
** basic operations on 'Rand64' values
*/
/* build a new Rand64 value */
static Rand64 packI (lu_int32 h, lu_int32 l) {
Rand64 result;
result.h = h;
result.l = l;
return result;
}
/* return i << n */
static Rand64 Ishl (Rand64 i, int n) {
lua_assert(n > 0 && n < 32);
return packI((i.h << n) | (trim32(i.l) >> (32 - n)), i.l << n);
}
/* i1 ^= i2 */
static void Ixor (Rand64 *i1, Rand64 i2) {
i1->h ^= i2.h;
i1->l ^= i2.l;
}
/* return i1 + i2 */
static Rand64 Iadd (Rand64 i1, Rand64 i2) {
Rand64 result = packI(i1.h + i2.h, i1.l + i2.l);
if (trim32(result.l) < trim32(i1.l)) /* carry? */
result.h++;
return result;
}
/* return i * 5 */
static Rand64 times5 (Rand64 i) {
return Iadd(Ishl(i, 2), i); /* i * 5 == (i << 2) + i */
}
/* return i * 9 */
static Rand64 times9 (Rand64 i) {
return Iadd(Ishl(i, 3), i); /* i * 9 == (i << 3) + i */
}
/* return 'i' rotated left 'n' bits */
static Rand64 rotl (Rand64 i, int n) {
lua_assert(n > 0 && n < 32);
return packI((i.h << n) | (trim32(i.l) >> (32 - n)),
(trim32(i.h) >> (32 - n)) | (i.l << n));
}
/* for offsets larger than 32, rotate right by 64 - offset */
static Rand64 rotl1 (Rand64 i, int n) {
lua_assert(n > 32 && n < 64);
n = 64 - n;
return packI((trim32(i.h) >> n) | (i.l << (32 - n)),
(i.h << (32 - n)) | (trim32(i.l) >> n));
}
/*
** implementation of 'xoshiro256**' algorithm on 'Rand64' values
*/
static Rand64 nextrand (Rand64 *state) {
Rand64 res = times9(rotl(times5(state[1]), 7));
Rand64 t = Ishl(state[1], 17);
Ixor(&state[2], state[0]);
Ixor(&state[3], state[1]);
Ixor(&state[1], state[2]);
Ixor(&state[0], state[3]);
Ixor(&state[2], t);
state[3] = rotl1(state[3], 45);
return res;
}
/*
** Converts a 'Rand64' into a float.
*/
/* an unsigned 1 with proper type */
#define UONE ((lu_int32)1)
#if FIGS <= 32
/* 2^(-FIGS) */
#define scaleFIG (l_mathop(0.5) / (UONE << (FIGS - 1)))
/*
** get up to 32 bits from higher half, shifting right to
** throw out the extra bits.
*/
static lua_Number I2d (Rand64 x) {
lua_Number h = (lua_Number)(trim32(x.h) >> (32 - FIGS));
return h * scaleFIG;
}
#else /* 32 < FIGS <= 64 */
/* must take care to not shift stuff by more than 31 slots */
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
#define scaleFIG \
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
/*
** use FIGS - 32 bits from lower half, throwing out the other
** (32 - (FIGS - 32)) = (64 - FIGS) bits
*/
#define shiftLOW (64 - FIGS)
/*
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
*/
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
static lua_Number I2d (Rand64 x) {
lua_Number h = (lua_Number)trim32(x.h) * shiftHI;
lua_Number l = (lua_Number)(trim32(x.l) >> shiftLOW);
return (h + l) * scaleFIG;
}
#endif
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */
/*
** A state uses four 'Rand64' values.
*/
typedef struct {
Rand64 s[4];
} RanState;
/*
** Project the random integer 'ran' into the interval [0, n].
** Because 'ran' has 2^B possible values, the projection can only be
** uniform when the size of the interval is a power of 2 (exact
** division). Otherwise, to get a uniform projection into [0, n], we
** first compute 'lim', the smallest Mersenne number not smaller than
** 'n'. We then project 'ran' into the interval [0, lim]. If the result
** is inside [0, n], we are done. Otherwise, we try with another 'ran',
** until we have a result inside the interval.
*/
static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n,
RanState *state) {
if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */
return ran & n; /* no bias */
else {
lua_Unsigned lim = n;
/* compute the smallest (2^b - 1) not smaller than 'n' */
lim |= (lim >> 1);
lim |= (lim >> 2);
lim |= (lim >> 4);
lim |= (lim >> 8);
lim |= (lim >> 16);
#if (LUA_MAXUNSIGNED >> 31) >= 3
lim |= (lim >> 32); /* integer type has more than 32 bits */
#endif
lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */
&& lim >= n /* not smaller than 'n', */
&& (lim >> 1) < n); /* and it is the smallest one */
while ((ran &= lim) > n) /* project 'ran' into [0..lim] */
ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */
return ran;
}
}
static int math_random (lua_State *L) {
lua_Integer low, up;
lua_Unsigned p;
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
Rand64 rv = nextrand(state->s); /* next pseudo-random value */
switch (lua_gettop(L)) { /* check number of arguments */
case 0: { /* no arguments */
lua_pushnumber(L, I2d(rv)); /* float between 0 and 1 */
return 1;
}
case 1: { /* only upper limit */
low = 1;
up = luaL_checkinteger(L, 1);
if (up == 0) { /* single 0 as argument? */
lua_pushinteger(L, I2UInt(rv)); /* full random integer */
return 1;
}
break;
}
case 2: { /* lower and upper limits */
low = luaL_checkinteger(L, 1);
up = luaL_checkinteger(L, 2);
break;
}
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
luaL_argcheck(L, low <= up, 1, "interval is empty");
/* project random integer into the interval [0, up - low] */
p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state);
lua_pushinteger(L, p + (lua_Unsigned)low);
return 1;
}
static void setseed (lua_State *L, Rand64 *state,
lua_Unsigned n1, lua_Unsigned n2) {
int i;
state[0] = Int2I(n1);
state[1] = Int2I(0xff); /* avoid a zero state */
state[2] = Int2I(n2);
state[3] = Int2I(0);
for (i = 0; i < 16; i++)
nextrand(state); /* discard initial values to "spread" seed */
lua_pushinteger(L, n1);
lua_pushinteger(L, n2);
}
/*
** Set a "random" seed. To get some randomness, use the current time
** and the address of 'L' (in case the machine does address space layout
** randomization).
*/
static void randseed (lua_State *L, RanState *state) {
lua_Unsigned seed1 = (lua_Unsigned)time(NULL);
lua_Unsigned seed2 = (lua_Unsigned)(size_t)L;
setseed(L, state->s, seed1, seed2);
}
static int math_randomseed (lua_State *L) {
RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1));
if (lua_isnone(L, 1)) {
randseed(L, state);
}
else {
lua_Integer n1 = luaL_checkinteger(L, 1);
lua_Integer n2 = luaL_optinteger(L, 2, 0);
setseed(L, state->s, n1, n2);
}
return 2; /* return seeds */
}
static const luaL_Reg randfuncs[] = {
{"random", math_random},
{"randomseed", math_randomseed},
{NULL, NULL}
};
/*
** Register the random functions and initialize their state.
*/
static void setrandfunc (lua_State *L) {
RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0);
randseed(L, state); /* initialize with a "random" seed */
lua_pop(L, 2); /* remove pushed seeds */
luaL_setfuncs(L, randfuncs, 1);
}
/* }================================================================== */
/*
** {==================================================================
** Deprecated functions (for compatibility only)
** ===================================================================
*/
#if defined(LUA_COMPAT_MATHLIB)
static int math_cosh (lua_State *L) {
lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_sinh (lua_State *L) {
lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_tanh (lua_State *L) {
lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_pow (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
lua_Number y = luaL_checknumber(L, 2);
lua_pushnumber(L, l_mathop(pow)(x, y));
return 1;
}
@@ -160,107 +687,60 @@ static int math_frexp (lua_State *L) {
static int math_ldexp (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
int ep = luaL_checkint(L, 2);
int ep = (int)luaL_checkinteger(L, 2);
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
return 1;
}
static int math_min (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
lua_Number dmin = luaL_checknumber(L, 1);
int i;
for (i=2; i<=n; i++) {
lua_Number d = luaL_checknumber(L, i);
if (d < dmin)
dmin = d;
}
lua_pushnumber(L, dmin);
static int math_log10 (lua_State *L) {
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
return 1;
}
#endif
/* }================================================================== */
static int math_max (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
lua_Number dmax = luaL_checknumber(L, 1);
int i;
for (i=2; i<=n; i++) {
lua_Number d = luaL_checknumber(L, i);
if (d > dmax)
dmax = d;
}
lua_pushnumber(L, dmax);
return 1;
}
static int math_random (lua_State *L) {
/* the `%' avoids the (rare) case of r==1, and is needed also because on
some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
switch (lua_gettop(L)) { /* check number of arguments */
case 0: { /* no arguments */
lua_pushnumber(L, r); /* Number between 0 and 1 */
break;
}
case 1: { /* only upper limit */
lua_Number u = luaL_checknumber(L, 1);
luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */
break;
}
case 2: { /* lower and upper limits */
lua_Number l = luaL_checknumber(L, 1);
lua_Number u = luaL_checknumber(L, 2);
luaL_argcheck(L, l <= u, 2, "interval is empty");
lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */
break;
}
default: return luaL_error(L, "wrong number of arguments");
}
return 1;
}
static int math_randomseed (lua_State *L) {
srand(luaL_checkunsigned(L, 1));
(void)rand(); /* discard first value to avoid undesirable correlations */
return 0;
}
static const luaL_Reg mathlib[] = {
{"abs", math_abs},
{"acos", math_acos},
{"asin", math_asin},
{"atan2", math_atan2},
{"atan", math_atan},
{"ceil", math_ceil},
{"cosh", math_cosh},
{"cos", math_cos},
{"deg", math_deg},
{"exp", math_exp},
{"tointeger", math_toint},
{"floor", math_floor},
{"fmod", math_fmod},
{"frexp", math_frexp},
{"ldexp", math_ldexp},
#if defined(LUA_COMPAT_LOG10)
{"log10", math_log10},
#endif
{"ult", math_ult},
{"log", math_log},
{"max", math_max},
{"min", math_min},
{"modf", math_modf},
{"pow", math_pow},
{"rad", math_rad},
{"random", math_random},
{"randomseed", math_randomseed},
{"sinh", math_sinh},
{"sin", math_sin},
{"sqrt", math_sqrt},
{"tanh", math_tanh},
{"tan", math_tan},
{"type", math_type},
#if defined(LUA_COMPAT_MATHLIB)
{"atan2", math_atan},
{"cosh", math_cosh},
{"sinh", math_sinh},
{"tanh", math_tanh},
{"pow", math_pow},
{"frexp", math_frexp},
{"ldexp", math_ldexp},
{"log10", math_log10},
#endif
/* placeholders */
{"random", NULL},
{"randomseed", NULL},
{"pi", NULL},
{"huge", NULL},
{"maxinteger", NULL},
{"mininteger", NULL},
{NULL, NULL}
};
@@ -272,8 +752,13 @@ LUAMOD_API int luaopen_math (lua_State *L) {
luaL_newlib(L, mathlib);
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
lua_pushnumber(L, HUGE_VAL);
lua_pushnumber(L, (lua_Number)HUGE_VAL);
lua_setfield(L, -2, "huge");
lua_pushinteger(L, LUA_MAXINTEGER);
lua_setfield(L, -2, "maxinteger");
lua_pushinteger(L, LUA_MININTEGER);
lua_setfield(L, -2, "mininteger");
setrandfunc(L);
return 1;
}

View File

@@ -1,15 +1,17 @@
/*
** $Id: lmem.c,v 1.84.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lmem.c $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define lmem_c
#define LUA_CORE
#include "lprefix.h"
#include <stddef.h>
#include "lua.h"
#include "ldebug.h"
@@ -23,77 +25,191 @@
/*
** About the realloc function:
** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
** (`osize' is the old size, `nsize' is the new size)
** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
** ('osize' is the old size, 'nsize' is the new size)
**
** * frealloc(ud, NULL, x, s) creates a new block of size `s' (no
** matter 'x').
** - frealloc(ud, p, x, 0) frees the block 'p' and returns NULL.
** Particularly, frealloc(ud, NULL, 0, 0) does nothing,
** which is equivalent to free(NULL) in ISO C.
**
** * frealloc(ud, p, x, 0) frees the block `p'
** (in this specific case, frealloc must return NULL);
** particularly, frealloc(ud, NULL, 0, 0) does nothing
** (which is equivalent to free(NULL) in ANSI C)
** - frealloc(ud, NULL, x, s) creates a new block of size 's'
** (no matter 'x'). Returns NULL if it cannot create the new block.
**
** frealloc returns NULL if it cannot create or reallocate the area
** (any reallocation to an equal or smaller size cannot fail!)
** - otherwise, frealloc(ud, b, x, y) reallocates the block 'b' from
** size 'x' to size 'y'. Returns NULL if it cannot reallocate the
** block to the new size.
*/
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/*
** {==================================================================
** Functions to allocate/deallocate arrays for the Parser
** ===================================================================
*/
/*
** Minimum size for arrays during parsing, to avoid overhead of
** reallocating to size 1, then 2, and then 4. All these arrays
** will be reallocated to exact sizes or erased when parsing ends.
*/
#define MINSIZEARRAY 4
void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
int limit, const char *what) {
void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
int size_elems, int limit, const char *what) {
void *newblock;
int newsize;
if (*size >= limit/2) { /* cannot double it? */
if (*size >= limit) /* cannot grow even a little? */
int size = *psize;
if (nelems + 1 <= size) /* does one extra element still fit? */
return block; /* nothing to be done */
if (size >= limit / 2) { /* cannot double it? */
if (l_unlikely(size >= limit)) /* cannot grow even a little? */
luaG_runerror(L, "too many %s (limit is %d)", what, limit);
newsize = limit; /* still have at least one free place */
size = limit; /* still have at least one free place */
}
else {
newsize = (*size)*2;
if (newsize < MINSIZEARRAY)
newsize = MINSIZEARRAY; /* minimum size */
size *= 2;
if (size < MINSIZEARRAY)
size = MINSIZEARRAY; /* minimum size */
}
newblock = luaM_reallocv(L, block, *size, newsize, size_elems);
*size = newsize; /* update only when everything else is OK */
lua_assert(nelems + 1 <= size && size <= limit);
/* 'limit' ensures that multiplication will not overflow */
newblock = luaM_saferealloc_(L, block, cast_sizet(*psize) * size_elems,
cast_sizet(size) * size_elems);
*psize = size; /* update only when everything else is OK */
return newblock;
}
/*
** In prototypes, the size of the array is also its number of
** elements (to save memory). So, if it cannot shrink an array
** to its number of elements, the only option is to raise an
** error.
*/
void *luaM_shrinkvector_ (lua_State *L, void *block, int *size,
int final_n, int size_elem) {
void *newblock;
size_t oldsize = cast_sizet((*size) * size_elem);
size_t newsize = cast_sizet(final_n * size_elem);
lua_assert(newsize <= oldsize);
newblock = luaM_saferealloc_(L, block, oldsize, newsize);
*size = final_n;
return newblock;
}
/* }================================================================== */
l_noret luaM_toobig (lua_State *L) {
luaG_runerror(L, "memory allocation error: block too big");
}
/*
** Free memory
*/
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
/*
** generic allocation routine.
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
return callfrealloc(g, block, osize, nsize); /* try again */
}
else return NULL; /* cannot run an emergency collection */
}
/*
** Generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
void *newblock;
global_State *g = G(L);
size_t realosize = (block) ? osize : 0;
lua_assert((realosize == 0) == (block == NULL));
#if defined(HARDMEMTESTS)
if (nsize > realosize && g->gcrunning)
luaC_fullgc(L, 1); /* force a GC whenever possible */
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
api_check(L, nsize > realosize,
"realloc cannot fail when shrinking a block");
if (g->gcrunning) {
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
}
if (newblock == NULL)
luaD_throw(L, LUA_ERRMEM);
lua_assert((osize == 0) == (block == NULL));
newblock = firsttry(g, block, osize, nsize);
if (l_unlikely(newblock == NULL && nsize > 0)) {
newblock = tryagain(L, block, osize, nsize);
if (newblock == NULL) /* still no memory? */
return NULL; /* do not update 'GCdebt' */
}
lua_assert((nsize == 0) == (newblock == NULL));
g->GCdebt = (g->GCdebt + nsize) - realosize;
g->GCdebt = (g->GCdebt + nsize) - osize;
return newblock;
}
void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
size_t nsize) {
void *newblock = luaM_realloc_(L, block, osize, nsize);
if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */
luaM_error(L);
return newblock;
}
void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
if (size == 0)
return NULL; /* that's all */
else {
global_State *g = G(L);
void *newblock = firsttry(g, NULL, tag, size);
if (l_unlikely(newblock == NULL)) {
newblock = tryagain(L, NULL, tag, size);
if (newblock == NULL)
luaM_error(L);
}
g->GCdebt += size;
return newblock;
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lmem.h $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -14,44 +14,80 @@
#include "lua.h"
#define luaM_error(L) luaD_throw(L, LUA_ERRMEM)
/*
** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is
** always constant.
** The macro is somewhat complex to avoid warnings:
** +1 avoids warnings of "comparison has constant result";
** cast to 'void' avoids warnings of "value unused".
** This macro tests whether it is safe to multiply 'n' by the size of
** type 't' without overflows. Because 'e' is always constant, it avoids
** the runtime division MAX_SIZET/(e).
** (The macro is somewhat complex to avoid warnings: The 'sizeof'
** comparison avoids a runtime comparison when overflow cannot occur.
** The compiler should be able to optimize the real test by itself, but
** when it does it, it may give a warning about "comparison is always
** false due to limited range of data type"; the +1 tricks the compiler,
** avoiding this warning but also this optimization.)
*/
#define luaM_reallocv(L,b,on,n,e) \
(cast(void, \
(cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \
luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
#define luaM_testsize(n,e) \
(sizeof(n) >= sizeof(size_t) && cast_sizet((n)) + 1 > MAX_SIZET/(e))
#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)
#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0)
#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0]))
#define luaM_checksize(L,n,e) \
(luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0))
#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s))
#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t)))
#define luaM_newvector(L,n,t) \
cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s))
/*
** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that
** the result is not larger than 'n' and cannot overflow a 'size_t'
** when multiplied by the size of type 't'. (Assumes that 'n' is an
** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.)
*/
#define luaM_limitN(n,t) \
((cast_sizet(n) <= MAX_SIZET/sizeof(t)) ? (n) : \
cast_uint((MAX_SIZET/sizeof(t))))
/*
** Arrays of chars do not need any test
*/
#define luaM_reallocvchar(L,b,on,n) \
cast_charp(luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char)))
#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s))
#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b)))
#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b)))
#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0))
#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0))
#define luaM_newvectorchecked(L,n,t) \
(luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t))
#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
if ((nelems)+1 > (size)) \
((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
luaM_limitN(limit,t),e)))
#define luaM_reallocvector(L, v,oldn,n,t) \
((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
(cast(t *, luaM_realloc_(L, v, cast_sizet(oldn) * sizeof(t), \
cast_sizet(n) * sizeof(t))))
#define luaM_shrinkvector(L,v,size,fs,t) \
((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t))))
LUAI_FUNC l_noret luaM_toobig (lua_State *L);
/* not to be called directly */
LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
size_t size);
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
size_t size_elem, int limit,
LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize,
size_t size);
LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize);
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems,
int *size, int size_elem, int limit,
const char *what);
LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem,
int final_n, int size_elem);
LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: loadlib.c $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -8,22 +8,16 @@
** systems.
*/
/*
** if needed, includes windows header before everything else
*/
#if defined(_WIN32)
#include <windows.h>
#endif
#include <stdlib.h>
#include <string.h>
#define loadlib_c
#define LUA_LIB
#include "lprefix.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
@@ -31,40 +25,9 @@
/*
** LUA_PATH and LUA_CPATH are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH)
#define LUA_PATH "LUA_PATH"
#endif
#if !defined(LUA_CPATH)
#define LUA_CPATH "LUA_CPATH"
#endif
#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX
#define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
#if !defined (LUA_PATH_SEP)
#define LUA_PATH_SEP ";"
#endif
#if !defined (LUA_PATH_MARK)
#define LUA_PATH_MARK "?"
#endif
#if !defined (LUA_EXEC_DIR)
#define LUA_EXEC_DIR "!"
#endif
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
@@ -92,29 +55,53 @@
#define LUA_OFSEP "_"
/* table (in the registry) that keeps handles for all loaded C libraries */
#define CLIBS "_CLIBS"
/*
** key for table in the registry that keeps handles
** for all loaded C libraries
*/
static const char *const CLIBS = "_CLIBS";
#define LIB_FAIL "open"
/* error codes for ll_loadfunc */
#define ERRLIB 1
#define ERRFUNC 2
#define setprogdir(L) ((void)0)
#define setprogdir(L) ((void)0)
/*
** Special type equivalent to '(void*)' for functions in gcc
** (to suppress warnings when converting function pointers)
*/
typedef void (*voidf)(void);
/*
** system-dependent functions
*/
static void ll_unloadlib (void *lib);
static void *ll_load (lua_State *L, const char *path, int seeglb);
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
/*
** unload library 'lib'
*/
static void lsys_unloadlib (void *lib);
/*
** load C library in file 'path'. If 'seeglb', load with all names in
** the library global.
** Returns the library; in case of error, returns NULL plus an
** error string in the stack.
*/
static void *lsys_load (lua_State *L, const char *path, int seeglb);
/*
** Try to find a function named 'sym' in library 'lib'.
** Returns the function; in case of error, returns NULL plus an
** error string in the stack.
*/
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
#if defined(LUA_USE_DLOPEN)
#if defined(LUA_USE_DLOPEN) /* { */
/*
** {========================================================================
** This is an implementation of loadlib based on the dlfcn interface.
@@ -126,21 +113,35 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
#include <dlfcn.h>
static void ll_unloadlib (void *lib) {
/*
** Macro to convert pointer-to-void* to pointer-to-function. This cast
** is undefined according to ISO C, but POSIX assumes that it works.
** (The '__extension__' in gnu compilers is only to avoid warnings.)
*/
#if defined(__GNUC__)
#define cast_func(p) (__extension__ (lua_CFunction)(p))
#else
#define cast_func(p) ((lua_CFunction)(p))
#endif
static void lsys_unloadlib (void *lib) {
dlclose(lib);
}
static void *ll_load (lua_State *L, const char *path, int seeglb) {
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
if (lib == NULL) lua_pushstring(L, dlerror());
if (l_unlikely(lib == NULL))
lua_pushstring(L, dlerror());
return lib;
}
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
if (f == NULL) lua_pushstring(L, dlerror());
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = cast_func(dlsym(lib, sym));
if (l_unlikely(f == NULL))
lua_pushstring(L, dlerror());
return f;
}
@@ -148,14 +149,15 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
#elif defined(LUA_DL_DLL)
#elif defined(LUA_DL_DLL) /* }{ */
/*
** {======================================================================
** This is an implementation of loadlib for Windows using native functions.
** =======================================================================
*/
#undef setprogdir
#include <windows.h>
/*
** optional flags for LoadLibraryEx
@@ -165,21 +167,30 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
#endif
#undef setprogdir
/*
** Replace in the path (on the top of the stack) any occurrence
** of LUA_EXEC_DIR with the executable's path.
*/
static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff)/sizeof(char);
DWORD n = GetModuleFileNameA(NULL, buff, nsize);
DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName");
else {
*lb = '\0';
*lb = '\0'; /* cut name on the last '\\' to get the path */
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
static void pusherror (lua_State *L) {
int error = GetLastError();
char buffer[128];
@@ -190,12 +201,12 @@ static void pusherror (lua_State *L) {
lua_pushfstring(L, "system error %d\n", error);
}
static void ll_unloadlib (void *lib) {
static void lsys_unloadlib (void *lib) {
FreeLibrary((HMODULE)lib);
}
static void *ll_load (lua_State *L, const char *path, int seeglb) {
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);
(void)(seeglb); /* not used: symbols are 'global' by default */
if (lib == NULL) pusherror(L);
@@ -203,8 +214,8 @@ static void *ll_load (lua_State *L, const char *path, int seeglb) {
}
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym);
if (f == NULL) pusherror(L);
return f;
}
@@ -212,7 +223,7 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
/* }====================================================== */
#else
#else /* }{ */
/*
** {======================================================
** Fallback for other systems
@@ -226,29 +237,102 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
#define DLMSG "dynamic libraries not enabled; check your Lua installation"
static void ll_unloadlib (void *lib) {
static void lsys_unloadlib (void *lib) {
(void)(lib); /* not used */
}
static void *ll_load (lua_State *L, const char *path, int seeglb) {
static void *lsys_load (lua_State *L, const char *path, int seeglb) {
(void)(path); (void)(seeglb); /* not used */
lua_pushliteral(L, DLMSG);
return NULL;
}
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
(void)(lib); (void)(sym); /* not used */
lua_pushliteral(L, DLMSG);
return NULL;
}
/* }====================================================== */
#endif /* } */
/*
** {==================================================================
** Set Paths
** ===================================================================
*/
/*
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH_VAR)
#define LUA_PATH_VAR "LUA_PATH"
#endif
#if !defined(LUA_CPATH_VAR)
#define LUA_CPATH_VAR "LUA_CPATH"
#endif
static void *ll_checkclib (lua_State *L, const char *path) {
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
/*
** Set a path
*/
static void setpath (lua_State *L, const char *fieldname,
const char *envname,
const char *dft) {
const char *dftmark;
const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
const char *path = getenv(nver); /* try versioned name */
if (path == NULL) /* no versioned environment variable? */
path = getenv(envname); /* try unversioned name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, dft); /* use default */
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL)
lua_pushstring(L, path); /* nothing to change */
else { /* path contains a ";;": insert default path in its place */
size_t len = strlen(path);
luaL_Buffer b;
luaL_buffinit(L, &b);
if (path < dftmark) { /* is there a prefix before ';;'? */
luaL_addlstring(&b, path, dftmark - path); /* add it */
luaL_addchar(&b, *LUA_PATH_SEP);
}
luaL_addstring(&b, dft); /* add default */
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */
luaL_addchar(&b, *LUA_PATH_SEP);
luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark);
}
luaL_pushresult(&b);
}
setprogdir(L);
lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
lua_pop(L, 1); /* pop versioned variable name ('nver') */
}
/* }================================================================== */
/*
** return registry.CLIBS[path]
*/
static void *checkclib (lua_State *L, const char *path) {
void *plib;
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
lua_getfield(L, -1, path);
@@ -258,7 +342,11 @@ static void *ll_checkclib (lua_State *L, const char *path) {
}
static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
/*
** registry.CLIBS[path] = plib -- for queries
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries
*/
static void addtoclib (lua_State *L, const char *path, void *plib) {
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
lua_pushlightuserdata(L, plib);
lua_pushvalue(L, -1);
@@ -269,33 +357,49 @@ static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
/*
** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib
** handles in list CLIBS
*/
static int gctm (lua_State *L) {
int n = luaL_len(L, 1);
lua_Integer n = luaL_len(L, 1);
for (; n >= 1; n--) { /* for each handle, in reverse order */
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
ll_unloadlib(lua_touserdata(L, -1));
lsys_unloadlib(lua_touserdata(L, -1));
lua_pop(L, 1); /* pop handle */
}
return 0;
}
static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
void *reg = ll_checkclib(L, path); /* check loaded C libraries */
/* error codes for 'lookforfunc' */
#define ERRLIB 1
#define ERRFUNC 2
/*
** Look for a C function named 'sym' in a dynamically loaded library
** 'path'.
** First, check whether the library is already loaded; if not, try
** to load it.
** Then, if 'sym' is '*', return true (as library has been loaded).
** Otherwise, look for symbol 'sym' in the library and push a
** C function with that symbol.
** Return 0 and 'true' or a function in the stack; in case of
** errors, return an error code and an error message in the stack.
*/
static int lookforfunc (lua_State *L, const char *path, const char *sym) {
void *reg = checkclib(L, path); /* check loaded C libraries */
if (reg == NULL) { /* must load library? */
reg = ll_load(L, path, *sym == '*');
reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */
if (reg == NULL) return ERRLIB; /* unable to load library */
ll_addtoclib(L, path, reg);
addtoclib(L, path, reg);
}
if (*sym == '*') { /* loading only library (no function)? */
lua_pushboolean(L, 1); /* return 'true' */
return 0; /* no errors */
}
else {
lua_CFunction f = ll_sym(L, reg, sym);
lua_CFunction f = lsys_sym(L, reg, sym);
if (f == NULL)
return ERRFUNC; /* unable to find function */
lua_pushcfunction(L, f); /* else create new function */
@@ -307,14 +411,14 @@ static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
static int ll_loadlib (lua_State *L) {
const char *path = luaL_checkstring(L, 1);
const char *init = luaL_checkstring(L, 2);
int stat = ll_loadfunc(L, path, init);
if (stat == 0) /* no errors? */
int stat = lookforfunc(L, path, init);
if (l_likely(stat == 0)) /* no errors? */
return 1; /* return the loaded function */
else { /* error; error message is on stack top */
lua_pushnil(L);
luaL_pushfail(L);
lua_insert(L, -2);
lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
return 3; /* return nil, error message, and where */
return 3; /* return fail, error message, and where */
}
}
@@ -335,14 +439,42 @@ static int readable (const char *filename) {
}
static const char *pushnexttemplate (lua_State *L, const char *path) {
const char *l;
while (*path == *LUA_PATH_SEP) path++; /* skip separators */
if (*path == '\0') return NULL; /* no more templates */
l = strchr(path, *LUA_PATH_SEP); /* find next separator */
if (l == NULL) l = path + strlen(path);
lua_pushlstring(L, path, l - path); /* template */
return l;
/*
** Get the next name in '*path' = 'name1;name2;name3;...', changing
** the ending ';' to '\0' to create a zero-terminated string. Return
** NULL when list ends.
*/
static const char *getnextfilename (char **path, char *end) {
char *sep;
char *name = *path;
if (name == end)
return NULL; /* no more names */
else if (*name == '\0') { /* from previous iteration? */
*name = *LUA_PATH_SEP; /* restore separator */
name++; /* skip it */
}
sep = strchr(name, *LUA_PATH_SEP); /* find next separator */
if (sep == NULL) /* separator not found? */
sep = end; /* name goes until the end */
*sep = '\0'; /* finish file name */
*path = sep; /* will start next search from here */
return name;
}
/*
** Given a path such as ";blabla.so;blublu.so", pushes the string
**
** no file 'blabla.so'
** no file 'blublu.so'
*/
static void pusherrornotfound (lua_State *L, const char *path) {
luaL_Buffer b;
luaL_buffinit(L, &b);
luaL_addstring(&b, "no file '");
luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '");
luaL_addstring(&b, "'");
luaL_pushresult(&b);
}
@@ -350,21 +482,25 @@ static const char *searchpath (lua_State *L, const char *name,
const char *path,
const char *sep,
const char *dirsep) {
luaL_Buffer msg; /* to build error message */
luaL_buffinit(L, &msg);
if (*sep != '\0') /* non-empty separator? */
luaL_Buffer buff;
char *pathname; /* path with name inserted */
char *endpathname; /* its end */
const char *filename;
/* separator is non-empty and appears in 'name'? */
if (*sep != '\0' && strchr(name, *sep) != NULL)
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */
while ((path = pushnexttemplate(L, path)) != NULL) {
const char *filename = luaL_gsub(L, lua_tostring(L, -1),
LUA_PATH_MARK, name);
lua_remove(L, -2); /* remove path template */
luaL_buffinit(L, &buff);
/* add path to the buffer, replacing marks ('?') with the file name */
luaL_addgsub(&buff, path, LUA_PATH_MARK, name);
luaL_addchar(&buff, '\0');
pathname = luaL_buffaddr(&buff); /* writable list of file names */
endpathname = pathname + luaL_bufflen(&buff) - 1;
while ((filename = getnextfilename(&pathname, endpathname)) != NULL) {
if (readable(filename)) /* does file exist and is readable? */
return filename; /* return that file name */
lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
lua_remove(L, -2); /* remove file name */
luaL_addvalue(&msg); /* concatenate error msg. entry */
return lua_pushstring(L, filename); /* save and return name */
}
luaL_pushresult(&msg); /* create error message */
luaL_pushresult(&buff); /* push path to create error message */
pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */
return NULL; /* not found */
}
@@ -376,9 +512,9 @@ static int ll_searchpath (lua_State *L) {
luaL_optstring(L, 4, LUA_DIRSEP));
if (f != NULL) return 1;
else { /* error message is on top of the stack */
lua_pushnil(L);
luaL_pushfail(L);
lua_insert(L, -2);
return 2; /* return nil + error message */
return 2; /* return fail + error message */
}
}
@@ -389,20 +525,19 @@ static const char *findfile (lua_State *L, const char *name,
const char *path;
lua_getfield(L, lua_upvalueindex(1), pname);
path = lua_tostring(L, -1);
if (path == NULL)
luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
if (l_unlikely(path == NULL))
luaL_error(L, "'package.%s' must be a string", pname);
return searchpath(L, name, path, ".", dirsep);
}
static int checkload (lua_State *L, int stat, const char *filename) {
if (stat) { /* module loaded successfully? */
if (l_likely(stat)) { /* module loaded successfully? */
lua_pushstring(L, filename); /* will be 2nd argument to module */
return 2; /* return open function and file name */
}
else
return luaL_error(L, "error loading module " LUA_QS
" from file " LUA_QS ":\n\t%s",
return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s",
lua_tostring(L, 1), filename, lua_tostring(L, -1));
}
@@ -416,21 +551,29 @@ static int searcher_Lua (lua_State *L) {
}
/*
** Try to find a load function for module 'modname' at file 'filename'.
** First, change '.' to '_' in 'modname'; then, if 'modname' has
** the form X-Y (that is, it has an "ignore mark"), build a function
** name "luaopen_X" and look for it. (For compatibility, if that
** fails, it also tries "luaopen_Y".) If there is no ignore mark,
** look for a function named "luaopen_modname".
*/
static int loadfunc (lua_State *L, const char *filename, const char *modname) {
const char *funcname;
const char *openfunc;
const char *mark;
modname = luaL_gsub(L, modname, ".", LUA_OFSEP);
mark = strchr(modname, *LUA_IGMARK);
if (mark) {
int stat;
funcname = lua_pushlstring(L, modname, mark - modname);
funcname = lua_pushfstring(L, LUA_POF"%s", funcname);
stat = ll_loadfunc(L, filename, funcname);
openfunc = lua_pushlstring(L, modname, mark - modname);
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);
stat = lookforfunc(L, filename, openfunc);
if (stat != ERRFUNC) return stat;
modname = mark + 1; /* else go ahead and try old-style name */
}
funcname = lua_pushfstring(L, LUA_POF"%s", modname);
return ll_loadfunc(L, filename, funcname);
openfunc = lua_pushfstring(L, LUA_POF"%s", modname);
return lookforfunc(L, filename, openfunc);
}
@@ -455,8 +598,7 @@ static int searcher_Croot (lua_State *L) {
if (stat != ERRFUNC)
return checkload(L, 0, filename); /* real error */
else { /* open function not found */
lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
name, filename);
lua_pushfstring(L, "no module '%s' in file '%s'", name, filename);
return 1;
}
}
@@ -467,29 +609,34 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
lua_getfield(L, -1, name);
if (lua_isnil(L, -1)) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */
lua_pushfstring(L, "no field package.preload['%s']", name);
return 1;
}
else {
lua_pushliteral(L, ":preload:");
return 2;
}
}
static void findloader (lua_State *L, const char *name) {
int i;
luaL_Buffer msg; /* to build error message */
/* push 'package.searchers' to index 3 in the stack */
if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers")
!= LUA_TTABLE))
luaL_error(L, "'package.searchers' must be a table");
luaL_buffinit(L, &msg);
lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */
if (!lua_istable(L, 3))
luaL_error(L, LUA_QL("package.searchers") " must be a table");
/* iterate over available searchers to find a loader */
for (i = 1; ; i++) {
lua_rawgeti(L, 3, i); /* get a searcher */
if (lua_isnil(L, -1)) { /* no more searchers? */
luaL_addstring(&msg, "\n\t"); /* error-message prefix */
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
lua_pop(L, 1); /* remove nil */
luaL_buffsub(&msg, 2); /* remove prefix */
luaL_pushresult(&msg); /* create error message */
luaL_error(L, "module " LUA_QS " not found:%s",
name, lua_tostring(L, -1));
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));
}
lua_pushstring(L, name);
lua_call(L, 1, 2); /* call it */
@@ -499,222 +646,117 @@ static void findloader (lua_State *L, const char *name) {
lua_pop(L, 1); /* remove extra return */
luaL_addvalue(&msg); /* concatenate error message */
}
else
else { /* no error message */
lua_pop(L, 2); /* remove both returns */
luaL_buffsub(&msg, 2); /* remove prefix */
}
}
}
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_settop(L, 1); /* _LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, 2, name); /* _LOADED[name] */
lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */
/* else must load package */
lua_pop(L, 1); /* remove 'getfield' result */
findloader(L, name);
lua_pushstring(L, name); /* pass name as argument to module loader */
lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_rotate(L, -2, 1); /* function <-> loader data */
lua_pushvalue(L, 1); /* name is 1st argument to module loader */
lua_pushvalue(L, -3); /* loader data is 2nd argument */
/* stack: ...; loader data; loader function; mod. name; loader data */
lua_call(L, 2, 1); /* run loader to load module */
/* stack: ...; loader data; result from loader */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_getfield(L, 2, name);
if (lua_isnil(L, -1)) { /* module did not set a value? */
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
else
lua_pop(L, 1); /* pop nil */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */
lua_copy(L, -1, -2); /* replace loader result */
lua_setfield(L, 2, name); /* LOADED[name] = true */
}
return 1;
lua_rotate(L, -2, 1); /* loader data <-> module result */
return 2; /* return module result and loader data */
}
/* }====================================================== */
/*
** {======================================================
** 'module' function
** =======================================================
*/
#if defined(LUA_COMPAT_MODULE)
/*
** changes the environment variable of calling function
*/
static void set_env (lua_State *L) {
lua_Debug ar;
if (lua_getstack(L, 1, &ar) == 0 ||
lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
lua_iscfunction(L, -1))
luaL_error(L, LUA_QL("module") " not called from a Lua function");
lua_pushvalue(L, -2); /* copy new environment table to top */
lua_setupvalue(L, -2, 1);
lua_pop(L, 1); /* remove function */
}
static void dooptions (lua_State *L, int n) {
int i;
for (i = 2; i <= n; i++) {
if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */
lua_pushvalue(L, i); /* get option (a function) */
lua_pushvalue(L, -2); /* module */
lua_call(L, 1, 0);
}
}
}
static void modinit (lua_State *L, const char *modname) {
const char *dot;
lua_pushvalue(L, -1);
lua_setfield(L, -2, "_M"); /* module._M = module */
lua_pushstring(L, modname);
lua_setfield(L, -2, "_NAME");
dot = strrchr(modname, '.'); /* look for last dot in module name */
if (dot == NULL) dot = modname;
else dot++;
/* set _PACKAGE as package name (full module name minus last part) */
lua_pushlstring(L, modname, dot - modname);
lua_setfield(L, -2, "_PACKAGE");
}
static int ll_module (lua_State *L) {
const char *modname = luaL_checkstring(L, 1);
int lastarg = lua_gettop(L); /* last parameter */
luaL_pushmodule(L, modname, 1); /* get/create module table */
/* check whether table already has a _NAME field */
lua_getfield(L, -1, "_NAME");
if (!lua_isnil(L, -1)) /* is table an initialized module? */
lua_pop(L, 1);
else { /* no; initialize it */
lua_pop(L, 1);
modinit(L, modname);
}
lua_pushvalue(L, -1);
set_env(L);
dooptions(L, lastarg);
return 1;
}
static int ll_seeall (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
if (!lua_getmetatable(L, 1)) {
lua_createtable(L, 0, 1); /* create new metatable */
lua_pushvalue(L, -1);
lua_setmetatable(L, 1);
}
lua_pushglobaltable(L);
lua_setfield(L, -2, "__index"); /* mt.__index = _G */
return 0;
}
#endif
/* }====================================================== */
/* auxiliary mark (for internal use) */
#define AUXMARK "\1"
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
static void setpath (lua_State *L, const char *fieldname, const char *envname1,
const char *envname2, const char *def) {
const char *path = getenv(envname1);
if (path == NULL) /* no environment variable? */
path = getenv(envname2); /* try alternative name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, def); /* use default */
else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2);
}
setprogdir(L);
lua_setfield(L, -2, fieldname);
}
static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib},
{"searchpath", ll_searchpath},
#if defined(LUA_COMPAT_MODULE)
{"seeall", ll_seeall},
#endif
/* placeholders */
{"preload", NULL},
{"cpath", NULL},
{"path", NULL},
{"searchers", NULL},
{"loaded", NULL},
{NULL, NULL}
};
static const luaL_Reg ll_funcs[] = {
#if defined(LUA_COMPAT_MODULE)
{"module", ll_module},
#endif
{"require", ll_require},
{NULL, NULL}
};
static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] =
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
static const lua_CFunction searchers[] = {
searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
/* fill it with pre-defined searchers */
/* fill it with predefined searchers */
for (i=0; searchers[i] != NULL; i++) {
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
lua_pushcclosure(L, searchers[i], 1);
lua_rawseti(L, -2, i+1);
}
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
}
/*
** create table CLIBS to keep track of loaded C libraries,
** setting a finalizer to close all libraries when closing state.
*/
static void createclibstable (lua_State *L) {
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */
lua_createtable(L, 0, 1); /* create metatable for CLIBS */
lua_pushcfunction(L, gctm);
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
lua_setmetatable(L, -2);
}
LUAMOD_API int luaopen_package (lua_State *L) {
/* create table CLIBS to keep track of loaded C libraries */
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);
lua_createtable(L, 0, 1); /* metatable for CLIBS */
lua_pushcfunction(L, gctm);
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
lua_setmetatable(L, -2);
/* create `package' table */
luaL_newlib(L, pk_funcs);
createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L);
#if defined(LUA_COMPAT_LOADERS)
lua_pushvalue(L, -1); /* make a copy of 'searchers' table */
lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */
#endif
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */
/* set field 'path' */
setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT);
/* set field 'cpath' */
setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT);
/* set paths */
setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field `loaded' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
/* set field 'loaded' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded");
/* set field `preload' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
/* set field 'preload' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */

View File

@@ -1,17 +1,22 @@
/*
** $Id: lobject.c,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lobject.c $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
#define lobject_c
#define LUA_CORE
#include "lprefix.h"
#include <locale.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define lobject_c
#define LUA_CORE
#include "lua.h"
#include "lctype.h"
@@ -24,36 +29,11 @@
#include "lvm.h"
LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
/*
** converts an integer to a "floating point byte", represented as
** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
** eeeee != 0 and (xxx) otherwise.
** Computes ceil(log2(x))
*/
int luaO_int2fb (unsigned int x) {
int e = 0; /* exponent */
if (x < 8) return x;
while (x >= 0x10) {
x = (x+1) >> 1;
e++;
}
return ((e+1) << 3) | (cast_int(x) - 8);
}
/* converts back */
int luaO_fb2int (int x) {
int e = (x >> 3) & 0x1f;
if (e == 0) return x;
else return ((x & 7) + 8) << (e - 1);
}
int luaO_ceillog2 (unsigned int x) {
static const lu_byte log_2[256] = {
static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
@@ -70,31 +50,94 @@ int luaO_ceillog2 (unsigned int x) {
}
lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2) {
static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
lua_Integer v2) {
switch (op) {
case LUA_OPADD: return luai_numadd(NULL, v1, v2);
case LUA_OPSUB: return luai_numsub(NULL, v1, v2);
case LUA_OPMUL: return luai_nummul(NULL, v1, v2);
case LUA_OPDIV: return luai_numdiv(NULL, v1, v2);
case LUA_OPMOD: return luai_nummod(NULL, v1, v2);
case LUA_OPPOW: return luai_numpow(NULL, v1, v2);
case LUA_OPUNM: return luai_numunm(NULL, v1);
case LUA_OPADD: return intop(+, v1, v2);
case LUA_OPSUB:return intop(-, v1, v2);
case LUA_OPMUL:return intop(*, v1, v2);
case LUA_OPMOD: return luaV_mod(L, v1, v2);
case LUA_OPIDIV: return luaV_idiv(L, v1, v2);
case LUA_OPBAND: return intop(&, v1, v2);
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
}
}
static lua_Number numarith (lua_State *L, int op, lua_Number v1,
lua_Number v2) {
switch (op) {
case LUA_OPADD: return luai_numadd(L, v1, v2);
case LUA_OPSUB: return luai_numsub(L, v1, v2);
case LUA_OPMUL: return luai_nummul(L, v1, v2);
case LUA_OPDIV: return luai_numdiv(L, v1, v2);
case LUA_OPPOW: return luai_numpow(L, v1, v2);
case LUA_OPIDIV: return luai_numidiv(L, v1, v2);
case LUA_OPUNM: return luai_numunm(L, v1);
case LUA_OPMOD: return luaV_modf(L, v1, v2);
default: lua_assert(0); return 0;
}
}
int luaO_rawarith (lua_State *L, int op, const TValue *p1, const TValue *p2,
TValue *res) {
switch (op) {
case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
case LUA_OPSHL: case LUA_OPSHR:
case LUA_OPBNOT: { /* operate only on integers */
lua_Integer i1; lua_Integer i2;
if (tointegerns(p1, &i1) && tointegerns(p2, &i2)) {
setivalue(res, intarith(L, op, i1, i2));
return 1;
}
else return 0; /* fail */
}
case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */
lua_Number n1; lua_Number n2;
if (tonumberns(p1, n1) && tonumberns(p2, n2)) {
setfltvalue(res, numarith(L, op, n1, n2));
return 1;
}
else return 0; /* fail */
}
default: { /* other operations */
lua_Number n1; lua_Number n2;
if (ttisinteger(p1) && ttisinteger(p2)) {
setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2)));
return 1;
}
else if (tonumberns(p1, n1) && tonumberns(p2, n2)) {
setfltvalue(res, numarith(L, op, n1, n2));
return 1;
}
else return 0; /* fail */
}
}
}
void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
StkId res) {
if (!luaO_rawarith(L, op, p1, p2, s2v(res))) {
/* could not perform raw operation; try metamethod */
luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
}
}
int luaO_hexavalue (int c) {
if (lisdigit(c)) return c - '0';
else return ltolower(c) - 'a' + 10;
else return (ltolower(c) - 'a') + 10;
}
#if !defined(lua_strx2number)
#include <math.h>
static int isneg (const char **s) {
if (**s == '-') { (*s)++; return 1; }
else if (**s == '+') (*s)++;
@@ -102,131 +145,404 @@ static int isneg (const char **s) {
}
static lua_Number readhexa (const char **s, lua_Number r, int *count) {
for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */
r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s)));
(*count)++;
}
return r;
}
/*
** convert an hexadecimal numeric string to a number, following
** {==================================================================
** Lua's implementation for 'lua_strx2number'
** ===================================================================
*/
#if !defined(lua_strx2number)
/* maximum number of significant digits to read (to avoid overflows
even with single floats) */
#define MAXSIGDIG 30
/*
** convert a hexadecimal numeric string to a number, following
** C99 specification for 'strtod'
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
lua_Number r = 0.0;
int e = 0, i = 0;
int neg = 0; /* 1 if number is negative */
*endptr = cast(char *, s); /* nothing is valid yet */
int dot = lua_getlocaledecpoint();
lua_Number r = l_mathop(0.0); /* result (accumulator) */
int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
int neg; /* 1 if number is negative */
int hasdot = 0; /* true after seen a dot */
*endptr = cast_charp(s); /* nothing is valid yet */
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check signal */
neg = isneg(&s); /* check sign */
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */
s += 2; /* skip '0x' */
r = readhexa(&s, r, &i); /* read integer part */
if (*s == '.') {
s++; /* skip dot */
r = readhexa(&s, r, &e); /* read fractional part */
return l_mathop(0.0); /* invalid format (no '0x') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */
if (*s == dot) {
if (hasdot) break; /* second dot? stop loop */
else hasdot = 1;
}
else if (lisxdigit(cast_uchar(*s))) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
nosigdig++;
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */
if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
if (i == 0 && e == 0)
return 0.0; /* invalid format (no digit) */
e *= -4; /* each fractional digit divides value by 2^-4 */
*endptr = cast(char *, s); /* valid up to here */
if (nosigdig + sigdig == 0) /* no digits? */
return l_mathop(0.0); /* invalid format */
*endptr = cast_charp(s); /* valid up to here */
e *= 4; /* each digit multiplies/divides value by 2^4 */
if (*s == 'p' || *s == 'P') { /* exponent part? */
int exp1 = 0;
int neg1;
int exp1 = 0; /* exponent value */
int neg1; /* exponent sign */
s++; /* skip 'p' */
neg1 = isneg(&s); /* signal */
neg1 = isneg(&s); /* sign */
if (!lisdigit(cast_uchar(*s)))
goto ret; /* must have at least one digit */
return l_mathop(0.0); /* invalid; must have at least one digit */
while (lisdigit(cast_uchar(*s))) /* read exponent */
exp1 = exp1 * 10 + *(s++) - '0';
if (neg1) exp1 = -exp1;
e += exp1;
*endptr = cast_charp(s); /* valid up to here */
}
*endptr = cast(char *, s); /* valid up to here */
ret:
if (neg) r = -r;
return l_mathop(ldexp)(r, e);
}
#endif
/* }====================================================== */
int luaO_str2d (const char *s, size_t len, lua_Number *result) {
/* maximum length of a numeral to be converted to a number */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL on
** fail or the address of the ending '\0' on success. ('mode' == 'x')
** means a hexadecimal numeral.
*/
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
return 0;
else if (strpbrk(s, "xX")) /* hexa? */
*result = lua_strx2number(s, &endptr);
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
: lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized? */
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
return (*endptr == '\0') ? endptr : NULL; /* OK iff no trailing chars */
}
/*
** Convert string 's' to a Lua number (put in 'result') handling the
** current locale.
** This function accepts both the current locale or a dot as the radix
** mark. If the conversion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
** The variable 'mode' checks for special characters in the string:
** - 'n' means 'inf' or 'nan' (which should be rejected)
** - 'x' means a hexadecimal numeral
** - '.' just optimizes the search for the common case (no special chars)
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN"); /* look for special chars */
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
const char *pdot = strchr(s, '.');
if (pdot == NULL || strlen(s) > L_MAXLENNUM)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
int neg;
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s);
if (s[0] == '0' &&
(s[1] == 'x' || s[1] == 'X')) { /* hex? */
s += 2; /* skip '0x' */
for (; lisxdigit(cast_uchar(*s)); s++) {
a = a * 16 + luaO_hexavalue(*s);
empty = 0;
}
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0;
}
}
while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */
if (empty || *s != '\0') return NULL; /* something wrong in the numeral */
else {
*result = l_castU2S((neg) ? 0u - a : a);
return s;
}
}
size_t luaO_str2num (const char *s, TValue *o) {
lua_Integer i; lua_Number n;
const char *e;
if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */
setivalue(o, i);
}
else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */
setfltvalue(o, n);
}
else
*result = lua_str2number(s, &endptr);
if (endptr == s) return 0; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (endptr == s + len); /* OK if no trailing characters */
return 0; /* conversion failed */
return (e - s) + 1; /* success; return string size */
}
int luaO_utf8esc (char *buff, unsigned long x) {
int n = 1; /* number of bytes put in buffer (backwards) */
lua_assert(x <= 0x7FFFFFFFu);
if (x < 0x80) /* ascii? */
buff[UTF8BUFFSZ - 1] = cast_char(x);
else { /* need continuation bytes */
unsigned int mfb = 0x3f; /* maximum that fits in first byte */
do { /* add continuation bytes */
buff[UTF8BUFFSZ - (n++)] = cast_char(0x80 | (x & 0x3f));
x >>= 6; /* remove added bits */
mfb >>= 1; /* now there is one less bit available in first byte */
} while (x > mfb); /* still needs continuation byte? */
buff[UTF8BUFFSZ - n] = cast_char((~mfb << 1) | x); /* add first byte */
}
return n;
}
/*
** Maximum length of the conversion of a number to a string. Must be
** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
** (For a long long int, this is 19 digits plus a sign and a final '\0',
** adding to 21. For a long double, it can go to a sign, 33 digits,
** the dot, an exponent letter, an exponent sign, 5 exponent digits,
** and a final '\0', adding to 43.)
*/
#define MAXNUMBER2STR 44
/*
** Convert a number object to a string, adding it to a buffer
*/
static int tostringbuff (TValue *obj, char *buff) {
int len;
lua_assert(ttisnumber(obj));
if (ttisinteger(obj))
len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
else {
len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj));
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
buff[len++] = lua_getlocaledecpoint();
buff[len++] = '0'; /* adds '.0' to result */
}
}
return len;
}
/*
** Convert a number object to a Lua string, replacing the value at 'obj'
*/
void luaO_tostring (lua_State *L, TValue *obj) {
char buff[MAXNUMBER2STR];
int len = tostringbuff(obj, buff);
setsvalue(L, obj, luaS_newlstr(L, buff, len));
}
static void pushstr (lua_State *L, const char *str, size_t l) {
setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
/*
** {==================================================================
** 'luaO_pushvfstring'
** ===================================================================
*/
/*
** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
** Push given string to the stack, as part of the result, and
** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/
static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top.p++; /* may use one slot from EXTRA_STACK */
if (!buff->pushed) /* no previous string on the stack? */
buff->pushed = 1; /* now there is one */
else /* join previous string with new one */
luaV_concat(L, 2);
}
/* this function handles only `%d', `%c', %f, %p, and `%s' formats */
/*
** empty the buffer space into the stack
*/
static void clearbuff (BuffFS *buff) {
pushstr(buff, buff->space, buff->blen); /* push buffer contents */
buff->blen = 0; /* space now is empty */
}
/*
** Get a space of size 'sz' in the buffer. If buffer has not enough
** space, empty it. 'sz' must fit in an empty buffer.
*/
static char *getbuff (BuffFS *buff, int sz) {
lua_assert(buff->blen <= BUFVFS); lua_assert(sz <= BUFVFS);
if (sz > BUFVFS - buff->blen) /* not enough space? */
clearbuff(buff);
return buff->space + buff->blen;
}
#define addsize(b,sz) ((b)->blen += (sz))
/*
** Add 'str' to the buffer. If string is larger than the buffer space,
** push the string directly to the stack.
*/
static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
if (slen <= BUFVFS) { /* does string fit into buffer? */
char *bf = getbuff(buff, cast_int(slen));
memcpy(bf, str, slen); /* add string to buffer */
addsize(buff, cast_int(slen));
}
else { /* string larger than buffer */
clearbuff(buff); /* string comes after buffer's content */
pushstr(buff, str, slen); /* push string */
}
}
/*
** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
int len = tostringbuff(num, numbuff); /* format number into 'numbuff' */
addsize(buff, len);
}
/*
** this function handles only '%d', '%c', '%f', '%p', '%s', and '%%'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
luaD_checkstack(L, 2); /* fmt + item */
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
case 's': {
BuffFS buff; /* holds last part of the result */
const char *e; /* points to next '%' */
buff.pushed = buff.blen = 0;
buff.L = L;
while ((e = strchr(fmt, '%')) != NULL) {
addstr2buff(&buff, fmt, e - fmt); /* add 'fmt' up to '%' */
switch (*(e + 1)) { /* conversion specifier */
case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
addstr2buff(&buff, s, strlen(s));
break;
}
case 'c': {
char buff;
buff = cast(char, va_arg(argp, int));
pushstr(L, &buff, 1);
case 'c': { /* an 'int' as a character */
char c = cast_uchar(va_arg(argp, int));
addstr2buff(&buff, &c, sizeof(char));
break;
}
case 'd': {
setnvalue(L->top++, cast_num(va_arg(argp, int)));
case 'd': { /* an 'int' */
TValue num;
setivalue(&num, va_arg(argp, int));
addnum2buff(&buff, &num);
break;
}
case 'f': {
setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
case 'I': { /* a 'lua_Integer' */
TValue num;
setivalue(&num, cast(lua_Integer, va_arg(argp, l_uacInt)));
addnum2buff(&buff, &num);
break;
}
case 'p': {
char buff[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */
int l = sprintf(buff, "%p", va_arg(argp, void *));
pushstr(L, buff, l);
case 'f': { /* a 'lua_Number' */
TValue num;
setfltvalue(&num, cast_num(va_arg(argp, l_uacNumber)));
addnum2buff(&buff, &num);
break;
}
case 'p': { /* a pointer */
const int sz = 3 * sizeof(void*) + 8; /* enough space for '%p' */
char *bf = getbuff(&buff, sz);
void *p = va_arg(argp, void *);
int len = lua_pointer2str(bf, sz, p);
addsize(&buff, len);
break;
}
case 'U': { /* a 'long' as a UTF-8 sequence */
char bf[UTF8BUFFSZ];
int len = luaO_utf8esc(bf, va_arg(argp, long));
addstr2buff(&buff, bf + UTF8BUFFSZ - len, len);
break;
}
case '%': {
pushstr(L, "%", 1);
addstr2buff(&buff, "%", 1);
break;
}
default: {
luaG_runerror(L,
"invalid option " LUA_QL("%%%c") " to " LUA_QL("lua_pushfstring"),
*(e + 1));
luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'",
*(e + 1));
}
}
n += 2;
fmt = e+2;
fmt = e + 2; /* skip '%' and the specifier */
}
luaD_checkstack(L, 1);
pushstr(L, fmt, strlen(fmt));
if (n > 0) luaV_concat(L, n + 1);
return svalue(L->top - 1);
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
return svalue(s2v(L->top.p - 1));
}
@@ -239,9 +555,8 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
return msg;
}
/* }================================================================== */
/* number of chars of a literal string without the ending \0 */
#define LL(x) (sizeof(x)/sizeof(char) - 1)
#define RETS "..."
#define PRE "[string \""
@@ -249,36 +564,36 @@ const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
#define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) )
void luaO_chunkid (char *out, const char *source, size_t bufflen) {
size_t l = strlen(source);
void luaO_chunkid (char *out, const char *source, size_t srclen) {
size_t bufflen = LUA_IDSIZE; /* free space in buffer */
if (*source == '=') { /* 'literal' source */
if (l <= bufflen) /* small enough? */
memcpy(out, source + 1, l * sizeof(char));
if (srclen <= bufflen) /* small enough? */
memcpy(out, source + 1, srclen * sizeof(char));
else { /* truncate it */
addstr(out, source + 1, bufflen - 1);
*out = '\0';
}
}
else if (*source == '@') { /* file name */
if (l <= bufflen) /* small enough? */
memcpy(out, source + 1, l * sizeof(char));
if (srclen <= bufflen) /* small enough? */
memcpy(out, source + 1, srclen * sizeof(char));
else { /* add '...' before rest of name */
addstr(out, RETS, LL(RETS));
bufflen -= LL(RETS);
memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char));
memcpy(out, source + 1 + srclen - bufflen, bufflen * sizeof(char));
}
}
else { /* string; format as [string "source"] */
const char *nl = strchr(source, '\n'); /* find first new line (if any) */
addstr(out, PRE, LL(PRE)); /* add prefix */
bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */
if (l < bufflen && nl == NULL) { /* small one-line source? */
addstr(out, source, l); /* keep it */
if (srclen < bufflen && nl == NULL) { /* small one-line source? */
addstr(out, source, srclen); /* keep it */
}
else {
if (nl != NULL) l = nl - source; /* stop at first newline */
if (l > bufflen) l = bufflen;
addstr(out, source, l);
if (nl != NULL) srclen = nl - source; /* stop at first newline */
if (srclen > bufflen) srclen = bufflen;
addstr(out, source, srclen);
addstr(out, RETS, LL(RETS));
}
memcpy(out, POS, (LL(POS) + 1) * sizeof(char));

File diff suppressed because it is too large Load Diff

View File

@@ -1,107 +1,104 @@
/*
** $Id: lopcodes.c,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lopcodes.c $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
#define lopcodes_c
#define LUA_CORE
#include "lprefix.h"
#include "lopcodes.h"
/* ORDER OP */
LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"MOVE",
"LOADK",
"LOADKX",
"LOADBOOL",
"LOADNIL",
"GETUPVAL",
"GETTABUP",
"GETTABLE",
"SETTABUP",
"SETUPVAL",
"SETTABLE",
"NEWTABLE",
"SELF",
"ADD",
"SUB",
"MUL",
"DIV",
"MOD",
"POW",
"UNM",
"NOT",
"LEN",
"CONCAT",
"JMP",
"EQ",
"LT",
"LE",
"TEST",
"TESTSET",
"CALL",
"TAILCALL",
"RETURN",
"FORLOOP",
"FORPREP",
"TFORCALL",
"TFORLOOP",
"SETLIST",
"CLOSURE",
"VARARG",
"EXTRAARG",
NULL
};
#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
/* T A B C mode opcode */
opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */
,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */
,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */
,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */
,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */
,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */
,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */
,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */
,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */
,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */
,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */
,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */
,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */
,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */
,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */
/* MM OT IT T A mode opcode */
opmode(0, 0, 0, 0, 1, iABC) /* OP_MOVE */
,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADI */
,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADF */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADK */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADKX */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADFALSE */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LFALSESKIP */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADTRUE */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADNIL */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETUPVAL */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABUP */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETTABLE */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETI */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETFIELD */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABUP */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETTABLE */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETI */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETFIELD */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NEWTABLE */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SELF */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDI */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADDK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUBK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MULK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MODK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_POWK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIVK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIVK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BANDK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BORK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXORK */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHRI */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHLI */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_ADD */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SUB */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MUL */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_MOD */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_POW */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_DIV */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_IDIV */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BAND */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BOR */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BXOR */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHL */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_SHR */
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBIN */
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINI*/
,opmode(1, 0, 0, 0, 0, iABC) /* OP_MMBINK*/
,opmode(0, 0, 0, 0, 1, iABC) /* OP_UNM */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_BNOT */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_NOT */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LEN */
,opmode(0, 0, 0, 0, 1, iABC) /* OP_CONCAT */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_CLOSE */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TBC */
,opmode(0, 0, 0, 0, 0, isJ) /* OP_JMP */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQ */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_LT */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_LE */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQK */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_EQI */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_LTI */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_LEI */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_GTI */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_GEI */
,opmode(0, 0, 0, 1, 0, iABC) /* OP_TEST */
,opmode(0, 0, 0, 1, 1, iABC) /* OP_TESTSET */
,opmode(0, 1, 1, 0, 1, iABC) /* OP_CALL */
,opmode(0, 1, 1, 0, 1, iABC) /* OP_TAILCALL */
,opmode(0, 0, 1, 0, 0, iABC) /* OP_RETURN */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN0 */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_RETURN1 */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORLOOP */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_FORPREP */
,opmode(0, 0, 0, 0, 0, iABx) /* OP_TFORPREP */
,opmode(0, 0, 0, 0, 0, iABC) /* OP_TFORCALL */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
};

View File

@@ -1,5 +1,5 @@
/*
** $Id: lopcodes.h,v 1.142.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lopcodes.h $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -11,75 +11,100 @@
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
We assume that instructions are unsigned 32-bit integers.
All instructions have an opcode in the first 7 bits.
Instructions can have the following formats:
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
corresponding unsigned argument.
===========================================================================*/
enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
/*
** size and position of opcode arguments.
*/
#define SIZE_C 9
#define SIZE_B 9
#define SIZE_Bx (SIZE_C + SIZE_B)
#define SIZE_C 8
#define SIZE_B 8
#define SIZE_Bx (SIZE_C + SIZE_B + 1)
#define SIZE_A 8
#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A)
#define SIZE_Ax (SIZE_Bx + SIZE_A)
#define SIZE_sJ (SIZE_Bx + SIZE_A)
#define SIZE_OP 6
#define SIZE_OP 7
#define POS_OP 0
#define POS_A (POS_OP + SIZE_OP)
#define POS_C (POS_A + SIZE_A)
#define POS_B (POS_C + SIZE_C)
#define POS_Bx POS_C
#define POS_k (POS_A + SIZE_A)
#define POS_B (POS_k + 1)
#define POS_C (POS_B + SIZE_B)
#define POS_Bx POS_k
#define POS_Ax POS_A
#define POS_sJ POS_A
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
** we use (signed) 'int' to manipulate most arguments,
** so they must fit in ints.
*/
#if SIZE_Bx < LUAI_BITSINT-1
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */
/* Check whether type 'int' has at least 'b' bits ('b' < 32) */
#define L_INTHASBITS(b) ((UINT_MAX >> ((b) - 1)) >= 1)
#if L_INTHASBITS(SIZE_Bx)
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
#else
#define MAXARG_Bx MAX_INT
#define MAXARG_sBx MAX_INT
#define MAXARG_Bx MAX_INT
#endif
#if SIZE_Ax < LUAI_BITSINT-1
#define OFFSET_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */
#if L_INTHASBITS(SIZE_Ax)
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
#else
#define MAXARG_Ax MAX_INT
#endif
#if L_INTHASBITS(SIZE_sJ)
#define MAXARG_sJ ((1 << SIZE_sJ) - 1)
#else
#define MAXARG_sJ MAX_INT
#endif
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
#define OFFSET_sJ (MAXARG_sJ >> 1)
/* creates a mask with `n' 1 bits at position `p' */
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
#define OFFSET_sC (MAXARG_C >> 1)
#define int2sC(i) ((i) + OFFSET_sC)
#define sC2int(i) ((i) - OFFSET_sC)
/* creates a mask with 'n' 1 bits at position 'p' */
#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
/* creates a mask with `n' 0 bits at position `p' */
/* creates a mask with 'n' 0 bits at position 'p' */
#define MASK0(n,p) (~MASK1(n,p))
/*
@@ -90,33 +115,49 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
#define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0)))
#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
#define getarg(i,pos,size) (cast_int(((i)>>(pos)) & MASK1(size,0)))
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
#define GETARG_B(i) getarg(i, POS_B, SIZE_B)
#define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
#define GETARG_sB(i) sC2int(GETARG_B(i))
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
#define GETARG_C(i) getarg(i, POS_C, SIZE_C)
#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
#define GETARG_sC(i) sC2int(GETARG_C(i))
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx)
#define TESTARG_k(i) check_exp(checkopm(i, iABC), (cast_int(((i) & (1u << POS_k)))))
#define GETARG_k(i) check_exp(checkopm(i, iABC), getarg(i, POS_k, 1))
#define SETARG_k(i,v) setarg(i, v, POS_k, 1)
#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx)
#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax)
#define GETARG_Ax(i) check_exp(checkopm(i, iAx), getarg(i, POS_Ax, SIZE_Ax))
#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax)
#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
#define GETARG_sBx(i) \
check_exp(checkopm(i, iAsBx), getarg(i, POS_Bx, SIZE_Bx) - OFFSET_sBx)
#define SETARG_sBx(i,b) SETARG_Bx((i),cast_uint((b)+OFFSET_sBx))
#define GETARG_sJ(i) \
check_exp(checkopm(i, isJ), getarg(i, POS_sJ, SIZE_sJ) - OFFSET_sJ)
#define SETARG_sJ(i,j) \
setarg(i, cast_uint((j)+OFFSET_sJ), POS_sJ, SIZE_sJ)
#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \
#define CREATE_ABCk(o,a,b,c,k) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, b)<<POS_B) \
| (cast(Instruction, c)<<POS_C))
| (cast(Instruction, c)<<POS_C) \
| (cast(Instruction, k)<<POS_k))
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
@@ -125,24 +166,14 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_Ax))
#define CREATE_sJ(o,j,k) ((cast(Instruction, o) << POS_OP) \
| (cast(Instruction, j) << POS_sJ) \
| (cast(Instruction, k) << POS_k))
/*
** Macros to operate RK indices
*/
/* this bit 1 means constant (0 means register) */
#define BITRK (1 << (SIZE_B - 1))
/* test whether value is a constant */
#define ISK(x) ((x) & BITRK)
/* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK)
#define MAXINDEXRK (BITRK - 1)
/* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK)
#if !defined(MAXINDEXRK) /* (for debugging only) */
#define MAXINDEXRK MAXARG_B
#endif
/*
@@ -152,137 +183,223 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
** R[x] - register
** K[x] - constant (in constant table)
** RK(x) == if k(i) then K[x] else R[x]
*/
/*
** grep "ORDER OP" if you change these enums
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
** has extra descriptions in the notes after the enumeration.
*/
typedef enum {
/*----------------------------------------------------------------------
name args description
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
OP_LOADKX,/* A R(A) := Kst(extra arg) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
OP_MOVE,/* A B R[A] := R[B] */
OP_LOADI,/* A sBx R[A] := sBx */
OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
OP_LOADK,/* A Bx R[A] := K[Bx] */
OP_LOADKX,/* A R[A] := K[extra arg] */
OP_LOADFALSE,/* A R[A] := false */
OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */
OP_LOADTRUE,/* A R[A] := true */
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */
OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */
OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */
OP_GETI,/* A B C R[A] := R[B][C] */
OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */
OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */
OP_SETUPVAL,/* A B UpValue[B] := R(A) */
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */
OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */
OP_SETI,/* A B C R[A][B] := RK(C) */
OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
OP_NEWTABLE,/* A B C k R[A] := {} */
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
OP_UNM,/* A B R(A) := -R(B) */
OP_NOT,/* A B R(A) := not R(B) */
OP_LEN,/* A B R(A) := length of R(B) */
OP_ADDI,/* A B sC R[A] := R[B] + sC */
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */
OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */
OP_MULK,/* A B C R[A] := R[B] * K[C]:number */
OP_MODK,/* A B C R[A] := R[B] % K[C]:number */
OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */
OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */
OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */
OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A) + 1 */
OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */
OP_BXORK,/* A B C R[A] := R[B] ~ K[C]:integer */
OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
OP_SHRI,/* A B sC R[A] := R[B] >> sC */
OP_SHLI,/* A B sC R[A] := sC << R[B] */
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
OP_ADD,/* A B C R[A] := R[B] + R[C] */
OP_SUB,/* A B C R[A] := R[B] - R[C] */
OP_MUL,/* A B C R[A] := R[B] * R[C] */
OP_MOD,/* A B C R[A] := R[B] % R[C] */
OP_POW,/* A B C R[A] := R[B] ^ R[C] */
OP_DIV,/* A B C R[A] := R[B] / R[C] */
OP_IDIV,/* A B C R[A] := R[B] // R[C] */
OP_FORLOOP,/* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */
OP_BAND,/* A B C R[A] := R[B] & R[C] */
OP_BOR,/* A B C R[A] := R[B] | R[C] */
OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
OP_SHL,/* A B C R[A] := R[B] << R[C] */
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
OP_UNM,/* A B R[A] := -R[B] */
OP_BNOT,/* A B R[A] := ~R[B] */
OP_NOT,/* A B R[A] := not R[B] */
OP_LEN,/* A B R[A] := #R[B] (length operator) */
OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_CONCAT,/* A B R[A] := R[A].. ... ..R[A + B - 1] */
OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
OP_CLOSE,/* A close all upvalues >= R[A] */
OP_TBC,/* A mark variable A "to be closed" */
OP_JMP,/* sJ pc += sJ */
OP_EQ,/* A B k if ((R[A] == R[B]) ~= k) then pc++ */
OP_LT,/* A B k if ((R[A] < R[B]) ~= k) then pc++ */
OP_LE,/* A B k if ((R[A] <= R[B]) ~= k) then pc++ */
OP_EQK,/* A B k if ((R[A] == K[B]) ~= k) then pc++ */
OP_EQI,/* A sB k if ((R[A] == sB) ~= k) then pc++ */
OP_LTI,/* A sB k if ((R[A] < sB) ~= k) then pc++ */
OP_LEI,/* A sB k if ((R[A] <= sB) ~= k) then pc++ */
OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
OP_TEST,/* A k if (not R[A] == k) then pc++ */
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */
OP_RETURN0,/* return */
OP_RETURN1,/* A return R[A] */
OP_FORLOOP,/* A Bx update counters; if loop continues then pc-=Bx; */
OP_FORPREP,/* A Bx <check values and prepare counters>;
if not to run then pc+=Bx+1; */
OP_TFORPREP,/* A Bx create upvalue for R[A + 3]; pc+=Bx */
OP_TFORCALL,/* A C R[A+4], ... ,R[A+3+C] := R[A](R[A+1], R[A+2]); */
OP_TFORLOOP,/* A Bx if R[A+2] ~= nil then { R[A]=R[A+2]; pc -= Bx } */
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
OP_VARARGPREP,/*A (adjust vararg parameters) */
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
} OpCode;
#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1)
#define NUM_OPCODES ((int)(OP_EXTRAARG) + 1)
/*===========================================================================
Notes:
(*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
OP_SETLIST) may use `top'.
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
(*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
value, in a code equivalent to (not cond ? false : true). (It
produces false and skips the next instruction producing true.)
(*) Opcodes OP_MMBIN and variants follow each arithmetic and
bitwise opcode. If the operation succeeds, it skips this next
opcode. Otherwise, this opcode calls the corresponding metamethod.
(*) Opcode OP_TESTSET is used in short-circuit expressions that need
both to jump and to produce a value, such as (a = b or c).
(*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
'top' is set to last_result+1, so next open instruction (OP_CALL,
OP_RETURN*, OP_SETLIST) may use 'top'.
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0).
(*) In OP_RETURN, if (B == 0) then return up to `top'.
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
(*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
'instruction' is EXTRAARG(real C).
(*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always
OP_EXTRAARG.
(*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
(*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then
real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the
bits of C).
(*) For comparisons, A specifies what condition the test should accept
(*) In OP_NEWTABLE, B is log2 of the hash size (which is always a
power of 2) plus 1, or zero for size zero. If not k, the array size
is C. Otherwise, the array size is EXTRAARG _ C.
(*) For comparisons, k specifies what condition the test should accept
(true or false).
(*) All `skips' (pc++) assume that next instruction is a jump.
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
(the constant is the first operand).
(*) All 'skips' (pc++) assume that next instruction is a jump.
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
function builds upvalues, which may need to be closed. C > 0 means
the function is vararg, so that its 'func' must be corrected before
returning; in this case, (C - 1) is its number of fixed parameters.
(*) In comparisons with an immediate operand, C signals whether the
original operand was a float. (It must be corrected in case of
metamethods.)
===========================================================================*/
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
** bits 2-3: C arg mode
** bits 4-5: B arg mode
** bit 6: instruction set register A
** bit 7: operator is a test (next instruction must be a jump)
** bits 0-2: op mode
** bit 3: instruction set register A
** bit 4: operator is a test (next instruction must be a jump)
** bit 5: instruction uses 'L->top' set by previous instruction (when B == 0)
** bit 6: instruction sets 'L->top' for next instruction (when C == 0)
** bit 7: instruction is an MM instruction (call a metamethod)
*/
enum OpArgMask {
OpArgN, /* argument is not used */
OpArgU, /* argument is used */
OpArgR, /* argument is a register or a jump offset */
OpArgK /* argument is a constant or register/constant */
};
LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
#define testITMode(m) (luaP_opmodes[m] & (1 << 5))
#define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
#define testMMMode(m) (luaP_opmodes[m] & (1 << 7))
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
#define testAMode(m) (luaP_opmodes[m] & (1 << 6))
#define testTMode(m) (luaP_opmodes[m] & (1 << 7))
/* "out top" (set top for next instruction) */
#define isOT(i) \
((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \
GET_OPCODE(i) == OP_TAILCALL)
/* "in top" (uses top from previous instruction) */
#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)
LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
#define opmode(mm,ot,it,t,a,m) \
(((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m))
/* number of list items to accumulate before a SETLIST instruction */
#define LFIELDS_PER_FLUSH 50
#endif

103
3rd/lua/lopnames.h Normal file
View File

@@ -0,0 +1,103 @@
/*
** $Id: lopnames.h $
** Opcode names
** See Copyright Notice in lua.h
*/
#if !defined(lopnames_h)
#define lopnames_h
#include <stddef.h>
/* ORDER OP */
static const char *const opnames[] = {
"MOVE",
"LOADI",
"LOADF",
"LOADK",
"LOADKX",
"LOADFALSE",
"LFALSESKIP",
"LOADTRUE",
"LOADNIL",
"GETUPVAL",
"SETUPVAL",
"GETTABUP",
"GETTABLE",
"GETI",
"GETFIELD",
"SETTABUP",
"SETTABLE",
"SETI",
"SETFIELD",
"NEWTABLE",
"SELF",
"ADDI",
"ADDK",
"SUBK",
"MULK",
"MODK",
"POWK",
"DIVK",
"IDIVK",
"BANDK",
"BORK",
"BXORK",
"SHRI",
"SHLI",
"ADD",
"SUB",
"MUL",
"MOD",
"POW",
"DIV",
"IDIV",
"BAND",
"BOR",
"BXOR",
"SHL",
"SHR",
"MMBIN",
"MMBINI",
"MMBINK",
"UNM",
"BNOT",
"NOT",
"LEN",
"CONCAT",
"CLOSE",
"TBC",
"JMP",
"EQ",
"LT",
"LE",
"EQK",
"EQI",
"LTI",
"LEI",
"GTI",
"GEI",
"TEST",
"TESTSET",
"CALL",
"TAILCALL",
"RETURN",
"RETURN0",
"RETURN1",
"FORLOOP",
"FORPREP",
"TFORPREP",
"TFORCALL",
"TFORLOOP",
"SETLIST",
"CLOSURE",
"VARARG",
"VARARGPREP",
"EXTRAARG",
NULL
};
#endif

View File

@@ -1,9 +1,14 @@
/*
** $Id: loslib.c,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: loslib.c $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
#define loslib_c
#define LUA_LIB
#include "lprefix.h"
#include <errno.h>
#include <locale.h>
@@ -11,9 +16,6 @@
#include <string.h>
#include <time.h>
#define loslib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
@@ -21,65 +23,127 @@
/*
** list of valid conversion specifiers for the 'strftime' function
** {==================================================================
** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** ===================================================================
*/
#if !defined(LUA_STRFTIMEOPTIONS)
#if !defined(LUA_USE_POSIX)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
#else
#define LUA_STRFTIMEOPTIONS \
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
"", "E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#endif
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
/* }================================================================== */
/*
** By default, Lua uses tmpnam except when POSIX is available, where it
** uses mkstemp.
** {==================================================================
** Configuration for time-related stuff
** ===================================================================
*/
#if defined(LUA_USE_MKSTEMP)
#include <unistd.h>
#define LUA_TMPNAMBUFSIZE 32
#define lua_tmpnam(b,e) { \
strcpy(b, "/tmp/lua_XXXXXX"); \
e = mkstemp(b); \
if (e != -1) close(e); \
e = (e == -1); }
#elif !defined(lua_tmpnam)
/*
** type to represent time_t in Lua
*/
#if !defined(LUA_NUMTIME) /* { */
#define LUA_TMPNAMBUFSIZE L_tmpnam
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
#define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
#define l_gettime(L,arg) luaL_checkinteger(L, arg)
#endif
#else /* }{ */
#define l_timet lua_Number
#define l_pushtime(L,t) lua_pushnumber(L,(lua_Number)(t))
#define l_gettime(L,arg) luaL_checknumber(L, arg)
#endif /* } */
#if !defined(l_gmtime) /* { */
/*
** By default, Lua uses gmtime/localtime, except when POSIX is available,
** where it uses gmtime_r/localtime_r
*/
#if defined(LUA_USE_GMTIME_R)
#if defined(LUA_USE_POSIX) /* { */
#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)
#elif !defined(l_gmtime)
#else /* }{ */
#define l_gmtime(t,r) ((void)r, gmtime(t))
#define l_localtime(t,r) ((void)r, localtime(t))
/* ISO C definitions */
#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
#endif /* } */
#endif /* } */
/* }================================================================== */
/*
** {==================================================================
** Configuration for 'tmpnam':
** By default, Lua uses tmpnam except when POSIX is available, where
** it uses mkstemp.
** ===================================================================
*/
#if !defined(lua_tmpnam) /* { */
#if defined(LUA_USE_POSIX) /* { */
#include <unistd.h>
#define LUA_TMPNAMBUFSIZE 32
#if !defined(LUA_TMPNAMTEMPLATE)
#define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX"
#endif
#define lua_tmpnam(b,e) { \
strcpy(b, LUA_TMPNAMTEMPLATE); \
e = mkstemp(b); \
if (e != -1) close(e); \
e = (e == -1); }
#else /* }{ */
/* ISO C definitions */
#define LUA_TMPNAMBUFSIZE L_tmpnam
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
#endif /* } */
#endif /* } */
/* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat = system(cmd);
int stat;
errno = 0;
stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@@ -106,7 +170,7 @@ static int os_tmpname (lua_State *L) {
char buff[LUA_TMPNAMBUFSIZE];
int err;
lua_tmpnam(buff, err);
if (err)
if (l_unlikely(err))
return luaL_error(L, "unable to generate a unique filename");
lua_pushstring(L, buff);
return 1;
@@ -133,11 +197,25 @@ static int os_clock (lua_State *L) {
** =======================================================
*/
static void setfield (lua_State *L, const char *key, int value) {
lua_pushinteger(L, value);
/*
** About the overflow check: an overflow cannot occur when time
** is represented by a lua_Integer, because either lua_Integer is
** large enough to represent all int fields or it is not large enough
** to represent a time that cause a field to overflow. However, if
** times are represented as doubles and lua_Integer is int, then the
** time 0x1.e1853b0d184f6p+55 would cause an overflow when adding 1900
** to compute the year.
*/
static void setfield (lua_State *L, const char *key, int value, int delta) {
#if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
if (l_unlikely(value > LUA_MAXINTEGER - delta))
luaL_error(L, "field '%s' is out-of-bound", key);
#endif
lua_pushinteger(L, (lua_Integer)value + delta);
lua_setfield(L, -2, key);
}
static void setboolfield (lua_State *L, const char *key, int value) {
if (value < 0) /* undefined? */
return; /* does not set field */
@@ -145,45 +223,63 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
setfield(L, "year", stm->tm_year, 1900);
setfield(L, "month", stm->tm_mon, 1);
setfield(L, "day", stm->tm_mday, 0);
setfield(L, "hour", stm->tm_hour, 0);
setfield(L, "min", stm->tm_min, 0);
setfield(L, "sec", stm->tm_sec, 0);
setfield(L, "yday", stm->tm_yday, 1);
setfield(L, "wday", stm->tm_wday, 1);
setboolfield(L, "isdst", stm->tm_isdst);
}
static int getboolfield (lua_State *L, const char *key) {
int res;
lua_getfield(L, -1, key);
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}
static int getfield (lua_State *L, const char *key, int d) {
int res, isnum;
lua_getfield(L, -1, key);
res = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum) {
if (d < 0)
return luaL_error(L, "field " LUA_QS " missing in date table", key);
static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum;
int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not an integer? */
if (l_unlikely(t != LUA_TNIL)) /* some other value? */
return luaL_error(L, "field '%s' is not an integer", key);
else if (l_unlikely(d < 0)) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
else {
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
lua_pop(L, 1);
return res;
return (int)res;
}
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static const char *const options[] = LUA_STRFTIMEOPTIONS;
unsigned int i;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
buff[1] = *conv;
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
buff[2] = '\0'; /* end buffer */
return conv + 1;
}
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
static const char *checkoption (lua_State *L, const char *conv,
ptrdiff_t convlen, char *buff) {
const char *option = LUA_STRFTIMEOPTIONS;
int oplen = 1; /* length of options being checked */
for (; *option != '\0' && oplen <= convlen; option += oplen) {
if (*option == '|') /* next block? */
oplen++; /* will check options with next length (+1) */
else if (memcmp(conv, option, oplen) == 0) { /* match? */
memcpy(buff, conv, oplen); /* copy valid option to buffer */
buff[oplen] = '\0';
return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -192,44 +288,51 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
}
static time_t l_checktime (lua_State *L, int arg) {
l_timet t = l_gettime(L, arg);
luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
return (time_t)t;
}
/* maximum size for an individual 'strftime' item */
#define SIZETIMEFMT 250
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
size_t slen;
const char *s = luaL_optlstring(L, 1, "%c", &slen);
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
const char *se = s + slen; /* 's' end */
struct tm tmr, *stm;
if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr);
s++; /* skip `!' */
s++; /* skip '!' */
}
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
lua_pushnil(L);
else if (strcmp(s, "*t") == 0) {
return luaL_error(L,
"date result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
setallfields(L, stm);
}
else {
char cc[4];
char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
while (*s) {
if (*s != '%') /* no conversion specifier? */
while (s < se) {
if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
char buff[200]; /* should be big enough for any conversion result */
s = checkoption(L, s + 1, cc);
reslen = strftime(buff, sizeof(buff), cc, stm);
luaL_addlstring(&b, buff, reslen);
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s++; /* skip '%' */
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen);
}
}
luaL_pushresult(&b);
@@ -246,26 +349,28 @@ static int os_time (lua_State *L) {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
ts.tm_sec = getfield(L, "sec", 0);
ts.tm_min = getfield(L, "min", 0);
ts.tm_hour = getfield(L, "hour", 12);
ts.tm_mday = getfield(L, "day", -1);
ts.tm_mon = getfield(L, "month", -1) - 1;
ts.tm_year = getfield(L, "year", -1) - 1900;
ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_mon = getfield(L, "month", -1, 1);
ts.tm_mday = getfield(L, "day", -1, 0);
ts.tm_hour = getfield(L, "hour", 12, 0);
ts.tm_min = getfield(L, "min", 0, 0);
ts.tm_sec = getfield(L, "sec", 0, 0);
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
setallfields(L, &ts); /* update fields with normalized values */
}
if (t == (time_t)(-1))
lua_pushnil(L);
else
lua_pushnumber(L, (lua_Number)t);
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
return luaL_error(L,
"time result cannot be represented in this installation");
l_pushtime(L, t);
return 1;
}
static int os_difftime (lua_State *L) {
lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
(time_t)(luaL_optnumber(L, 2, 0))));
time_t t1 = l_checktime(L, 1);
time_t t2 = l_checktime(L, 2);
lua_pushnumber(L, (lua_Number)difftime(t1, t2));
return 1;
}
@@ -289,7 +394,7 @@ static int os_exit (lua_State *L) {
if (lua_isboolean(L, 1))
status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE);
else
status = luaL_optint(L, 1, EXIT_SUCCESS);
status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS);
if (lua_toboolean(L, 2))
lua_close(L);
if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lparser.h $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,58 +13,106 @@
/*
** Expression descriptor
** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/
/* kinds of variables/expressions */
typedef enum {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in `k' */
VKNUM, /* nval = numerical value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register/upvalue; idx = index R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
VVOID, /* when 'expdesc' describes the last expression of a list,
this kind means an empty list (so, no expression) */
VNIL, /* constant nil */
VTRUE, /* constant true */
VFALSE, /* constant false */
VK, /* constant in 'k'; info = index of constant in 'k' */
VKFLT, /* floating constant; nval = numerical float value */
VKINT, /* integer constant; ival = numerical integer value */
VKSTR, /* string constant; strval = TString address;
(string is fixed by the lexer) */
VNONRELOC, /* expression has its value in a fixed register;
info = result register */
VLOCAL, /* local variable; var.ridx = register index;
var.vidx = relative index in 'actvar.arr' */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VCONST, /* compile-time <const> variable;
info = absolute index in 'actvar.arr' */
VINDEXED, /* indexed variable;
ind.t = table register;
ind.idx = key's R index */
VINDEXUP, /* indexed upvalue;
ind.t = table upvalue;
ind.idx = key's K index */
VINDEXI, /* indexed variable with constant integer;
ind.t = table register;
ind.idx = key's value */
VINDEXSTR, /* indexed variable with literal string;
ind.t = table register;
ind.idx = key's K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOC, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind;
#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED)
#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL)
#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXSTR)
#define vkisindexed(k) (VINDEXED <= (k) && (k) <= VINDEXSTR)
typedef struct expdesc {
expkind k;
union {
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
TString *strval; /* for VKSTR */
int info; /* for generic use */
lua_Number nval; /* for VKNUM */
struct { /* for indexed variables */
short idx; /* index (R or "long" K) */
lu_byte t; /* table (register or upvalue) */
} ind;
struct { /* for local variables */
lu_byte ridx; /* register holding the variable */
unsigned short vidx; /* compiler index (in 'actvar.arr') */
} var;
} u;
int t; /* patch list of `exit when true' */
int f; /* patch list of `exit when false' */
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */
} expdesc;
/* description of active local variable */
typedef struct Vardesc {
short idx; /* variable index in stack */
/* kinds of variables */
#define VDKREG 0 /* regular */
#define RDKCONST 1 /* constant */
#define RDKTOCLOSE 2 /* to-be-closed */
#define RDKCTC 3 /* compile-time constant */
/* description of an active local variable */
typedef union Vardesc {
struct {
TValuefields; /* constant value (if it is a compile-time constant) */
lu_byte kind;
lu_byte ridx; /* register holding the variable */
short pidx; /* index of the variable in the Proto's 'locvars' array */
TString *name; /* variable name */
} vd;
TValue k; /* constant value (if any) */
} Vardesc;
/* description of pending goto statements and label statements */
typedef struct Labeldesc {
TString *name; /* label identifier */
int pc; /* position in code */
int line; /* line where it appeared */
lu_byte nactvar; /* local level where it appears in current block */
lu_byte nactvar; /* number of active variables in that position */
lu_byte close; /* goto that escapes upvalues */
} Labeldesc;
@@ -78,7 +126,7 @@ typedef struct Labellist {
/* dynamic structures used by the parser */
typedef struct Dyndata {
struct { /* list of active local variables */
struct { /* list of all active local variables */
Vardesc *arr;
int n;
int size;
@@ -95,25 +143,29 @@ struct BlockCnt; /* defined in lparser.c */
/* state needed to generate code for a given function */
typedef struct FuncState {
Proto *f; /* current function header */
Table *h; /* table to find (and reuse) elements in `k' */
struct FuncState *prev; /* enclosing function */
struct LexState *ls; /* lexical state */
struct BlockCnt *bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int pc; /* next position to code (equivalent to 'ncode') */
int lasttarget; /* 'label' of last 'jump label' */
int jpc; /* list of pending jumps to `pc' */
int nk; /* number of elements in `k' */
int np; /* number of elements in `p' */
int previousline; /* last line that was saved in 'lineinfo' */
int nk; /* number of elements in 'k' */
int np; /* number of elements in 'p' */
int nabslineinfo; /* number of elements in 'abslineinfo' */
int firstlocal; /* index of first local var (in Dyndata array) */
short nlocvars; /* number of elements in 'f->locvars' */
int firstlabel; /* index of first label (in 'dyd->label->arr') */
short ndebugvars; /* number of elements in 'f->locvars' */
lu_byte nactvar; /* number of active local variables */
lu_byte nups; /* number of upvalues */
lu_byte freereg; /* first free register */
lu_byte iwthabs; /* instructions issued since last absolute line info */
lu_byte needclose; /* function needs to close upvalues when returning */
} FuncState;
LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
LUAI_FUNC int luaY_nvarstack (FuncState *fs);
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
#endif

45
3rd/lua/lprefix.h Normal file
View File

@@ -0,0 +1,45 @@
/*
** $Id: lprefix.h $
** Definitions for Lua code that must come before any other header file
** See Copyright Notice in lua.h
*/
#ifndef lprefix_h
#define lprefix_h
/*
** Allows POSIX/XSI stuff
*/
#if !defined(LUA_USE_C89) /* { */
#if !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE 600
#elif _XOPEN_SOURCE == 0
#undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */
#endif
/*
** Allows manipulation of large files in gcc and some other compilers
*/
#if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS)
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
#endif
#endif /* } */
/*
** Windows stuff
*/
#if defined(_WIN32) /* { */
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */
#endif
#endif /* } */
#endif

View File

@@ -1,16 +1,18 @@
/*
** $Id: lstate.c,v 2.99.1.2 2013/11/08 17:45:31 roberto Exp $
** $Id: lstate.c $
** Global State
** See Copyright Notice in lua.h
*/
#define lstate_c
#define LUA_CORE
#include "lprefix.h"
#include <stddef.h>
#include <string.h>
#define lstate_c
#define LUA_CORE
#include "lua.h"
#include "lapi.h"
@@ -26,40 +28,12 @@
#include "ltm.h"
#if !defined(LUAI_GCPAUSE)
#define LUAI_GCPAUSE 200 /* 200% */
#endif
#if !defined(LUAI_GCMAJOR)
#define LUAI_GCMAJOR 200 /* 200% */
#endif
#if !defined(LUAI_GCMUL)
#define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */
#endif
#define MEMERRMSG "not enough memory"
/*
** a macro to help the creation of a unique random seed when a state is
** created; the seed is used to randomize hashes.
*/
#if !defined(luai_makeseed)
#include <time.h>
#define luai_makeseed() cast(unsigned int, time(NULL))
#endif
/*
** thread state + extra space
*/
typedef struct LX {
#if defined(LUAI_EXTRASPACE)
char buff[LUAI_EXTRASPACE];
#endif
lu_byte extra_[LUA_EXTRASPACE];
lua_State l;
} LX;
@@ -78,47 +52,73 @@ typedef struct LG {
/*
** Compute an initial seed as random as possible. In ANSI, rely on
** Address Space Layout Randomization (if present) to increase
** randomness..
** A macro to create a "random" seed when a state is created;
** the seed is used to randomize string hashes.
*/
#if 0 && !defined(luai_makeseed)
#include <time.h>
/*
** Compute an initial seed with some level of randomness.
** Rely on Address Space Layout Randomization (if present) and
** current time.
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
{ size_t t = cast_sizet(e); \
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
unsigned int h = luai_makeseed();
static unsigned int luai_makeseed (lua_State *L) {
char buff[3 * sizeof(size_t)];
unsigned int h = cast_uint(time(NULL));
int p = 0;
addbuff(buff, p, L); /* heap variable */
addbuff(buff, p, &h); /* local variable */
addbuff(buff, p, luaO_nilobject); /* global variable */
addbuff(buff, p, &lua_newstate); /* public function */
lua_assert(p == sizeof(buff));
return luaS_hash(buff, p, h);
}
#endif
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant
** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
g->totalbytes -= (debt - g->GCdebt);
l_mem tb = gettotalbytes(g);
lua_assert(tb > 0);
if (debt < tb - MAX_LMEM)
debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
g->totalbytes = tb - debt;
g->GCdebt = debt;
}
LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
UNUSED(L); UNUSED(limit);
return LUAI_MAXCCALLS; /* warning?? */
}
CallInfo *luaE_extendCI (lua_State *L) {
CallInfo *ci = luaM_new(L, CallInfo);
CallInfo *ci;
lua_assert(L->ci->next == NULL);
ci = luaM_new(L, CallInfo);
lua_assert(L->ci->next == NULL);
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
ci->u.l.trap = 0;
L->nci++;
return ci;
}
/*
** free all CallInfo structures not in use by a thread
*/
void luaE_freeCI (lua_State *L) {
CallInfo *ci = L->ci;
CallInfo *next = ci->next;
@@ -126,36 +126,87 @@ void luaE_freeCI (lua_State *L) {
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
L->nci--;
}
}
/*
** free half of the CallInfo structures not in use by a thread,
** keeping the first one.
*/
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci->next; /* first free CallInfo */
CallInfo *next;
if (ci == NULL)
return; /* no extra elements */
while ((next = ci->next) != NULL) { /* two extra elements? */
CallInfo *next2 = next->next; /* next's next */
ci->next = next2; /* remove next from the list */
L->nci--;
luaM_free(L, next); /* free next */
if (next2 == NULL)
break; /* no more elements */
else {
next2->previous = ci;
ci = next2; /* continue */
}
}
}
/*
** Called when 'getCcalls(L)' larger or equal to LUAI_MAXCCALLS.
** If equal, raises an overflow error. If value is larger than
** LUAI_MAXCCALLS (which means it is handling an overflow) but
** not much larger, does not report an error (to allow overflow
** handling to work).
*/
void luaE_checkcstack (lua_State *L) {
if (getCcalls(L) == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
}
LUAI_FUNC void luaE_incCstack (lua_State *L) {
L->nCcalls++;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
luaE_checkcstack(L);
}
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
L1->stacksize = BASIC_STACK_SIZE;
for (i = 0; i < BASIC_STACK_SIZE; i++)
setnilvalue(L1->stack + i); /* erase new stack */
L1->top = L1->stack;
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
L1->top.p = L1->stack.p;
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = 0;
ci->func = L1->top;
setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
ci->top = L1->top + LUA_MINSTACK;
ci->callstatus = CIST_C;
ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top.p++;
ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
if (L->stack == NULL)
if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -163,71 +214,69 @@ static void freestack (lua_State *L) {
** Create registry table and its predefined values
*/
static void init_registry (lua_State *L, global_State *g) {
TValue mt;
/* create registry */
Table *registry = luaH_new(L);
sethvalue(L, &g->l_registry, registry);
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
/* registry[LUA_RIDX_MAINTHREAD] = L */
setthvalue(L, &mt, L);
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt);
/* registry[LUA_RIDX_GLOBALS] = table of globals */
sethvalue(L, &mt, luaH_new(L));
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt);
setthvalue(L, &registry->array[LUA_RIDX_MAINTHREAD - 1], L);
/* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
sethvalue(L, &registry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
}
/*
** open parts of the state that may cause memory-allocation errors
** open parts of the state that may cause memory-allocation errors.
*/
static void f_luaopen (lua_State *L, void *ud) {
global_State *g = G(L);
UNUSED(ud);
stack_init(L, L); /* init stack */
init_registry(L, g);
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
luaS_init(L);
luaT_init(L);
luaX_init(L);
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaS_fix(g->memerrmsg); /* it should never be collected */
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
g->gcstp = 0; /* allow gc */
setnilvalue(&g->nilvalue); /* now state is complete */
luai_userstateopen(L);
}
/*
** preinitialize a state with consistent values without allocating
** preinitialize a thread with consistent values without allocating
** any memory (to avoid errors)
*/
static void preinit_state (lua_State *L, global_State *g) {
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->stack.p = NULL;
L->ci = NULL;
L->stacksize = 0;
L->errorJmp = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
L->nCcalls = 0;
L->errorJmp = NULL;
L->hook = NULL;
L->hookmask = 0;
L->basehookcount = 0;
L->allowhook = 1;
resethookcount(L);
L->openupval = NULL;
L->nny = 1;
L->status = LUA_OK;
L->errfunc = 0;
L->oldpc = 0;
}
static void close_state (lua_State *L) {
global_State *g = G(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
luaC_freeallobjects(L); /* collect all objects */
if (g->version) /* closing a fully built state? */
if (!completestate(g)) /* closing a partially built state? */
luaC_freeallobjects(L); /* just collect its objects */
else { /* closing a fully built state */
L->ci = &L->base_ci; /* unwind CallInfo list */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
luaC_freeallobjects(L); /* collect all objects */
luai_userstateclose(L);
}
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
@@ -235,17 +284,25 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g = G(L);
GCObject *o;
lua_State *L1;
lua_lock(L);
luaC_checkGC(L);
L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th;
setthvalue(L, L->top, L1);
/* create new thread */
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1 = gco2th(o);
/* anchor it on L stack */
setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_state(L1, G(L));
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
L1->basehookcount = L->basehookcount;
L1->hook = L->hook;
resethookcount(L1);
/* initialize L1 extra space */
memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread),
LUA_EXTRASPACE);
luai_userstatethread(L, L1);
stack_init(L1, L); /* init stack */
lua_unlock(L);
@@ -255,7 +312,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@@ -263,6 +320,43 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
}
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack.p + 1);
else
L->top.p = L->stack.p + 1;
ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
/*
** Deprecated! Use 'lua_closethread' instead.
*/
LUA_API int lua_resetthread (lua_State *L) {
return lua_closethread(L, NULL);
}
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@@ -271,39 +365,43 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
if (l == NULL) return NULL;
L = &l->l.l;
g = &l->g;
L->next = NULL;
L->tt = LUA_TTHREAD;
g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
L->tt = LUA_VTHREAD;
g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);
g->gckind = KGC_NORMAL;
preinit_state(L, g);
preinit_thread(L, g);
g->allgc = obj2gco(L); /* by now, only object is the main thread */
L->next = NULL;
incnny(L); /* main thread is always non yieldable */
g->frealloc = f;
g->ud = ud;
g->warnf = NULL;
g->ud_warn = NULL;
g->mainthread = L;
g->seed = makeseed(L);
g->uvhead.u.l.prev = &g->uvhead;
g->uvhead.u.l.next = &g->uvhead;
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = 0;
g->strt.nuse = 0;
g->gcstp = GCSTPGC; /* no GC while building state */
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
g->allgc = NULL;
g->finobj = NULL;
g->tobefnz = NULL;
g->sweepgc = g->sweepfin = NULL;
g->gckind = KGC_INC;
g->gcstopem = 0;
g->gcemergency = 0;
g->finobj = g->tobefnz = g->fixedgc = NULL;
g->firstold1 = g->survival = g->old1 = g->reallyold = NULL;
g->finobjsur = g->finobjold1 = g->finobjrold = NULL;
g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcmajorinc = LUAI_GCMAJOR;
g->gcstepmul = LUAI_GCMUL;
g->lastatomic = 0;
setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */
setgcparam(g->gcpause, LUAI_GCPAUSE);
setgcparam(g->gcstepmul, LUAI_GCMUL);
g->gcstepsize = LUAI_GCSTEPSIZE;
setgcparam(g->genmajormul, LUAI_GENMAJORMUL);
g->genminormul = LUAI_GENMINORMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */
@@ -315,9 +413,32 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
LUA_API void lua_close (lua_State *L) {
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
L = G(L)->mainthread; /* only the main thread can be closed */
close_state(L);
}
void luaE_warning (lua_State *L, const char *msg, int tocont) {
lua_WarnFunction wf = G(L)->warnf;
if (wf != NULL)
wf(G(L)->ud_warn, msg, tocont);
}
/*
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";
/* produce warning "error in %s (%s)" (where, msg) */
luaE_warning(L, "error in ", 1);
luaE_warning(L, where, 1);
luaE_warning(L, " (", 1);
luaE_warning(L, msg, 1);
luaE_warning(L, ")", 0);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lstate.h $
** Global State
** See Copyright Notice in lua.h
*/
@@ -9,219 +9,399 @@
#include "lua.h"
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "lobject.h"
#include "ltm.h"
#include "lzio.h"
/*
** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed.
** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed, so all objects always
** belong to one (and only one) of these lists, using field 'next' of
** the 'CommonHeader' for the link:
**
** Lua keeps most objects linked in list g->allgc. The link uses field
** 'next' of the CommonHeader.
** 'allgc': all objects not marked for finalization;
** 'finobj': all objects marked for finalization;
** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
**
** Strings are kept in several lists headed by the array g->strt.hash.
** For the generational collector, some of these lists have marks for
** generations. Each mark points to the first element in the list for
** that particular generation; that generation goes until the next mark.
**
** Open upvalues are not subject to independent garbage collection. They
** are collected together with their respective threads. Lua keeps a
** double-linked list with all open upvalues (g->uvhead) so that it can
** mark objects referred by them. (They are always gray, so they must
** be remarked in the atomic step. Usually their contents would be marked
** when traversing the respective threads, but the thread may already be
** dead, while the upvalue is still accessible through closures.)
** 'allgc' -> 'survival': new objects;
** 'survival' -> 'old': objects that survived one collection;
** 'old1' -> 'reallyold': objects that became old in last collection;
** 'reallyold' -> NULL: objects old for more than one cycle.
**
** Objects with finalizers are kept in the list g->finobj.
** 'finobj' -> 'finobjsur': new objects marked for finalization;
** 'finobjsur' -> 'finobjold1': survived """";
** 'finobjold1' -> 'finobjrold': just old """";
** 'finobjrold' -> NULL: really old """".
**
** The list g->tobefnz links all objects being finalized.
** All lists can contain elements older than their main ages, due
** to 'luaC_checkfinalizer' and 'udata2finalize', which move
** objects between the normal lists and the "marked for finalization"
** lists. Moreover, barriers can age young objects in young lists as
** OLD0, which then become OLD1. However, a list never contains
** elements younger than their main ages.
**
** The generational collector also uses a pointer 'firstold1', which
** points to the first OLD1 object in the list. It is used to optimize
** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
** and 'reallyold', but often the list has no OLD1 objects or they are
** after 'old1'.) Note the difference between it and 'old1':
** 'firstold1': no OLD1 objects before this point; there can be all
** ages after it.
** 'old1': no objects younger than OLD1 after this point.
*/
/*
** Moreover, there is another set of lists that control gray objects.
** These lists are linked by fields 'gclist'. (All objects that
** can become gray have such a field. The field is not the same
** in all objects, but it always has this name.) Any gray object
** must belong to one of these lists, and all objects in these lists
** must be gray (with two exceptions explained below):
**
** 'gray': regular gray objects, still waiting to be visited.
** 'grayagain': objects that must be revisited at the atomic phase.
** That includes
** - black objects got in a write barrier;
** - all kinds of weak tables during propagation phase;
** - all threads.
** 'weak': tables with weak values to be cleared;
** 'ephemeron': ephemeron tables with white->white entries;
** 'allweak': tables with weak keys and/or weak values to be cleared.
**
** The exceptions to that "gray rule" are:
** - TOUCHED2 objects in generational mode stay in a gray list (because
** they must be visited again at the end of the cycle), but they are
** marked black because assignments to them must activate barriers (to
** move them back to TOUCHED1).
** - Open upvales are kept gray to avoid barriers, but they stay out
** of gray lists. (They don't even have a 'gclist' field.)
*/
/*
** About 'nCcalls': This count has two parts: the lower 16 bits counts
** the number of recursive invocations in the C stack; the higher
** 16 bits counts the number of non-yieldable calls in the stack.
** (They are together so that we can change and save both with one
** instruction.)
*/
/* true if this thread does not have non-yieldable calls in the stack */
#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0)
/* real number of C calls */
#define getCcalls(L) ((L)->nCcalls & 0xffff)
/* Increment the number of non-yieldable calls */
#define incnny(L) ((L)->nCcalls += 0x10000)
/* Decrement the number of non-yieldable calls */
#define decnny(L) ((L)->nCcalls -= 0x10000)
/* Non-yieldable call increment */
#define nyci (0x10000 | 1)
struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */
/*
** Extra stack space to handle TM calls and some other extras. This
** space is not included in 'stack_last'. It is used only to avoid stack
** checks, either because the element will be promptly popped or because
** there will be a stack check soon after the push. Function frames
** never use this extra space, so it does not need to be kept clean.
*/
#define EXTRA_STACK 5
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
#define KGC_GEN 2 /* generational collection */
#define KGC_INC 0 /* incremental gc */
#define KGC_GEN 1 /* generational gc */
typedef struct stringtable {
GCObject **hash;
lu_int32 nuse; /* number of elements */
TString **hash;
int nuse; /* number of elements */
int size;
} stringtable;
/*
** information about a call
** Information about a call.
** About union 'u':
** - field 'l' is used only for Lua functions;
** - field 'c' is used only for C functions.
** About union 'u2':
** - field 'funcidx' is used only by C functions while doing a
** protected call;
** - field 'nyield' is used only while a function is "doing" an
** yield (from the yield until the next resume);
** - field 'nres' is used only while closing tbc variables when
** returning from a function;
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo {
StkIdRel func; /* function index in the stack */
StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
short nresults; /* expected number of results from this function */
lu_byte callstatus;
ptrdiff_t extra;
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
const Instruction *savedpc;
volatile l_signalT trap;
int nextraargs; /* # of extra arguments in vararg functions */
} l;
struct { /* only for C functions */
int ctx; /* context info. in case of yields */
lua_CFunction k; /* continuation in case of yields */
lua_KFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
lu_byte old_allowhook;
lu_byte status;
lua_KContext ctx; /* context info. in case of yields */
} c;
} u;
} CallInfo;
union {
int funcidx; /* called-function index */
int nyield; /* number of values yielded */
int nres; /* number of values returned */
struct { /* info about transferred values (for call/return hooks) */
unsigned short ftransfer; /* offset of first value transferred */
unsigned short ntransfer; /* number of values transferred */
} transferinfo;
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
};
/*
** Bits in CallInfo status
*/
#define CIST_LUA (1<<0) /* call is running a Lua function */
#define CIST_HOOKED (1<<1) /* call is running a debug hook */
#define CIST_REENTRY (1<<2) /* call is running on same invocation of
luaV_execute of previous call */
#define CIST_YIELDED (1<<3) /* call reentered after suspension */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_STAT (1<<5) /* call has an error status (pcall) */
#define CIST_TAIL (1<<6) /* call was tail called */
#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_C (1<<1) /* call is running a C function */
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
#define CIST_HOOKED (1<<3) /* call is running a debug hook */
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_FIN (1<<7) /* function "called" a finalizer */
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */
#define CIST_RECST 10
#if defined(LUA_COMPAT_LT_LE)
#define CIST_LEQ (1<<13) /* using __lt for __le */
#endif
/*
** `global state', shared by all threads of this state
** Field CIST_RECST stores the "recover status", used to keep the error
** status while closing to-be-closed variables in coroutines, so that
** Lua can correctly resume after an yield from a __close method called
** because of an error. (Three bits are enough for error status.)
*/
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
#define setcistrecst(ci,st) \
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
| ((st) << CIST_RECST)))
/* active function is a Lua function */
#define isLua(ci) (!((ci)->callstatus & CIST_C))
/* call is running Lua code (not a hook) */
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
#define getoah(st) ((st) & CIST_OAH)
/*
** 'global state', shared by all threads of this state
*/
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to `frealloc' */
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
void *ud; /* auxiliary data to 'frealloc' */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */
stringtable strt; /* hash table for strings */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
TValue nilvalue; /* a nil value */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte gcrunning; /* true if GC is running */
int sweepstrgc; /* position of sweep in `strt' */
lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */
lu_byte gcstp; /* control whether GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
lu_byte gcstepsize; /* (log2 of) GC granularity */
GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
GCObject **sweepgc; /* current position of sweep in list 'allgc' */
GCObject **sweepfin; /* current position of sweep in list 'finobj' */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
UpVal uvhead; /* head of double-linked list of all open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
int gcpause; /* size of pause between successive GCs */
int gcmajorinc; /* pause between major collections (only in gen. mode) */
int gcstepmul; /* GC `granularity' */
GCObject *fixedgc; /* list of objects not to be collected */
/* fields for generational collector */
GCObject *survival; /* start of objects that survived one GC cycle */
GCObject *old1; /* start of old1 objects */
GCObject *reallyold; /* objects more than one cycle old ("really old") */
GCObject *firstold1; /* first OLD1 object in the list (if any) */
GCObject *finobjsur; /* list of survival objects with finalizers */
GCObject *finobjold1; /* list of old1 objects with finalizers */
GCObject *finobjrold; /* list of really old objects with finalizers */
struct lua_State *twups; /* list of threads with open upvalues */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */
TString *memerrmsg; /* memory-error message */
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
} global_State;
/*
** `per thread' state
** 'per thread' state
*/
struct lua_State {
CommonHeader;
lu_byte status;
StkId top; /* first free slot in the stack */
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
const Instruction *oldpc; /* last pc traced */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
int stacksize;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
lu_byte allowhook;
StkIdRel stack_last; /* end of stack (last element + 1) */
StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
int oldpc; /* last pc traced */
int basehookcount;
int hookcount;
lua_Hook hook;
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile l_signalT hookmask;
};
#define G(L) (L->l_G)
/*
** 'g->nilvalue' being a nil value flags that the state was completely
** build.
*/
#define completestate(g) ttisnil(&g->nilvalue)
/*
** Union of all collectable objects
** Union of all collectable objects (only for conversions)
** ISO C99, 6.5.2.3 p.5:
** "if a union contains several structures that share a common initial
** sequence [...], and if the union object currently contains one
** of these structures, it is permitted to inspect the common initial
** part of any of them anywhere that a declaration of the complete type
** of the union is visible."
*/
union GCObject {
GCheader gch; /* common header */
union TString ts;
union Udata u;
union GCUnion {
GCObject gc; /* common header */
struct TString ts;
struct Udata u;
union Closure cl;
struct Table h;
struct Proto p;
struct UpVal uv;
struct lua_State th; /* thread */
struct UpVal upv;
};
#define gch(o) (&(o)->gch)
/*
** ISO C99, 6.7.2.1 p.14:
** "A pointer to a union object, suitably converted, points to each of
** its members [...], and vice versa."
*/
#define cast_u(o) cast(union GCUnion *, (o))
/* macros to convert a GCObject into a specific value */
#define rawgco2ts(o) \
check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts))
#define gco2ts(o) (&rawgco2ts(o)->tsv)
#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
#define gco2u(o) (&rawgco2u(o)->uv)
#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l))
#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c))
#define gco2ts(o) \
check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u))
#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l))
#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c))
#define gco2cl(o) \
check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))
/* macro to convert any Lua object into a GCObject */
#define obj2gco(v) (cast(GCObject *, (v)))
/*
** macro to convert a Lua object into a GCObject
** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.)
*/
#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
/* actual number of total bytes allocated */
#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L);
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
#endif

View File

@@ -1,152 +1,261 @@
/*
** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lstring.c $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
#include <string.h>
#define lstring_c
#define LUA_CORE
#include "lprefix.h"
#include <string.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "atomic.h"
static unsigned int STRSEED;
static ATOM_SIZET STRID = 0;
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
** compute its hash
** Maximum size for string table.
*/
#if !defined(LUAI_HASHLIMIT)
#define LUAI_HASHLIMIT 5
#endif
#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*))
/*
** equality for long strings
*/
int luaS_eqlngstr (TString *a, TString *b) {
size_t len = a->tsv.len;
lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR);
size_t len = a->u.lnglen;
lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR);
return (a == b) || /* same instance or... */
((len == b->tsv.len) && /* equal length and ... */
((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
}
/*
** equality for strings
*/
int luaS_eqstr (TString *a, TString *b) {
return (a->tsv.tt == b->tsv.tt) &&
(a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b));
int luaS_eqshrstr (TString *a, TString *b) {
int r;
lu_byte len = a->shrlen;
lua_assert(b->tt == LUA_VSHRSTR);
r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
if (r) {
if (a->id < b->id) {
a->id = b->id;
} else {
b->id = a->id;
}
}
return r;
}
void luaS_share (TString *ts) {
if (ts == NULL || isshared(ts))
return;
makeshared(ts);
ts->id = ATOM_FDEC(&STRID)-1;
}
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1;
for (l1 = l; l1 >= step; l1 -= step)
h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
unsigned int h = seed ^ cast_uint(l);
for (; l > 0; l--)
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
}
/*
** resizes the string table
*/
void luaS_resize (lua_State *L, int newsize) {
int i;
stringtable *tb = &G(L)->strt;
/* cannot resize while GC is traversing strings */
luaC_runtilstate(L, ~bitmask(GCSsweepstring));
if (newsize > tb->size) {
luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL;
unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_VLNGSTR);
if (ts->extra == 0) { /* no hash? */
size_t len = ts->u.lnglen;
ts->hash = luaS_hash(getstr(ts), len, ts->hash);
ts->extra = 1; /* now it has its hash */
}
/* rehash */
for (i=0; i<tb->size; i++) {
GCObject *p = tb->hash[i];
tb->hash[i] = NULL;
while (p) { /* for each node in the list */
GCObject *next = gch(p)->next; /* save next */
unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */
gch(p)->next = tb->hash[h]; /* chain it */
tb->hash[h] = p;
resetoldbit(p); /* see MOVE OLD rule */
p = next;
return ts->hash;
}
static void tablerehash (TString **vect, int osize, int nsize) {
int i;
for (i = osize; i < nsize; i++) /* clear new elements */
vect[i] = NULL;
for (i = 0; i < osize; i++) { /* rehash old part of the array */
TString *p = vect[i];
vect[i] = NULL;
while (p) { /* for each string in the list */
TString *hnext = p->u.hnext; /* save next */
unsigned int h = lmod(p->hash, nsize); /* new position */
p->u.hnext = vect[h]; /* chain it into array */
vect[h] = p;
p = hnext;
}
}
if (newsize < tb->size) {
/* shrinking slice must be empty */
lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL);
luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
}
tb->size = newsize;
}
/*
** Resize the string table. If allocation fails, keep the current size.
** (This can degrade performance, but any non-zero size should work
** correctly.)
*/
void luaS_resize (lua_State *L, int nsize) {
stringtable *tb = &G(L)->strt;
int osize = tb->size;
TString **newvect;
if (nsize < osize) /* shrinking table? */
tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */
newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*);
if (l_unlikely(newvect == NULL)) { /* reallocation failed? */
if (nsize < osize) /* was it shrinking table? */
tablerehash(tb->hash, nsize, osize); /* restore to original size */
/* leave table as it was */
}
else { /* allocation succeeded */
tb->hash = newvect;
tb->size = nsize;
if (nsize > osize)
tablerehash(newvect, osize, nsize); /* rehash for new size */
}
}
/*
** Clear API string cache. (Entries cannot be empty, so fill them with
** a non-collectable string.)
*/
void luaS_clearcache (global_State *g) {
int i, j;
for (i = 0; i < STRCACHE_N; i++)
for (j = 0; j < STRCACHE_M; j++) {
if (iswhite(g->strcache[i][j])) /* will entry be collected? */
g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
}
}
#if !defined(luai_makeseed)
#include <time.h>
static unsigned int luai_makeseed(lua_State *L) {
size_t buff[4];
unsigned int h = time(NULL);
buff[0] = cast(size_t, h);
buff[1] = cast(size_t, &STRSEED);
buff[2] = cast(size_t, &luai_makeseed);
buff[3] = cast(size_t, L);
return luaS_hash((const char*)buff, sizeof(buff), h);
}
#endif
/*
** Initialize the string table and the string cache
*/
void luaS_init (lua_State *L) {
global_State *g = G(L);
int i, j;
stringtable *tb;
if (STRSEED == 0) {
STRSEED = luai_makeseed(L);
}
tb = &G(L)->strt;
tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*);
tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */
tb->size = MINSTRTABSIZE;
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
for (j = 0; j < STRCACHE_M; j++)
g->strcache[i][j] = g->memerrmsg;
}
/*
** creates a new string object
*/
static TString *createstrobj (lua_State *L, const char *str, size_t l,
int tag, unsigned int h, GCObject **list) {
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
totalsize = sizeof(TString) + ((l + 1) * sizeof(char));
ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;
ts->tsv.len = l;
ts->tsv.hash = h;
ts->tsv.extra = 0;
memcpy(ts+1, str, l*sizeof(char));
((char *)(ts+1))[l] = '\0'; /* ending 0 */
totalsize = sizelstring(l);
o = luaC_newobj(L, tag, totalsize);
ts = gco2ts(o);
ts->hash = h;
ts->extra = 0;
ts->id = 0;
getstr(ts)[l] = '\0'; /* ending 0 */
return ts;
}
/*
** creates a new short string, inserting it into string table
*/
static TString *newshrstr (lua_State *L, const char *str, size_t l,
unsigned int h) {
GCObject **list; /* (pointer to) list where it will be inserted */
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_VLNGSTR, STRSEED);
ts->u.lnglen = l;
return ts;
}
void luaS_remove (lua_State *L, TString *ts) {
stringtable *tb = &G(L)->strt;
TString *s;
if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
luaS_resize(L, tb->size*2); /* too crowded */
list = &tb->hash[lmod(h, tb->size)];
s = createstrobj(L, str, l, LUA_TSHRSTR, h, list);
tb->nuse++;
return s;
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
while (*p != ts) /* find previous element */
p = &(*p)->u.hnext;
*p = (*p)->u.hnext; /* remove element from its list */
tb->nuse--;
}
static void growstrtab (lua_State *L, stringtable *tb) {
if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
luaC_fullgc(L, 1); /* try to free some... */
if (tb->nuse == MAX_INT) /* still too many? */
luaM_error(L); /* cannot even create a message... */
}
if (tb->size <= MAXSTRTB / 2) /* can grow string table? */
luaS_resize(L, tb->size * 2);
}
/*
** checks whether short string exists and reuses it or creates a new one
** Checks whether short string exists and reuses it or creates a new one.
*/
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
GCObject *o;
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
for (o = g->strt.hash[lmod(h, g->strt.size)];
o != NULL;
o = gch(o)->next) {
TString *ts = rawgco2ts(o);
if (h == ts->tsv.hash &&
l == ts->tsv.len &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */
changewhite(o); /* resurrect it */
stringtable *tb = &g->strt;
unsigned int h = luaS_hash(str, l, STRSEED);
TString **list = &tb->hash[lmod(h, tb->size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
/* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */
changewhite(ts); /* resurrect it */
return ts;
}
}
return newshrstr(L, str, l, h); /* not found; create a new string */
/* else must create a new string */
if (tb->nuse >= tb->size) { /* need to grow string table? */
growstrtab(L, tb);
list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */
}
ts = createstrobj(L, l, LUA_VSHRSTR, h);
memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l);
ts->u.hnext = *list;
*list = ts;
tb->nuse++;
return ts;
}
@@ -157,29 +266,52 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
if (l <= LUAI_MAXSHORTLEN) /* short string? */
return internshrstr(L, str, l);
else {
if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
TString *ts;
if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
luaM_toobig(L);
return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL);
ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char));
return ts;
}
}
/*
** new zero-terminated string
** Create or reuse a zero-terminated string, first checking in the
** cache (using the string address as a key). The cache can contain
** only zero-terminated strings, so it is safe to use 'strcmp' to
** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
return luaS_newlstr(L, str, strlen(str));
unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
int j;
TString **p = G(L)->strcache[i];
for (j = 0; j < STRCACHE_M; j++) {
if (strcmp(str, getstr(p[j])) == 0) /* hit? */
return p[j]; /* that is it */
}
/* normal route */
for (j = STRCACHE_M - 1; j > 0; j--)
p[j] = p[j - 1]; /* move out last element */
/* new element is first in the list */
p[0] = luaS_newlstr(L, str, strlen(str));
return p[0];
}
Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
Udata *u;
if (s > MAX_SIZET - sizeof(Udata))
int i;
GCObject *o;
if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
luaM_toobig(L);
u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u;
u->uv.len = s;
u->uv.metatable = NULL;
u->uv.env = e;
o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s));
u = gco2u(o);
u->len = s;
u->nuvalue = nuvalue;
u->metatable = NULL;
for (i = 0; i < nuvalue; i++)
setnilvalue(&u->uv[i].uv);
return u;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lstring.h $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -12,35 +12,47 @@
#include "lstate.h"
#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char))
/*
** Memory-allocation error message must be preallocated (it cannot
** be created after memory is exhausted)
*/
#define MEMERRMSG "not enough memory"
#define sizeudata(u) (sizeof(union Udata)+(u)->len)
/*
** Size of a TString: Size of the header plus space for the string
** itself (including final '\0').
*/
#define sizelstring(l) (offsetof(TString, contents) + ((l) + 1) * sizeof(char))
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
(sizeof(s)/sizeof(char))-1))
#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
/*
** test whether a string is a reserved word
*/
#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0)
#define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
/*
** equality for short strings, which are always internalized
** equality for short strings, compare id first
*/
#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b))
#define eqshrstr(a,b) check_exp((a)->tt == LUA_VSHRSTR, (a) == (b) || \
( ((a)->id == (b)->id) ? ((a)->id != 0) : ((a)->hash == (b)->hash && luaS_eqshrstr(a,b)) ) )
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
LUAI_FUNC int luaS_eqshrstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
LUAI_FUNC void luaS_clearcache (global_State *g);
LUAI_FUNC void luaS_init (lua_State *L);
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
LUAI_FUNC void luaS_share(TString *ts);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $
** $Id: ltable.h $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -11,34 +11,54 @@
#define gnode(t,i) (&(t)->node[i])
#define gkey(n) (&(n)->i_key.tvk)
#define gval(n) (&(n)->i_val)
#define gnext(n) ((n)->i_key.nk.next)
#define invalidateTMcache(t) ((t)->flags = 0)
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
#define gnext(n) ((n)->u.next)
LUAI_FUNC const TValue *luaH_getint (Table *t, int key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value);
/*
** Clear all bits of fast-access metamethods, which means that the table
** may have any of these metamethods. (First access that fails after the
** clearing will set the bit again.)
*/
#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
/* true when 't' is using 'dummynode' as its hash part */
#define isdummy(t) ((t)->lastfree == NULL)
/* allocated size for hash nodes */
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
/* returns the Node, given the value of a table entry */
#define nodefromval(v) cast(Node *, (v))
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
const TValue *slot, TValue *value);
LUAI_FUNC Table *luaH_new (lua_State *L);
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize);
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int nhsize);
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
LUAI_FUNC int luaH_getn (Table *t);
LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (Node *n);
#endif

View File

@@ -1,103 +1,165 @@
/*
** $Id: ltablib.c,v 1.65.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ltablib.c $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define ltablib_c
#define LUA_LIB
#include "lprefix.h"
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
/*
** Operations that an object must define to mimic a table
** (some functions only need some of them)
*/
#define TAB_R 1 /* read */
#define TAB_W 2 /* write */
#define TAB_L 4 /* length */
#define TAB_RW (TAB_R | TAB_W) /* read/write */
#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
#if defined(LUA_COMPAT_MAXN)
static int maxn (lua_State *L) {
lua_Number max = 0;
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushnil(L); /* first key */
while (lua_next(L, 1)) {
lua_pop(L, 1); /* remove value */
if (lua_type(L, -1) == LUA_TNUMBER) {
lua_Number v = lua_tonumber(L, -1);
if (v > max) max = v;
}
}
lua_pushnumber(L, max);
return 1;
static int checkfield (lua_State *L, const char *key, int n) {
lua_pushstring(L, key);
return (lua_rawget(L, -n) != LUA_TNIL);
}
/*
** Check that 'arg' either is a table or can behave like one (that is,
** has a metatable with the required metamethods)
*/
static void checktab (lua_State *L, int arg, int what) {
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
int n = 1; /* number of elements to pop */
if (lua_getmetatable(L, arg) && /* must have metatable */
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
lua_pop(L, n); /* pop metatable and tested metamethods */
}
else
luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
#endif
static int tinsert (lua_State *L) {
int e = aux_getn(L, 1) + 1; /* first empty element */
int pos; /* where to insert new element */
lua_Integer pos; /* where to insert new element */
lua_Integer e = aux_getn(L, 1, TAB_RW);
e = luaL_intop(+, e, 1); /* first empty element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
pos = e; /* insert new element at the end */
break;
}
case 3: {
int i;
pos = luaL_checkint(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
lua_Integer i;
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
/* check whether 'pos' is in [1, e] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u < (lua_Unsigned)e, 2,
"position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */
lua_rawgeti(L, 1, i-1);
lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
lua_geti(L, 1, i - 1);
lua_seti(L, 1, i); /* t[i] = t[i - 1] */
}
break;
}
default: {
return luaL_error(L, "wrong number of arguments to " LUA_QL("insert"));
return luaL_error(L, "wrong number of arguments to 'insert'");
}
}
lua_rawseti(L, 1, pos); /* t[pos] = v */
lua_seti(L, 1, pos); /* t[pos] = v */
return 0;
}
static int tremove (lua_State *L) {
int size = aux_getn(L, 1);
int pos = luaL_optint(L, 2, size);
lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
lua_rawgeti(L, 1, pos); /* result = t[pos] */
/* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
lua_rawgeti(L, 1, pos+1);
lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
lua_geti(L, 1, pos + 1);
lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
}
lua_pushnil(L);
lua_rawseti(L, 1, pos); /* t[pos] = nil */
lua_seti(L, 1, pos); /* remove entry t[pos] */
return 1;
}
static void addfield (lua_State *L, luaL_Buffer *b, int i) {
lua_rawgeti(L, 1, i);
if (!lua_isstring(L, -1))
luaL_error(L, "invalid value (%s) at index %d in table for "
LUA_QL("concat"), luaL_typename(L, -1), i);
/*
** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
** possible, copy in increasing order, which is better for rehashing.
** "possible" means destination after original range, or smaller
** than origin, or copying to another table.
*/
static int tmove (lua_State *L) {
lua_Integer f = luaL_checkinteger(L, 2);
lua_Integer e = luaL_checkinteger(L, 3);
lua_Integer t = luaL_checkinteger(L, 4);
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
checktab(L, 1, TAB_R);
checktab(L, tt, TAB_W);
if (e >= f) { /* otherwise, nothing to move */
lua_Integer n, i;
luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
"too many elements to move");
n = e - f + 1; /* number of elements to move */
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around");
if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
else {
for (i = n - 1; i >= 0; i--) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
}
lua_pushvalue(L, tt); /* return destination table */
return 1;
}
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i);
if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
luaL_typename(L, -1), (LUAI_UACINT)i);
luaL_addvalue(b);
}
static int tconcat (lua_State *L) {
luaL_Buffer b;
lua_Integer last = aux_getn(L, 1, TAB_R);
size_t lsep;
int i, last;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
luaL_checktype(L, 1, LUA_TTABLE);
i = luaL_optint(L, 3, 1);
last = luaL_opt(L, luaL_checkint, 4, luaL_len(L, 1));
lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
addfield(L, &b, i);
@@ -116,36 +178,33 @@ static int tconcat (lua_State *L) {
** =======================================================
*/
static int pack (lua_State *L) {
static int tpack (lua_State *L) {
int i;
int n = lua_gettop(L); /* number of elements to pack */
lua_createtable(L, n, 1); /* create result table */
lua_insert(L, 1); /* put it at index 1 */
for (i = n; i >= 1; i--) /* assign elements */
lua_seti(L, 1, i);
lua_pushinteger(L, n);
lua_setfield(L, -2, "n"); /* t.n = number of elements */
if (n > 0) { /* at least one element? */
int i;
lua_pushvalue(L, 1);
lua_rawseti(L, -2, 1); /* insert first element */
lua_replace(L, 1); /* move table into index 1 */
for (i = n; i >= 2; i--) /* assign other elements */
lua_rawseti(L, 1, i);
}
lua_setfield(L, 1, "n"); /* t.n = number of elements */
return 1; /* return table */
}
static int unpack (lua_State *L) {
int i, e, n;
luaL_checktype(L, 1, LUA_TTABLE);
i = luaL_optint(L, 2, 1);
e = luaL_opt(L, luaL_checkint, 3, luaL_len(L, 1));
static int tunpack (lua_State *L) {
lua_Unsigned n;
lua_Integer i = luaL_optinteger(L, 2, 1);
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = e - i + 1; /* number of elements */
if (n <= 0 || !lua_checkstack(L, n)) /* n <= 0 means arith. overflow */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (l_unlikely(n >= (unsigned int)INT_MAX ||
!lua_checkstack(L, (int)(++n))))
return luaL_error(L, "too many results to unpack");
lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */
while (i++ < e) /* push arg[i + 1...e] */
lua_rawgeti(L, 1, i);
return n;
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
lua_geti(L, 1, i);
}
lua_geti(L, 1, e); /* push last element */
return (int)n;
}
/* }====================================================== */
@@ -155,102 +214,197 @@ static int unpack (lua_State *L) {
/*
** {======================================================
** Quicksort
** (based on `Algorithms in MODULA-3', Robert Sedgewick;
** (based on 'Algorithms in MODULA-3', Robert Sedgewick;
** Addison-Wesley, 1993.)
** =======================================================
*/
static void set2 (lua_State *L, int i, int j) {
lua_rawseti(L, 1, i);
lua_rawseti(L, 1, j);
/* type for array indices */
typedef unsigned int IdxT;
/*
** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result
** of a partition. (If you don't want/need this "randomness", ~0 is a
** good choice.)
*/
#if !defined(l_randomizePivot) /* { */
#include <time.h>
/* size of 'e' measured in number of 'unsigned int's */
#define sof(e) (sizeof(e) / sizeof(unsigned int))
/*
** Use 'time' and 'clock' as sources of "randomness". Because we don't
** know the types 'clock_t' and 'time_t', we cannot cast them to
** anything without risking overflows. A safe way to use their values
** is to copy them to an array of a known type and use the array values.
*/
static unsigned int l_randomizePivot (void) {
clock_t c = clock();
time_t t = time(NULL);
unsigned int buff[sof(c) + sof(t)];
unsigned int i, rnd = 0;
memcpy(buff, &c, sof(c) * sizeof(unsigned int));
memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
for (i = 0; i < sof(buff); i++)
rnd += buff[i];
return rnd;
}
#endif /* } */
/* arrays larger than 'RANLIMIT' may use randomized pivots */
#define RANLIMIT 100u
static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i);
lua_seti(L, 1, j);
}
/*
** Return true iff value at stack index 'a' is less than the value at
** index 'b' (according to the order of the sort).
*/
static int sort_comp (lua_State *L, int a, int b) {
if (!lua_isnil(L, 2)) { /* function? */
if (lua_isnil(L, 2)) /* no function? */
return lua_compare(L, a, b, LUA_OPLT); /* a < b */
else { /* function */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, 2); /* push function */
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
lua_call(L, 2, 1);
res = lua_toboolean(L, -1);
lua_pop(L, 1);
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
lua_call(L, 2, 1); /* call function */
res = lua_toboolean(L, -1); /* get result */
lua_pop(L, 1); /* pop result */
return res;
}
else /* a < b? */
return lua_compare(L, a, b, LUA_OPLT);
}
static void auxsort (lua_State *L, int l, int u) {
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
lua_rawgeti(L, 1, l);
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
set2(L, l, u); /* swap a[l] - a[u] */
/*
** Does the partition: Pivot P is at the top of the stack.
** precondition: a[lo] <= P == a[up-1] <= a[up],
** so it only needs to do the partition from lo + 1 to up - 2.
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'.
*/
static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
IdxT i = lo; /* will be incremented before first use */
IdxT j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) {
/* next loop: repeat ++i while a[i] < P */
while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
/* next loop: repeat --j while P < a[j] */
while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
/* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
if (j < i) { /* no elements out of place? */
/* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
lua_pop(L, 1); /* pop a[j] */
/* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
set2(L, up - 1, i);
return i;
}
/* otherwise, swap a[i] - a[j] to restore invariant and repeat */
set2(L, i, j);
}
}
/*
** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd'
*/
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
IdxT r4 = (up - lo) / 4; /* range/4 */
IdxT p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4);
return p;
}
/*
** Quicksort algorithm (recursive function)
*/
static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */
IdxT p; /* Pivot index */
IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo);
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
set2(L, lo, up); /* swap a[lo] - a[up] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
lua_rawgeti(L, 1, i);
lua_rawgeti(L, 1, l);
if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
set2(L, i, l);
lua_pop(L, 2); /* remove both values */
if (up - lo == 1) /* only 2 elements? */
return; /* already sorted */
if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
p = (lo + up)/2; /* middle element is a good pivot */
else /* for larger intervals, it is worth a random pivot */
p = choosePivot(lo, up, rnd);
lua_geti(L, 1, p);
lua_geti(L, 1, lo);
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
set2(L, p, lo); /* swap a[p] - a[lo] */
else {
lua_pop(L, 1); /* remove a[l] */
lua_rawgeti(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
set2(L, i, u);
lua_pop(L, 1); /* remove a[lo] */
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
set2(L, p, up); /* swap a[up] - a[p] */
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
lua_rawgeti(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
lua_rawgeti(L, 1, u-1);
set2(L, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l; j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i>=u) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* repeat --j until a[j] <= P */
while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j<=l) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
if (j<i) {
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
break;
}
set2(L, i, j);
}
lua_rawgeti(L, 1, u-1);
lua_rawgeti(L, 1, i);
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
if (i-l < u-i) {
j=l; i=i-1; l=i+2;
if (up - lo == 2) /* only 3 elements? */
return; /* already sorted */
lua_geti(L, 1, p); /* get middle element (Pivot) */
lua_pushvalue(L, -1); /* push Pivot */
lua_geti(L, 1, up - 1); /* push a[up - 1] */
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
p = partition(L, lo, up);
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
if (p - lo < up - p) { /* lower interval is smaller? */
auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
n = p - lo; /* size of smaller interval */
lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
}
else {
j=i+1; i=u; u=j-2;
auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
auxsort(L, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */
}
static int sort (lua_State *L) {
int n = aux_getn(L, 1);
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_settop(L, 2); /* make sure there is two arguments */
auxsort(L, 1, n);
lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big");
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (IdxT)n, 0);
}
return 0;
}
@@ -259,13 +413,11 @@ static int sort (lua_State *L) {
static const luaL_Reg tab_funcs[] = {
{"concat", tconcat},
#if defined(LUA_COMPAT_MAXN)
{"maxn", maxn},
#endif
{"insert", tinsert},
{"pack", pack},
{"unpack", unpack},
{"pack", tpack},
{"unpack", tunpack},
{"remove", tremove},
{"move", tmove},
{"sort", sort},
{NULL, NULL}
};
@@ -273,11 +425,6 @@ static const luaL_Reg tab_funcs[] = {
LUAMOD_API int luaopen_table (lua_State *L) {
luaL_newlib(L, tab_funcs);
#if defined(LUA_COMPAT_UNPACK)
/* _G.unpack = table.unpack */
lua_getfield(L, -1, "unpack");
lua_setglobal(L, "unpack");
#endif
return 1;
}

1977
3rd/lua/ltests.c Normal file

File diff suppressed because it is too large Load Diff

151
3rd/lua/ltests.h Normal file
View File

@@ -0,0 +1,151 @@
/*
** $Id: ltests.h $
** Internal Header for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
#ifndef ltests_h
#define ltests_h
#include <stdio.h>
#include <stdlib.h>
/* test Lua with compatibility code */
#define LUA_COMPAT_MATHLIB
#define LUA_COMPAT_LT_LE
#define LUA_DEBUG
/* turn on assertions */
#define LUAI_ASSERT
/* to avoid warnings, and to make sure value is really unused */
#define UNUSED(x) (x=0, (void)(x))
/* test for sizes in 'l_sprintf' (make sure whole buffer is available) */
#undef l_sprintf
#if !defined(LUA_USE_C89)
#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), snprintf(s,sz,f,i))
#else
#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), sprintf(s,f,i))
#endif
/* get a chance to test code without jump tables */
#define LUA_USE_JUMPTABLE 0
/* use 32-bit integers in random generator */
#define LUA_RAND32
/* memory-allocator control variables */
typedef struct Memcontrol {
int failnext;
unsigned long numblocks;
unsigned long total;
unsigned long maxmem;
unsigned long memlimit;
unsigned long countlimit;
unsigned long objcount[LUA_NUMTYPES];
} Memcontrol;
LUA_API Memcontrol l_memcontrol;
/*
** generic variable for debug tricks
*/
extern void *l_Trick;
/*
** Function to traverse and check all memory used by Lua
*/
LUAI_FUNC int lua_checkmemory (lua_State *L);
/*
** Function to print an object GC-friendly
*/
struct GCObject;
LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o);
/* test for lock/unlock */
struct L_EXTRA { int lock; int *plock; };
#undef LUA_EXTRASPACE
#define LUA_EXTRASPACE sizeof(struct L_EXTRA)
#define getlock(l) cast(struct L_EXTRA*, lua_getextraspace(l))
#define luai_userstateopen(l) \
(getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock))
#define luai_userstateclose(l) \
lua_assert(getlock(l)->lock == 1 && getlock(l)->plock == &(getlock(l)->lock))
#define luai_userstatethread(l,l1) \
lua_assert(getlock(l1)->plock == getlock(l)->plock)
#define luai_userstatefree(l,l1) \
lua_assert(getlock(l)->plock == getlock(l1)->plock)
#define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0)
#define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0)
LUA_API int luaB_opentests (lua_State *L);
LUA_API void *debug_realloc (void *ud, void *block,
size_t osize, size_t nsize);
#if defined(lua_c)
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
#define luaL_openlibs(L) \
{ (luaL_openlibs)(L); \
luaL_requiref(L, "T", luaB_opentests, 1); \
lua_pop(L, 1); }
#endif
/* change some sizes to give some bugs a chance */
#undef LUAL_BUFFERSIZE
#define LUAL_BUFFERSIZE 23
#define MINSTRTABSIZE 2
#define MAXIWTHABS 3
#define STRCACHE_N 23
#define STRCACHE_M 5
#undef LUAI_USER_ALIGNMENT_T
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
/*
** This one is not compatible with tests for opcode optimizations,
** as it blocks some optimizations
#define MAXINDEXRK 0
*/
/* make stack-overflow tests run faster */
#undef LUAI_MAXSTACK
#define LUAI_MAXSTACK 50000
/* test mode uses more stack space */
#undef LUAI_MAXCCALLS
#define LUAI_MAXCCALLS 180
/* force Lua to use its own implementations */
#undef lua_strx2number
#undef lua_number2strx
#endif

View File

@@ -1,31 +1,37 @@
/*
** $Id: ltm.c,v 2.14.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ltm.c $
** Tag methods
** See Copyright Notice in lua.h
*/
#include <string.h>
#define ltm_c
#define LUA_CORE
#include "lprefix.h"
#include <string.h>
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
static const char udatatypename[] = "userdata";
LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = {
LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTYPES] = {
"no value",
"nil", "boolean", udatatypename, "number",
"string", "table", "function", udatatypename, "thread",
"proto", "upval" /* these last two cases are used for tests only */
"upvalue", "proto" /* these last cases are used for tests only */
};
@@ -33,14 +39,16 @@ void luaT_init (lua_State *L) {
static const char *const luaT_eventname[] = { /* ORDER TM */
"__index", "__newindex",
"__gc", "__mode", "__len", "__eq",
"__add", "__sub", "__mul", "__div", "__mod",
"__pow", "__unm", "__lt", "__le",
"__concat", "__call"
"__add", "__sub", "__mul", "__mod", "__pow",
"__div", "__idiv",
"__band", "__bor", "__bxor", "__shl", "__shr",
"__unm", "__bnot", "__lt", "__le",
"__concat", "__call", "__close"
};
int i;
for (i=0; i<TM_N; i++) {
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
luaS_fix(G(L)->tmname[i]); /* never collect these names */
luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
}
}
@@ -50,9 +58,9 @@ void luaT_init (lua_State *L) {
** tag methods
*/
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *tm = luaH_getstr(events, ename);
const TValue *tm = luaH_getshortstr(events, ename);
lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
if (notm(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */
return NULL;
}
@@ -62,7 +70,7 @@ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
Table *mt;
switch (ttypenv(o)) {
switch (ttype(o)) {
case LUA_TTABLE:
mt = hvalue(o)->metatable;
break;
@@ -70,8 +78,194 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
mt = uvalue(o)->metatable;
break;
default:
mt = G(L)->mt[ttypenv(o)];
mt = G(L)->mt[ttype(o)];
}
return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : &G(L)->nilvalue);
}
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttype(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
else
luaD_callnoyield(L, func, 0);
}
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
setobjs2s(L, res, --L->top.p); /* move result to its place */
}
static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event) {
const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */
if (notm(tm))
tm = luaT_gettmbyobj(L, p2, event); /* try second operand */
if (notm(tm)) return 0;
luaT_callTMres(L, tm, p1, p2, res);
return 1;
}
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event) {
if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
switch (event) {
case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: {
if (ttisnumber(p1) && ttisnumber(p2))
luaG_tointerror(L, p1, p2);
else
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
}
/* calls never return, but to avoid warnings: *//* FALLTHROUGH */
default:
luaG_opinterror(L, p1, p2, "perform arithmetic on");
}
}
}
void luaT_tryconcatTM (lua_State *L) {
StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
}
void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2,
int flip, StkId res, TMS event) {
if (flip)
luaT_trybinTM(L, p2, p1, res, event);
else
luaT_trybinTM(L, p1, p2, res, event);
}
void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
int flip, StkId res, TMS event) {
TValue aux;
setivalue(&aux, i2);
luaT_trybinassocTM(L, p1, &aux, flip, res, event);
}
/*
** Calls an order tag method.
** For lessequal, LUA_COMPAT_LT_LE keeps compatibility with old
** behavior: if there is no '__le', try '__lt', based on l <= r iff
** !(r < l) (assuming a total order). If the metamethod yields during
** this substitution, the continuation has to know about it (to negate
** the result of r<l); bit CIST_LEQ in the call status keeps that
** information.
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
#endif
luaG_ordererror(L, p1, p2); /* no metamethod found */
return 0; /* to avoid warnings */
}
int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int flip, int isfloat, TMS event) {
TValue aux; const TValue *p2;
if (isfloat) {
setfltvalue(&aux, cast_num(v2));
}
else
setivalue(&aux, v2);
if (flip) { /* arguments were exchanged? */
p2 = p1; p1 = &aux; /* correct them */
}
else
p2 = &aux;
return luaT_callorderTM(L, p1, p2, event);
}
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
ci->func.p += actual + 1;
ci->top.p += actual + 1;
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
int i;
int nextra = ci->u.l.nextraargs;
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: ltm.h $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -9,11 +9,12 @@
#include "lobject.h"
#include "lstate.h"
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER TM"
* grep "ORDER TM" and "ORDER OP"
*/
typedef enum {
TM_INDEX,
@@ -21,22 +22,45 @@ typedef enum {
TM_GC,
TM_MODE,
TM_LEN,
TM_EQ, /* last tag method with `fast' access */
TM_EQ, /* last tag method with fast access */
TM_ADD,
TM_SUB,
TM_MUL,
TM_DIV,
TM_MOD,
TM_POW,
TM_DIV,
TM_IDIV,
TM_BAND,
TM_BOR,
TM_BXOR,
TM_SHL,
TM_SHR,
TM_UNM,
TM_BNOT,
TM_LT,
TM_LE,
TM_CONCAT,
TM_CALL,
TM_CLOSE,
TM_N /* number of elements in the enum */
} TMS;
/*
** Mask with 1 in all fast-access methods. A 1 in any of these bits
** in the flag of a (meta)table means the metatable does not have the
** corresponding metamethod field. (Bit 7 of the flag is used for
** 'isrealasize'.)
*/
#define maskflags (~(~0u << (TM_EQ + 1)))
/*
** Test whether there is no tagmethod.
** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
*/
#define notm(tm) ttisnil(tm)
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
@@ -44,14 +68,37 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttypenv(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_DDEC(const char *const luaT_typenames_[LUA_TOTALTYPES];)
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);
LUAI_FUNC void luaT_init (lua_State *L);
LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3);
LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f,
const TValue *p1, const TValue *p2, StkId p3);
LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event);
LUAI_FUNC void luaT_tryconcatTM (lua_State *L);
LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1,
const TValue *p2, int inv, StkId res, TMS event);
LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
int inv, StkId res, TMS event);
LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
const TValue *p2, TMS event);
LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.285.1.2 2013/11/11 12:09:16 roberto Exp $
** $Id: lua.h $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -17,27 +17,31 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "2"
#define LUA_VERSION_NUM 502
#define LUA_VERSION_RELEASE "3"
#define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
/* mark for precompiled code ('<esc>Lua') */
#define LUA_SIGNATURE "\033Lua"
#define LUA_SIGNATURE "\x1bLua"
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
#define LUA_MULTRET (-1)
/*
** pseudo-indices
** Pseudo-indices
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
** space after that to help overflow detection)
*/
#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
@@ -47,28 +51,11 @@
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRGCMM 5
#define LUA_ERRERR 6
#define LUA_ERRERR 5
typedef struct lua_State lua_State;
typedef int (*lua_CFunction) (lua_State *L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
/*
** prototype for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** basic types
@@ -85,7 +72,7 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_NUMTAGS 9
#define LUA_NUMTYPES 9
@@ -109,6 +96,51 @@ typedef LUA_INTEGER lua_Integer;
/* unsigned integer type */
typedef LUA_UNSIGNED lua_Unsigned;
/* type for continuation-function contexts */
typedef LUA_KCONTEXT lua_KContext;
/*
** Type for C functions registered with Lua
*/
typedef int (*lua_CFunction) (lua_State *L);
/*
** Type for continuation functions
*/
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
/*
** Type for functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
/*
** Type for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** Type for warning functions
*/
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@@ -131,11 +163,13 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
LUA_API const lua_Number *(lua_version) (lua_State *L);
LUA_API lua_Number (lua_version) (lua_State *L);
/*
@@ -145,11 +179,9 @@ LUA_API int (lua_absindex) (lua_State *L, int idx);
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_remove) (lua_State *L, int idx);
LUA_API void (lua_insert) (lua_State *L, int idx);
LUA_API void (lua_replace) (lua_State *L, int idx);
LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
LUA_API int (lua_checkstack) (lua_State *L, int sz);
LUA_API int (lua_checkstack) (lua_State *L, int n);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
@@ -161,16 +193,16 @@ LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
LUA_API lua_Unsigned (lua_rawlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
@@ -181,13 +213,20 @@ LUA_API const void *(lua_topointer) (lua_State *L, int idx);
** Comparison and arithmetic functions
*/
#define LUA_OPADD 0 /* ORDER TM */
#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
#define LUA_OPSUB 1
#define LUA_OPMUL 2
#define LUA_OPDIV 3
#define LUA_OPMOD 4
#define LUA_OPPOW 5
#define LUA_OPUNM 6
#define LUA_OPMOD 3
#define LUA_OPPOW 4
#define LUA_OPDIV 5
#define LUA_OPIDIV 6
#define LUA_OPBAND 7
#define LUA_OPBOR 8
#define LUA_OPBXOR 9
#define LUA_OPSHL 10
#define LUA_OPSHR 11
#define LUA_OPUNM 12
#define LUA_OPBNOT 13
LUA_API void (lua_arith) (lua_State *L, int op);
@@ -205,8 +244,7 @@ LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
@@ -216,64 +254,78 @@ LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
LUA_API void (lua_clonefunction) (lua_State *L, const void * fp);
LUA_API void (lua_sharefunction) (lua_State *L, int index);
LUA_API void (lua_sharestring) (lua_State *L, int index);
LUA_API void (lua_clonetable) (lua_State *L, const void * t);
/*
** get functions (Lua -> stack)
*/
LUA_API void (lua_getglobal) (lua_State *L, const char *var);
LUA_API void (lua_gettable) (lua_State *L, int idx);
LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawget) (lua_State *L, int idx);
LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API int (lua_getglobal) (lua_State *L, const char *name);
LUA_API int (lua_gettable) (lua_State *L, int idx);
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawget) (lua_State *L, int idx);
LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API void *(lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API void (lua_getuservalue) (lua_State *L, int idx);
LUA_API int (lua_getiuservalue) (lua_State *L, int idx, int n);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_setglobal) (lua_State *L, const char *var);
LUA_API void (lua_setglobal) (lua_State *L, const char *name);
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API void (lua_setuservalue) (lua_State *L, int idx);
LUA_API int (lua_setiuservalue) (lua_State *L, int idx, int n);
/*
** 'load' and 'call' functions (load and run Lua code)
*/
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
lua_CFunction k);
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k);
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
LUA_API int (lua_getctx) (lua_State *L, int *ctx);
LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
int ctx, lua_CFunction k);
lua_KContext ctx, lua_KFunction k);
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname,
const char *mode);
const char *chunkname, const char *mode);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
LUA_API void (lua_clonefunction) (lua_State *L, const void *eL);
/*
** coroutine functions
*/
LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx,
lua_CFunction k);
LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
lua_KFunction k);
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg,
int *nres);
LUA_API int (lua_status) (lua_State *L);
LUA_API int (lua_isyieldable) (lua_State *L);
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
LUA_API int (lua_status) (lua_State *L);
/*
** Warning-related functions
*/
LUA_API void (lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud);
LUA_API void (lua_warning) (lua_State *L, const char *msg, int tocont);
/*
** garbage-collection function and options
@@ -287,12 +339,11 @@ LUA_API int (lua_status) (lua_State *L);
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCSETMAJORINC 8
#define LUA_GCISRUNNING 9
#define LUA_GCGEN 10
#define LUA_GCINC 11
LUA_API int (lua_gc) (lua_State *L, int what, int data);
LUA_API int (lua_gc) (lua_State *L, int what, ...);
/*
@@ -306,20 +357,25 @@ LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API void (lua_len) (lua_State *L, int idx);
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
LUA_API void (lua_toclose) (lua_State *L, int idx);
LUA_API void (lua_closeslot) (lua_State *L, int idx);
/*
** ===============================================================
** {==============================================================
** some useful macros
** ===============================================================
*/
#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL)
#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL)
#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
#define lua_pop(L,n) lua_settop(L, -(n)-1)
@@ -338,15 +394,43 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
/* }============================================================== */
/*
** {==============================================================
** compatibility macros
** ===============================================================
*/
#if defined(LUA_COMPAT_APIINTCASTS)
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
#endif
#define lua_newuserdata(L,s) lua_newuserdatauv(L,s,1)
#define lua_getuservalue(L,idx) lua_getiuservalue(L,idx,1)
#define lua_setuservalue(L,idx) lua_setiuservalue(L,idx,1)
#define LUA_NUMTAGS LUA_NUMTYPES
/* }============================================================== */
/*
** {======================================================================
@@ -373,12 +457,6 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -391,11 +469,12 @@ LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
int fidx2, int n2);
LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
LUA_API int (lua_setcstacklimit) (lua_State *L, unsigned int limit);
struct lua_Debug {
int event;
@@ -403,6 +482,7 @@ struct lua_Debug {
const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
const char *source; /* (S) */
size_t srclen; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
@@ -410,6 +490,8 @@ struct lua_Debug {
unsigned char nparams;/* (u) number of parameters */
char isvararg; /* (u) */
char istailcall; /* (t) */
unsigned short ftransfer; /* (r) index of first value transferred */
unsigned short ntransfer; /* (r) number of transferred values */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
struct CallInfo *i_ci; /* active function */
@@ -419,7 +501,7 @@ struct lua_Debug {
/******************************************************************************
* Copyright (C) 1994-2013 Lua.org, PUC-Rio.
* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

View File

@@ -1,21 +1,27 @@
/*
** $Id: luac.c,v 1.69 2011/11/29 17:46:33 lhf Exp $
** Lua compiler (saves bytecodes to files; also list bytecodes)
** $Id: luac.c $
** Lua compiler (saves bytecodes to files; also lists bytecodes)
** See Copyright Notice in lua.h
*/
#define luac_c
#define LUA_CORE
#include "lprefix.h"
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define luac_c
#define LUA_CORE
#include "lua.h"
#include "lauxlib.h"
#include "ldebug.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lopnames.h"
#include "lstate.h"
#include "lundump.h"
@@ -31,6 +37,7 @@ static int stripping=0; /* strip debug information? */
static char Output[]={ OUTPUT }; /* default output file name */
static const char* output=Output; /* actual output file name */
static const char* progname=PROGNAME; /* actual program name */
static TString **tmname;
static void fatal(const char* message)
{
@@ -47,14 +54,14 @@ static void cannot(const char* what)
static void usage(const char* message)
{
if (*message=='-')
fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
else
fprintf(stderr,"%s: %s\n",progname,message);
fprintf(stderr,
"usage: %s [options] [filenames]\n"
"Available options are:\n"
" -l list (use -l -l for full listing)\n"
" -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
" -o name output to file 'name' (default is \"%s\")\n"
" -p parse only\n"
" -s strip debug information\n"
" -v show version information\n"
@@ -89,7 +96,7 @@ static int doargs(int argc, char* argv[])
{
output=argv[++i];
if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
usage(LUA_QL("-o") " needs argument");
usage("'-o' needs argument");
if (IS("-")) output=NULL;
}
else if (IS("-p")) /* parse only */
@@ -114,9 +121,9 @@ static int doargs(int argc, char* argv[])
return i;
}
#define FUNCTION "(function()end)();"
#define FUNCTION "(function()end)();\n"
static const char* reader(lua_State *L, void *ud, size_t *size)
static const char* reader(lua_State* L, void* ud, size_t* size)
{
UNUSED(L);
if ((*(int*)ud)--)
@@ -131,7 +138,7 @@ static const char* reader(lua_State *L, void *ud, size_t *size)
}
}
#define toproto(L,i) getproto(L->top+(i))
#define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n)
{
@@ -146,9 +153,8 @@ static const Proto* combine(lua_State* L, int n)
for (i=0; i<n; i++)
{
f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sp->sizeupvalues>0) f->p[i]->sp->upvalues[0].instack=0;
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
}
f->sp->sizelineinfo=0;
return f;
}
}
@@ -165,6 +171,7 @@ static int pmain(lua_State* L)
char** argv=(char**)lua_touserdata(L,2);
const Proto* f;
int i;
tmname=G(L)->tmname;
if (!lua_checkstack(L,argc)) fatal("too many input files");
for (i=0; i<argc; i++)
{
@@ -203,82 +210,131 @@ int main(int argc, char* argv[])
}
/*
** $Id: print.c,v 1.69 2013/07/04 01:03:46 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
#include <ctype.h>
#include <stdio.h>
#define luac_c
#define LUA_CORE
#include "ldebug.h"
#include "lobject.h"
#include "lopcodes.h"
#define VOID(p) ((const void*)(p))
#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
#define VOID(p) ((const void*)(p))
#define eventname(i) (getstr(tmname[i]))
static void PrintString(const TString* ts)
{
const char* s=getstr(ts);
size_t i,n=ts->tsv.len;
printf("%c",'"');
size_t i,n=tsslen(ts);
printf("\"");
for (i=0; i<n; i++)
{
int c=(int)(unsigned char)s[i];
switch (c)
{
case '"': printf("\\\""); break;
case '\\': printf("\\\\"); break;
case '\a': printf("\\a"); break;
case '\b': printf("\\b"); break;
case '\f': printf("\\f"); break;
case '\n': printf("\\n"); break;
case '\r': printf("\\r"); break;
case '\t': printf("\\t"); break;
case '\v': printf("\\v"); break;
default: if (isprint(c))
printf("%c",c);
else
printf("\\%03d",c);
case '"':
printf("\\\"");
break;
case '\\':
printf("\\\\");
break;
case '\a':
printf("\\a");
break;
case '\b':
printf("\\b");
break;
case '\f':
printf("\\f");
break;
case '\n':
printf("\\n");
break;
case '\r':
printf("\\r");
break;
case '\t':
printf("\\t");
break;
case '\v':
printf("\\v");
break;
default:
if (isprint(c)) printf("%c",c); else printf("\\%03d",c);
break;
}
}
printf("%c",'"');
printf("\"");
}
static void PrintType(const Proto* f, int i)
{
const TValue* o=&f->k[i];
switch (ttypetag(o))
{
case LUA_VNIL:
printf("N");
break;
case LUA_VFALSE:
case LUA_VTRUE:
printf("B");
break;
case LUA_VNUMFLT:
printf("F");
break;
case LUA_VNUMINT:
printf("I");
break;
case LUA_VSHRSTR:
case LUA_VLNGSTR:
printf("S");
break;
default: /* cannot happen */
printf("?%d",ttypetag(o));
break;
}
printf("\t");
}
static void PrintConstant(const Proto* f, int i)
{
const TValue* o=&f->k[i];
switch (ttypenv(o))
switch (ttypetag(o))
{
case LUA_TNIL:
case LUA_VNIL:
printf("nil");
break;
case LUA_TBOOLEAN:
printf(bvalue(o) ? "true" : "false");
case LUA_VFALSE:
printf("false");
break;
case LUA_TNUMBER:
printf(LUA_NUMBER_FMT,nvalue(o));
case LUA_VTRUE:
printf("true");
break;
case LUA_TSTRING:
PrintString(rawtsvalue(o));
case LUA_VNUMFLT:
{
char buff[100];
sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
printf("%s",buff);
if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
break;
}
case LUA_VNUMINT:
printf(LUA_INTEGER_FMT,ivalue(o));
break;
case LUA_VSHRSTR:
case LUA_VLNGSTR:
PrintString(tsvalue(o));
break;
default: /* cannot happen */
printf("? type=%d",ttype(o));
printf("?%d",ttypetag(o));
break;
}
}
#define UPVALNAME(x) ((f->sp->upvalues[x].name) ? getstr(f->sp->upvalues[x].name) : "-")
#define MYK(x) (-1-(x))
#define COMMENT "\t; "
#define EXTRAARG GETARG_Ax(code[pc+1])
#define EXTRAARGC (EXTRAARG*(MAXARG_C+1))
#define ISK (isk ? "k" : "")
static void PrintCode(const Proto* f)
{
const SharedProto *sp = f->sp;
const Instruction* code=sp->code;
int pc,n=sp->sizecode;
const Instruction* code=f->code;
int pc,n=f->sizecode;
for (pc=0; pc<n; pc++)
{
Instruction i=code[pc];
@@ -288,95 +344,328 @@ static void PrintCode(const Proto* f)
int c=GETARG_C(i);
int ax=GETARG_Ax(i);
int bx=GETARG_Bx(i);
int sb=GETARG_sB(i);
int sc=GETARG_sC(i);
int sbx=GETARG_sBx(i);
int line=getfuncline(f,pc);
int isk=GETARG_k(i);
int line=luaG_getfuncline(f,pc);
printf("\t%d\t",pc+1);
if (line>0) printf("[%d]\t",line); else printf("[-]\t");
printf("%-9s\t",luaP_opnames[o]);
switch (getOpMode(o))
{
case iABC:
printf("%d",a);
if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
break;
case iABx:
printf("%d",a);
if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
if (getBMode(o)==OpArgU) printf(" %d",bx);
break;
case iAsBx:
printf("%d %d",a,sbx);
break;
case iAx:
printf("%d",MYK(ax));
break;
}
printf("%-9s\t",opnames[o]);
switch (o)
{
case OP_MOVE:
printf("%d %d",a,b);
break;
case OP_LOADI:
printf("%d %d",a,sbx);
break;
case OP_LOADF:
printf("%d %d",a,sbx);
break;
case OP_LOADK:
printf("\t; "); PrintConstant(f,bx);
break;
printf("%d %d",a,bx);
printf(COMMENT); PrintConstant(f,bx);
break;
case OP_LOADKX:
printf("%d",a);
printf(COMMENT); PrintConstant(f,EXTRAARG);
break;
case OP_LOADFALSE:
printf("%d",a);
break;
case OP_LFALSESKIP:
printf("%d",a);
break;
case OP_LOADTRUE:
printf("%d",a);
break;
case OP_LOADNIL:
printf("%d %d",a,b);
printf(COMMENT "%d out",b+1);
break;
case OP_GETUPVAL:
printf("%d %d",a,b);
printf(COMMENT "%s",UPVALNAME(b));
break;
case OP_SETUPVAL:
printf("\t; %s",UPVALNAME(b));
break;
printf("%d %d",a,b);
printf(COMMENT "%s",UPVALNAME(b));
break;
case OP_GETTABUP:
printf("\t; %s",UPVALNAME(b));
if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
break;
case OP_SETTABUP:
printf("\t; %s",UPVALNAME(a));
if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
break;
printf("%d %d %d",a,b,c);
printf(COMMENT "%s",UPVALNAME(b));
printf(" "); PrintConstant(f,c);
break;
case OP_GETTABLE:
case OP_SELF:
if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
break;
printf("%d %d %d",a,b,c);
break;
case OP_GETI:
printf("%d %d %d",a,b,c);
break;
case OP_GETFIELD:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_SETTABUP:
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT "%s",UPVALNAME(a));
printf(" "); PrintConstant(f,b);
if (isk) { printf(" "); PrintConstant(f,c); }
break;
case OP_SETTABLE:
printf("%d %d %d%s",a,b,c,ISK);
if (isk) { printf(COMMENT); PrintConstant(f,c); }
break;
case OP_SETI:
printf("%d %d %d%s",a,b,c,ISK);
if (isk) { printf(COMMENT); PrintConstant(f,c); }
break;
case OP_SETFIELD:
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT); PrintConstant(f,b);
if (isk) { printf(" "); PrintConstant(f,c); }
break;
case OP_NEWTABLE:
printf("%d %d %d",a,b,c);
printf(COMMENT "%d",c+EXTRAARGC);
break;
case OP_SELF:
printf("%d %d %d%s",a,b,c,ISK);
if (isk) { printf(COMMENT); PrintConstant(f,c); }
break;
case OP_ADDI:
printf("%d %d %d",a,b,sc);
break;
case OP_ADDK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_SUBK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_MULK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_MODK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_POWK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_DIVK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_IDIVK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_BANDK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_BORK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_BXORK:
printf("%d %d %d",a,b,c);
printf(COMMENT); PrintConstant(f,c);
break;
case OP_SHRI:
printf("%d %d %d",a,b,sc);
break;
case OP_SHLI:
printf("%d %d %d",a,b,sc);
break;
case OP_ADD:
printf("%d %d %d",a,b,c);
break;
case OP_SUB:
printf("%d %d %d",a,b,c);
break;
case OP_MUL:
case OP_DIV:
printf("%d %d %d",a,b,c);
break;
case OP_MOD:
printf("%d %d %d",a,b,c);
break;
case OP_POW:
case OP_EQ:
case OP_LT:
case OP_LE:
if (ISK(b) || ISK(c))
{
printf("\t; ");
if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
printf(" ");
if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
}
break;
printf("%d %d %d",a,b,c);
break;
case OP_DIV:
printf("%d %d %d",a,b,c);
break;
case OP_IDIV:
printf("%d %d %d",a,b,c);
break;
case OP_BAND:
printf("%d %d %d",a,b,c);
break;
case OP_BOR:
printf("%d %d %d",a,b,c);
break;
case OP_BXOR:
printf("%d %d %d",a,b,c);
break;
case OP_SHL:
printf("%d %d %d",a,b,c);
break;
case OP_SHR:
printf("%d %d %d",a,b,c);
break;
case OP_MMBIN:
printf("%d %d %d",a,b,c);
printf(COMMENT "%s",eventname(c));
break;
case OP_MMBINI:
printf("%d %d %d %d",a,sb,c,isk);
printf(COMMENT "%s",eventname(c));
if (isk) printf(" flip");
break;
case OP_MMBINK:
printf("%d %d %d %d",a,b,c,isk);
printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
if (isk) printf(" flip");
break;
case OP_UNM:
printf("%d %d",a,b);
break;
case OP_BNOT:
printf("%d %d",a,b);
break;
case OP_NOT:
printf("%d %d",a,b);
break;
case OP_LEN:
printf("%d %d",a,b);
break;
case OP_CONCAT:
printf("%d %d",a,b);
break;
case OP_CLOSE:
printf("%d",a);
break;
case OP_TBC:
printf("%d",a);
break;
case OP_JMP:
printf("%d",GETARG_sJ(i));
printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
break;
case OP_EQ:
printf("%d %d %d",a,b,isk);
break;
case OP_LT:
printf("%d %d %d",a,b,isk);
break;
case OP_LE:
printf("%d %d %d",a,b,isk);
break;
case OP_EQK:
printf("%d %d %d",a,b,isk);
printf(COMMENT); PrintConstant(f,b);
break;
case OP_EQI:
printf("%d %d %d",a,sb,isk);
break;
case OP_LTI:
printf("%d %d %d",a,sb,isk);
break;
case OP_LEI:
printf("%d %d %d",a,sb,isk);
break;
case OP_GTI:
printf("%d %d %d",a,sb,isk);
break;
case OP_GEI:
printf("%d %d %d",a,sb,isk);
break;
case OP_TEST:
printf("%d %d",a,isk);
break;
case OP_TESTSET:
printf("%d %d %d",a,b,isk);
break;
case OP_CALL:
printf("%d %d %d",a,b,c);
printf(COMMENT);
if (b==0) printf("all in "); else printf("%d in ",b-1);
if (c==0) printf("all out"); else printf("%d out",c-1);
break;
case OP_TAILCALL:
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT "%d in",b-1);
break;
case OP_RETURN:
printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT);
if (b==0) printf("all out"); else printf("%d out",b-1);
break;
case OP_RETURN0:
break;
case OP_RETURN1:
printf("%d",a);
break;
case OP_FORLOOP:
printf("%d %d",a,bx);
printf(COMMENT "to %d",pc-bx+2);
break;
case OP_FORPREP:
printf("%d %d",a,bx);
printf(COMMENT "exit to %d",pc+bx+3);
break;
case OP_TFORPREP:
printf("%d %d",a,bx);
printf(COMMENT "to %d",pc+bx+2);
break;
case OP_TFORCALL:
printf("%d %d",a,c);
break;
case OP_TFORLOOP:
printf("\t; to %d",sbx+pc+2);
break;
case OP_CLOSURE:
printf("\t; %p",VOID(f->p[bx]));
break;
printf("%d %d",a,bx);
printf(COMMENT "to %d",pc-bx+2);
break;
case OP_SETLIST:
if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
break;
printf("%d %d %d",a,b,c);
if (isk) printf(COMMENT "%d",c+EXTRAARGC);
break;
case OP_CLOSURE:
printf("%d %d",a,bx);
printf(COMMENT "%p",VOID(f->p[bx]));
break;
case OP_VARARG:
printf("%d %d",a,c);
printf(COMMENT);
if (c==0) printf("all out"); else printf("%d out",c-1);
break;
case OP_VARARGPREP:
printf("%d",a);
break;
case OP_EXTRAARG:
printf("\t; "); PrintConstant(f,ax);
break;
printf("%d",ax);
break;
#if 0
default:
break;
printf("%d %d %d",a,b,c);
printf(COMMENT "not handled");
break;
#endif
}
printf("\n");
}
}
#define SS(x) ((x==1)?"":"s")
#define S(x) (int)(x),SS(x)
static void PrintHeader(const SharedProto* f)
static void PrintHeader(const Proto* f)
{
const char* s=f->source ? getstr(f->source) : "=?";
if (*s=='@' || *s=='=')
@@ -386,7 +675,7 @@ static void PrintHeader(const SharedProto* f)
else
s="(string)";
printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
(f->linedefined==0)?"main":"function",s,
(f->linedefined==0)?"main":"function",s,
f->linedefined,f->lastlinedefined,
S(f->sizecode),VOID(f));
printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
@@ -398,36 +687,36 @@ static void PrintHeader(const SharedProto* f)
static void PrintDebug(const Proto* f)
{
const SharedProto *sp = f->sp;
int i,n;
n=sp->sizek;
n=f->sizek;
printf("constants (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t",i+1);
printf("\t%d\t",i);
PrintType(f,i);
PrintConstant(f,i);
printf("\n");
}
n=sp->sizelocvars;
n=f->sizelocvars;
printf("locals (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t%s\t%d\t%d\n",
i,getstr(sp->locvars[i].varname),sp->locvars[i].startpc+1,sp->locvars[i].endpc+1);
i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
}
n=sp->sizeupvalues;
n=f->sizeupvalues;
printf("upvalues (%d) for %p:\n",n,VOID(f));
for (i=0; i<n; i++)
{
printf("\t%d\t%s\t%d\t%d\n",
i,UPVALNAME(i),sp->upvalues[i].instack,sp->upvalues[i].idx);
i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
}
}
static void PrintFunction(const Proto* f, int full)
{
int i,n=f->sp->sizep;
PrintHeader(f->sp);
int i,n=f->sizep;
PrintHeader(f);
PrintCode(f);
if (full) PrintDebug(f);
for (i=0; i<n; i++) PrintFunction(f->p[i],full);

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lualib.h $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,9 @@
#include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
LUAMOD_API int (luaopen_base) (lua_State *L);
@@ -29,8 +32,8 @@ LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
#define LUA_UTF8LIBNAME "utf8"
LUAMOD_API int (luaopen_utf8) (lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);
@@ -43,15 +46,10 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
#define LUA_CACHELIB
LUAMOD_API int (luaopen_cache) (lua_State *L);
LUALIB_API void (luaL_initcodecache) (void);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
#endif

View File

@@ -1,14 +1,18 @@
/*
** $Id: lundump.c,v 2.22.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lundump.c $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#include <string.h>
#define lundump_c
#define LUA_CORE
#include "lprefix.h"
#include <limits.h>
#include <string.h>
#include "lua.h"
#include "ldebug.h"
@@ -20,240 +24,312 @@
#include "lundump.h"
#include "lzio.h"
typedef struct {
lua_State* L;
ZIO* Z;
Mbuffer* b;
const char* name;
} LoadState;
static l_noret error(LoadState* S, const char* why)
{
luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);
luaD_throw(S->L,LUA_ERRSYNTAX);
}
#define LoadMem(S,b,n,size) LoadBlock(S,b,(n)*(size))
#define LoadByte(S) (lu_byte)LoadChar(S)
#define LoadVar(S,x) LoadMem(S,&x,1,sizeof(x))
#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
#if !defined(luai_verifycode)
#define luai_verifycode(L,b,f) /* empty */
#define luai_verifycode(L,f) /* empty */
#endif
static void LoadBlock(LoadState* S, void* b, size_t size)
{
if (luaZ_read(S->Z,b,size)!=0) error(S,"truncated");
typedef struct {
lua_State *L;
ZIO *Z;
const char *name;
} LoadState;
static l_noret error (LoadState *S, const char *why) {
luaO_pushfstring(S->L, "%s: bad binary format (%s)", S->name, why);
luaD_throw(S->L, LUA_ERRSYNTAX);
}
static int LoadChar(LoadState* S)
{
char x;
LoadVar(S,x);
return x;
/*
** All high-level loads go through loadVector; you can change it to
** adapt to the endianness of the input
*/
#define loadVector(S,b,n) loadBlock(S,b,(n)*sizeof((b)[0]))
static void loadBlock (LoadState *S, void *b, size_t size) {
if (luaZ_read(S->Z, b, size) != 0)
error(S, "truncated chunk");
}
static int LoadInt(LoadState* S)
{
int x;
LoadVar(S,x);
if (x<0) error(S,"corrupted");
return x;
#define loadVar(S,x) loadVector(S,&x,1)
static lu_byte loadByte (LoadState *S) {
int b = zgetc(S->Z);
if (b == EOZ)
error(S, "truncated chunk");
return cast_byte(b);
}
static lua_Number LoadNumber(LoadState* S)
{
lua_Number x;
LoadVar(S,x);
return x;
static size_t loadUnsigned (LoadState *S, size_t limit) {
size_t x = 0;
int b;
limit >>= 7;
do {
b = loadByte(S);
if (x >= limit)
error(S, "integer overflow");
x = (x << 7) | (b & 0x7f);
} while ((b & 0x80) == 0);
return x;
}
static TString* LoadString(LoadState* S)
{
size_t size;
LoadVar(S,size);
if (size==0)
return NULL;
else
{
char* s=luaZ_openspace(S->L,S->b,size);
LoadBlock(S,s,size*sizeof(char));
return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
}
static size_t loadSize (LoadState *S) {
return loadUnsigned(S, ~(size_t)0);
}
static void LoadCode(LoadState* S, SharedProto* f)
{
int n=LoadInt(S);
f->code=luaM_newvector(S->L,n,Instruction);
f->sizecode=n;
LoadVector(S,f->code,n,sizeof(Instruction));
static int loadInt (LoadState *S) {
return cast_int(loadUnsigned(S, INT_MAX));
}
static void LoadFunction(LoadState* S, Proto* f);
static void LoadConstants(LoadState* S, Proto* f)
{
int i,n;
n=LoadInt(S);
f->k=luaM_newvector(S->L,n,TValue);
f->sp->sizek=n;
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
for (i=0; i<n; i++)
{
TValue* o=&f->k[i];
int t=LoadChar(S);
switch (t)
{
case LUA_TNIL:
setnilvalue(o);
break;
case LUA_TBOOLEAN:
setbvalue(o,LoadChar(S));
break;
case LUA_TNUMBER:
setnvalue(o,LoadNumber(S));
break;
case LUA_TSTRING:
setsvalue2n(S->L,o,LoadString(S));
break;
default: lua_assert(0);
static lua_Number loadNumber (LoadState *S) {
lua_Number x;
loadVar(S, x);
return x;
}
static lua_Integer loadInteger (LoadState *S) {
lua_Integer x;
loadVar(S, x);
return x;
}
/*
** Load a nullable string into prototype 'p'.
*/
static TString *loadStringN (LoadState *S, Proto *p) {
lua_State *L = S->L;
TString *ts;
size_t size = loadSize(S);
if (size == 0) /* no string? */
return NULL;
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
char buff[LUAI_MAXSHORTLEN];
loadVector(S, buff, size); /* load string into buffer */
ts = luaS_newlstr(L, buff, size); /* create string */
}
}
n=LoadInt(S);
f->p=luaM_newvector(S->L,n,Proto*);
f->sp->sizep=n;
for (i=0; i<n; i++) f->p[i]=NULL;
for (i=0; i<n; i++)
{
f->p[i]=luaF_newproto(S->L, NULL);
LoadFunction(S,f->p[i]);
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
}
static void LoadUpvalues(LoadState* S, SharedProto* f)
{
int i,n;
n=LoadInt(S);
f->upvalues=luaM_newvector(S->L,n,Upvaldesc);
f->sizeupvalues=n;
for (i=0; i<n; i++) f->upvalues[i].name=NULL;
for (i=0; i<n; i++)
{
f->upvalues[i].instack=LoadByte(S);
f->upvalues[i].idx=LoadByte(S);
}
}
static void LoadDebug(LoadState* S, SharedProto* f)
{
int i,n;
f->source=LoadString(S);
n=LoadInt(S);
f->lineinfo=luaM_newvector(S->L,n,int);
f->sizelineinfo=n;
LoadVector(S,f->lineinfo,n,sizeof(int));
n=LoadInt(S);
f->locvars=luaM_newvector(S->L,n,LocVar);
f->sizelocvars=n;
for (i=0; i<n; i++) f->locvars[i].varname=NULL;
for (i=0; i<n; i++)
{
f->locvars[i].varname=LoadString(S);
f->locvars[i].startpc=LoadInt(S);
f->locvars[i].endpc=LoadInt(S);
}
n=LoadInt(S);
for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S);
}
static void LoadFunction(LoadState* S, Proto* f)
{
SharedProto *sp = f->sp;
sp->linedefined=LoadInt(S);
sp->lastlinedefined=LoadInt(S);
sp->numparams=LoadByte(S);
sp->is_vararg=LoadByte(S);
sp->maxstacksize=LoadByte(S);
LoadCode(S,sp);
LoadConstants(S,f);
LoadUpvalues(S,sp);
LoadDebug(S,sp);
}
/* the code below must be consistent with the code in luaU_header */
#define N0 LUAC_HEADERSIZE
#define N1 (sizeof(LUA_SIGNATURE)-sizeof(char))
#define N2 N1+2
#define N3 N2+6
static void LoadHeader(LoadState* S)
{
lu_byte h[LUAC_HEADERSIZE];
lu_byte s[LUAC_HEADERSIZE];
luaU_header(h);
memcpy(s,h,sizeof(char)); /* first char already read */
LoadBlock(S,s+sizeof(char),LUAC_HEADERSIZE-sizeof(char));
if (memcmp(h,s,N0)==0) return;
if (memcmp(h,s,N1)!=0) error(S,"not a");
if (memcmp(h,s,N2)!=0) error(S,"version mismatch in");
if (memcmp(h,s,N3)!=0) error(S,"incompatible"); else error(S,"corrupted");
}
/*
** load precompiled chunk
** Load a non-nullable string into prototype 'p'.
*/
Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
{
LoadState S;
Closure* cl;
if (*name=='@' || *name=='=')
S.name=name+1;
else if (*name==LUA_SIGNATURE[0])
S.name="binary string";
else
S.name=name;
S.L=L;
S.Z=Z;
S.b=buff;
LoadHeader(&S);
cl=luaF_newLclosure(L,1);
setclLvalue(L,L->top,cl); incr_top(L);
cl->l.p=luaF_newproto(L, NULL);
LoadFunction(&S,cl->l.p);
if (cl->l.p->sp->sizeupvalues != 1)
{
Proto* p=cl->l.p;
cl=luaF_newLclosure(L,cl->l.p->sp->sizeupvalues);
cl->l.p=p;
setclLvalue(L,L->top-1,cl);
}
luai_verifycode(L,buff,cl->l.p);
return cl;
static TString *loadString (LoadState *S, Proto *p) {
TString *st = loadStringN(S, p);
if (st == NULL)
error(S, "bad format for constant string");
return st;
}
static void loadCode (LoadState *S, Proto *f) {
int n = loadInt(S);
f->code = luaM_newvectorchecked(S->L, n, Instruction);
f->sizecode = n;
loadVector(S, f->code, n);
}
static void loadFunction(LoadState *S, Proto *f, TString *psource);
static void loadConstants (LoadState *S, Proto *f) {
int i;
int n = loadInt(S);
f->k = luaM_newvectorchecked(S->L, n, TValue);
f->sizek = n;
for (i = 0; i < n; i++)
setnilvalue(&f->k[i]);
for (i = 0; i < n; i++) {
TValue *o = &f->k[i];
int t = loadByte(S);
switch (t) {
case LUA_VNIL:
setnilvalue(o);
break;
case LUA_VFALSE:
setbfvalue(o);
break;
case LUA_VTRUE:
setbtvalue(o);
break;
case LUA_VNUMFLT:
setfltvalue(o, loadNumber(S));
break;
case LUA_VNUMINT:
setivalue(o, loadInteger(S));
break;
case LUA_VSHRSTR:
case LUA_VLNGSTR:
setsvalue2n(S->L, o, loadString(S, f));
break;
default: lua_assert(0);
}
}
}
static void loadProtos (LoadState *S, Proto *f) {
int i;
int n = loadInt(S);
f->p = luaM_newvectorchecked(S->L, n, Proto *);
f->sizep = n;
for (i = 0; i < n; i++)
f->p[i] = NULL;
for (i = 0; i < n; i++) {
f->p[i] = luaF_newproto(S->L);
luaC_objbarrier(S->L, f, f->p[i]);
loadFunction(S, f->p[i], f->source);
}
}
#define MYINT(s) (s[0]-'0')
#define VERSION MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)
#define FORMAT 0 /* this is the official format */
/*
* make header for precompiled chunks
* if you change the code below be sure to update LoadHeader and FORMAT above
* and LUAC_HEADERSIZE in lundump.h
** Load the upvalues for a function. The names must be filled first,
** because the filling of the other fields can raise read errors and
** the creation of the error message can call an emergency collection;
** in that case all prototypes must be consistent for the GC.
*/
void luaU_header (lu_byte* h)
{
int x=1;
memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-sizeof(char));
h+=sizeof(LUA_SIGNATURE)-sizeof(char);
*h++=cast_byte(VERSION);
*h++=cast_byte(FORMAT);
*h++=cast_byte(*(char*)&x); /* endianness */
*h++=cast_byte(sizeof(int));
*h++=cast_byte(sizeof(size_t));
*h++=cast_byte(sizeof(Instruction));
*h++=cast_byte(sizeof(lua_Number));
*h++=cast_byte(((lua_Number)0.5)==0); /* is lua_Number integral? */
memcpy(h,LUAC_TAIL,sizeof(LUAC_TAIL)-sizeof(char));
static void loadUpvalues (LoadState *S, Proto *f) {
int i, n;
n = loadInt(S);
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
f->sizeupvalues = n;
for (i = 0; i < n; i++) /* make array valid for GC */
f->upvalues[i].name = NULL;
for (i = 0; i < n; i++) { /* following calls can raise errors */
f->upvalues[i].instack = loadByte(S);
f->upvalues[i].idx = loadByte(S);
f->upvalues[i].kind = loadByte(S);
}
}
static void loadDebug (LoadState *S, Proto *f) {
int i, n;
n = loadInt(S);
f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte);
f->sizelineinfo = n;
loadVector(S, f->lineinfo, n);
n = loadInt(S);
f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo);
f->sizeabslineinfo = n;
for (i = 0; i < n; i++) {
f->abslineinfo[i].pc = loadInt(S);
f->abslineinfo[i].line = loadInt(S);
}
n = loadInt(S);
f->locvars = luaM_newvectorchecked(S->L, n, LocVar);
f->sizelocvars = n;
for (i = 0; i < n; i++)
f->locvars[i].varname = NULL;
for (i = 0; i < n; i++) {
f->locvars[i].varname = loadStringN(S, f);
f->locvars[i].startpc = loadInt(S);
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
static void loadFunction (LoadState *S, Proto *f, TString *psource) {
f->source = loadStringN(S, f);
if (f->source == NULL) /* no source in dump? */
f->source = psource; /* reuse parent's source */
f->linedefined = loadInt(S);
f->lastlinedefined = loadInt(S);
f->numparams = loadByte(S);
f->is_vararg = loadByte(S);
f->maxstacksize = loadByte(S);
loadCode(S, f);
loadConstants(S, f);
loadUpvalues(S, f);
loadProtos(S, f);
loadDebug(S, f);
}
static void checkliteral (LoadState *S, const char *s, const char *msg) {
char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
size_t len = strlen(s);
loadVector(S, buff, len);
if (memcmp(s, buff, len) != 0)
error(S, msg);
}
static void fchecksize (LoadState *S, size_t size, const char *tname) {
if (loadByte(S) != size)
error(S, luaO_pushfstring(S->L, "%s size mismatch", tname));
}
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
static void checkHeader (LoadState *S) {
/* skip 1st char (already read and checked) */
checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
if (loadByte(S) != LUAC_VERSION)
error(S, "version mismatch");
if (loadByte(S) != LUAC_FORMAT)
error(S, "format mismatch");
checkliteral(S, LUAC_DATA, "corrupted chunk");
checksize(S, Instruction);
checksize(S, lua_Integer);
checksize(S, lua_Number);
if (loadInteger(S) != LUAC_INT)
error(S, "integer format mismatch");
if (loadNumber(S) != LUAC_NUM)
error(S, "float format mismatch");
}
/*
** Load precompiled chunk.
*/
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
S.name = name + 1;
else if (*name == LUA_SIGNATURE[0])
S.name = "binary string";
else
S.name = name;
S.L = L;
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
loadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luai_verifycode(L, cl->p);
return cl;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lundump.h $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -7,22 +7,30 @@
#ifndef lundump_h
#define lundump_h
#include "llimits.h"
#include "lobject.h"
#include "lzio.h"
/* load one chunk; from lundump.c */
LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
/* make header; from lundump.c */
LUAI_FUNC void luaU_header (lu_byte* h);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
/* data to catch conversion errors */
#define LUAC_TAIL "\x19\x93\r\n\x1a\n"
#define LUAC_DATA "\x19\x93\r\n\x1a\n"
/* size in bytes of header of binary files */
#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char))
#define LUAC_INT 0x5678
#define LUAC_NUM cast_num(370.5)
/*
** Encode major-minor version in one byte, one nibble for each
*/
#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */
#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR))
#define LUAC_FORMAT 0 /* this is the official format */
/* load one chunk; from lundump.c */
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
void* data, int strip);
#endif

291
3rd/lua/lutf8lib.c Normal file
View File

@@ -0,0 +1,291 @@
/*
** $Id: lutf8lib.c $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
#define lutf8lib_c
#define LUA_LIB
#include "lprefix.h"
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define MAXUNICODE 0x10FFFFu
#define MAXUTF 0x7FFFFFFFu
#define MSGInvalid "invalid UTF-8 code"
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
#if (UINT_MAX >> 30) >= 1
typedef unsigned int utfint;
#else
typedef unsigned long utfint;
#endif
#define iscont(c) (((c) & 0xC0) == 0x80)
#define iscontp(p) iscont(*(p))
/* from strlib */
/* translate a relative string position: negative means back from end */
static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
if (pos >= 0) return pos;
else if (0u - (size_t)pos > len) return 0;
else return (lua_Integer)len + pos + 1;
}
/*
** Decode one UTF-8 sequence, returning NULL if byte sequence is
** invalid. The array 'limits' stores the minimum value for each
** sequence length, to check for overlong representations. Its first
** entry forces an error for non-ascii bytes with no continuation
** bytes (count == 0).
*/
static const char *utf8_decode (const char *s, utfint *val, int strict) {
static const utfint limits[] =
{~(utfint)0, 0x80, 0x800, 0x10000u, 0x200000u, 0x4000000u};
unsigned int c = (unsigned char)s[0];
utfint res = 0; /* final result */
if (c < 0x80) /* ascii? */
res = c;
else {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
res |= ((utfint)(c & 0x7F) << (count * 5)); /* add first byte */
if (count > 5 || res > MAXUTF || res < limits[count])
return NULL; /* invalid byte sequence */
s += count; /* skip continuation bytes read */
}
if (strict) {
/* check for invalid code points; too large or surrogates */
if (res > MAXUNICODE || (0xD800u <= res && res <= 0xDFFFu))
return NULL;
}
if (val) *val = res;
return s + 1; /* +1 to include first byte */
}
/*
** utf8len(s [, i [, j [, lax]]]) --> number of characters that
** start in the range [i,j], or nil + current position if 's' is not
** well formed in that interval
*/
static int utflen (lua_State *L) {
lua_Integer n = 0; /* counter for the number of characters */
size_t len; /* string length in bytes */
const char *s = luaL_checklstring(L, 1, &len);
lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len);
int lax = lua_toboolean(L, 4);
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2,
"initial position out of bounds");
luaL_argcheck(L, --posj < (lua_Integer)len, 3,
"final position out of bounds");
while (posi <= posj) {
const char *s1 = utf8_decode(s + posi, NULL, !lax);
if (s1 == NULL) { /* conversion error? */
luaL_pushfail(L); /* return fail ... */
lua_pushinteger(L, posi + 1); /* ... and current position */
return 2;
}
posi = s1 - s;
n++;
}
lua_pushinteger(L, n);
return 1;
}
/*
** codepoint(s, [i, [j [, lax]]]) -> returns codepoints for all
** characters that start in the range [i,j]
*/
static int codepoint (lua_State *L) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len);
lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len);
int lax = lua_toboolean(L, 4);
int n;
const char *se;
luaL_argcheck(L, posi >= 1, 2, "out of bounds");
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of bounds");
if (posi > pose) return 0; /* empty interval; return no values */
if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1; /* upper bound for number of returns */
luaL_checkstack(L, n, "string slice too long");
n = 0; /* count the number of returns */
se = s + pose; /* string end */
for (s += posi - 1; s < se;) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
return n;
}
static void pushutfchar (lua_State *L, int arg) {
lua_Unsigned code = (lua_Unsigned)luaL_checkinteger(L, arg);
luaL_argcheck(L, code <= MAXUTF, arg, "value out of range");
lua_pushfstring(L, "%U", (long)code);
}
/*
** utfchar(n1, n2, ...) -> char(n1)..char(n2)...
*/
static int utfchar (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
if (n == 1) /* optimize common case of single char */
pushutfchar(L, 1);
else {
int i;
luaL_Buffer b;
luaL_buffinit(L, &b);
for (i = 1; i <= n; i++) {
pushutfchar(L, i);
luaL_addvalue(&b);
}
luaL_pushresult(&b);
}
return 1;
}
/*
** offset(s, n, [i]) -> index where n-th character counting from
** position 'i' starts; 0 means character at 'i'.
*/
static int byteoffset (lua_State *L) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
lua_Integer n = luaL_checkinteger(L, 2);
lua_Integer posi = (n >= 0) ? 1 : len + 1;
posi = u_posrelat(luaL_optinteger(L, 3, posi), len);
luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3,
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
} while (posi > 0 && iscontp(s + posi));
n++;
}
}
else {
n--; /* do not move for 1st character */
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
}
if (n == 0) /* did it find given character? */
lua_pushinteger(L, posi + 1);
else /* no such character */
luaL_pushfail(L);
return 1;
}
static int iter_aux (lua_State *L, int strict) {
size_t len;
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
if (next == NULL || iscontp(next))
return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
}
}
static int iter_auxstrict (lua_State *L) {
return iter_aux(L, 1);
}
static int iter_auxlax (lua_State *L) {
return iter_aux(L, 0);
}
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
const char *s = luaL_checkstring(L, 1);
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
return 3;
}
/* pattern to match a single UTF-8 character */
#define UTF8PATT "[\0-\x7F\xC2-\xFD][\x80-\xBF]*"
static const luaL_Reg funcs[] = {
{"offset", byteoffset},
{"codepoint", codepoint},
{"char", utfchar},
{"len", utflen},
{"codes", iter_codes},
/* placeholders */
{"charpattern", NULL},
{NULL, NULL}
};
LUAMOD_API int luaopen_utf8 (lua_State *L) {
luaL_newlib(L, funcs);
lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
lua_setfield(L, -2, "charpattern");
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lvm.h $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -13,32 +13,131 @@
#include "ltm.h"
#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o)))
#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2))
#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2)
#if !defined(LUA_NOCVTN2S)
#define cvt2str(o) ttisnumber(o)
#else
#define cvt2str(o) 0 /* no conversion from numbers to strings */
#endif
/* not to called directly */
LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2);
#if !defined(LUA_NOCVTS2N)
#define cvt2num(o) ttisstring(o)
#else
#define cvt2num(o) 0 /* no conversion from strings to numbers */
#endif
/*
** You can define LUA_FLOORN2I if you want to convert floats to integers
** by flooring them (instead of raising an error if they are not
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I F2Ieq
#endif
/*
** Rounding modes for float->integer coercion
*/
typedef enum {
F2Ieq, /* no rounding; accepts only integral values */
F2Ifloor, /* takes the floor of the number */
F2Iceil /* takes the ceil of the number */
} F2Imod;
/* convert an object to a float (including string coercion) */
#define tonumber(o,n) \
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
/* convert an object to a float (without string coercion) */
#define tonumberns(o,n) \
(ttisfloat(o) ? ((n) = fltvalue(o), 1) : \
(ttisinteger(o) ? ((n) = cast_num(ivalue(o)), 1) : 0))
/* convert an object to an integer (including string coercion) */
#define tointeger(o,i) \
(l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
: luaV_tointeger(o,i,LUA_FLOORN2I))
/* convert an object to an integer (without string coercion) */
#define tointegerns(o,i) \
(l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
: luaV_tointegerns(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is present,
** return 1 with 'slot' pointing to 't[k]' (position of final result).
** Otherwise, return 0 (meaning it will have to check metamethod)
** with 'slot' pointing to an empty 't[k]' (if 't' is a table) or NULL
** (otherwise). 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!isempty(slot))) /* result not empty? */
#define luaV_fastset(L,t,k,slot,f) (luaV_fastget(L,t,k,slot,f)) && !isshared(hvalue(t))
/*
** Special case of 'luaV_fastget' for integers, inlining the fast case
** of 'luaH_getint'.
*/
#define luaV_fastgeti(L,t,k,slot) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = (l_castS2U(k) - 1u < hvalue(t)->alimit) \
? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
!isempty(slot))) /* result not empty? */
#define luaV_fastseti(L,t,k,slot) (luaV_fastgeti(L,t,k,slot)) && !isshared(hvalue(t))
/*
** Finish a fast set operation (when fast get succeeds). In that case,
** 'slot' points to the place to put the value.
*/
#define luaV_finishfastset(L,t,slot,v) \
{ setobj2t(L, cast(TValue *,slot), v); \
luaC_barrierback(L, gcvalue(t), v); }
/*
** Shift right is the same as shift left with a negative 'y'
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode);
LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
F2Imod mode);
LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
TValue *val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
const TValue *rc, TMS op);
LUAI_FUNC lua_Integer luaV_idiv (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Number luaV_modf (lua_State *L, lua_Number x, lua_Number y);
LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
#endif

View File

@@ -1,15 +1,17 @@
/*
** $Id: lzio.c,v 1.35.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lzio.c $
** Buffered streams
** See Copyright Notice in lua.h
*/
#include <string.h>
#define lzio_c
#define LUA_CORE
#include "lprefix.h"
#include <string.h>
#include "lua.h"
#include "llimits.h"
@@ -64,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
return 0;
}
/* ------------------------------------------------------------------------ */
char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
if (n > buff->buffsize) {
if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
luaZ_resizebuffer(L, buff, n);
}
return buff->buffer;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $
** $Id: lzio.h $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -32,20 +32,21 @@ typedef struct Mbuffer {
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
#define luaZ_bufflen(buff) ((buff)->n)
#define luaZ_buffremove(buff,i) ((buff)->n -= (i))
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
#define luaZ_resizebuffer(L, buff, size) \
(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \
(buff)->buffsize, size), \
(buff)->buffsize = size)
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
void *data);
LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */
@@ -55,7 +56,7 @@ struct Zio {
size_t n; /* bytes still unread */
const char *p; /* current position in buffer */
lua_Reader reader; /* reader function */
void* data; /* additional data */
void *data; /* additional data */
lua_State *L; /* Lua state (for reader) */
};

225
3rd/lua/makefile Normal file
View File

@@ -0,0 +1,225 @@
# Makefile for building Lua
# See ../doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= guess
CC= gcc -std=gnu99
CFLAGS= -O2 -Wall -Wextra $(SYSCFLAGS) $(MYCFLAGS)
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
AR= ar rcu
RANLIB= ranlib
RM= rm -f
UNAME= uname
SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS= -I../../skynet-src -g
MYLDFLAGS=
MYLIBS=
MYOBJS=
# Special flags for compiler modules; -Os reduces code size.
CMCFLAGS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
LIB_O= lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o linit.o
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
LUA_T= lua
LUA_O= lua.o
LUAC_T= luac
LUAC_O= luac.o
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
ALL_A= $(LUA_A)
# Targets start here.
default: $(PLAT)
all: $(ALL_T)
o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(BASE_O)
$(AR) $@ $(BASE_O)
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
$(LUAC_T): $(LUAC_O) $(LUA_A)
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
test:
./$(LUA_T) -v
clean:
$(RM) $(ALL_T) $(ALL_O)
depend:
@$(CC) $(CFLAGS) -MM l*.c
echo:
@echo "PLAT= $(PLAT)"
@echo "CC= $(CC)"
@echo "CFLAGS= $(CFLAGS)"
@echo "LDFLAGS= $(LDFLAGS)"
@echo "LIBS= $(LIBS)"
@echo "AR= $(AR)"
@echo "RANLIB= $(RANLIB)"
@echo "RM= $(RM)"
@echo "UNAME= $(UNAME)"
# Convenience targets for popular platforms.
ALL= all
help:
@echo "Do 'make PLATFORM' where PLATFORM is one of these:"
@echo " $(PLATS)"
@echo "See doc/readme.html for complete instructions."
guess:
@echo Guessing `$(UNAME)`
@$(MAKE) `$(UNAME)`
AIX aix:
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
bsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
c89:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
@echo ''
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
@echo '*** Make sure to compile all external Lua libraries'
@echo '*** with LUA_USE_C89 to ensure consistency'
@echo ''
FreeBSD NetBSD OpenBSD freebsd:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE -I/usr/include/edit" SYSLIBS="-Wl,-E -ledit" CC="cc"
generic: $(ALL)
ios:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
Linux linux: linux-noreadline
linux-noreadline:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
linux-readline:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE" SYSLIBS="-Wl,-E -ldl -lreadline"
Darwin macos macosx:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" SYSLIBS="-lreadline"
mingw:
$(MAKE) "LUA_A=lua54.dll" "LUA_T=lua.exe" \
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
$(MAKE) "LUAC_T=luac.exe" luac.exe
posix:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
SunOS solaris:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
# Targets that do not create files (not all makes understand .PHONY).
.PHONY: all $(PLATS) help test clean default o a depend echo
# Compiler modules may use special flags.
llex.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c llex.c
lparser.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c lparser.c
lcode.o:
$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
# DO NOT DELETE
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lgc.h lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
lparser.h lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
ltm.h lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
lstring.h ltable.h
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
lvm.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
lstring.h ltable.h
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h lopcodes.h lopnames.h lundump.h
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
lundump.h
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
ltable.h lvm.h ljumptab.h
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
lobject.h ltm.h lzio.h
# (end of Makefile)

107
3rd/lua/onelua.c Normal file
View File

@@ -0,0 +1,107 @@
/*
* one.c -- Lua core, libraries, and interpreter in a single file
*/
/* default is to build the full interpreter */
#ifndef MAKE_LIB
#ifndef MAKE_LUAC
#ifndef MAKE_LUA
#define MAKE_LUA
#endif
#endif
#endif
/* choose suitable platform-specific features */
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
#if 0
#define LUA_USE_LINUX
#define LUA_USE_MACOSX
#define LUA_USE_POSIX
#define LUA_ANSI
#endif
/* no need to change anything below this line ----------------------------- */
#include "lprefix.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* setup for luaconf.h */
#define LUA_CORE
#define LUA_LIB
#define ltable_c
#define lvm_c
#include "luaconf.h"
/* do not export internal symbols */
#undef LUAI_FUNC
#undef LUAI_DDEC
#undef LUAI_DDEF
#define LUAI_FUNC static
#define LUAI_DDEC(def) /* empty */
#define LUAI_DDEF static
/* core -- used by all */
#include "lzio.c"
#include "lctype.c"
#include "lopcodes.c"
#include "lmem.c"
#include "lundump.c"
#include "ldump.c"
#include "lstate.c"
#include "lgc.c"
#include "llex.c"
#include "lcode.c"
#include "lparser.c"
#include "ldebug.c"
#include "lfunc.c"
#include "lobject.c"
#include "ltm.c"
#include "lstring.c"
#include "ltable.c"
#include "ldo.c"
#include "lvm.c"
#include "lapi.c"
/* auxiliary library -- used by all */
#include "lauxlib.c"
/* standard library -- not used by luac */
#ifndef MAKE_LUAC
#include "lbaselib.c"
#include "lcorolib.c"
#include "ldblib.c"
#include "liolib.c"
#include "lmathlib.c"
#include "loadlib.c"
#include "loslib.c"
#include "lstrlib.c"
#include "ltablib.c"
#include "lutf8lib.c"
#include "linit.c"
#endif
/* lua */
#ifdef MAKE_LUA
#include "lua.c"
#endif
/* luac */
#ifdef MAKE_LUAC
#include "luac.c"
#endif

View File

@@ -1,3 +1,321 @@
v1.7.0 (2023-11-13)
-----------
* Update Lua to 5.4.6
* Update lpeg to 1.1.0
* Improve mongo driver
* Fix service session rewind issue
* Add websocket.is_closed
v1.6.0 (2022-11-16)
-----------
* Update Lua to 5.4.4 (github Nov 8, 2022)
* Update jemalloc to 5.3.0
* Update lpeg to 1.0.2 (For sproto)
* Update mongo driver to support the newest wire protocol
* socket.listen()/cluster.open() returns ip address and port
* Add service.close()
v1.5.0 (2021-11-9)
-----------
* Update Lua to 5.4.3
* Fix socket half close issues
* Fix TLS issues
* Improve websocket support
* Improve redis support
* Rework skynet.init/skynet.require
* Add socket.onclose
* Add httpc.request_stream
v1.4.0 (2020-11-16)
-----------
* Update Lua to 5.4.2
* Add skynet.select
* Improve mysql driver (@zero-rp @xiaojin @yxt945)
* Improve websocket and ssl (@lvzixun)
* Improve sproto (double @lvzixun map @t0350)
* Add padding mode PKCS7 for DES
* Add jmem in debug console
* Add skynet_socket_pause for net traffic control
* Add timestamp to default logger
v1.3.0 (2019-11-19)
-----------
* Improve mysql driver (@yxt945)
* Improve cluster
* Improve lua shared proto (@hongling0)
* Improve socket.write
* Add lua sharetable
* Add https support (@lvzixun)
* Add websocket support (@lvzixun)
* Fix bug in dns
* Fix some memory leaks
* jemalloc update to 5.2.1
v1.2.0 (2018-11-6)
-----------
* Improve cluster support
* Improve mongodb driver
* Improve redis driver
* Improve socket concurrent write
* Improve socket channel
* Improve service gate
* Improve udp support
* Add skynet.ignoreret
* Add skynet.trace
* Add skynet.context
* Improve skynet.wait/wakeup
* Add socket.netstat
* Add socketchannel.overload
* Fix memory leak for dead service
* lua update to 5.3.5
* jemalloc update to 5.1.0
v1.1.0 (2017-10-31)
-----------
* add socket.disconnected()
* fix bugs : see comments for detail
v1.1.0-rc (2017-7-18)
-----------
* config file : support include
* debug console : User config binding IP
* debug console : Add call command
* debug console : Report error message of inject code
* debug console : Change response message
* sharedata : Add sharedata.flush
* sharedata : Add sharedata.deepcopy
* cluster : Add cluster.send
* cluster : Add API to update config table
* skynet : Add skynet.state
* skynet : Keep the order of skynet.wakeup
* skynet : Add a MEMORY_CHECK macro for debugging
* httpc : Add httpc.timeout
* mongo driver : sort support multi-key
* bson : Check utf8 string
* bson : No longer support numberic key
* daemon mode: Can output the error messages
* sproto : Support decimal number
* sproto: Support binary type
* sproto: Support response nil
* crypt: Add crypt.hmac64_md5
* redis: Add redis-cluster support
* socket server : Optimize socket write (Try direct write from worker thread first)
* Add prefix skynet to all skynet lua modules
* datasheet : New module for replacement of sharedata
* jemalloc : Update to 5.0.1
* lua : Update to 5.3.4
* lpeg : Update to 1.0.1
v1.0.0 (2016-7-11)
-----------
* Version 1.0.0 Released
v1.0.0-rc5 (2016-7-4)
-----------
* MongoDB : Support auth_scram_sha1
* MongoDB : Auto determine primary host
* Bugfix : memory leak in multicast
* Bugfix : Lua 5.3.3
* Bson : support meta array
v1.0.0-rc4 (2016-6-13)
-----------
* Update lua to 5.3.3
* Update jemalloc to 4.2.1
* Add debug console command ping
* Lua bson support __pairs
* Add mongo.createIndexes and fix bug in old mongo.createIndex
* Handle signal HUP to reopen log file (for logrotate)
v1.0.0-rc3 (2016-5-9)
-----------
* Update jemalloc 4.1.1
* Update lua 5.3.3 rc1
* Update sproto to support encoding empty table
* Make skynet.init stable (keep order)
* skynet.getenv can return empty string
* Add lua VM memory warning
* lua VM support memory limit
* skynet.pcall suport varargs
* Bugfix : Global name query
* Bugfix : snax.queryglobal
v1.0.0-rc2 (2016-3-7)
-----------
* Fix a bug in lua 5.3.2
* Update sproto (fix bugs and add ud for package)
* Fix a bug in http
* Fix a bug in harbor
* Fix a bug in socket channel
* Enhance remote debugger
v1.0.0-rc (2015-12-28)
-----------
* Update to lua 5.3.2
* Add skynet.coroutine lib
* Add new debug api to show c memory used
* httpc can use async dns query
* Redis driver support pipeline
* socket.send support string table, and rewrite redis driver
* socket.shutdown would abandon unsend buffer
* Improve some sproto api
* c memory doesn't count the memory allocated by lua vm
* some other bugfix (In multicast, socketchannel, etc)
v1.0.0-beta (2015-11-10)
-----------
* Improve and fix bug for sproto
* Add global short string pool for lua vm
* Add code cache mode
* Add a callback for mysql auth
* Add hmac_md5
* Sharedata support filename as a string
* Fix a bug in socket.httpc
* Fix a lua stack overflow bug in lua bson
* Fix a socketchannel bug may block the data steam
* Avoid dead loop when sending message to the service exiting
* Fix memory leak in netpack
* Improve DH key exchange implement
* Minor fix for socket
* Minor fix for multicast
* Update jemalloc to 4.0.4
* Update lpeg to 1.0.0
v1.0.0-alpha10 (2015-8-17)
-----------
* Remove the size limit of cluster RPC message.
* Remove the size limit of local message.
* Add cluster.query and clsuter.register.
* Add an option of pthread mutex lock.
* Add skynet.core.intcommand to optimize skynet.sleep etc.
* Fix a memory leak bug in lua shared proto.
* snax.msgserver use string instead of lightuserdata/size.
* Remove some unused api in netpack.
* Raise error when skynet.send to 0.
v1.0.0-alpha9 (2015-8-10)
-----------
* Improve lua serialization , support pairs metamethod.
* Bugfix : sproto (See commits log of sproto)
* Add user log service support (In config)
* Other minor bugfix (See commits log)
v1.0.0-alpha8 (2015-6-29)
-----------
* Update lua 5.3.1
* Bugfix: skynet exit issue
* Bugfix: timer race condition
* Use atom increment in bson object id
* remove assert when write to a listen fd
* sproto encode doesn't use raw table api
v1.0.0-alpha7 (2015-6-8)
-----------
* console support launch snax service
* Add cluster.snax
* Add nodelay in clusterd
* Merge sproto bugfix patch
* Move some skynet api into skynet.manager
* DNS support underscore
* Add logservice in config file for user defined log service
* skynet.fork returns coroutine
* Fix a few of bugs , see the commits log
v1.0.0-alpha6 (2015-5-18)
-----------
* bugfix: httpc.get
* bugfix: seri lib stack overflow
* bugfix: udp send
* bugfix: udp address
* bugfix: sproto dump
* add: sproto default
* improve: skynet.wakeup (can wakeup skynet.call by raise an error)
* improve: skynet.exit (raise error when uncall response)
* remove: task overload warning
* move: some skynet api move into skynet.manager
v1.0.0-alpha5 (2015-4-27)
-----------
* merge lua 5.3 offical bugfix
* improve sproto rpc api
* fix a deadlock bug when service retire
* improve cluster config reload
* add skynet.pcall for calling a function with `require`
* better error log in loginserver
v1.0.0-alpha4 (2015-4-13)
-----------
* sproto can share c struct between states
* udp api changed (use lua string now)
* fix memory leak in dns module
v1.0.0-alpha3 (2015-3-30)
-----------
* Update sproto (bugfix)
* Add async dns query
* improve httpc
v1.0.0-alpha2 (2015-3-16)
-----------
* Update examples client to lua 5.3
* Patch lua 5.3 to interrupt the dead loop (for debug)
* Update sproto (fix some bugs and support unordered map)
v1.0.0-alpha (2015-3-9)
-----------
* Update lua from 5.2 to 5.3
* Add an online lua debugger
* Add sharemap as an example use case of stm
* Improve sproto for multi-state
* Improve mongodb driver
* Fix known bugs
v0.9.3 (2015-1-5)
-----------
* Add : mongo createIndex
* Update : sproto
* bugfix : sharedata check dirty flag when len/pairs metamethod
* bugfix : multicast
v0.9.2 (2014-12-8)
-----------
* Simplify the message queue
* Add create_index in mongo driver
* Fix a bug in big-endian architecture (sproto)
v0.9.0 / v0.9.1 (2014-11-17)
-----------
* Add UDP support
* Add IPv6 support
* socket send package can define a release method
* dispatch read before write in epoll
* remove snax queue mode
* Fix a bug in big-endian architecture
v0.8.1 (2014-11-3)
-----------
* Send to an invalid remote service will raise an error
* Bugifx: socket open address string
* Remove sha1 from mysqlaux
* merge lua and sproto bugfix , use crypt lib instead
* Fix a memory leak in socket
* minor bugfix in http module
v0.8.0 (2014-10-27)
-----------
* Add mysql client driver
* Bugfix : skynet.queue
v0.7.4 (2014-10-13)
-----------
* Bugfix : clear coroutine pool when GC
* hotfix : A bug introduce by 0.7.3
v0.7.3 (2014-10-13)
-----------
* Add some logs (warning) when overload
* Bugfix: crash on exit
v0.7.2 (2014-9-29)
-----------
* Bugfix : datacenter.wait

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2012-2014 codingnow.com
Copyright (c) 2012-2022 codingnow.com
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -5,7 +5,8 @@ CSERVICE_PATH ?= cservice
SKYNET_BUILD_PATH ?= .
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
# CFLAGS += -DUSE_PTHREAD_LOCK
# lua
@@ -14,16 +15,22 @@ LUA_LIB ?= $(LUA_STATICLIB)
LUA_INC ?= 3rd/lua
$(LUA_STATICLIB) :
cd 3rd/lua && $(MAKE) CC=$(CC) $(PLAT)
cd 3rd/lua && $(MAKE) CC='$(CC) -std=gnu99' $(PLAT)
# jemalloc
# https : turn on TLS_MODULE to add https support
# TLS_MODULE=ltls
TLS_LIB=
TLS_INC=
# jemalloc
JEMALLOC_STATICLIB := 3rd/jemalloc/lib/libjemalloc_pic.a
JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
all : jemalloc
.PHONY : jemalloc
.PHONY : jemalloc update3rd
MALLOC_STATICLIB := $(JEMALLOC_STATICLIB)
@@ -34,16 +41,35 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
git submodule update --init
3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --disable-valgrind
cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof
jemalloc : $(MALLOC_STATICLIB)
update3rd :
rm -rf 3rd/jemalloc && git submodule update --init
# skynet
CSERVICE = snlua logger gate harbor
LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack \
clientsocket memory profile multicast \
cluster crypt sharedata stm sproto lpeg
LUA_CLIB = skynet \
client \
bson md5 sproto lpeg $(TLS_MODULE)
LUA_CLIB_SKYNET = \
lua-skynet.c lua-seri.c \
lua-socket.c \
lua-mongo.c \
lua-netpack.c \
lua-memory.c \
lua-multicast.c \
lua-cluster.c \
lua-crypt.c lsha1.c \
lua-sharedata.c \
lua-stm.c \
lua-debugchannel.c \
lua-datasheet.c \
lua-sharetable.c \
\
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \
@@ -71,61 +97,35 @@ endef
$(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))
$(LUA_CLIB_PATH)/skynet.so : lualib-src/lua-skynet.c lualib-src/lua-seri.c | $(LUA_CLIB_PATH)
$(LUA_CLIB_PATH)/skynet.so : $(addprefix lualib-src/,$(LUA_CLIB_SKYNET)) | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src -Ilualib-src
$(LUA_CLIB_PATH)/socketdriver.so : lualib-src/lua-socket.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src
$(LUA_CLIB_PATH)/int64.so : 3rd/lua-int64/int64.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
$(LUA_CLIB_PATH)/mongo.so : lualib-src/lua-mongo.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/md5.so : 3rd/lua-md5/md5.c 3rd/lua-md5/md5lib.c 3rd/lua-md5/compat-5.2.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -I3rd/lua-md5 $^ -o $@
$(LUA_CLIB_PATH)/netpack.so : lualib-src/lua-netpack.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -Iskynet-src -o $@
$(LUA_CLIB_PATH)/clientsocket.so : lualib-src/lua-clientsocket.c | $(LUA_CLIB_PATH)
$(LUA_CLIB_PATH)/client.so : lualib-src/lua-clientsocket.c lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -lpthread
$(LUA_CLIB_PATH)/memory.so : lualib-src/lua-memory.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/profile.so : lualib-src/lua-profile.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/multicast.so : lualib-src/lua-multicast.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/cluster.so : lualib-src/lua-cluster.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/crypt.so : lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/sharedata.so : lualib-src/lua-sharedata.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/stm.so : lualib-src/lua-stm.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/sproto.so : lualib-src/sproto/sproto.c lualib-src/sproto/lsproto.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Ilualib-src/sproto $^ -o $@
$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c | $(LUA_CLIB_PATH)
$(LUA_CLIB_PATH)/ltls.so : lualib-src/ltls.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src -L$(TLS_LIB) -I$(TLS_INC) $^ -o $@ -lssl
$(LUA_CLIB_PATH)/lpeg.so : 3rd/lpeg/lpcap.c 3rd/lpeg/lpcode.c 3rd/lpeg/lpprint.c 3rd/lpeg/lptree.c 3rd/lpeg/lpvm.c 3rd/lpeg/lpcset.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -I3rd/lpeg $^ -o $@
clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so && \
rm -rf $(SKYNET_BUILD_PATH)/*.dSYM $(CSERVICE_PATH)/*.dSYM $(LUA_CLIB_PATH)/*.dSYM
cleanall: clean
cd 3rd/jemalloc && $(MAKE) clean
ifneq (,$(wildcard 3rd/jemalloc/Makefile))
cd 3rd/jemalloc && $(MAKE) clean && rm Makefile
endif
cd 3rd/lua && $(MAKE) clean
rm -f $(LUA_STATICLIB)

View File

@@ -1,6 +1,14 @@
## ![skynet logo](https://github.com/cloudwu/skynet/wiki/image/skynet_metro.jpg)
Skynet is a multi-user Lua framework supporting the actor model, often used in games.
[It is heavily used in the Chinese game industry](https://github.com/cloudwu/skynet/wiki/Uses), but is also now spreading to other industries, and to English-centric developers. To visit related sites, visit the Chinese pages using something like Google or Deepl translate.
The community is friendly and almost contributors can speak English, so English speakers are welcome to ask questions in [Discussion](https://github.com/cloudwu/skynet/discussions), or sumbit issues in English.
## Build
For linux, install autoconf first for jemalloc
For Linux, install autoconf first for jemalloc:
```
git clone https://github.com/cloudwu/skynet.git
@@ -8,32 +16,31 @@ cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
Or you can :
Or:
```
export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
For FreeBSD , use gmake instead of make.
## Test
Run these in different console
Run these in different consoles:
```
./skynet examples/config # Launch first skynet node (Gate server) and a skynet-master (see config for standalone option)
lua examples/client.lua # Launch a client, and try to input some words.
./3rd/lua/lua examples/client.lua # Launch a client, and try to input hello.
```
## About Lua
## About Lua version
Skynet put a modified version of lua 5.2.3 in 3rd/lua , it can share proto type between lua state (http://lua-users.org/lists/lua-l/2014-03/msg00489.html) .
Skynet now uses a modified version of lua 5.4.4 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.
Each lua file only load once and cache it in memory during skynet start . so if you want to reflush the cache , call skynet.cache.clear() .
Official Lua versions can also be used as long as the Makefile is edited.
You can also use the offical lua version , edit the makefile by yourself .
## How To Use
## How To (in Chinese)
* Read Wiki https://github.com/cloudwu/skynet/wiki
* Read Wiki for documents https://github.com/cloudwu/skynet/wiki (Written in both English and Chinese)
* The FAQ in wiki https://github.com/cloudwu/skynet/wiki/FAQ (In Chinese, but you can visit them using something like Google or Deepl translate.)

Some files were not shown because too many files have changed in this diff Show More