Compare commits
293 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce8f120e48 | ||
|
|
048fd2349a | ||
|
|
2627957e5a | ||
|
|
16b0ca0fc7 | ||
|
|
e3189ba38a | ||
|
|
ad48622f68 | ||
|
|
0a9439ad22 | ||
|
|
a7577d5054 | ||
|
|
668cdcb4db | ||
|
|
4ec3e87473 | ||
|
|
90b4f38223 | ||
|
|
c1918e5c38 | ||
|
|
34baaa9447 | ||
|
|
817938593a | ||
|
|
b944f9d01d | ||
|
|
5d4b2395b5 | ||
|
|
f9ab1546ff | ||
|
|
971e7c8316 | ||
|
|
60a89b8f32 | ||
|
|
7275f0d11a | ||
|
|
35213d7d3b | ||
|
|
cde26253e3 | ||
|
|
b45c0600c7 | ||
|
|
5784dea99a | ||
|
|
e880fdde60 | ||
|
|
b7d8512b7b | ||
|
|
a7a8f32c91 | ||
|
|
9fc4ab5e9b | ||
|
|
37434534cc | ||
|
|
fc03c2843b | ||
|
|
2abbad04ac | ||
|
|
dbb392e009 | ||
|
|
65947ff924 | ||
|
|
d8324b269d | ||
|
|
ac9c2e9a84 | ||
|
|
3b2fcfd1f9 | ||
|
|
14fe7af771 | ||
|
|
7b0405bc79 | ||
|
|
fc6b0c176d | ||
|
|
5c50a2645b | ||
|
|
11cfbfa68d | ||
|
|
e6b318c643 | ||
|
|
1351db6114 | ||
|
|
b58e931409 | ||
|
|
e0eb05b122 | ||
|
|
8ecd8dfa6b | ||
|
|
c1961e5c4b | ||
|
|
3ead2966d8 | ||
|
|
0bcf590f45 | ||
|
|
e8f308ca08 | ||
|
|
ecb59ceb9e | ||
|
|
a317f986e1 | ||
|
|
623905c81c | ||
|
|
11b702ac6e | ||
|
|
f926aef2f8 | ||
|
|
3754406e85 | ||
|
|
981bccbe27 | ||
|
|
047a9e8ac5 | ||
|
|
d1f2e8450a | ||
|
|
21cfba9cb6 | ||
|
|
3f711373ed | ||
|
|
00fe05e89f | ||
|
|
3bcd54bd46 | ||
|
|
8de9e41fd6 | ||
|
|
29b6755a9b | ||
|
|
7d6be282f1 | ||
|
|
f89fd4d752 | ||
|
|
03adda1cef | ||
|
|
2992424e87 | ||
|
|
e302a97682 | ||
|
|
7b5d37d595 | ||
|
|
01ae85dc5a | ||
|
|
f650d8f64f | ||
|
|
602f8ef223 | ||
|
|
6afc999b75 | ||
|
|
2ccd214a1f | ||
|
|
8efde0ec1f | ||
|
|
1c5b14870c | ||
|
|
2c87909920 | ||
|
|
2a2a3bed96 | ||
|
|
e2f65bced5 | ||
|
|
c979d60d28 | ||
|
|
7954ff1f64 | ||
|
|
a3a5c75694 | ||
|
|
d6f3b4052b | ||
|
|
7bc64d90c7 | ||
|
|
56d262b753 | ||
|
|
a368f0acf9 | ||
|
|
d4a53733e7 | ||
|
|
1117e9df9a | ||
|
|
230de3450f | ||
|
|
0ae48ce6de | ||
|
|
6a90c5e850 | ||
|
|
f1ac72b265 | ||
|
|
79fd90c986 | ||
|
|
4dcf470c09 | ||
|
|
fcdbd456de | ||
|
|
e92127d6c8 | ||
|
|
0d8e6b0581 | ||
|
|
16d72396b1 | ||
|
|
6c7e289f71 | ||
|
|
deb99ec084 | ||
|
|
12f84d3509 | ||
|
|
3a18136076 | ||
|
|
1b057988bc | ||
|
|
92001a4a78 | ||
|
|
906c70248b | ||
|
|
4554c67c3e | ||
|
|
cb7ee575c7 | ||
|
|
c758d4c62a | ||
|
|
8c1c06bb16 | ||
|
|
99ca5fe952 | ||
|
|
1f064655cc | ||
|
|
9a05cc3678 | ||
|
|
6da3cb2c32 | ||
|
|
d2cb7cb1c2 | ||
|
|
0ac769ffba | ||
|
|
ef60786e48 | ||
|
|
f9c15faab8 | ||
|
|
59b28ef35c | ||
|
|
9db7d4ec8a | ||
|
|
40eaace714 | ||
|
|
fe000bb59e | ||
|
|
9aa220df41 | ||
|
|
97c52f15f3 | ||
|
|
54f578790b | ||
|
|
a51a08c1b8 | ||
|
|
7620e758a0 | ||
|
|
80da9253dd | ||
|
|
a133fa900e | ||
|
|
0fa62e544a | ||
|
|
601dbef6e5 | ||
|
|
01b3a4fd09 | ||
|
|
ed0df13acb | ||
|
|
642fd63724 | ||
|
|
a1586cd530 | ||
|
|
291cba2d79 | ||
|
|
96bffc1322 | ||
|
|
e88710fbbc | ||
|
|
99da8be0f8 | ||
|
|
c8c654cb2b | ||
|
|
cf68a42547 | ||
|
|
5c0d4cccdd | ||
|
|
b979b41688 | ||
|
|
b807fa9a99 | ||
|
|
ef5b1b0e09 | ||
|
|
04a038da45 | ||
|
|
bc0e3190d4 | ||
|
|
16dcd084e1 | ||
|
|
15f8c15039 | ||
|
|
bff0da36dc | ||
|
|
1e933a6b75 | ||
|
|
c9bb3e01ca | ||
|
|
e4e5e82660 | ||
|
|
c5f2d3cf18 | ||
|
|
017049f473 | ||
|
|
75ce8116ca | ||
|
|
73dc7ca2ed | ||
|
|
8c6e111e13 | ||
|
|
305cafbfcf | ||
|
|
8c3d927820 | ||
|
|
b83138c127 | ||
|
|
e7a789e466 | ||
|
|
d5f448c952 | ||
|
|
f43babc491 | ||
|
|
6a78042869 | ||
|
|
4984cf7a4b | ||
|
|
6693a6cd96 | ||
|
|
2909eeb0c3 | ||
|
|
61260f6e48 | ||
|
|
c741d35c67 | ||
|
|
18e06631bf | ||
|
|
efd78f57b9 | ||
|
|
e366377d64 | ||
|
|
4b334a0d40 | ||
|
|
c3471d0077 | ||
|
|
7c7a45d99d | ||
|
|
c57215aeeb | ||
|
|
66e0e04f45 | ||
|
|
9d1d3256c8 | ||
|
|
d61a0d64fc | ||
|
|
796e793902 | ||
|
|
adfc4d98a7 | ||
|
|
cb28bb1b97 | ||
|
|
77ae45ef8b | ||
|
|
d64b44943b | ||
|
|
8fb808d75f | ||
|
|
81e92eec88 | ||
|
|
7d763054b7 | ||
|
|
6b39babf34 | ||
|
|
214c598a85 | ||
|
|
a297104017 | ||
|
|
f6e72fc9ce | ||
|
|
631ca23a97 | ||
|
|
c2d9a0dbac | ||
|
|
cec4eb869d | ||
|
|
7602facb7a | ||
|
|
d5827e233c | ||
|
|
d59a92e0bf | ||
|
|
65d460452b | ||
|
|
867de8f3e4 | ||
|
|
ec756721c2 | ||
|
|
3b554526c6 | ||
|
|
4246d7683a | ||
|
|
b7c922e253 | ||
|
|
beaeb9a65d | ||
|
|
b3d0f40519 | ||
|
|
c64906d09a | ||
|
|
2d993203f8 | ||
|
|
3fdc605d36 | ||
|
|
393c0703a6 | ||
|
|
2c396b775e | ||
|
|
d14c4b544a | ||
|
|
730835a04d | ||
|
|
db315532ed | ||
|
|
cc9128ad73 | ||
|
|
99763ce992 | ||
|
|
c735b7476d | ||
|
|
932274fbbe | ||
|
|
7fed63512d | ||
|
|
14cf94f3bb | ||
|
|
14665f57dd | ||
|
|
414f44b6f5 | ||
|
|
0c1a335aa0 | ||
|
|
ae04d6e1aa | ||
|
|
6fb6c73495 | ||
|
|
5083d561d2 | ||
|
|
2a2bfa69a2 | ||
|
|
56f05aa5fe | ||
|
|
4607721020 | ||
|
|
329baf4b82 | ||
|
|
ed30c2399d | ||
|
|
7663cbbf0c | ||
|
|
c48182b902 | ||
|
|
9297a18b8d | ||
|
|
4fdeccdbc1 | ||
|
|
5c76dbabd6 | ||
|
|
b6176efd07 | ||
|
|
5327916817 | ||
|
|
78e52ac04a | ||
|
|
a9b1729057 | ||
|
|
a226c6e432 | ||
|
|
79af98d75b | ||
|
|
ab26ded71a | ||
|
|
defba4f767 | ||
|
|
585c5c0f9c | ||
|
|
047165b6aa | ||
|
|
3d0e52bdbe | ||
|
|
2e1a512f00 | ||
|
|
09dbdc1cb1 | ||
|
|
a9835c25cb | ||
|
|
dab674be91 | ||
|
|
8e5a6bc284 | ||
|
|
fe53414868 | ||
|
|
6f675b60cb | ||
|
|
85be275590 | ||
|
|
378fe2818e | ||
|
|
20ed88665a | ||
|
|
31759939f2 | ||
|
|
03b63b491e | ||
|
|
409f1f4214 | ||
|
|
caf9db40b1 | ||
|
|
fc7e075a01 | ||
|
|
c956350dc2 | ||
|
|
8273b622e9 | ||
|
|
85b016457b | ||
|
|
15154050f9 | ||
|
|
d6472a2fd5 | ||
|
|
3d452e3092 | ||
|
|
bc2a15915c | ||
|
|
6cdecea47c | ||
|
|
4967a0a68b | ||
|
|
2428b66add | ||
|
|
0a550c1d25 | ||
|
|
43e0566cb6 | ||
|
|
8739e37faa | ||
|
|
fcc11f7dff | ||
|
|
705b5f939c | ||
|
|
af27ef7682 | ||
|
|
863f2780b3 | ||
|
|
790191a681 | ||
|
|
ca0fda0bee | ||
|
|
81e4048754 | ||
|
|
353336796d | ||
|
|
c39ee8fb2f | ||
|
|
fbcc555f4e | ||
|
|
43237b1b1d | ||
|
|
5f8ee5ce63 | ||
|
|
edd82b8a4a | ||
|
|
d710fdb4a9 | ||
|
|
b7124a26ba | ||
|
|
fba27ba1b0 | ||
|
|
1a2a3ac721 |
@@ -1,160 +1,199 @@
|
||||
Estrela Editor License
|
||||
=============================================================================
|
||||
|
||||
Estrela Editor sources are released under the MIT License
|
||||
|
||||
Copyright (c) 2008-2011
|
||||
Luxinia DevTeam:
|
||||
Eike Decker & Christoph Kubisch
|
||||
info at luxinia.de
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
wxLua License
|
||||
=============================================================================
|
||||
http://wxlua.sourceforge.net/
|
||||
|
||||
Pre-Built binaries for wxLua/WxWindows
|
||||
|
||||
Original wxLua Lua sample IDE:
|
||||
Lomtick Software
|
||||
J. Winwood & John Labenski
|
||||
luascript at thersgb.net
|
||||
|
||||
wxLua is based on
|
||||
wxWindows Library Licence, Version 3
|
||||
|
||||
Copyright (c) 1998 Julian Smart, Robert Roebling et al
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this licence document, but changing it is not allowed.
|
||||
|
||||
WXWINDOWS LIBRARY LICENCE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public Licence as published by
|
||||
the Free Software Foundation; either version 2 of the Licence, or (at
|
||||
your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
|
||||
General Public Licence for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public Licence
|
||||
along with this software, usually in a file named COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA.
|
||||
|
||||
EXCEPTION NOTICE
|
||||
|
||||
1. As a special exception, the copyright holders of this library give
|
||||
permission for additional uses of the text contained in this release of
|
||||
the library as licenced under the wxWindows Library Licence, applying
|
||||
either version 3 of the Licence, or (at your option) any later version of
|
||||
the Licence as published by the copyright holders of version 3 of the
|
||||
Licence document.
|
||||
|
||||
2. The exception is that you may use, copy, link, modify and distribute
|
||||
under the user's own terms, binary object code versions of works based
|
||||
on the Library.
|
||||
|
||||
3. If you copy code from files distributed under the terms of the GNU
|
||||
General Public Licence or the GNU Library General Public Licence into a
|
||||
copy of this library, as this licence permits, the exception does not
|
||||
apply to the code that you add in this way. To avoid misleading anyone as
|
||||
to the status of such modified files, you must delete this exception
|
||||
notice from such code and/or adjust the licensing conditions notice
|
||||
accordingly.
|
||||
|
||||
4. If you write modifications of your own for this library, it is your
|
||||
choice whether to permit this exception to apply to your modifications.
|
||||
If you do not wish that, you must delete the exception notice from such
|
||||
code and/or adjust the licensing conditions notice accordingly.
|
||||
|
||||
|
||||
Lua License
|
||||
=============================================================================
|
||||
Copyright: © 1994-2006 Lua.org, PUC-Rio.
|
||||
Homepage: http://www.lua.org
|
||||
License: http://www.lua.org/copyright.html
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
LuaFileSystem
|
||||
=============================================================================
|
||||
LuaFileSystem was designed by Roberto Ierusalimschy, André Carregal and Tomás
|
||||
Guisasola as part of the Kepler Project, which holds its copyright.
|
||||
Homepage: http://www.keplerproject.org/luafilesystem/index.html
|
||||
License: http://www.keplerproject.org/luafilesystem/license.html
|
||||
=============================================================================
|
||||
|
||||
LuaSockets
|
||||
=============================================================================
|
||||
Copyright: © 2004-2006 Diego Nehab. All rights reserved.
|
||||
Homepage: http://www.cs.princeton.edu/~diego/professional/luasocket/
|
||||
License: http://www.lua.org/copyright.html (same as LUA)
|
||||
=============================================================================
|
||||
|
||||
ZMQ
|
||||
=============================================================================
|
||||
Copyright: © 2007-2011 iMatix Corporation and Contributors
|
||||
Homepage: http://www.zeromq.org/
|
||||
License: http://www.zeromq.org/area:licensing
|
||||
|
||||
LuaZMQ
|
||||
Copyright: © 2011 by Robert G. Jakabosky
|
||||
Homepage: https://github.com/Neopallium/lua-zmq
|
||||
=============================================================================
|
||||
|
||||
MojoShader
|
||||
=============================================================================
|
||||
Copyright: © 2008-2010 Ryan C. Gordon
|
||||
Homepage: http://icculus.org/mojoshader/
|
||||
License: http://hg.icculus.org/icculus/mojoshader/raw-file/tip/LICENSE.txt
|
||||
=============================================================================
|
||||
|
||||
|
||||
CLCC
|
||||
=============================================================================
|
||||
Copyright: © 2009 Organic Vectory B.V.
|
||||
Homepage: http://clcc.sourceforge.net/
|
||||
License: boost
|
||||
|
||||
CLCC was modified by Christoph Kubisch to support multiple platforms and
|
||||
output file generation.
|
||||
=============================================================================
|
||||
--[[ ZeroBrane Studio License ]]-------------------------------------------
|
||||
|
||||
ZeroBrane Studio sources are released under the MIT License
|
||||
|
||||
Copyright (c) 2011-2012 Paul Kulchenko (paul@kulchenko.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 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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
--[[ Estrela Editor License ]]---------------------------------------------
|
||||
|
||||
Estrela Editor sources are released under the MIT License
|
||||
|
||||
Copyright (c) 2008-2012
|
||||
Luxinia DevTeam:
|
||||
Christoph Kubisch & Eike Decker
|
||||
info at luxinia.de
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
--[[ wxLua License License ]]----------------------------------------------
|
||||
|
||||
http://wxlua.sourceforge.net/
|
||||
|
||||
Pre-Built binaries for wxLua/WxWindows
|
||||
|
||||
Original wxLua Lua sample IDE:
|
||||
Lomtick Software
|
||||
J. Winwood & John Labenski
|
||||
luascript at thersgb.net
|
||||
|
||||
wxLua is based on
|
||||
wxWindows Library Licence, Version 3
|
||||
|
||||
Copyright (c) 1998 Julian Smart, Robert Roebling et al
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this licence document, but changing it is not allowed.
|
||||
|
||||
WXWINDOWS LIBRARY LICENCE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Library General Public Licence as published by
|
||||
the Free Software Foundation; either version 2 of the Licence, or (at
|
||||
your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
|
||||
General Public Licence for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public Licence
|
||||
along with this software, usually in a file named COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA.
|
||||
|
||||
EXCEPTION NOTICE
|
||||
|
||||
1. As a special exception, the copyright holders of this library give
|
||||
permission for additional uses of the text contained in this release of
|
||||
the library as licenced under the wxWindows Library Licence, applying
|
||||
either version 3 of the Licence, or (at your option) any later version of
|
||||
the Licence as published by the copyright holders of version 3 of the
|
||||
Licence document.
|
||||
|
||||
2. The exception is that you may use, copy, link, modify and distribute
|
||||
under the user's own terms, binary object code versions of works based
|
||||
on the Library.
|
||||
|
||||
3. If you copy code from files distributed under the terms of the GNU
|
||||
General Public Licence or the GNU Library General Public Licence into a
|
||||
copy of this library, as this licence permits, the exception does not
|
||||
apply to the code that you add in this way. To avoid misleading anyone as
|
||||
to the status of such modified files, you must delete this exception
|
||||
notice from such code and/or adjust the licensing conditions notice
|
||||
accordingly.
|
||||
|
||||
4. If you write modifications of your own for this library, it is your
|
||||
choice whether to permit this exception to apply to your modifications.
|
||||
If you do not wish that, you must delete the exception notice from such
|
||||
code and/or adjust the licensing conditions notice accordingly.
|
||||
|
||||
--[[ Lua License ]]--------------------------------------------------------
|
||||
|
||||
Copyright: © 1994-2006 Lua.org, PUC-Rio.
|
||||
Homepage: http://www.lua.org
|
||||
License: http://www.lua.org/copyright.html
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
--[[ LuaFileSystem License ]]----------------------------------------------
|
||||
|
||||
LuaFileSystem was designed by Roberto Ierusalimschy, André Carregal and Tomás
|
||||
Guisasola as part of the Kepler Project, which holds its copyright.
|
||||
Homepage: http://www.keplerproject.org/luafilesystem/index.html
|
||||
License: http://www.keplerproject.org/luafilesystem/license.html
|
||||
|
||||
--[[ LuaSockets License ]]-------------------------------------------------
|
||||
|
||||
Copyright: © 2004-2006 Diego Nehab. All rights reserved.
|
||||
Homepage: http://www.cs.princeton.edu/~diego/professional/luasocket/
|
||||
License: http://www.lua.org/copyright.html (same as LUA)
|
||||
|
||||
--[[ ZMQ License ]]--------------------------------------------------------
|
||||
|
||||
Copyright: © 2007-2011 iMatix Corporation and Contributors
|
||||
Homepage: http://www.zeromq.org/
|
||||
License: http://www.zeromq.org/area:licensing
|
||||
|
||||
LuaZMQ
|
||||
Copyright: © 2011 by Robert G. Jakabosky
|
||||
Homepage: https://github.com/Neopallium/lua-zmq
|
||||
|
||||
--[[ MojoShader License ]]-------------------------------------------------
|
||||
|
||||
Copyright: © 2008-2010 Ryan C. Gordon
|
||||
Homepage: http://icculus.org/mojoshader/
|
||||
License: http://hg.icculus.org/icculus/mojoshader/raw-file/tip/LICENSE.txt
|
||||
|
||||
--[[ CLCC License ]]-------------------------------------------------------
|
||||
|
||||
Copyright: © 2009 Organic Vectory B.V.
|
||||
Homepage: http://clcc.sourceforge.net/
|
||||
License: boost
|
||||
|
||||
CLCC was modified by Christoph Kubisch to support multiple platforms and
|
||||
output file generation.
|
||||
|
||||
--[[ MobDebug License ]]---------------------------------------------------
|
||||
|
||||
MobDebug sources are released under the MIT License
|
||||
|
||||
Copyright (c) 2011 Paul Kulchenko (paul@kulchenko.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 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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
70
README.md
Normal file
70
README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Project Description
|
||||
|
||||
A simple and extensible Lua IDE and debugger. It supports multiple file
|
||||
formats, "api" for autocompletion and tooltips, and custom command-line
|
||||
tools. Its main focus is extensibility for target applications using Lua.
|
||||
|
||||
## Features
|
||||
|
||||
* Written in Lua, so easily customizable
|
||||
* Automatically loads several 'plugin' like classes
|
||||
- applications: overall control of applications settings
|
||||
- specs (spec/): file syntax, lexer, keywords
|
||||
- apis (api/): for code-completion and tool-tips
|
||||
- interpreters (interpreters/): how a project is run
|
||||
- config (cfg/): contains style and basic editor settings
|
||||
- tools (tools/): additional tools, e.g. cg compiler, dx fxc compiler
|
||||
* Auto-completion for functions, keywords...
|
||||
* Function tips
|
||||
* Function list in file (quick jump to)
|
||||
* Function call highlighting
|
||||
* Bracket matching/highlighting
|
||||
* Project file browser
|
||||
* Experimental type/class guessing for auto-completion
|
||||
* Support for different editor styles
|
||||
* Console to directly test code snippets with local and remote execution
|
||||
* Integrated debugger (with support for local and remote debugging)
|
||||
|
||||
## Frontends
|
||||
|
||||
There is currently two front-ends using the same editor engine. The original
|
||||
one is `Estrela`, which has a focus on 3d graphics related usage of Lua,
|
||||
especially in combination with the luxinia engine or luxinia2 framework.
|
||||
The second front-end is `ZeroBrane Studio` (zbstudio) which has a focus
|
||||
on using Lua in education, mobile development, and robotics.
|
||||
|
||||
Both are part of the standard distribution.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ git clone git://github.com/pkulchenko/ZeroBraneStudio.git zbstudio
|
||||
or
|
||||
$ git clone git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor estrelaeditor
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
Open File(s):
|
||||
<exe> <filename> [<filename>...]
|
||||
any non-option will be treated as filename
|
||||
|
||||
Overriding Config:
|
||||
<exe> [...] -cfg "<luacode overriding config>" [...]
|
||||
e.g.: zbstudio.exe -cfg "singleinstance=false;" somefile.lua
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
### Estrela Editor
|
||||
|
||||
**Luxinia Dev:** Christoph Kubisch (crazybutcher@luxinia.de)
|
||||
|
||||
### ZeroBrane Studio and MobDebug
|
||||
|
||||
**ZeroBrane LLC:** Paul Kulchenko (paul@kulchenko.com)
|
||||
|
||||
## License
|
||||
|
||||
See LICENSE file.
|
||||
@@ -1,205 +1,205 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local function fn (description)
|
||||
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
|
||||
if not description2 then
|
||||
return {type="function",description=description,
|
||||
returns="(?)"}
|
||||
end
|
||||
return {type="function",description=description2,
|
||||
returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args}
|
||||
end
|
||||
|
||||
local function val (description)
|
||||
return {type="value",description = description}
|
||||
end
|
||||
-- docs
|
||||
local api = {
|
||||
abs = fn "returns absolute value of scalars and vectors. - (typeN)(typeN)",
|
||||
acos = fn "returns arccosine of scalars and vectors. - (typeN)(typeN)",
|
||||
all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)",
|
||||
any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)",
|
||||
asin = fn "returns arcsine of scalars and vectors. - (typeN)(typeN)",
|
||||
atan = fn "returns arctangent of scalars and vectors. - (typeN)(typeN)",
|
||||
atan2 = fn "returns the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0. - (typeN)(typeN y, typeN x)",
|
||||
ceil = fn "returns smallest integer not less than a scalar or each vector component. - (typeN)(typeN)",
|
||||
clamp = fn "returns x clamped to the range [a,b]. - (typeN)(typeN x, a, b)",
|
||||
clip = fn "conditionally (<0) kill a pixel before output. - ()(typeN)",
|
||||
cos = fn "returns cosine of scalars and vectors. - (typeN)(typeN)",
|
||||
cosh = fn "returns hyperbolic cosine of scalars and vectors. - (typeN)(typeN)",
|
||||
cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)",
|
||||
ddx = fn "returns approximate partial derivative with respect to window-space X. - (typeN)(typeN)",
|
||||
ddy = fn "returns approximate partial derivative with respect to window-space Y. - (typeN)(typeN)",
|
||||
degrees = fn "converts values of scalars and vectors from radians to degrees. - (typeN)(typeN)",
|
||||
determinant = fn "returns the scalar determinant of a square matrix. - (float)(floatNxN)",
|
||||
distance = fn "return the Euclidean distance between two points. - (typeN)(typeN a, b)",
|
||||
dot = fn "returns the scalar dot product of two vectors. - (type)(typeN a, b)",
|
||||
exp = fn "returns the base-e exponential of scalars and vectors. - (typeN)(typeN)",
|
||||
exp2 = fn "returns the base-2 exponential of scalars and vectors. - (typeN)(typeN)",
|
||||
faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (typeN)(typeN Nperturbated, Incident, Ngeometric)",
|
||||
floatToIntBits = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (intN)(floatN)",
|
||||
floatToRawIntBits = fn "returns the raw 32-bit integer representation of an IEEE 754 floating-point scalar or vector. - (intN)(floatN)",
|
||||
floor = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
|
||||
fmod = fn "returns the remainder of x/y with the same sign as x. - (typeN)(typeN x, y)",
|
||||
frac = fn "returns the fractional portion of a scalar or each vector component. - (typeN)(typeN)",
|
||||
frexp = fn "splits scalars and vectors into normalized fraction and a power of 2. - (typeN)(typeN x, out typeN e)",
|
||||
fwidth = fn "returns sum of approximate window-space partial derivatives magnitudes. - (typeN)(typeN)",
|
||||
intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)",
|
||||
isfinite = fn "test whether or not a scalar or each vector component is a finite value. - (boolN)(typeN)",
|
||||
isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(typeN)",
|
||||
isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(typeN)",
|
||||
ldexp = fn "returns x times 2 rained to n. - (typeN)(typeN a, n)",
|
||||
length = fn "return scalar Euclidean length of a vector. - (type)(typeN)",
|
||||
lerp = fn "lerp - returns linear interpolation of two scalars or vectors based on a weight. - (typeN)(typeN a, b, weight)",
|
||||
lit = fn "computes lighting coefficients for ambient(x), diffuse(y), and specular(z) lighting contributions (w=1). - (type4)(type NdotL, NdotH, specshiny)",
|
||||
log = fn "returns the natural logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
log10 = fn "returns the base-10 logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
log2 = fn "returns the base-2 logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
max = fn "returns the maximum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
|
||||
min = fn "returns the minimum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
|
||||
mul = fn "Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B. - (typeN)(typeNxN/typeN a, typeN/typeNxN b)",
|
||||
normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (typeN)(typeN)",
|
||||
pow = fn "returns x to the y-th power of scalars and vectors. - (typeN)(typeN x, y)",
|
||||
radians = fn "converts values of scalars and vectors from degrees to radians. - (typeN)(typeN)",
|
||||
reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (typeN)(typeN incidence, normal)",
|
||||
refract = fn "computes a refraction vector. - (typeN)(typeN incidence, normal, type eta)",
|
||||
round = fn "returns the rounded value of scalars or vectors. - (typeN)(typeN a)",
|
||||
rsqrt = fn "returns reciprocal square root of scalars and vectors. 1/sqrt. - (typeN)(typeN)",
|
||||
saturate = fn "returns x saturated to the range [0,1]. - (typeN)(typeN)",
|
||||
sign = fn "returns sign (1 or -1) of scalar or each vector component. - (typeN)(typeN)",
|
||||
sin = fn "returns sine of scalars and vectors. - (typeN)(typeN)",
|
||||
sincos = fn "returns sine of scalars and vectors. - ()(typeN x, out typeN sin, out typeN cos)",
|
||||
sinh = fn "returns hyperbolic sine of scalars and vectors. - (typeN)(typeN)",
|
||||
sqrt = fn "returns square root of scalars and vectors. - (typeN)(typeN)",
|
||||
step = fn "implement a step function returning either zero or one (a <= b). - (typeN)(typeN a, b)",
|
||||
tan = fn "returns tangent of scalars and vectors. - (typeN)(typeN)",
|
||||
tanh = fn "returns hyperbolic tangent of scalars and vectors. - (typeN)(typeN)",
|
||||
transpose = fn "returns transpose matrix of a matrix. - (typeRxC)(typeCxR)",
|
||||
trunc = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
|
||||
|
||||
tex1D = fn "performs a texture lookup in a given 1D sampler and, in some cases, a shadow comparison (as .y coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1D, float/float2 s, |float dx, dy|,[int texeloffset])",
|
||||
tex1Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .y, bias as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler1D, int4 s, [int texeloffset])",
|
||||
tex1Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .y for float3 coord, proj in .y or .z) - (float4)(sampler1D, float2/float3 s, [int texeloff])",
|
||||
tex1Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
|
||||
|
||||
tex2D = fn "performs a texture lookup in a given 2D sampler and, in some cases, a shadow comparison (as .z coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2D, float2/float3 s, |float2 dx, dy|,[int texeloffset])",
|
||||
tex2Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .z, bias as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2D, int4 s, [int texeloffset])",
|
||||
tex2Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler2D, float3/float4 s, [int texeloff])",
|
||||
tex2Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
|
||||
tex2Dgather = fn "returns 4 texels of a given single channel texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
|
||||
|
||||
tex3D = fn "performs a texture lookup in a given 3D sampler. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler3D, float3 s, {float3 dx, dy},[int texeloffset])",
|
||||
tex3Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler3D, float4 s, [int texeloffset])",
|
||||
tex3Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler3D, int4 s, [int texeloffset])",
|
||||
tex3Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler3D, float4 s, [int texeloffset])",
|
||||
tex3Dproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(sampler3D, float4 s, [int texeloff])",
|
||||
tex3Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler3D, int lod)",
|
||||
|
||||
texBUF = fn "performs an unfiltered texture lookup in a given texture buffer sampler. (only gp4 profiles) - (float4)(samplerBUF, int s)",
|
||||
texBUFsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerBUF, int lod)",
|
||||
|
||||
texRBUF = fn "performs a multi-sampled texture lookup in a renderbuffer. (only gp4 profiles) - (float4)(samplerRBUF, int2 s, int sample)",
|
||||
texRBUFsize = fn "returns the size of a given renderbuffer. (only gp4 profiles) - (int2)(samplerBUF)",
|
||||
|
||||
texCUBE = fn "performs a texture lookup in a given CUBE sampler and, in some cases, a shadow comparison (float4 coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBE, float3/float4 s, |float3 dx, dy|)",
|
||||
texCUBEbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
texCUBElod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
texCUBEproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(samplerCUBE, float4 s)",
|
||||
texCUBEsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
|
||||
|
||||
texRECT = fn "performs a texture lookup in a given RECT sampler and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerRECT, float2/float3 s, |float2 dx, dy|, [int texeloff])",
|
||||
texRECTbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(samplerRECT, float4 s, [int texeloffset])",
|
||||
texRECTfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(samplerRECT, int4 s, [int texeloffset])",
|
||||
texRECTlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(samplerRECT, float4 s, [int texeloffset])",
|
||||
texRECTproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(samplerRECT, float3/float4 s, [int texeloff])",
|
||||
texRECTsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerRECT, int lod)",
|
||||
|
||||
tex1DARRAY = fn "performs a texture lookup in a given 1D sampler array and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1DARRAY, float2/float3 s, {float dx, dy},[int texeloffset])",
|
||||
tex1DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (layer as .y, compare as .z, bias as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .z, lod as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .z). - (float4)(sampler1DARRAY, int3 s, [int texeloffset])",
|
||||
tex1DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .z) - (float4)(sampler1DARRAY, float3 s, [int texeloffset])",
|
||||
tex1DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler1DARRAY, float3/float4 s, [int texeloff])",
|
||||
tex1DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1DARRAY, int lod)",
|
||||
|
||||
tex2DARRAY = fn "performs a texture lookup in a given 2D sampler array and, in some cases, a shadow comparison (as .w coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2DARRAY, float3/float4 s, {float2 dx, dy},[int texeloffset])",
|
||||
tex2DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
|
||||
tex2DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2DARRAY, int4 s, [int texeloffset])",
|
||||
tex2DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
|
||||
tex2DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (proj in .w) - (float4)(sampler2DARRAY, float4 s, [int texeloff])",
|
||||
tex2DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2DARRAY, int lod)",
|
||||
|
||||
texCUBEARRAY = fn "performs a texture lookup in a given CUBE sampler array. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBEARRAY, float4 s, {float3 dx, dy},[int texeloffset])",
|
||||
texCUBEARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerCUBEARRAY, int lod)",
|
||||
|
||||
unpack_4ubyte = fn "interprets the single float as 4 normalized unsigned bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
|
||||
pack_4ubyte = fn "packs the floats into a single storing as normalized unsigned bytes.(only nv/gp4 profiles) - (float)(float4)",
|
||||
unpack_4byte = fn "interprets the single float as 4 normalized signed bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
|
||||
pack_4ubyte = fn "packs the floats into a single storing as normalized signed bytes.(only nv/gp4 profiles) - (float)(float4)",
|
||||
unpack_4ushort = fn "interprets the single float as 2 normalized unsigned shorts and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
|
||||
pack_4ushort = fn "packs the floats into a single storing as normalized unsigned shorts.(only nv/gp4 profiles) - (float)(float2)",
|
||||
unpack_2half = fn "interprets the single float as 2 16-bit floats and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
|
||||
pack_2half = fn "packs the floats into a single storing as 16-bit floats.(only nv/gp4 profiles) - (float)(float2)",
|
||||
}
|
||||
|
||||
local keyw =
|
||||
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
|
||||
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
|
||||
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
|
||||
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
|
||||
int4 bool bool2 bool3 bool4 string struct typedef
|
||||
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY
|
||||
isampler isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY
|
||||
usamplerBUF isamplerBUF samplerBUF
|
||||
sampler sampler1D sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY
|
||||
texture texture1D texture2D texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY
|
||||
|
||||
decl do else extern false for if in inline inout out pass
|
||||
pixelshader return shared static string technique true
|
||||
uniform vector vertexshader void volatile while
|
||||
|
||||
asm compile const auto break case catch char class const_cast continue default delete
|
||||
dynamic_cast enum explicit friend goto long mutable namespace new operator private protected
|
||||
public register reinterpret_case short signed sizeof static_cast switch template this throw
|
||||
try typename union unsigned using virtual
|
||||
|
||||
POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG COLOR COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3
|
||||
TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14
|
||||
TEXCOORD15
|
||||
NORMAL WPOS
|
||||
ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5 ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
|
||||
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9 TEXUNIT10 TEXUNIT11 TEXUNIT12
|
||||
TEXUNIT13 TEXUNIT14 TEXUNIT15
|
||||
|
||||
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
|
||||
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
|
||||
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
|
||||
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
|
||||
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
|
||||
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
|
||||
VIEWPORTSIZE VIEWPORTDIMENSION
|
||||
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
|
||||
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
|
||||
|
||||
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
|
||||
|
||||
]]
|
||||
|
||||
-- keywords - shouldn't be left out
|
||||
for w in keyw:gmatch("([_%w]+)") do
|
||||
api[w] = {type="keyword"}
|
||||
end
|
||||
|
||||
return api
|
||||
|
||||
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
local function fn (description)
|
||||
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
|
||||
if not description2 then
|
||||
return {type="function",description=description,
|
||||
returns="(?)"}
|
||||
end
|
||||
return {type="function",description=description2,
|
||||
returns=returns:gsub("^%s+",""):gsub("%s+$",""), args = args}
|
||||
end
|
||||
|
||||
local function val (description)
|
||||
return {type="value",description = description}
|
||||
end
|
||||
-- docs
|
||||
local api = {
|
||||
abs = fn "returns absolute value of scalars and vectors. - (typeN)(typeN)",
|
||||
acos = fn "returns arccosine of scalars and vectors. - (typeN)(typeN)",
|
||||
all = fn "returns true if a boolean scalar or all components of a boolean vector are true. - (bool)(boolN)",
|
||||
any = fn "returns true if a boolean scalar or any component of a boolean vector is true. - (bool)(boolN)",
|
||||
asin = fn "returns arcsine of scalars and vectors. - (typeN)(typeN)",
|
||||
atan = fn "returns arctangent of scalars and vectors. - (typeN)(typeN)",
|
||||
atan2 = fn "returns the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0. - (typeN)(typeN y, typeN x)",
|
||||
ceil = fn "returns smallest integer not less than a scalar or each vector component. - (typeN)(typeN)",
|
||||
clamp = fn "returns x clamped to the range [a,b]. - (typeN)(typeN x, a, b)",
|
||||
clip = fn "conditionally (<0) kill a pixel before output. - ()(typeN)",
|
||||
cos = fn "returns cosine of scalars and vectors. - (typeN)(typeN)",
|
||||
cosh = fn "returns hyperbolic cosine of scalars and vectors. - (typeN)(typeN)",
|
||||
cross = fn "returns the cross product of two three-component vectors. - (type3)(type3 a, b)",
|
||||
ddx = fn "returns approximate partial derivative with respect to window-space X. - (typeN)(typeN)",
|
||||
ddy = fn "returns approximate partial derivative with respect to window-space Y. - (typeN)(typeN)",
|
||||
degrees = fn "converts values of scalars and vectors from radians to degrees. - (typeN)(typeN)",
|
||||
determinant = fn "returns the scalar determinant of a square matrix. - (float)(floatNxN)",
|
||||
distance = fn "return the Euclidean distance between two points. - (typeN)(typeN a, b)",
|
||||
dot = fn "returns the scalar dot product of two vectors. - (type)(typeN a, b)",
|
||||
exp = fn "returns the base-e exponential of scalars and vectors. - (typeN)(typeN)",
|
||||
exp2 = fn "returns the base-2 exponential of scalars and vectors. - (typeN)(typeN)",
|
||||
faceforward = fn "returns a normal as-is if a vertex's eye-space position vector points in the opposite direction of a geometric normal, otherwise return the negated version of the normal. - (typeN)(typeN Nperturbated, Incident, Ngeometric)",
|
||||
floatToIntBits = fn "returns the 32-bit integer representation of an IEEE 754 floating-point scalar or vector - (intN)(floatN)",
|
||||
floatToRawIntBits = fn "returns the raw 32-bit integer representation of an IEEE 754 floating-point scalar or vector. - (intN)(floatN)",
|
||||
floor = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
|
||||
fmod = fn "returns the remainder of x/y with the same sign as x. - (typeN)(typeN x, y)",
|
||||
frac = fn "returns the fractional portion of a scalar or each vector component. - (typeN)(typeN)",
|
||||
frexp = fn "splits scalars and vectors into normalized fraction and a power of 2. - (typeN)(typeN x, out typeN e)",
|
||||
fwidth = fn "returns sum of approximate window-space partial derivatives magnitudes. - (typeN)(typeN)",
|
||||
intBitsToFloat = fn "returns the float value corresponding to a given bit represention.of a scalar int value or vector of int values. - (floatN)(intN)",
|
||||
isfinite = fn "test whether or not a scalar or each vector component is a finite value. - (boolN)(typeN)",
|
||||
isinf = fn "test whether or not a scalar or each vector component is infinite. - (boolN)(typeN)",
|
||||
isnan = fn "test whether or not a scalar or each vector component is not-a-number. - (boolN)(typeN)",
|
||||
ldexp = fn "returns x times 2 rained to n. - (typeN)(typeN a, n)",
|
||||
length = fn "return scalar Euclidean length of a vector. - (type)(typeN)",
|
||||
lerp = fn "lerp - returns linear interpolation of two scalars or vectors based on a weight. - (typeN)(typeN a, b, weight)",
|
||||
lit = fn "computes lighting coefficients for ambient(x), diffuse(y), and specular(z) lighting contributions (w=1). - (type4)(type NdotL, NdotH, specshiny)",
|
||||
log = fn "returns the natural logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
log10 = fn "returns the base-10 logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
log2 = fn "returns the base-2 logarithm of scalars and vectors. - (typeN)(typeN)",
|
||||
max = fn "returns the maximum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
|
||||
min = fn "returns the minimum of two scalars or each respective component of two vectors. - (typeN)(typeN a, b)",
|
||||
mul = fn "Returns the vector result of multiplying a matrix M by a column vector v; a row vector v by a matrix M; or a matrix A by a second matrix B. - (typeN)(typeNxN/typeN a, typeN/typeNxN b)",
|
||||
normalize = fn "Returns the normalized version of a vector, meaning a vector in the same direction as the original vector but with a Euclidean length of one. - (typeN)(typeN)",
|
||||
pow = fn "returns x to the y-th power of scalars and vectors. - (typeN)(typeN x, y)",
|
||||
radians = fn "converts values of scalars and vectors from degrees to radians. - (typeN)(typeN)",
|
||||
reflect = fn "returns the reflectiton vector given an incidence vector and a normal vector. - (typeN)(typeN incidence, normal)",
|
||||
refract = fn "computes a refraction vector. - (typeN)(typeN incidence, normal, type eta)",
|
||||
round = fn "returns the rounded value of scalars or vectors. - (typeN)(typeN a)",
|
||||
rsqrt = fn "returns reciprocal square root of scalars and vectors. 1/sqrt. - (typeN)(typeN)",
|
||||
saturate = fn "returns x saturated to the range [0,1]. - (typeN)(typeN)",
|
||||
sign = fn "returns sign (1 or -1) of scalar or each vector component. - (typeN)(typeN)",
|
||||
sin = fn "returns sine of scalars and vectors. - (typeN)(typeN)",
|
||||
sincos = fn "returns sine of scalars and vectors. - ()(typeN x, out typeN sin, out typeN cos)",
|
||||
sinh = fn "returns hyperbolic sine of scalars and vectors. - (typeN)(typeN)",
|
||||
sqrt = fn "returns square root of scalars and vectors. - (typeN)(typeN)",
|
||||
step = fn "implement a step function returning either zero or one (a <= b). - (typeN)(typeN a, b)",
|
||||
tan = fn "returns tangent of scalars and vectors. - (typeN)(typeN)",
|
||||
tanh = fn "returns hyperbolic tangent of scalars and vectors. - (typeN)(typeN)",
|
||||
transpose = fn "returns transpose matrix of a matrix. - (typeRxC)(typeCxR)",
|
||||
trunc = fn "returns largest integer not greater than a scalar or each vector component. - (typeN)(typeN)",
|
||||
|
||||
tex1D = fn "performs a texture lookup in a given 1D sampler and, in some cases, a shadow comparison (as .y coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1D, float/float2 s, |float dx, dy|,[int texeloffset])",
|
||||
tex1Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .y, bias as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler1D, int4 s, [int texeloffset])",
|
||||
tex1Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
tex1Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .y for float3 coord, proj in .y or .z) - (float4)(sampler1D, float2/float3 s, [int texeloff])",
|
||||
tex1Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
|
||||
|
||||
tex2D = fn "performs a texture lookup in a given 2D sampler and, in some cases, a shadow comparison (as .z coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2D, float2/float3 s, |float2 dx, dy|,[int texeloffset])",
|
||||
tex2Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (compare as .z, bias as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .y, lod as .w). - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2D, int4 s, [int texeloffset])",
|
||||
tex2Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2D, float4 s, [int texeloffset])",
|
||||
tex2Dproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler2D, float3/float4 s, [int texeloff])",
|
||||
tex2Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
|
||||
tex2Dgather = fn "returns 4 texels of a given single channel texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2D, int lod)",
|
||||
|
||||
tex3D = fn "performs a texture lookup in a given 3D sampler. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler3D, float3 s, {float3 dx, dy},[int texeloffset])",
|
||||
tex3Dbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler3D, float4 s, [int texeloffset])",
|
||||
tex3Dfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler3D, int4 s, [int texeloffset])",
|
||||
tex3Dlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler3D, float4 s, [int texeloffset])",
|
||||
tex3Dproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(sampler3D, float4 s, [int texeloff])",
|
||||
tex3Dsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler3D, int lod)",
|
||||
|
||||
texBUF = fn "performs an unfiltered texture lookup in a given texture buffer sampler. (only gp4 profiles) - (float4)(samplerBUF, int s)",
|
||||
texBUFsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerBUF, int lod)",
|
||||
|
||||
texRBUF = fn "performs a multi-sampled texture lookup in a renderbuffer. (only gp4 profiles) - (float4)(samplerRBUF, int2 s, int sample)",
|
||||
texRBUFsize = fn "returns the size of a given renderbuffer. (only gp4 profiles) - (int2)(samplerBUF)",
|
||||
|
||||
texCUBE = fn "performs a texture lookup in a given CUBE sampler and, in some cases, a shadow comparison (float4 coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBE, float3/float4 s, |float3 dx, dy|)",
|
||||
texCUBEbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
texCUBElod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler1D, float4 s, [int texeloffset])",
|
||||
texCUBEproj = fn "performs a texture lookup with projection in a given sampler. (proj in .w) - (float4)(samplerCUBE, float4 s)",
|
||||
texCUBEsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1D, int lod)",
|
||||
|
||||
texRECT = fn "performs a texture lookup in a given RECT sampler and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerRECT, float2/float3 s, |float2 dx, dy|, [int texeloff])",
|
||||
texRECTbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(samplerRECT, float4 s, [int texeloffset])",
|
||||
texRECTfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(samplerRECT, int4 s, [int texeloffset])",
|
||||
texRECTlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(samplerRECT, float4 s, [int texeloffset])",
|
||||
texRECTproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(samplerRECT, float3/float4 s, [int texeloff])",
|
||||
texRECTsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerRECT, int lod)",
|
||||
|
||||
tex1DARRAY = fn "performs a texture lookup in a given 1D sampler array and, in some cases, a shadow comparison (as .z). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler1DARRAY, float2/float3 s, {float dx, dy},[int texeloffset])",
|
||||
tex1DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYcmpbias = fn "performs a texture lookup with bias and shadow compare in a given sampler (layer as .y, compare as .z, bias as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYcmplod = fn "performs a texture lookup with a specified level of detail and a shadow compare in a given sampler (compare as .z, lod as .w). - (float4)(sampler1DARRAY, float4 s, [int texeloffset])",
|
||||
tex1DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .z). - (float4)(sampler1DARRAY, int3 s, [int texeloffset])",
|
||||
tex1DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .z) - (float4)(sampler1DARRAY, float3 s, [int texeloffset])",
|
||||
tex1DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (shadow in .z for float3 coord, proj in .z or .w) - (float4)(sampler1DARRAY, float3/float4 s, [int texeloff])",
|
||||
tex1DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler1DARRAY, int lod)",
|
||||
|
||||
tex2DARRAY = fn "performs a texture lookup in a given 2D sampler array and, in some cases, a shadow comparison (as .w coord). May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(sampler2DARRAY, float3/float4 s, {float2 dx, dy},[int texeloffset])",
|
||||
tex2DARRAYbias = fn "performs a texture lookup with bias in a given sampler (as .w). - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
|
||||
tex2DARRAYfetch = fn "performs an unfiltered texture lookup in a given sampler (lod as .w). - (float4)(sampler2DARRAY, int4 s, [int texeloffset])",
|
||||
tex2DARRAYlod = fn "performs a texture lookup with a specified level of detail in a given sampler (lod as .w) - (float4)(sampler2DARRAY, float4 s, [int texeloffset])",
|
||||
tex2DARRAYproj = fn "performs a texture lookup with projection in a given sampler. May perform a shadow comparison if argument for shadow comparison is provided. (proj in .w) - (float4)(sampler2DARRAY, float4 s, [int texeloff])",
|
||||
tex2DARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(sampler2DARRAY, int lod)",
|
||||
|
||||
texCUBEARRAY = fn "performs a texture lookup in a given CUBE sampler array. May also use pre computed derivatives if those are provided. Texeloffset only in gp4 or higher profiles. - (float4)(samplerCUBEARRAY, float4 s, {float3 dx, dy},[int texeloffset])",
|
||||
texCUBEARRAYsize = fn "returns the size of a given texture image for a given level of detail. (only gp4 profiles) - (int3)(samplerCUBEARRAY, int lod)",
|
||||
|
||||
unpack_4ubyte = fn "interprets the single float as 4 normalized unsigned bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
|
||||
pack_4ubyte = fn "packs the floats into a single storing as normalized unsigned bytes.(only nv/gp4 profiles) - (float)(float4)",
|
||||
unpack_4byte = fn "interprets the single float as 4 normalized signed bytes and returns the vector. (only nv/gp4 profiles) - (float4)(float)",
|
||||
pack_4ubyte = fn "packs the floats into a single storing as normalized signed bytes.(only nv/gp4 profiles) - (float)(float4)",
|
||||
unpack_4ushort = fn "interprets the single float as 2 normalized unsigned shorts and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
|
||||
pack_4ushort = fn "packs the floats into a single storing as normalized unsigned shorts.(only nv/gp4 profiles) - (float)(float2)",
|
||||
unpack_2half = fn "interprets the single float as 2 16-bit floats and returns the vector. (only nv/gp4 profiles) - (float2)(float)",
|
||||
pack_2half = fn "packs the floats into a single storing as 16-bit floats.(only nv/gp4 profiles) - (float)(float2)",
|
||||
}
|
||||
|
||||
local keyw =
|
||||
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
|
||||
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
|
||||
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
|
||||
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
|
||||
int4 bool bool2 bool3 bool4 string struct typedef
|
||||
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY
|
||||
isampler isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY
|
||||
usamplerBUF isamplerBUF samplerBUF
|
||||
sampler sampler1D sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY
|
||||
texture texture1D texture2D texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY
|
||||
|
||||
decl do else extern false for if in inline inout out pass
|
||||
pixelshader return shared static string technique true
|
||||
uniform vector vertexshader void volatile while
|
||||
|
||||
asm compile const auto break case catch char class const_cast continue default delete
|
||||
dynamic_cast enum explicit friend goto long mutable namespace new operator private protected
|
||||
public register reinterpret_case short signed sizeof static_cast switch template this throw
|
||||
try typename union unsigned using virtual
|
||||
|
||||
POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG COLOR COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3
|
||||
TEXCOORD4 TEXCOORD5 TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14
|
||||
TEXCOORD15
|
||||
NORMAL WPOS
|
||||
ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5 ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
|
||||
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9 TEXUNIT10 TEXUNIT11 TEXUNIT12
|
||||
TEXUNIT13 TEXUNIT14 TEXUNIT15
|
||||
|
||||
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
|
||||
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
|
||||
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
|
||||
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
|
||||
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
|
||||
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
|
||||
VIEWPORTSIZE VIEWPORTDIMENSION
|
||||
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
|
||||
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
|
||||
|
||||
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
|
||||
|
||||
]]
|
||||
|
||||
-- keywords - shouldn't be left out
|
||||
for w in keyw:gmatch("([_%w]+)") do
|
||||
api[w] = {type="keyword"}
|
||||
end
|
||||
|
||||
return api
|
||||
|
||||
|
||||
|
||||
@@ -1,200 +1,200 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
-- function helpers
|
||||
|
||||
local function fn (description)
|
||||
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
|
||||
if not description2 then
|
||||
return {type="function",description=description,
|
||||
returns="(?)"}
|
||||
end
|
||||
returns = returns:gsub("^%s+",""):gsub("%s+$","")
|
||||
local ret = returns:sub(2,-2)
|
||||
local vt = ret:match("^%[?string") and "string"
|
||||
vt = vt or ret:match("^%[?table") and "table"
|
||||
vt = vt or ret:match("^%[?file") and "io"
|
||||
return {type="function",description=description2,
|
||||
returns=returns, args = args, valuetype = vt}
|
||||
end
|
||||
|
||||
local function val (description)
|
||||
return {type="value",description = description}
|
||||
end
|
||||
-- docs
|
||||
|
||||
local api = {
|
||||
table = {
|
||||
description = "Table functions",
|
||||
type = "lib",
|
||||
childs = {
|
||||
concat = fn "concatenates an array of elements - (string)(table,[sep])",
|
||||
insert = fn "inserts an element into an array - ()(table,idx,element)",
|
||||
remove = fn "removes an element from an array - (element)(table,idx)",
|
||||
maxn = fn "Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. - (number)(table)",
|
||||
sort = fn "Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. - ()(table,[comp])"
|
||||
}
|
||||
},
|
||||
|
||||
math = {
|
||||
type = "lib",
|
||||
description = "Math functions",
|
||||
childs = {
|
||||
abs = fn "Returns the absolute value of x. - (number)(number)",
|
||||
acos = fn "Returns the arc cosine of x (in radians). - (number)(number)",
|
||||
asin = fn "Returns the arc sine of x (in radians). - (number)(number)",
|
||||
atan = fn "Returns the arc tangent of x (in radians). - (number)(number)",
|
||||
atan2 = fn "Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.) - (number)(number,number)",
|
||||
ceil = fn "Returns the smallest integer larger than or equal to x. - (number)(number)",
|
||||
cos = fn "Returns the cosine of x (assumed to be in radians).",
|
||||
cosh = fn "Returns the hyperbolic cosine of x.",
|
||||
deg = fn "Returns the angle x (given in radians) in degrees.",
|
||||
exp = fn "Returns the the value ex.",
|
||||
floor = fn "Returns the largest integer smaller than or equal to x.",
|
||||
fmod = fn "Returns the remainder of the division of x by y.",
|
||||
frexp = fn "Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).",
|
||||
huge = val "The value HUGE_VAL, a value larger than or equal to any other numerical value.",
|
||||
ldexp = fn "Returns m2e (e should be an integer).",
|
||||
log = fn "Returns the natural logarithm of x.",
|
||||
log10 = fn "Returns the base-10 logarithm of x.",
|
||||
max = fn "Returns the maximum value among its arguments.",
|
||||
min = fn "Returns the minimum value among its arguments.",
|
||||
modf = fn "Returns two numbers, the integral part of x and the fractional part of x.",
|
||||
pi = val "The value PI.",
|
||||
pow = fn "Returns xy. (You can also use the expression x^y to compute this value.)",
|
||||
rad = fn "Returns the angle x (given in degrees) in radians.",
|
||||
random = fn "This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.) When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].",
|
||||
randomseed = fn "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.",
|
||||
sin = fn"Returns the sine of x (assumed to be in radians).",
|
||||
sinh = fn"Returns the hyperbolic sine of x.",
|
||||
sqrt = fn "Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)",
|
||||
tan = fn "Returns the tangent of x (assumed to be in radians).",
|
||||
tanh = fn "Returns the hyperbolic tangent of x. "
|
||||
}
|
||||
},
|
||||
|
||||
pairs = fn "returns an iterator function for the given table - (function)(table)",
|
||||
ipairs = fn "returns an iterator function for the given table - (function)(table)",
|
||||
xpcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called,errorfunc)",
|
||||
pcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called, args ...)",
|
||||
print = fn "prints out the arguments - ()(...)",
|
||||
assert = fn "error checking, if first arg is false, error message is thrown - (result)(compute,errormsg)",
|
||||
collectgarbage = fn "garbage collector manipulation - (...)(...)",
|
||||
dofile = fn "compile and execute a file - (...)(...)",
|
||||
error = fn "raise an error - (...)(...)",
|
||||
getfenv = fn "get the function environment for a function - (...)(...)",
|
||||
getmetatable = fn "not yet - (...)(...)",
|
||||
load = fn "not yet - (...)(...)",
|
||||
loadfile = fn "not yet - (...)(...)",
|
||||
loadstring = fn "not yet - (...)(...)",
|
||||
next = fn "not yet - (...)(...)",
|
||||
rawequal = fn "not yet - (...)(...)",
|
||||
rawget = fn "not yet - (...)(...)",
|
||||
rawset = fn "not yet - (...)(...)",
|
||||
select = fn "not yet - (...)(...)",
|
||||
setfenv = fn "not yet - (...)(...)",
|
||||
setmetatable = fn "not yet - (...)(...)",
|
||||
tonumber = fn "not yet - (number)(...)",
|
||||
tostring = fn "not yet - (string)(...)",
|
||||
type = fn "not yet - (string)(...)",
|
||||
unpack = fn "not yet - (...)(...)",
|
||||
|
||||
module = fn "Creates a module. - (?)(name,...)",
|
||||
require = fn "Loads the given module. - (?)(name)",
|
||||
|
||||
package = {
|
||||
type = "table",
|
||||
description = "package info",
|
||||
childs = {
|
||||
cpath = val "The path used by require to search for a C loader. ",
|
||||
loaded = val "A table used by require to control which modules are already loaded.",
|
||||
loadlib = fn "Dynamically links the host program with the C library libname. - (?)(libname, funcname)",
|
||||
path = val "The path used by require to search for a Lua loader. ",
|
||||
preload = val "A table to store loaders for specific modules (see require). ",
|
||||
seeall = fn "Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module. - (?)(module)"
|
||||
}
|
||||
},
|
||||
|
||||
string = {
|
||||
type = "lib",
|
||||
description = "string lib",
|
||||
childs = {
|
||||
byte = fn "Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i. - (number)(string [, i [, j]])",
|
||||
char = fn "Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument. - (string)(...)",
|
||||
dump = fn "Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. - (string)(func)",
|
||||
find = fn "Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain \"find substring\" operation, with no characters in pattern being considered \"magic\". Note that if plain is given, then init must be given as well. - (number,number)(string, pattern [, init [, plain]])",
|
||||
format = fn "Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. - (string)(formatstring, ···)",
|
||||
gmatch = fn "Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. - (func)(string, pattern)",
|
||||
gsub = fn "Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made. - (string,number)(string, pattern, repl [, n])",
|
||||
len = fn "Receives a string and returns its length. The empty string '' has length 0. Embedded zeros are counted, so 'a\\000bc\\000' has length 5. - (number)(string)",
|
||||
lower = fn "Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. - (string)(string)",
|
||||
match = fn "Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. - (string,...)(string, pattern [, init])",
|
||||
rep = fn "Returns a string that is the concatenation of n copies of the string s. - (string)(string s, n)",
|
||||
reverse = fn "Returns a string that is the string s reversed. - (string)(string)",
|
||||
sub = fn "Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i. - (string)(string, i [, j])",
|
||||
upper = fn "Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. - (string)(string)",
|
||||
}
|
||||
},
|
||||
|
||||
coroutine = {
|
||||
type = "lib",
|
||||
description = "Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.",
|
||||
childs = {
|
||||
create = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". - (thread)(function)',
|
||||
resume = fn 'Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield. - (boolean success, ...)(coroutine,...)',
|
||||
running = fn 'Returns the running coroutine, or nil when called by the main thread. - ([thread])()',
|
||||
status = fn 'Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error. - (status)(coroutine)',
|
||||
wrap = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error. - (function)(function)',
|
||||
yield = fn 'Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. - (...)(...)'
|
||||
}
|
||||
},
|
||||
|
||||
io = {
|
||||
type = "lib",
|
||||
description = "The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors. ",
|
||||
childs = {
|
||||
close = fn'Equivalent to file:close(). Without a file, closes the default output file. - ()([file])',
|
||||
flush = fn'Equivalent to file:flush over the default output file. - ()([file])',
|
||||
input = fn'When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. - ([in])([file])',
|
||||
lines = fn'Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. - (function)([file])',
|
||||
open = fn'This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. - (file,[errormsg])(filename,[mode])',
|
||||
output = fn'Similar to io.input, but operates over the default output file. - ([file])([file])',
|
||||
popen = fn'Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w"). - (file)([prog, [mode]])',
|
||||
read = fn'Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). - (string)(...)',
|
||||
tmpfile = fn'Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. - (file)()',
|
||||
type = fn'Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle. - (string)(file)',
|
||||
write = fn'Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. - (?)(...)',
|
||||
seek = fn'Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence - (?)([whence] [, offset])',
|
||||
setvbuf = fn'Sets the buffering mode for an output file. - (?)(mode [, size])',
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
os = {
|
||||
type = "lib",
|
||||
description = ' Operating System Facilities',
|
||||
childs = {
|
||||
clock = fn'Returns an approximation of the amount in seconds of CPU time used by the program. - (seconds)()',
|
||||
date = fn'Returns a string or a table containing date and time, formatted according to the given string format. - (string)([format [, time]])',
|
||||
difftime = fn'Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1. - (time)(t2,t1)',
|
||||
execute = fn'This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise. - (return)([cmd])',
|
||||
exit = fn'Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. - ()([code])',
|
||||
getenv = fn'Returns the value of the process environment variable varname, or nil if the variable is not defined. - ([string])(varname)',
|
||||
remove = fn'Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(filename)',
|
||||
rename = fn'Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(oldname, newname)',
|
||||
setlocale = fn'Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored. - ([string])(locale [, category])',
|
||||
time = fn'Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function). - (time)([table])',
|
||||
tmpname = fn'Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed. - (string)()',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
local function key (str)
|
||||
api[str] = {type="keyword"}
|
||||
return key
|
||||
end
|
||||
-- keywords - shouldn't be left out
|
||||
key "local" "not" "if" "elseif" "else" "end" "do" "while" "repeat" "function" "until" "or"
|
||||
"or" "and" "then" "true" "false" "return" "break" "in"
|
||||
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
-- function helpers
|
||||
|
||||
local function fn (description)
|
||||
local description2,returns,args = description:match("(.+)%-%s*(%b())%s*(%b())")
|
||||
if not description2 then
|
||||
return {type="function",description=description,
|
||||
returns="(?)"}
|
||||
end
|
||||
returns = returns:gsub("^%s+",""):gsub("%s+$","")
|
||||
local ret = returns:sub(2,-2)
|
||||
local vt = ret:match("^%[?string") and "string"
|
||||
vt = vt or ret:match("^%[?table") and "table"
|
||||
vt = vt or ret:match("^%[?file") and "io"
|
||||
return {type="function",description=description2,
|
||||
returns=returns, args = args, valuetype = vt}
|
||||
end
|
||||
|
||||
local function val (description)
|
||||
return {type="value",description = description}
|
||||
end
|
||||
-- docs
|
||||
|
||||
local api = {
|
||||
table = {
|
||||
description = "Table functions",
|
||||
type = "lib",
|
||||
childs = {
|
||||
concat = fn "concatenates an array of elements - (string)(table,[sep])",
|
||||
insert = fn "inserts an element into an array - ()(table,idx,element)",
|
||||
remove = fn "removes an element from an array - (element)(table,idx)",
|
||||
maxn = fn "Returns the largest positive numerical index of the given table, or zero if the table has no positive numerical indices. - (number)(table)",
|
||||
sort = fn "Sorts table elements in a given order, in-place, from table[1] to table[n], where n is the length of the table. - ()(table,[comp])"
|
||||
}
|
||||
},
|
||||
|
||||
math = {
|
||||
type = "lib",
|
||||
description = "Math functions",
|
||||
childs = {
|
||||
abs = fn "Returns the absolute value of x. - (number)(number)",
|
||||
acos = fn "Returns the arc cosine of x (in radians). - (number)(number)",
|
||||
asin = fn "Returns the arc sine of x (in radians). - (number)(number)",
|
||||
atan = fn "Returns the arc tangent of x (in radians). - (number)(number)",
|
||||
atan2 = fn "Returns the arc tangent of x/y (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of y being zero.) - (number)(number,number)",
|
||||
ceil = fn "Returns the smallest integer larger than or equal to x. - (number)(number)",
|
||||
cos = fn "Returns the cosine of x (assumed to be in radians).",
|
||||
cosh = fn "Returns the hyperbolic cosine of x.",
|
||||
deg = fn "Returns the angle x (given in radians) in degrees.",
|
||||
exp = fn "Returns the the value ex.",
|
||||
floor = fn "Returns the largest integer smaller than or equal to x.",
|
||||
fmod = fn "Returns the remainder of the division of x by y.",
|
||||
frexp = fn "Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero).",
|
||||
huge = val "The value HUGE_VAL, a value larger than or equal to any other numerical value.",
|
||||
ldexp = fn "Returns m2e (e should be an integer).",
|
||||
log = fn "Returns the natural logarithm of x.",
|
||||
log10 = fn "Returns the base-10 logarithm of x.",
|
||||
max = fn "Returns the maximum value among its arguments.",
|
||||
min = fn "Returns the minimum value among its arguments.",
|
||||
modf = fn "Returns two numbers, the integral part of x and the fractional part of x.",
|
||||
pi = val "The value PI.",
|
||||
pow = fn "Returns xy. (You can also use the expression x^y to compute this value.)",
|
||||
rad = fn "Returns the angle x (given in degrees) in radians.",
|
||||
random = fn "This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.) When called without arguments, returns a pseudo-random real number in the range [0,1). When called with a number m, math.random returns a pseudo-random integer in the range [1, m]. When called with two numbers m and n, math.random returns a pseudo-random integer in the range [m, n].",
|
||||
randomseed = fn "Sets x as the \"seed\" for the pseudo-random generator: equal seeds produce equal sequences of numbers.",
|
||||
sin = fn"Returns the sine of x (assumed to be in radians).",
|
||||
sinh = fn"Returns the hyperbolic sine of x.",
|
||||
sqrt = fn "Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)",
|
||||
tan = fn "Returns the tangent of x (assumed to be in radians).",
|
||||
tanh = fn "Returns the hyperbolic tangent of x. "
|
||||
}
|
||||
},
|
||||
|
||||
pairs = fn "returns an iterator function for the given table - (function)(table)",
|
||||
ipairs = fn "returns an iterator function for the given table - (function)(table)",
|
||||
xpcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called,errorfunc)",
|
||||
pcall = fn "calls a function in protected mode - (boolean success, [error string / result])(called, args ...)",
|
||||
print = fn "prints out the arguments - ()(...)",
|
||||
assert = fn "error checking, if first arg is false, error message is thrown - (result)(compute,errormsg)",
|
||||
collectgarbage = fn "garbage collector manipulation - (...)(...)",
|
||||
dofile = fn "compile and execute a file - (...)(...)",
|
||||
error = fn "raise an error - (...)(...)",
|
||||
getfenv = fn "get the function environment for a function - (...)(...)",
|
||||
getmetatable = fn "not yet - (...)(...)",
|
||||
load = fn "not yet - (...)(...)",
|
||||
loadfile = fn "not yet - (...)(...)",
|
||||
loadstring = fn "not yet - (...)(...)",
|
||||
next = fn "not yet - (...)(...)",
|
||||
rawequal = fn "not yet - (...)(...)",
|
||||
rawget = fn "not yet - (...)(...)",
|
||||
rawset = fn "not yet - (...)(...)",
|
||||
select = fn "not yet - (...)(...)",
|
||||
setfenv = fn "not yet - (...)(...)",
|
||||
setmetatable = fn "not yet - (...)(...)",
|
||||
tonumber = fn "not yet - (number)(...)",
|
||||
tostring = fn "not yet - (string)(...)",
|
||||
type = fn "not yet - (string)(...)",
|
||||
unpack = fn "not yet - (...)(...)",
|
||||
|
||||
module = fn "Creates a module. - (?)(name,...)",
|
||||
require = fn "Loads the given module. - (?)(name)",
|
||||
|
||||
package = {
|
||||
type = "table",
|
||||
description = "package info",
|
||||
childs = {
|
||||
cpath = val "The path used by require to search for a C loader. ",
|
||||
loaded = val "A table used by require to control which modules are already loaded.",
|
||||
loadlib = fn "Dynamically links the host program with the C library libname. - (?)(libname, funcname)",
|
||||
path = val "The path used by require to search for a Lua loader. ",
|
||||
preload = val "A table to store loaders for specific modules (see require). ",
|
||||
seeall = fn "Sets a metatable for module with its __index field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function module. - (?)(module)"
|
||||
}
|
||||
},
|
||||
|
||||
string = {
|
||||
type = "lib",
|
||||
description = "string lib",
|
||||
childs = {
|
||||
byte = fn "Returns the internal numerical codes of the characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the default value for j is i. - (number)(string [, i [, j]])",
|
||||
char = fn "Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument. - (string)(...)",
|
||||
dump = fn "Returns a string containing a binary representation of the given function, so that a later loadstring on this string returns a copy of the function. function must be a Lua function without upvalues. - (string)(func)",
|
||||
find = fn "Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain \"find substring\" operation, with no characters in pattern being considered \"magic\". Note that if plain is given, then init must be given as well. - (number,number)(string, pattern [, init [, plain]])",
|
||||
format = fn "Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. The only differences are that the options/modifiers *, l, L, n, p, and h are not supported and that there is an extra option, q. The q option formats a string in a form suitable to be safely read back by the Lua interpreter: the string is written between double quotes, and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly escaped when written. - (string)(formatstring, ···)",
|
||||
gmatch = fn "Returns an iterator function that, each time it is called, returns the next captures from pattern over string s. - (func)(string, pattern)",
|
||||
gsub = fn "Returns a copy of s in which all occurrences of the pattern have been replaced by a replacement string specified by repl, which may be a string, a table, or a function. gsub also returns, as its second value, the total number of substitutions made. - (string,number)(string, pattern, repl [, n])",
|
||||
len = fn "Receives a string and returns its length. The empty string '' has length 0. Embedded zeros are counted, so 'a\\000bc\\000' has length 5. - (number)(string)",
|
||||
lower = fn "Receives a string and returns a copy of this string with all uppercase letters changed to lowercase. All other characters are left unchanged. The definition of what an uppercase letter is depends on the current locale. - (string)(string)",
|
||||
match = fn "Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative. - (string,...)(string, pattern [, init])",
|
||||
rep = fn "Returns a string that is the concatenation of n copies of the string s. - (string)(string s, n)",
|
||||
reverse = fn "Returns a string that is the string s reversed. - (string)(string)",
|
||||
sub = fn "Returns the substring of s that starts at i and continues until j; i and j may be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i. - (string)(string, i [, j])",
|
||||
upper = fn "Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged. The definition of what a lowercase letter is depends on the current locale. - (string)(string)",
|
||||
}
|
||||
},
|
||||
|
||||
coroutine = {
|
||||
type = "lib",
|
||||
description = "Lua supports coroutines, also called collaborative multithreading. A coroutine in Lua represents an independent thread of execution. Unlike threads in multithread systems, however, a coroutine only suspends its execution by explicitly calling a yield function.",
|
||||
childs = {
|
||||
create = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns this new coroutine, an object with type "thread". - (thread)(function)',
|
||||
resume = fn 'Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ··· are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ··· are passed as the results from the yield. - (boolean success, ...)(coroutine,...)',
|
||||
running = fn 'Returns the running coroutine, or nil when called by the main thread. - ([thread])()',
|
||||
status = fn 'Returns the status of coroutine co, as a string: "running", if the coroutine is running (that is, it called status); "suspended", if the coroutine is suspended in a call to yield, or if it has not started running yet; "normal" if the coroutine is active but not running (that is, it has resumed another coroutine); and "dead" if the coroutine has finished its body function, or if it has stopped with an error. - (status)(coroutine)',
|
||||
wrap = fn 'Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error. - (function)(function)',
|
||||
yield = fn 'Suspends the execution of the calling coroutine. The coroutine cannot be running a C function, a metamethod, or an iterator. Any arguments to yield are passed as extra results to resume. - (...)(...)'
|
||||
}
|
||||
},
|
||||
|
||||
io = {
|
||||
type = "lib",
|
||||
description = "The I/O library provides two different styles for file manipulation. The first one uses implicit file descriptors; that is, there are operations to set a default input file and a default output file, and all input/output operations are over these default files. The second style uses explicit file descriptors. ",
|
||||
childs = {
|
||||
close = fn'Equivalent to file:close(). Without a file, closes the default output file. - ()([file])',
|
||||
flush = fn'Equivalent to file:flush over the default output file. - ()([file])',
|
||||
input = fn'When called with a file name, it opens the named file (in text mode), and sets its handle as the default input file. When called with a file handle, it simply sets this file handle as the default input file. When called without parameters, it returns the current default input file. - ([in])([file])',
|
||||
lines = fn'Opens the given file name in read mode and returns an iterator function that, each time it is called, returns a new line from the file. - (function)([file])',
|
||||
open = fn'This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message. - (file,[errormsg])(filename,[mode])',
|
||||
output = fn'Similar to io.input, but operates over the default output file. - ([file])([file])',
|
||||
popen = fn'Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w"). - (file)([prog, [mode]])',
|
||||
read = fn'Reads the file file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). - (string)(...)',
|
||||
tmpfile = fn'Returns a handle for a temporary file. This file is opened in update mode and it is automatically removed when the program ends. - (file)()',
|
||||
type = fn'Checks whether obj is a valid file handle. Returns the string "file" if obj is an open file handle, "closed file" if obj is a closed file handle, or nil if obj is not a file handle. - (string)(file)',
|
||||
write = fn'Writes the value of each of its arguments to the file. The arguments must be strings or numbers. To write other values, use tostring or string.format before write. - (?)(...)',
|
||||
seek = fn'Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence - (?)([whence] [, offset])',
|
||||
setvbuf = fn'Sets the buffering mode for an output file. - (?)(mode [, size])',
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
os = {
|
||||
type = "lib",
|
||||
description = ' Operating System Facilities',
|
||||
childs = {
|
||||
clock = fn'Returns an approximation of the amount in seconds of CPU time used by the program. - (seconds)()',
|
||||
date = fn'Returns a string or a table containing date and time, formatted according to the given string format. - (string)([format [, time]])',
|
||||
difftime = fn'Returns the number of seconds from time t1 to time t2. In POSIX, Windows, and some other systems, this value is exactly t2-t1. - (time)(t2,t1)',
|
||||
execute = fn'This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns a status code, which is system-dependent. If command is absent, then it returns nonzero if a shell is available and zero otherwise. - (return)([cmd])',
|
||||
exit = fn'Calls the C function exit, with an optional code, to terminate the host program. The default value for code is the success code. - ()([code])',
|
||||
getenv = fn'Returns the value of the process environment variable varname, or nil if the variable is not defined. - ([string])(varname)',
|
||||
remove = fn'Deletes the file or directory with the given name. Directories must be empty to be removed. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(filename)',
|
||||
rename = fn'Renames file or directory named oldname to newname. If this function fails, it returns nil, plus a string describing the error. - (success,[error])(oldname, newname)',
|
||||
setlocale = fn'Sets the current locale of the program. locale is a string specifying a locale; category is an optional string describing which category to change: "all", "collate", "ctype", "monetary", "numeric", or "time"; the default category is "all". The function returns the name of the new locale, or nil if the request cannot be honored. - ([string])(locale [, category])',
|
||||
time = fn'Returns the current time when called without arguments, or a time representing the date and time specified by the given table. This table must have fields year, month, and day, and may have fields hour, min, sec, and isdst (for a description of these fields, see the os.date function). - (time)([table])',
|
||||
tmpname = fn'Returns a string with a file name that can be used for a temporary file. The file must be explicitly opened before its use and explicitly removed when no longer needed. - (string)()',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
local function key (str)
|
||||
api[str] = {type="keyword"}
|
||||
return key
|
||||
end
|
||||
-- keywords - shouldn't be left out
|
||||
key "local" "not" "if" "elseif" "else" "end" "do" "while" "repeat" "function" "until" "or"
|
||||
"or" "and" "then" "true" "false" "return" "break" "in"
|
||||
|
||||
return api
|
||||
930
api/lua/glfw.lua
Normal file
930
api/lua/glfw.lua
Normal file
@@ -0,0 +1,930 @@
|
||||
--[[// glfw | GLFW window manager
|
||||
enum {
|
||||
/*************************************************************************
|
||||
* GLFW version
|
||||
*************************************************************************/
|
||||
|
||||
GLFW_VERSION_MAJOR =2,
|
||||
GLFW_VERSION_MINOR =7,
|
||||
GLFW_VERSION_REVISION =2,
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Input handling definitions
|
||||
*************************************************************************/
|
||||
|
||||
/* Key and button state/action definitions */
|
||||
GLFW_RELEASE =0,
|
||||
GLFW_PRESS =1,
|
||||
|
||||
GLFW_TRUE = 1,
|
||||
GLFW_FALSE = 0,
|
||||
|
||||
/* Keyboard key definitions: 8-bit ISO-8859-1 (Latin 1) encoding is used
|
||||
* for printable keys (such as A-Z, 0-9 etc), and values above 256
|
||||
* represent special (non-printable) keys (e.g. F1, Page Up etc).
|
||||
*/
|
||||
GLFW_KEY_UNKNOWN =-1,
|
||||
GLFW_KEY_SPACE =32,
|
||||
GLFW_KEY_APOSTROPHE = 39,
|
||||
GLFW_KEY_COMMA = 44,
|
||||
GLFW_KEY_MINUS = 45,
|
||||
GLFW_KEY_PERIOD = 46,
|
||||
GLFW_KEY_SLASH = 47,
|
||||
GLFW_KEY_0 = 48,
|
||||
GLFW_KEY_1 = 49,
|
||||
GLFW_KEY_2 = 50,
|
||||
GLFW_KEY_3 = 51,
|
||||
GLFW_KEY_4 = 52,
|
||||
GLFW_KEY_5 = 53,
|
||||
GLFW_KEY_6 = 54,
|
||||
GLFW_KEY_7 = 55,
|
||||
GLFW_KEY_8 = 56,
|
||||
GLFW_KEY_9 = 57,
|
||||
GLFW_KEY_SEMICOLON = 59,
|
||||
GLFW_KEY_EQUAL = 61,
|
||||
GLFW_KEY_A = 65,
|
||||
GLFW_KEY_B = 66,
|
||||
GLFW_KEY_C = 67,
|
||||
GLFW_KEY_D = 68,
|
||||
GLFW_KEY_E = 69,
|
||||
GLFW_KEY_F = 70,
|
||||
GLFW_KEY_G = 71,
|
||||
GLFW_KEY_H = 72,
|
||||
GLFW_KEY_I = 73,
|
||||
GLFW_KEY_J = 74,
|
||||
GLFW_KEY_K = 75,
|
||||
GLFW_KEY_L = 76,
|
||||
GLFW_KEY_M = 77,
|
||||
GLFW_KEY_N = 78,
|
||||
GLFW_KEY_O = 79,
|
||||
GLFW_KEY_P = 80,
|
||||
GLFW_KEY_Q = 81,
|
||||
GLFW_KEY_R = 82,
|
||||
GLFW_KEY_S = 83,
|
||||
GLFW_KEY_T = 84,
|
||||
GLFW_KEY_U = 85,
|
||||
GLFW_KEY_V = 86,
|
||||
GLFW_KEY_W = 87,
|
||||
GLFW_KEY_X = 88,
|
||||
GLFW_KEY_Y = 89,
|
||||
GLFW_KEY_Z = 90,
|
||||
GLFW_KEY_LEFT_BRACKET = 91,
|
||||
GLFW_KEY_BACKSLASH = 92,
|
||||
GLFW_KEY_RIGHT_BRACKET = 93,
|
||||
GLFW_KEY_GRAVE_ACCENT = 96,
|
||||
GLFW_KEY_WORLD_1 = 161,
|
||||
GLFW_KEY_WORLD_2 = 162,
|
||||
|
||||
GLFW_KEY_SPECIAL =256,
|
||||
GLFW_KEY_ESC =(GLFW_KEY_SPECIAL+1),
|
||||
GLFW_KEY_F1 =(GLFW_KEY_SPECIAL+2),
|
||||
GLFW_KEY_F2 =(GLFW_KEY_SPECIAL+3),
|
||||
GLFW_KEY_F3 =(GLFW_KEY_SPECIAL+4),
|
||||
GLFW_KEY_F4 =(GLFW_KEY_SPECIAL+5),
|
||||
GLFW_KEY_F5 =(GLFW_KEY_SPECIAL+6),
|
||||
GLFW_KEY_F6 =(GLFW_KEY_SPECIAL+7),
|
||||
GLFW_KEY_F7 =(GLFW_KEY_SPECIAL+8),
|
||||
GLFW_KEY_F8 =(GLFW_KEY_SPECIAL+9),
|
||||
GLFW_KEY_F9 =(GLFW_KEY_SPECIAL+10),
|
||||
GLFW_KEY_F10 =(GLFW_KEY_SPECIAL+11),
|
||||
GLFW_KEY_F11 =(GLFW_KEY_SPECIAL+12),
|
||||
GLFW_KEY_F12 =(GLFW_KEY_SPECIAL+13),
|
||||
GLFW_KEY_F13 =(GLFW_KEY_SPECIAL+14),
|
||||
GLFW_KEY_F14 =(GLFW_KEY_SPECIAL+15),
|
||||
GLFW_KEY_F15 =(GLFW_KEY_SPECIAL+16),
|
||||
GLFW_KEY_F16 =(GLFW_KEY_SPECIAL+17),
|
||||
GLFW_KEY_F17 =(GLFW_KEY_SPECIAL+18),
|
||||
GLFW_KEY_F18 =(GLFW_KEY_SPECIAL+19),
|
||||
GLFW_KEY_F19 =(GLFW_KEY_SPECIAL+20),
|
||||
GLFW_KEY_F20 =(GLFW_KEY_SPECIAL+21),
|
||||
GLFW_KEY_F21 =(GLFW_KEY_SPECIAL+22),
|
||||
GLFW_KEY_F22 =(GLFW_KEY_SPECIAL+23),
|
||||
GLFW_KEY_F23 =(GLFW_KEY_SPECIAL+24),
|
||||
GLFW_KEY_F24 =(GLFW_KEY_SPECIAL+25),
|
||||
GLFW_KEY_F25 =(GLFW_KEY_SPECIAL+26),
|
||||
GLFW_KEY_UP =(GLFW_KEY_SPECIAL+27),
|
||||
GLFW_KEY_DOWN =(GLFW_KEY_SPECIAL+28),
|
||||
GLFW_KEY_LEFT =(GLFW_KEY_SPECIAL+29),
|
||||
GLFW_KEY_RIGHT =(GLFW_KEY_SPECIAL+30),
|
||||
GLFW_KEY_LSHIFT =(GLFW_KEY_SPECIAL+31),
|
||||
GLFW_KEY_RSHIFT =(GLFW_KEY_SPECIAL+32),
|
||||
GLFW_KEY_LCTRL =(GLFW_KEY_SPECIAL+33),
|
||||
GLFW_KEY_RCTRL =(GLFW_KEY_SPECIAL+34),
|
||||
GLFW_KEY_LALT =(GLFW_KEY_SPECIAL+35),
|
||||
GLFW_KEY_RALT =(GLFW_KEY_SPECIAL+36),
|
||||
GLFW_KEY_TAB =(GLFW_KEY_SPECIAL+37),
|
||||
GLFW_KEY_ENTER =(GLFW_KEY_SPECIAL+38),
|
||||
GLFW_KEY_BACKSPACE =(GLFW_KEY_SPECIAL+39),
|
||||
GLFW_KEY_INSERT =(GLFW_KEY_SPECIAL+40),
|
||||
GLFW_KEY_DEL =(GLFW_KEY_SPECIAL+41),
|
||||
GLFW_KEY_PAGEUP =(GLFW_KEY_SPECIAL+42),
|
||||
GLFW_KEY_PAGEDOWN =(GLFW_KEY_SPECIAL+43),
|
||||
GLFW_KEY_HOME =(GLFW_KEY_SPECIAL+44),
|
||||
GLFW_KEY_END =(GLFW_KEY_SPECIAL+45),
|
||||
GLFW_KEY_KP_0 =(GLFW_KEY_SPECIAL+46),
|
||||
GLFW_KEY_KP_1 =(GLFW_KEY_SPECIAL+47),
|
||||
GLFW_KEY_KP_2 =(GLFW_KEY_SPECIAL+48),
|
||||
GLFW_KEY_KP_3 =(GLFW_KEY_SPECIAL+49),
|
||||
GLFW_KEY_KP_4 =(GLFW_KEY_SPECIAL+50),
|
||||
GLFW_KEY_KP_5 =(GLFW_KEY_SPECIAL+51),
|
||||
GLFW_KEY_KP_6 =(GLFW_KEY_SPECIAL+52),
|
||||
GLFW_KEY_KP_7 =(GLFW_KEY_SPECIAL+53),
|
||||
GLFW_KEY_KP_8 =(GLFW_KEY_SPECIAL+54),
|
||||
GLFW_KEY_KP_9 =(GLFW_KEY_SPECIAL+55),
|
||||
GLFW_KEY_KP_DIVIDE =(GLFW_KEY_SPECIAL+56),
|
||||
GLFW_KEY_KP_MULTIPLY =(GLFW_KEY_SPECIAL+57),
|
||||
GLFW_KEY_KP_SUBTRACT =(GLFW_KEY_SPECIAL+58),
|
||||
GLFW_KEY_KP_ADD =(GLFW_KEY_SPECIAL+59),
|
||||
GLFW_KEY_KP_DECIMAL =(GLFW_KEY_SPECIAL+60),
|
||||
GLFW_KEY_KP_EQUAL =(GLFW_KEY_SPECIAL+61),
|
||||
GLFW_KEY_KP_ENTER =(GLFW_KEY_SPECIAL+62),
|
||||
GLFW_KEY_KP_NUM_LOCK =(GLFW_KEY_SPECIAL+63),
|
||||
GLFW_KEY_CAPS_LOCK =(GLFW_KEY_SPECIAL+64),
|
||||
GLFW_KEY_SCROLL_LOCK =(GLFW_KEY_SPECIAL+65),
|
||||
GLFW_KEY_PAUSE =(GLFW_KEY_SPECIAL+66),
|
||||
GLFW_KEY_LSUPER =(GLFW_KEY_SPECIAL+67),
|
||||
GLFW_KEY_RSUPER =(GLFW_KEY_SPECIAL+68),
|
||||
GLFW_KEY_MENU =(GLFW_KEY_SPECIAL+69),
|
||||
GLFW_KEY_LAST =GLFW_KEY_MENU,
|
||||
|
||||
/* Mouse button definitions */
|
||||
GLFW_MOUSE_BUTTON_1 =0,
|
||||
GLFW_MOUSE_BUTTON_2 =1,
|
||||
GLFW_MOUSE_BUTTON_3 =2,
|
||||
GLFW_MOUSE_BUTTON_4 =3,
|
||||
GLFW_MOUSE_BUTTON_5 =4,
|
||||
GLFW_MOUSE_BUTTON_6 =5,
|
||||
GLFW_MOUSE_BUTTON_7 =6,
|
||||
GLFW_MOUSE_BUTTON_8 =7,
|
||||
GLFW_MOUSE_BUTTON_LAST =GLFW_MOUSE_BUTTON_8,
|
||||
|
||||
/* Mouse button aliases */
|
||||
GLFW_MOUSE_BUTTON_LEFT =GLFW_MOUSE_BUTTON_1,
|
||||
GLFW_MOUSE_BUTTON_RIGHT =GLFW_MOUSE_BUTTON_2,
|
||||
GLFW_MOUSE_BUTTON_MIDDLE =GLFW_MOUSE_BUTTON_3,
|
||||
|
||||
|
||||
/* Joystick identifiers */
|
||||
GLFW_JOYSTICK_1 =0,
|
||||
GLFW_JOYSTICK_2 =1,
|
||||
GLFW_JOYSTICK_3 =2,
|
||||
GLFW_JOYSTICK_4 =3,
|
||||
GLFW_JOYSTICK_5 =4,
|
||||
GLFW_JOYSTICK_6 =5,
|
||||
GLFW_JOYSTICK_7 =6,
|
||||
GLFW_JOYSTICK_8 =7,
|
||||
GLFW_JOYSTICK_9 =8,
|
||||
GLFW_JOYSTICK_10 =9,
|
||||
GLFW_JOYSTICK_11 =10,
|
||||
GLFW_JOYSTICK_12 =11,
|
||||
GLFW_JOYSTICK_13 =12,
|
||||
GLFW_JOYSTICK_14 =13,
|
||||
GLFW_JOYSTICK_15 =14,
|
||||
GLFW_JOYSTICK_16 =15,
|
||||
GLFW_JOYSTICK_LAST =GLFW_JOYSTICK_16,
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Other definitions
|
||||
*************************************************************************/
|
||||
|
||||
/* glfwOpenWindow modes */
|
||||
GLFW_WINDOW =0x00010001,
|
||||
GLFW_FULLSCREEN =0x00010002,
|
||||
|
||||
/* glfwGetWindowParam tokens */
|
||||
GLFW_OPENED =0x00020001,
|
||||
GLFW_ACTIVE =0x00020002,
|
||||
GLFW_ICONIFIED =0x00020003,
|
||||
GLFW_ACCELERATED =0x00020004,
|
||||
GLFW_RED_BITS =0x00020005,
|
||||
GLFW_GREEN_BITS =0x00020006,
|
||||
GLFW_BLUE_BITS =0x00020007,
|
||||
GLFW_ALPHA_BITS =0x00020008,
|
||||
GLFW_DEPTH_BITS =0x00020009,
|
||||
GLFW_STENCIL_BITS =0x0002000A,
|
||||
|
||||
/* The following constants are used for both glfwGetWindowParam
|
||||
* and glfwOpenWindowHint
|
||||
*/
|
||||
GLFW_REFRESH_RATE =0x0002000B,
|
||||
GLFW_ACCUM_RED_BITS =0x0002000C,
|
||||
GLFW_ACCUM_GREEN_BITS =0x0002000D,
|
||||
GLFW_ACCUM_BLUE_BITS =0x0002000E,
|
||||
GLFW_ACCUM_ALPHA_BITS =0x0002000F,
|
||||
GLFW_AUX_BUFFERS =0x00020010,
|
||||
GLFW_STEREO =0x00020011,
|
||||
GLFW_WINDOW_NO_RESIZE =0x00020012,
|
||||
GLFW_FSAA_SAMPLES =0x00020013,
|
||||
GLFW_OPENGL_VERSION_MAJOR =0x00020014,
|
||||
GLFW_OPENGL_VERSION_MINOR =0x00020015,
|
||||
GLFW_OPENGL_FORWARD_COMPAT =0x00020016,
|
||||
GLFW_OPENGL_DEBUG_CONTEXT =0x00020017,
|
||||
GLFW_OPENGL_PROFILE =0x00020018,
|
||||
|
||||
/* GLFW_OPENGL_PROFILE tokens */
|
||||
GLFW_OPENGL_CORE_PROFILE =0x00050001,
|
||||
GLFW_OPENGL_COMPAT_PROFILE =0x00050002,
|
||||
|
||||
/* glfwEnable/glfwDisable tokens */
|
||||
GLFW_MOUSE_CURSOR =0x00030001,
|
||||
GLFW_STICKY_KEYS =0x00030002,
|
||||
GLFW_STICKY_MOUSE_BUTTONS =0x00030003,
|
||||
GLFW_SYSTEM_KEYS =0x00030004,
|
||||
GLFW_KEY_REPEAT =0x00030005,
|
||||
GLFW_AUTO_POLL_EVENTS =0x00030006,
|
||||
|
||||
/* glfwWaitThread wait modes */
|
||||
GLFW_WAIT =0x00040001,
|
||||
GLFW_NOWAIT =0x00040002,
|
||||
|
||||
/* glfwGetJoystickParam tokens */
|
||||
GLFW_PRESENT =0x00050001,
|
||||
GLFW_AXES =0x00050002,
|
||||
GLFW_BUTTONS =0x00050003,
|
||||
|
||||
/* glfwReadImage/glfwLoadTexture2D flags */
|
||||
GLFW_NO_RESCALE_BIT =0x00000001 /* Only for glfwReadImage */,
|
||||
GLFW_ORIGIN_UL_BIT =0x00000002,
|
||||
GLFW_BUILD_MIPMAPS_BIT =0x00000004 /* Only for glfwLoadTexture2D */,
|
||||
GLFW_ALPHA_MAP_BIT =0x00000008,
|
||||
|
||||
/* Time spans longer than this (seconds) are considered to be infinity */
|
||||
};
|
||||
|
||||
const float GLFW_INFINITY =100000.0;
|
||||
|
||||
/* The video mode structure used by glfwGetVideoModes() */
|
||||
typedef struct {
|
||||
int Width, Height;
|
||||
int RedBits, BlueBits, GreenBits;
|
||||
} GLFWvidmode;
|
||||
|
||||
/* Image/texture information */
|
||||
typedef struct {
|
||||
int Width, Height;
|
||||
int Format;
|
||||
int BytesPerPixel;
|
||||
unsigned char *Data;
|
||||
} GLFWimage;
|
||||
|
||||
/* Thread ID */
|
||||
typedef int GLFWthread;
|
||||
|
||||
/* Mutex object */
|
||||
typedef void * GLFWmutex;
|
||||
|
||||
/* Condition variable object */
|
||||
typedef void * GLFWcond;
|
||||
|
||||
/* Function pointer types */
|
||||
typedef void (GLFWCALL * GLFWwindowsizefun)(int,int);
|
||||
typedef int (GLFWCALL * GLFWwindowclosefun)(void);
|
||||
typedef void (GLFWCALL * GLFWwindowrefreshfun)(void);
|
||||
typedef void (GLFWCALL * GLFWmousebuttonfun)(int,int);
|
||||
typedef void (GLFWCALL * GLFWmouseposfun)(int,int);
|
||||
typedef void (GLFWCALL * GLFWmousewheelfun)(int);
|
||||
typedef void (GLFWCALL * GLFWkeyfun)(int,int);
|
||||
typedef void (GLFWCALL * GLFWcharfun)(int,int);
|
||||
typedef void (GLFWCALL * GLFWthreadfun)(void *);
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Prototypes
|
||||
*************************************************************************/
|
||||
|
||||
/* GLFW initialization, termination and version querying */
|
||||
int glfwInit( void );
|
||||
void glfwTerminate( void );
|
||||
void glfwGetVersion( int *major, int *minor, int *rev );
|
||||
|
||||
/* Window handling */
|
||||
int glfwOpenWindow( int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode );
|
||||
void glfwOpenWindowHint( int target, int hint );
|
||||
void glfwCloseWindow( void );
|
||||
void glfwSetWindowTitle( const char *title );
|
||||
void glfwGetWindowSize( int *width, int *height );
|
||||
void glfwSetWindowSize( int width, int height );
|
||||
void glfwSetWindowPos( int x, int y );
|
||||
void glfwIconifyWindow( void );
|
||||
void glfwRestoreWindow( void );
|
||||
void glfwSwapBuffers( void );
|
||||
void glfwSwapInterval( int interval );
|
||||
int glfwGetWindowParam( int param );
|
||||
void glfwSetWindowSizeCallback( GLFWwindowsizefun cbfun );
|
||||
void glfwSetWindowCloseCallback( GLFWwindowclosefun cbfun );
|
||||
void glfwSetWindowRefreshCallback( GLFWwindowrefreshfun cbfun );
|
||||
|
||||
/* Video mode functions */
|
||||
int glfwGetVideoModes( GLFWvidmode *list, int maxcount );
|
||||
void glfwGetDesktopMode( GLFWvidmode *mode );
|
||||
|
||||
/* Input handling */
|
||||
void glfwPollEvents( void );
|
||||
void glfwWaitEvents( void );
|
||||
int glfwGetKey( int key );
|
||||
int glfwGetMouseButton( int button );
|
||||
void glfwGetMousePos( int *xpos, int *ypos );
|
||||
void glfwSetMousePos( int xpos, int ypos );
|
||||
int glfwGetMouseWheel( void );
|
||||
void glfwSetMouseWheel( int pos );
|
||||
void glfwSetKeyCallback( GLFWkeyfun cbfun );
|
||||
void glfwSetCharCallback( GLFWcharfun cbfun );
|
||||
void glfwSetMouseButtonCallback( GLFWmousebuttonfun cbfun );
|
||||
void glfwSetMousePosCallback( GLFWmouseposfun cbfun );
|
||||
void glfwSetMouseWheelCallback( GLFWmousewheelfun cbfun );
|
||||
|
||||
/* Joystick input */
|
||||
int glfwGetJoystickParam( int joy, int param );
|
||||
int glfwGetJoystickPos( int joy, float *pos, int numaxes );
|
||||
int glfwGetJoystickButtons( int joy, unsigned char *buttons, int numbuttons );
|
||||
|
||||
/* Time */
|
||||
double glfwGetTime( void );
|
||||
void glfwSetTime( double time );
|
||||
void glfwSleep( double time );
|
||||
|
||||
/* Extension support */
|
||||
int glfwExtensionSupported( const char *extension );
|
||||
void* glfwGetProcAddress( const char *procname );
|
||||
void glfwGetGLVersion( int *major, int *minor, int *rev );
|
||||
|
||||
/* Threading support */
|
||||
GLFWthread glfwCreateThread( GLFWthreadfun fun, void *arg );
|
||||
void glfwDestroyThread( GLFWthread ID );
|
||||
int glfwWaitThread( GLFWthread ID, int waitmode );
|
||||
GLFWthread glfwGetThreadID( void );
|
||||
GLFWmutex glfwCreateMutex( void );
|
||||
void glfwDestroyMutex( GLFWmutex mutex );
|
||||
void glfwLockMutex( GLFWmutex mutex );
|
||||
void glfwUnlockMutex( GLFWmutex mutex );
|
||||
GLFWcond glfwCreateCond( void );
|
||||
void glfwDestroyCond( GLFWcond cond );
|
||||
void glfwWaitCond( GLFWcond cond, GLFWmutex mutex, double timeout );
|
||||
void glfwSignalCond( GLFWcond cond );
|
||||
void glfwBroadcastCond( GLFWcond cond );
|
||||
int glfwGetNumberOfProcessors( void );
|
||||
|
||||
/* Enable/disable functions */
|
||||
void glfwEnable( int token );
|
||||
void glfwDisable( int token );
|
||||
|
||||
/* Image/texture I/O support */
|
||||
int glfwReadImage( const char *name, GLFWimage *img, int flags );
|
||||
int glfwReadMemoryImage( const void *data, long size, GLFWimage *img, int flags );
|
||||
void glfwFreeImage( GLFWimage *img );
|
||||
int glfwLoadTexture2D( const char *name, int flags );
|
||||
int glfwLoadMemoryTexture2D( const void *data, long size, int flags );
|
||||
int glfwLoadTextureImage2D( GLFWimage *img, int flags );
|
||||
]]
|
||||
--auto-generated api from ffi headers
|
||||
local api =
|
||||
{
|
||||
["GLFW_VERSION_MAJOR"] = { type ='value', },
|
||||
["GLFW_VERSION_MINOR"] = { type ='value', },
|
||||
["GLFW_VERSION_REVISION"] = { type ='value', },
|
||||
["GLFW_RELEASE"] = { type ='value', },
|
||||
["GLFW_PRESS"] = { type ='value', },
|
||||
["GLFW_KEY_UNKNOWN"] = { type ='value', },
|
||||
["GLFW_KEY_SPACE"] = { type ='value', },
|
||||
["GLFW_KEY_APOSTROPHE"] = { type ='value', },
|
||||
["GLFW_KEY_COMMA"] = { type ='value', },
|
||||
["GLFW_KEY_MINUS"] = { type ='value', },
|
||||
["GLFW_KEY_PERIOD"] = { type ='value', },
|
||||
["GLFW_KEY_SLASH"] = { type ='value', },
|
||||
["GLFW_KEY_0"] = { type ='value', },
|
||||
["GLFW_KEY_1"] = { type ='value', },
|
||||
["GLFW_KEY_2"] = { type ='value', },
|
||||
["GLFW_KEY_3"] = { type ='value', },
|
||||
["GLFW_KEY_4"] = { type ='value', },
|
||||
["GLFW_KEY_5"] = { type ='value', },
|
||||
["GLFW_KEY_6"] = { type ='value', },
|
||||
["GLFW_KEY_7"] = { type ='value', },
|
||||
["GLFW_KEY_8"] = { type ='value', },
|
||||
["GLFW_KEY_9"] = { type ='value', },
|
||||
["GLFW_KEY_SEMICOLON"] = { type ='value', },
|
||||
["GLFW_KEY_EQUAL"] = { type ='value', },
|
||||
["GLFW_KEY_A"] = { type ='value', },
|
||||
["GLFW_KEY_B"] = { type ='value', },
|
||||
["GLFW_KEY_C"] = { type ='value', },
|
||||
["GLFW_KEY_D"] = { type ='value', },
|
||||
["GLFW_KEY_E"] = { type ='value', },
|
||||
["GLFW_KEY_F"] = { type ='value', },
|
||||
["GLFW_KEY_G"] = { type ='value', },
|
||||
["GLFW_KEY_H"] = { type ='value', },
|
||||
["GLFW_KEY_I"] = { type ='value', },
|
||||
["GLFW_KEY_J"] = { type ='value', },
|
||||
["GLFW_KEY_K"] = { type ='value', },
|
||||
["GLFW_KEY_L"] = { type ='value', },
|
||||
["GLFW_KEY_M"] = { type ='value', },
|
||||
["GLFW_KEY_N"] = { type ='value', },
|
||||
["GLFW_KEY_O"] = { type ='value', },
|
||||
["GLFW_KEY_P"] = { type ='value', },
|
||||
["GLFW_KEY_Q"] = { type ='value', },
|
||||
["GLFW_KEY_R"] = { type ='value', },
|
||||
["GLFW_KEY_S"] = { type ='value', },
|
||||
["GLFW_KEY_T"] = { type ='value', },
|
||||
["GLFW_KEY_U"] = { type ='value', },
|
||||
["GLFW_KEY_V"] = { type ='value', },
|
||||
["GLFW_KEY_W"] = { type ='value', },
|
||||
["GLFW_KEY_X"] = { type ='value', },
|
||||
["GLFW_KEY_Y"] = { type ='value', },
|
||||
["GLFW_KEY_Z"] = { type ='value', },
|
||||
["GLFW_KEY_LEFT_BRACKET"] = { type ='value', },
|
||||
["GLFW_KEY_BACKSLASH"] = { type ='value', },
|
||||
["GLFW_KEY_RIGHT_BRACKET"] = { type ='value', },
|
||||
["GLFW_KEY_GRAVE_ACCENT"] = { type ='value', },
|
||||
["GLFW_KEY_WORLD_1"] = { type ='value', },
|
||||
["GLFW_KEY_WORLD_2"] = { type ='value', },
|
||||
["GLFW_KEY_SPECIAL"] = { type ='value', },
|
||||
["GLFW_KEY_ESC"] = { type ='value', },
|
||||
["GLFW_KEY_F1"] = { type ='value', },
|
||||
["GLFW_KEY_F2"] = { type ='value', },
|
||||
["GLFW_KEY_F3"] = { type ='value', },
|
||||
["GLFW_KEY_F4"] = { type ='value', },
|
||||
["GLFW_KEY_F5"] = { type ='value', },
|
||||
["GLFW_KEY_F6"] = { type ='value', },
|
||||
["GLFW_KEY_F7"] = { type ='value', },
|
||||
["GLFW_KEY_F8"] = { type ='value', },
|
||||
["GLFW_KEY_F9"] = { type ='value', },
|
||||
["GLFW_KEY_F10"] = { type ='value', },
|
||||
["GLFW_KEY_F11"] = { type ='value', },
|
||||
["GLFW_KEY_F12"] = { type ='value', },
|
||||
["GLFW_KEY_F13"] = { type ='value', },
|
||||
["GLFW_KEY_F14"] = { type ='value', },
|
||||
["GLFW_KEY_F15"] = { type ='value', },
|
||||
["GLFW_KEY_F16"] = { type ='value', },
|
||||
["GLFW_KEY_F17"] = { type ='value', },
|
||||
["GLFW_KEY_F18"] = { type ='value', },
|
||||
["GLFW_KEY_F19"] = { type ='value', },
|
||||
["GLFW_KEY_F20"] = { type ='value', },
|
||||
["GLFW_KEY_F21"] = { type ='value', },
|
||||
["GLFW_KEY_F22"] = { type ='value', },
|
||||
["GLFW_KEY_F23"] = { type ='value', },
|
||||
["GLFW_KEY_F24"] = { type ='value', },
|
||||
["GLFW_KEY_F25"] = { type ='value', },
|
||||
["GLFW_KEY_UP"] = { type ='value', },
|
||||
["GLFW_KEY_DOWN"] = { type ='value', },
|
||||
["GLFW_KEY_LEFT"] = { type ='value', },
|
||||
["GLFW_KEY_RIGHT"] = { type ='value', },
|
||||
["GLFW_KEY_LSHIFT"] = { type ='value', },
|
||||
["GLFW_KEY_RSHIFT"] = { type ='value', },
|
||||
["GLFW_KEY_LCTRL"] = { type ='value', },
|
||||
["GLFW_KEY_RCTRL"] = { type ='value', },
|
||||
["GLFW_KEY_LALT"] = { type ='value', },
|
||||
["GLFW_KEY_RALT"] = { type ='value', },
|
||||
["GLFW_KEY_TAB"] = { type ='value', },
|
||||
["GLFW_KEY_ENTER"] = { type ='value', },
|
||||
["GLFW_KEY_BACKSPACE"] = { type ='value', },
|
||||
["GLFW_KEY_INSERT"] = { type ='value', },
|
||||
["GLFW_KEY_DEL"] = { type ='value', },
|
||||
["GLFW_KEY_PAGEUP"] = { type ='value', },
|
||||
["GLFW_KEY_PAGEDOWN"] = { type ='value', },
|
||||
["GLFW_KEY_HOME"] = { type ='value', },
|
||||
["GLFW_KEY_END"] = { type ='value', },
|
||||
["GLFW_KEY_KP_0"] = { type ='value', },
|
||||
["GLFW_KEY_KP_1"] = { type ='value', },
|
||||
["GLFW_KEY_KP_2"] = { type ='value', },
|
||||
["GLFW_KEY_KP_3"] = { type ='value', },
|
||||
["GLFW_KEY_KP_4"] = { type ='value', },
|
||||
["GLFW_KEY_KP_5"] = { type ='value', },
|
||||
["GLFW_KEY_KP_6"] = { type ='value', },
|
||||
["GLFW_KEY_KP_7"] = { type ='value', },
|
||||
["GLFW_KEY_KP_8"] = { type ='value', },
|
||||
["GLFW_KEY_KP_9"] = { type ='value', },
|
||||
["GLFW_KEY_KP_DIVIDE"] = { type ='value', },
|
||||
["GLFW_KEY_KP_MULTIPLY"] = { type ='value', },
|
||||
["GLFW_KEY_KP_SUBTRACT"] = { type ='value', },
|
||||
["GLFW_KEY_KP_ADD"] = { type ='value', },
|
||||
["GLFW_KEY_KP_DECIMAL"] = { type ='value', },
|
||||
["GLFW_KEY_KP_EQUAL"] = { type ='value', },
|
||||
["GLFW_KEY_KP_ENTER"] = { type ='value', },
|
||||
["GLFW_KEY_KP_NUM_LOCK"] = { type ='value', },
|
||||
["GLFW_KEY_CAPS_LOCK"] = { type ='value', },
|
||||
["GLFW_KEY_SCROLL_LOCK"] = { type ='value', },
|
||||
["GLFW_KEY_PAUSE"] = { type ='value', },
|
||||
["GLFW_KEY_LSUPER"] = { type ='value', },
|
||||
["GLFW_KEY_RSUPER"] = { type ='value', },
|
||||
["GLFW_KEY_MENU"] = { type ='value', },
|
||||
["GLFW_KEY_LAST"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_1"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_2"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_3"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_4"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_5"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_6"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_7"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_8"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_LAST"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_LEFT"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_RIGHT"] = { type ='value', },
|
||||
["GLFW_MOUSE_BUTTON_MIDDLE"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_1"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_2"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_3"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_4"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_5"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_6"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_7"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_8"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_9"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_10"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_11"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_12"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_13"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_14"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_15"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_16"] = { type ='value', },
|
||||
["GLFW_JOYSTICK_LAST"] = { type ='value', },
|
||||
["GLFW_WINDOW"] = { type ='value', },
|
||||
["GLFW_FULLSCREEN"] = { type ='value', },
|
||||
["GLFW_OPENED"] = { type ='value', },
|
||||
["GLFW_ACTIVE"] = { type ='value', },
|
||||
["GLFW_ICONIFIED"] = { type ='value', },
|
||||
["GLFW_ACCELERATED"] = { type ='value', },
|
||||
["GLFW_RED_BITS"] = { type ='value', },
|
||||
["GLFW_GREEN_BITS"] = { type ='value', },
|
||||
["GLFW_BLUE_BITS"] = { type ='value', },
|
||||
["GLFW_ALPHA_BITS"] = { type ='value', },
|
||||
["GLFW_DEPTH_BITS"] = { type ='value', },
|
||||
["GLFW_STENCIL_BITS"] = { type ='value', },
|
||||
["GLFW_REFRESH_RATE"] = { type ='value', },
|
||||
["GLFW_ACCUM_RED_BITS"] = { type ='value', },
|
||||
["GLFW_ACCUM_GREEN_BITS"] = { type ='value', },
|
||||
["GLFW_ACCUM_BLUE_BITS"] = { type ='value', },
|
||||
["GLFW_ACCUM_ALPHA_BITS"] = { type ='value', },
|
||||
["GLFW_AUX_BUFFERS"] = { type ='value', },
|
||||
["GLFW_STEREO"] = { type ='value', },
|
||||
["GLFW_WINDOW_NO_RESIZE"] = { type ='value', },
|
||||
["GLFW_FSAA_SAMPLES"] = { type ='value', },
|
||||
["GLFW_OPENGL_VERSION_MAJOR"] = { type ='value', },
|
||||
["GLFW_OPENGL_VERSION_MINOR"] = { type ='value', },
|
||||
["GLFW_OPENGL_FORWARD_COMPAT"] = { type ='value', },
|
||||
["GLFW_OPENGL_DEBUG_CONTEXT"] = { type ='value', },
|
||||
["GLFW_OPENGL_PROFILE"] = { type ='value', },
|
||||
["GLFW_OPENGL_CORE_PROFILE"] = { type ='value', },
|
||||
["GLFW_OPENGL_COMPAT_PROFILE"] = { type ='value', },
|
||||
["GLFW_MOUSE_CURSOR"] = { type ='value', },
|
||||
["GLFW_STICKY_KEYS"] = { type ='value', },
|
||||
["GLFW_STICKY_MOUSE_BUTTONS"] = { type ='value', },
|
||||
["GLFW_SYSTEM_KEYS"] = { type ='value', },
|
||||
["GLFW_KEY_REPEAT"] = { type ='value', },
|
||||
["GLFW_AUTO_POLL_EVENTS"] = { type ='value', },
|
||||
["GLFW_WAIT"] = { type ='value', },
|
||||
["GLFW_NOWAIT"] = { type ='value', },
|
||||
["GLFW_PRESENT"] = { type ='value', },
|
||||
["GLFW_AXES"] = { type ='value', },
|
||||
["GLFW_BUTTONS"] = { type ='value', },
|
||||
["GLFW_NO_RESCALE_BIT"] = { type ='value', },
|
||||
["GLFW_ORIGIN_UL_BIT"] = { type ='value', },
|
||||
["GLFW_BUILD_MIPMAPS_BIT"] = { type ='value', },
|
||||
["GLFW_ALPHA_MAP_BIT"] = { type ='value', },
|
||||
["glfwInit"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwTerminate"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwGetVersion"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int *major, int *minor, int *rev)", },
|
||||
["glfwOpenWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int width, int height, int redbits, int greenbits, int bluebits, int alphabits, int depthbits, int stencilbits, int mode)", },
|
||||
["glfwOpenWindowHint"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int target, int hint)", },
|
||||
["glfwCloseWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwSetWindowTitle"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(const char *title)", },
|
||||
["glfwGetWindowSize"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int *width, int *height)", },
|
||||
["glfwSetWindowSize"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int width, int height)", },
|
||||
["glfwSetWindowPos"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int x, int y)", },
|
||||
["glfwIconifyWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwRestoreWindow"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwSwapBuffers"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwSwapInterval"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int interval)", },
|
||||
["glfwGetWindowParam"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int param)", },
|
||||
["glfwSetWindowSizeCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWwindowsizefun cbfun)", },
|
||||
["glfwSetWindowCloseCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWwindowclosefun cbfun)", },
|
||||
["glfwSetWindowRefreshCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWwindowrefreshfun cbfun)", },
|
||||
["glfwGetVideoModes"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(GLFWvidmode *list, int maxcount)", },
|
||||
["glfwGetDesktopMode"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWvidmode *mode)", },
|
||||
["glfwPollEvents"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwWaitEvents"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwGetKey"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int key)", },
|
||||
["glfwGetMouseButton"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int button)", },
|
||||
["glfwGetMousePos"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int *xpos, int *ypos)", },
|
||||
["glfwSetMousePos"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int xpos, int ypos)", },
|
||||
["glfwGetMouseWheel"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwSetMouseWheel"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int pos)", },
|
||||
["glfwSetKeyCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWkeyfun cbfun)", },
|
||||
["glfwSetCharCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWcharfun cbfun)", },
|
||||
["glfwSetMouseButtonCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmousebuttonfun cbfun)", },
|
||||
["glfwSetMousePosCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmouseposfun cbfun)", },
|
||||
["glfwSetMouseWheelCallback"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmousewheelfun cbfun)", },
|
||||
["glfwGetJoystickParam"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int joy, int param)", },
|
||||
["glfwGetJoystickPos"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int joy, float *pos, int numaxes)", },
|
||||
["glfwGetJoystickButtons"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(int joy, unsigned char *buttons, int numbuttons)", },
|
||||
["glfwGetTime"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(double)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwSetTime"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(double time)", },
|
||||
["glfwSleep"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(double time)", },
|
||||
["glfwExtensionSupported"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const char *extension)", },
|
||||
["glfwGetProcAddress"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void*)",
|
||||
valuetype = nil,
|
||||
args = "(const char *procname)", },
|
||||
["glfwGetGLVersion"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(void)",
|
||||
valuetype = nil,
|
||||
args = "(int *major, int *minor, int *rev)", },
|
||||
["glfwCreateThread"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(GLFWthread)",
|
||||
valuetype = nil,
|
||||
args = "(GLFWthreadfun fun, void *arg)", },
|
||||
["glfwDestroyThread"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWthread ID)", },
|
||||
["glfwWaitThread"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(GLFWthread ID, int waitmode)", },
|
||||
["glfwGetThreadID"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(GLFWthread)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwCreateMutex"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(GLFWmutex)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwDestroyMutex"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmutex mutex)", },
|
||||
["glfwLockMutex"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmutex mutex)", },
|
||||
["glfwUnlockMutex"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWmutex mutex)", },
|
||||
["glfwCreateCond"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(GLFWcond)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwDestroyCond"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWcond cond)", },
|
||||
["glfwWaitCond"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWcond cond, GLFWmutex mutex, double timeout)", },
|
||||
["glfwSignalCond"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWcond cond)", },
|
||||
["glfwBroadcastCond"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWcond cond)", },
|
||||
["glfwGetNumberOfProcessors"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(void)", },
|
||||
["glfwEnable"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int token)", },
|
||||
["glfwDisable"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(int token)", },
|
||||
["glfwReadImage"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const char *name, GLFWimage *img, int flags)", },
|
||||
["glfwReadMemoryImage"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *data, long size, GLFWimage *img, int flags)", },
|
||||
["glfwFreeImage"] = { type ='function',
|
||||
description = "",
|
||||
returns = "()",
|
||||
valuetype = nil,
|
||||
args = "(GLFWimage *img)", },
|
||||
["glfwLoadTexture2D"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const char *name, int flags)", },
|
||||
["glfwLoadMemoryTexture2D"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(const void *data, long size, int flags)", },
|
||||
["glfwLoadTextureImage2D"] = { type ='function',
|
||||
description = "",
|
||||
returns = "(int)",
|
||||
valuetype = nil,
|
||||
args = "(GLFWimage *img, int flags)", },
|
||||
["GLFWvidmode"] = { type ='class',
|
||||
description = "",
|
||||
childs = {
|
||||
["Width"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["Height"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["RedBits"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["BlueBits"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["GreenBits"] = { type ='value', description = "int", valuetype = nil, },
|
||||
}
|
||||
},
|
||||
["GLFWimage"] = { type ='class',
|
||||
description = "",
|
||||
childs = {
|
||||
["Width"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["Height"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["Format"] = { type ='value', description = "int", valuetype = nil, },
|
||||
["BytesPerPixel"] = { type ='value', description = "int", valuetype = nil, },
|
||||
}
|
||||
},
|
||||
}
|
||||
return {
|
||||
glfw = {
|
||||
type = 'lib',
|
||||
description = "GLFW window manager",
|
||||
childs = api,
|
||||
},
|
||||
}
|
||||
|
||||
4301
api/lua/love2d.lua
Normal file
4301
api/lua/love2d.lua
Normal file
File diff suppressed because it is too large
Load Diff
11716
api/lua/luxiniaapi.lua
11716
api/lua/luxiniaapi.lua
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
This directory contains API definitions.
|
||||
|
||||
An API definition is a set of functions that are used
|
||||
for displaying tooltip information on function calls or
|
||||
autocomplete information.
|
||||
|
||||
This directory contains API definitions.
|
||||
|
||||
An API definition is a set of functions that are used
|
||||
for displaying tooltip information on function calls or
|
||||
autocomplete information.
|
||||
|
||||
|
||||
BIN
bin/clibs/mime/core.dll
Normal file
BIN
bin/clibs/mime/core.dll
Normal file
Binary file not shown.
BIN
bin/clibs/ssl.dll
Normal file
BIN
bin/clibs/ssl.dll
Normal file
Binary file not shown.
BIN
bin/lua.exe
BIN
bin/lua.exe
Binary file not shown.
BIN
bin/lua5.1.dll
BIN
bin/lua5.1.dll
Binary file not shown.
BIN
bin/winapi.dll
Normal file
BIN
bin/winapi.dll
Normal file
Binary file not shown.
@@ -1,38 +1,38 @@
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
|
||||
stringtxt = {fg = {127, 0, 127},},
|
||||
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
|
||||
preprocessor = {fg = {127, 127, 0 },},
|
||||
operator = {fg = {0, 0, 0 },},
|
||||
number = {fg = {90, 100, 0 },},
|
||||
|
||||
keywords0 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords1 = {fg = {127, 0, 0}, b = true,},
|
||||
keywords2 = {fg = {0, 127, 0}, b = true,},
|
||||
keywords3 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords4 = {fg = {127, 0, 95}, b = true,},
|
||||
keywords5 = {fg = {35, 95, 175}, b = true,},
|
||||
keywords6 = {fg = {0, 127, 127}, b = true,},
|
||||
keywords7 = {fg = {240, 255, 255}, b = true,},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = nil, -- let os pick
|
||||
linenumber = {fg = {90, 90, 80},},
|
||||
bracematch = {fg = {0, 0, 255}, b = true},
|
||||
bracemiss = {fg = {255, 0, 0 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
|
||||
calltip = nil,
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = {fg = {180, 180, 180,},},
|
||||
|
||||
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
|
||||
stringtxt = {fg = {127, 0, 127},},
|
||||
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
|
||||
preprocessor = {fg = {127, 127, 0 },},
|
||||
operator = {fg = {0, 0, 0 },},
|
||||
number = {fg = {90, 100, 0 },},
|
||||
|
||||
keywords0 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords1 = {fg = {127, 0, 0}, b = true,},
|
||||
keywords2 = {fg = {0, 127, 0}, b = true,},
|
||||
keywords3 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords4 = {fg = {127, 0, 95}, b = true,},
|
||||
keywords5 = {fg = {35, 95, 175}, b = true,},
|
||||
keywords6 = {fg = {0, 127, 127}, b = true,},
|
||||
keywords7 = {fg = {240, 255, 255}, b = true,},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = nil, -- let os pick
|
||||
linenumber = {fg = {90, 90, 80},},
|
||||
bracematch = {fg = {0, 0, 255}, b = true},
|
||||
bracemiss = {fg = {255, 0, 0 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
|
||||
calltip = nil,
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = {fg = {180, 180, 180,},},
|
||||
|
||||
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
local luxpath = os.getenv("LUXINIA")
|
||||
path.luxinia = luxpath and luxpath.."/" or "../../engine/"
|
||||
local luxpath2 = os.getenv("LUXINIA2")
|
||||
path.luxinia2 = luxpath2 and luxpath2.."/" or "../luxinia2/runtime/bin_Windows_x86/"
|
||||
|
||||
editor.fontname = "Courier New"
|
||||
editor.caretline = true
|
||||
editor.showfncall = true
|
||||
|
||||
filehistorylength = 20
|
||||
|
||||
singleinstance = true
|
||||
singleinstanceport = 0xe493
|
||||
acandtip.shorttip = true
|
||||
|
||||
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
|
||||
stringtxt = {fg = {127, 0, 127},},
|
||||
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
|
||||
preprocessor = {fg = {127, 127, 0 },},
|
||||
operator = {fg = {0, 0, 0 },},
|
||||
number = {fg = {90, 100, 0 },},
|
||||
|
||||
keywords0 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords1 = {fg = {127, 0, 0}, b = true,},
|
||||
keywords2 = {fg = {0, 127, 0}, b = true,},
|
||||
keywords3 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords4 = {fg = {127, 0, 95}, b = true,},
|
||||
keywords5 = {fg = {35, 95, 175}, b = true,},
|
||||
keywords6 = {fg = {0, 127, 127}, b = true,},
|
||||
keywords7 = {fg = {240, 255, 255}, b = true,},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = nil, -- let os pick
|
||||
linenumber = {fg = {90, 90, 80},},
|
||||
bracematch = {fg = {0, 0, 255}, b = true},
|
||||
bracemiss = {fg = {255, 0, 0 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
|
||||
calltip = nil,
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = nil,
|
||||
|
||||
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
@@ -1,39 +1,38 @@
|
||||
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
|
||||
stringtxt = {fg = {240,128,240},},
|
||||
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220,175,140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {240,240,0}},
|
||||
keywords1 = {fg = {255,64,64},},
|
||||
keywords2 = {fg = {0,240,240},},
|
||||
keywords3 = {fg = {140,140,240},},
|
||||
keywords4 = {fg = {255, 128, 0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 250, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {240,240,240},bg = {24,24,24},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {255, 127, 0}, b = true},
|
||||
bracemiss = {fg = {255, 0,0}, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {54,54,54},},
|
||||
|
||||
fncall = {fg = {140,140,0}, st = wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
|
||||
stringtxt = {fg = {240,128,240},},
|
||||
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220,175,140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {240,240,0}},
|
||||
keywords1 = {fg = {255,64,64},},
|
||||
keywords2 = {fg = {0,240,240},},
|
||||
keywords3 = {fg = {140,140,240},},
|
||||
keywords4 = {fg = {255, 128, 0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 250, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {240,240,240},bg = {24,24,24},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {255, 127, 0}, b = true},
|
||||
bracemiss = {fg = {255, 0,0}, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {54,54,54},},
|
||||
|
||||
fncall = {fg = {140,140,0}, st = wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {100, 155, 65}, bg = {30, 35, 30 }, fill= true,},
|
||||
stringtxt = {fg = {200, 145, 145},},
|
||||
stringeol = {fg = {200, 145, 145},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220, 175, 140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {128,128,255},},
|
||||
keywords1 = {fg = {210,90,90},},
|
||||
keywords2 = {fg = {0,220,220},},
|
||||
keywords3 = {fg = {220,220,0},},
|
||||
keywords4 = {fg = {240, 128,0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 240, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {200,200,200},bg = {18,24,26},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {255, 127, 0}, b = true},
|
||||
bracemiss = {fg = {255, 0,0}, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {54,54,54},},
|
||||
|
||||
fncall = {fg = {75,75,150}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {100, 155, 65}, bg = {30, 35, 30 }, fill= true,},
|
||||
stringtxt = {fg = {200, 145, 145},},
|
||||
stringeol = {fg = {200, 145, 145},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220, 175, 140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {128,128,255},},
|
||||
keywords1 = {fg = {210,90,90},},
|
||||
keywords2 = {fg = {0,220,220},},
|
||||
keywords3 = {fg = {220,220,0},},
|
||||
keywords4 = {fg = {240, 128,0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 240, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {200,200,200},bg = {18,24,26},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {255, 127, 0}, b = true},
|
||||
bracemiss = {fg = {255, 0,0}, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {54,54,54},},
|
||||
|
||||
fncall = {fg = {75,75,150}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
|
||||
27
cfg/user-sample.lua
Normal file
27
cfg/user-sample.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[-- Rename this file to `user.lua` to get loaded
|
||||
|
||||
Configuration files are loaded in the following order
|
||||
|
||||
1. <application>\config.lua
|
||||
2. cfg\user.lua
|
||||
3. -cfg commandline strings
|
||||
|
||||
-- an example of how loaded configuration can be modified from this file
|
||||
|
||||
local G = ... -- this now points to the global environment in the script
|
||||
local luaspec = G.ide.specs['lua']
|
||||
luaspec.exts[2] = "luaz"
|
||||
luaspec.keywords[1] = luaspec.keywords[1] .. ' foo'
|
||||
|
||||
-- these changes are going to be mapped to ide.config.editor...
|
||||
-- change encoding to Cyrillic
|
||||
editor.fontencoding = G.wx.wxFONTENCODING_ISO8859_5
|
||||
-- or WinCyrillic
|
||||
editor.fontencoding = G.wx.wxFONTENCODING_CP1251
|
||||
outputshell.fontencoding = G.wx.wxFONTENCODING_CP1251
|
||||
|
||||
-- specify full path to love2d executable; this is only needed
|
||||
-- if the game folder and the executable are NOT in the same folder.
|
||||
path.love2d = 'd:/lua/love/love' -- set the path of love executable
|
||||
|
||||
--]]--
|
||||
@@ -1,52 +0,0 @@
|
||||
|
||||
local luxpath = os.getenv("LUXINIA")
|
||||
path.luxinia = luxpath and luxpath.."/" or "../luxinia/"
|
||||
|
||||
interpreter = "estrelashell"
|
||||
acandtip.shorttip = true
|
||||
acandtip.nodynwords = true
|
||||
editor.iofilter = "GermanUtf8Ascii"
|
||||
cgprofile = "gp4"
|
||||
cgperfgpu = "G80"
|
||||
|
||||
--[[
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
|
||||
stringtxt = {fg = {240,128,240},},
|
||||
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220,175,140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {240,240,0}},
|
||||
keywords1 = {fg = {255,64,64},},
|
||||
keywords2 = {fg = {0,240,240},},
|
||||
keywords3 = {fg = {140,140,240},},
|
||||
keywords4 = {fg = {255, 128, 0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 250, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {240,240,240},bg = {24,24,24},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {200, 200, 0}, b = true},
|
||||
bracemiss = {fg = {255, 50, 50 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {224,224,224},bg = {24,24,24},},
|
||||
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
local luxpath = os.getenv("LUXINIA")
|
||||
path.luxinia = luxpath and luxpath.."/" or "../luxinia/"
|
||||
path.cgbin = "../Cg/bin"
|
||||
|
||||
interpreter = "luxinia"
|
||||
acandtip.shorttip = true
|
||||
acandtip.nodynwords = true
|
||||
editor.iofilter = "GermanUtf8Ascii"
|
||||
|
||||
--[[
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {200, 230, 120 },bg = {30, 40, 30 }, fill= true,},
|
||||
stringtxt = {fg = {240,128,240},},
|
||||
stringeol = {fg = {240,128,200},bg = {48, 24, 24}, fill = true,},
|
||||
preprocessor = {fg = {220,175,140},},
|
||||
operator = {fg = {210, 230, 240 },},
|
||||
number = {fg = {210, 230, 255, },},
|
||||
|
||||
keywords0 = {fg = {240,240,0}},
|
||||
keywords1 = {fg = {255,64,64},},
|
||||
keywords2 = {fg = {0,240,240},},
|
||||
keywords3 = {fg = {140,140,240},},
|
||||
keywords4 = {fg = {255, 128, 0},},
|
||||
keywords5 = {fg = {200,200,240},},
|
||||
keywords6 = {fg = {64, 250, 64},},
|
||||
keywords7 = {fg = {255, 128, 128},},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = {fg = {240,240,240},bg = {24,24,24},},
|
||||
linenumber = {fg = {30, 30, 40},bg = {230, 230, 230},},
|
||||
bracematch = {fg = {200, 200, 0}, b = true},
|
||||
bracemiss = {fg = {255, 50, 50 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {80, 80, 80},bg = {24,24,24},},
|
||||
calltip = {fg = {255,255,255},bg = {10,10,10},},
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = {fg = {240,240,240},bg = {10,10,10},},
|
||||
sel = {fg = {180,220,140},bg = {70,105,100},},
|
||||
caret = {fg = {250,250,250},},
|
||||
caretlinebg = {fg = {180,220,140},bg = {24,44,44},},
|
||||
fold = nil,
|
||||
whitespace = {fg = {224,224,224},bg = {24,24,24},},
|
||||
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
289
doc/defs.lua
289
doc/defs.lua
@@ -1,289 +0,0 @@
|
||||
-- About
|
||||
-- ----------------------------------------------------
|
||||
-- This file contains lua table definitons used by
|
||||
-- automatic loaded files, not part of the
|
||||
-- editor source.
|
||||
--
|
||||
-- /cfg/config.lua
|
||||
-- /cfg/user.lua
|
||||
-- /spec/*.lua
|
||||
-- /tools/*.lua
|
||||
-- /api/*<apitype>/*.lua
|
||||
|
||||
|
||||
-- style definition
|
||||
-- ----------------------------------------------------
|
||||
-- all entries are optiona
|
||||
stattr = {
|
||||
fg = {r,g,b}, -- foreground color 0-255
|
||||
bg = {r,g,b}, -- background color
|
||||
i = false, -- italic
|
||||
b = false, -- bold
|
||||
u = false, -- underline
|
||||
fill = true, -- fill to lineend
|
||||
}
|
||||
|
||||
style = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = stattr,
|
||||
comment = stattr,
|
||||
stringtxt = stattr,
|
||||
stringeol = stattr,
|
||||
preprocessor = stattr,
|
||||
operator = stattr,
|
||||
number = stattr,
|
||||
|
||||
keywords0 = stattr,
|
||||
keywords1 = stattr,
|
||||
keywords2 = stattr,
|
||||
keywords3 = stattr,
|
||||
keywords4 = stattr,
|
||||
keywords5 = stattr,
|
||||
keywords6 = stattr,
|
||||
keywords7 = stattr,
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = stattr,
|
||||
linenumber = stattr,
|
||||
bracematch = stattr,
|
||||
bracemiss = stattr,
|
||||
escapechar = stattr,
|
||||
indent = stattr,
|
||||
calltip = stattr,
|
||||
|
||||
-- common special (need custom fg & bg )
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = nil,
|
||||
|
||||
-- special, functioncall indicator
|
||||
fncall = {
|
||||
fg = {r,g,b},
|
||||
st = wxstc.wxSTC_INDIC_BOX,
|
||||
},
|
||||
}
|
||||
|
||||
-- config definition
|
||||
-- ----------------------------------------------------
|
||||
-- tables must exist
|
||||
-- content is optional
|
||||
-- config is loaded into existing config table
|
||||
config = {
|
||||
appname = "estrela", -- by default the launcher name
|
||||
|
||||
path = {
|
||||
-- path for tools/interpreters
|
||||
luxinia = "C:/luxbin/",
|
||||
-- path to luxinia exe
|
||||
|
||||
projectdir = "",
|
||||
-- the project directory, used by
|
||||
-- some tools/interpreters
|
||||
},
|
||||
editor = {
|
||||
fontname = "Courier New",
|
||||
-- default font
|
||||
fontsize = 10,
|
||||
-- defailt size
|
||||
caretline = true,
|
||||
-- show active line
|
||||
|
||||
-- input/output filtering of strings
|
||||
-- current filters "GermanUtf8Ascii"
|
||||
iofilter = nil,
|
||||
|
||||
-- use indicator to show function calls
|
||||
-- if spec allows
|
||||
showfncall = true,
|
||||
|
||||
tabwidth = 4,
|
||||
usetabs = true, -- if false then spaces are used
|
||||
whitespace = false,
|
||||
autotabs = true, -- if true test for tabs after file load,
|
||||
-- sets "usetabs" to true for this file
|
||||
},
|
||||
|
||||
outputshell = {
|
||||
-- output and shell settings
|
||||
fontname = "Courier New",
|
||||
-- default font
|
||||
fontsize = 10,
|
||||
-- defult size
|
||||
}
|
||||
|
||||
styles = {},
|
||||
-- styles table as above for editor
|
||||
|
||||
stylesoutshell = {},
|
||||
-- styles for output/shell
|
||||
|
||||
interpreter = "EstrelaEditor",
|
||||
-- the default "project" lua interpreter
|
||||
-- EstrelaEditor, Luxinia, Lua
|
||||
|
||||
autocomplete = true,
|
||||
-- whether autocomplete is on by default
|
||||
|
||||
acandtip = {
|
||||
shorttip = false,
|
||||
-- tooltips are compact during typing
|
||||
nodynwords = false,
|
||||
-- no dynamic words (user entered words)
|
||||
ignorecase = false,
|
||||
-- ignores case when performing comparison with autocomplete list
|
||||
strategy = 0,
|
||||
-- 0: is string comparison
|
||||
-- 1: substring leading characters (camel case or _ separated)
|
||||
-- 2: leading + any correctly ordered fragments (default)
|
||||
}
|
||||
|
||||
savebak = false,
|
||||
-- if bak files are created on save
|
||||
|
||||
filehistorylength = 20,
|
||||
-- historylength for files
|
||||
|
||||
projecthistorylength = 15,
|
||||
-- historylength for project directories
|
||||
|
||||
singleinstance = true,
|
||||
-- if true creates a UDP server to exchange messages
|
||||
-- for loading commandline passed files
|
||||
|
||||
singleinstanceport = 0xe493,
|
||||
-- UDP port for single instance communication
|
||||
}
|
||||
|
||||
-- application engine
|
||||
-- ----------------------------------------------------
|
||||
|
||||
app = {
|
||||
|
||||
postinit = function() end, -- post init, prior starting mainloop
|
||||
loadfilters = {
|
||||
tools = function(file) return true end,
|
||||
specs = function(file) return true end,
|
||||
interpreters = function(file) return true end,
|
||||
}
|
||||
stringtable = { -- optional entries uses defaults otherwise
|
||||
editor = nil,
|
||||
statuswelcome = nil,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-- api definition
|
||||
-- ----------------------------------------------------
|
||||
-- hierarchy encoded into children
|
||||
|
||||
api = {
|
||||
-- global space words, e.g "table"
|
||||
["blah"] = {
|
||||
-- "function", "class", "keyword", "value", "lib"
|
||||
type = "function",
|
||||
description = "this does something",
|
||||
|
||||
-- value and function:
|
||||
valuetype = "api.ClassName",
|
||||
|
||||
-- function:
|
||||
args = "(blah,blubb)",
|
||||
returns = "(foo)",
|
||||
|
||||
-- autogenerated post load:
|
||||
-- concated hierarchy name (e.g. "lib.class")
|
||||
classname = "blah",
|
||||
|
||||
-- children in the class hierarchy
|
||||
childs = {
|
||||
--.. recursive
|
||||
}
|
||||
},
|
||||
["blubb"] = {
|
||||
--...
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- spec definition
|
||||
-- ----------------------------------------------------
|
||||
-- all entries are optional
|
||||
spec = {
|
||||
exts = {"ext","ext2",..},
|
||||
-- compatible extensions
|
||||
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
-- scintilla lexer
|
||||
|
||||
lexerstyleconvert = {
|
||||
-- table mapping each styles to
|
||||
-- appropriate lexer id
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
-- ...
|
||||
}
|
||||
|
||||
linecomment = "//",
|
||||
-- string for linecomments
|
||||
|
||||
sep = "[%.:]",
|
||||
-- class.function separator match string,
|
||||
-- e.g in lua both . and : are allowed
|
||||
-- default is "\1" which should yield no matches
|
||||
-- and therefore disable class.func type autocompletion
|
||||
|
||||
isfncall = function(str) return from,to end
|
||||
-- function that detects positions for a substring that
|
||||
-- stands for a functioncall, ie " call(..)" -> 2,5
|
||||
|
||||
|
||||
apitype = "api",
|
||||
-- which sub directory of "api" is relevant
|
||||
-- api files handle autocomplete and tooltips
|
||||
-- api won't affect syntax coloring
|
||||
|
||||
keywords = {
|
||||
-- up to 8 strings containing space separated keywords
|
||||
-- used by the lexer for coloring (NOT for autocomplete).
|
||||
-- however each lexer supports varying amount
|
||||
-- of keyword types
|
||||
|
||||
"foo bar word",
|
||||
"more words",
|
||||
}
|
||||
}
|
||||
|
||||
-- tool definition
|
||||
-- ----------------------------------------------------
|
||||
-- main entries are optional
|
||||
tool = {
|
||||
fninit = function(frame,menubar) end,
|
||||
-- guarantees that ide is initialized
|
||||
-- can be used for init
|
||||
-- and adding custom menu
|
||||
|
||||
exec = {
|
||||
-- quick exec action, listed under "Tools" menu
|
||||
name = "",
|
||||
description = "",
|
||||
fn = function(wxfilename,projectdir) end,
|
||||
}
|
||||
}
|
||||
|
||||
-- interpreter definition
|
||||
-- ----------------------------------------------------
|
||||
interpreter = {
|
||||
name = "",
|
||||
description = "",
|
||||
api = {"apifile_without_extension"} -- optional to limit loaded apis
|
||||
frun = function(self,wfilename)
|
||||
return "execommand"
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return "projpath_from_filename" -- optional
|
||||
end,
|
||||
}
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="6" />
|
||||
<Project>
|
||||
<Option title="starter" />
|
||||
<Option pch_mode="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Build>
|
||||
<Target title="Debug">
|
||||
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="..\..\" />
|
||||
<Option object_output="obj\Debug\" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Option use_console_runner="0" />
|
||||
<Compiler>
|
||||
<Add option="-g" />
|
||||
</Compiler>
|
||||
</Target>
|
||||
<Target title="Release">
|
||||
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="..\..\" />
|
||||
<Option object_output="obj\Release\" />
|
||||
<Option type="0" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add option="-O2" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
</Linker>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-D__MINGW__" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add library="kernel32" />
|
||||
</Linker>
|
||||
<Unit filename="..\res\estrela.ico" />
|
||||
<Unit filename="..\res\estrela.rc">
|
||||
<Option compilerVar="WINDRES" />
|
||||
</Unit>
|
||||
<Unit filename="..\win32_starter.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Extensions>
|
||||
<code_completion />
|
||||
<envvars />
|
||||
<debugger />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="6" />
|
||||
<Project>
|
||||
<Option title="starter" />
|
||||
<Option pch_mode="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Build>
|
||||
<Target title="Debug">
|
||||
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="..\..\" />
|
||||
<Option object_output="obj\Debug\" />
|
||||
<Option type="1" />
|
||||
<Option compiler="gcc" />
|
||||
<Option use_console_runner="0" />
|
||||
<Compiler>
|
||||
<Add option="-g" />
|
||||
</Compiler>
|
||||
</Target>
|
||||
<Target title="Release">
|
||||
<Option output="..\..\estrela" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="..\..\" />
|
||||
<Option object_output="obj\Release\" />
|
||||
<Option type="0" />
|
||||
<Option compiler="gcc" />
|
||||
<Compiler>
|
||||
<Add option="-O2" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
</Linker>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-D__MINGW__" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add library="kernel32" />
|
||||
</Linker>
|
||||
<Unit filename="..\res\estrela.ico" />
|
||||
<Unit filename="..\res\estrela.rc">
|
||||
<Option compilerVar="WINDRES" />
|
||||
</Unit>
|
||||
<Unit filename="..\win32_starter.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Extensions>
|
||||
<code_completion />
|
||||
<envvars />
|
||||
<debugger />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
||||
|
||||
61
estrela/config.lua
Normal file
61
estrela/config.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
local luxpath = os.getenv("LUXINIA")
|
||||
path.luxinia = luxpath and luxpath.."/" or "../luxinia/engine/"
|
||||
local luxpath2 = os.getenv("LUXINIA2")
|
||||
path.luxinia2 = luxpath2 and luxpath2.."/" or "../luxinia2/runtime/bin_Windows_x86/"
|
||||
|
||||
interpreter = "estrelashell"
|
||||
|
||||
editor.fontname = "Courier New"
|
||||
editor.caretline = true
|
||||
editor.showfncall = true
|
||||
editor.whitespace = true
|
||||
editor.usetabs = false
|
||||
editor.autotabs = true
|
||||
editor.tabwidth = 2
|
||||
|
||||
filehistorylength = 20
|
||||
|
||||
singleinstance = true
|
||||
singleinstanceport = 0xe493
|
||||
acandtip.shorttip = true
|
||||
acandtip.nodynwords = true
|
||||
acandtip.ignorecase = true
|
||||
|
||||
styles = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = {fg = {128, 128, 128},},
|
||||
comment = {fg = {0, 127, 0 },bg = {240, 240, 220}, fill= true,},
|
||||
stringtxt = {fg = {127, 0, 127},},
|
||||
stringeol = {fg = {0, 0, 0 },bg = {224, 192, 224}, fill = true, },
|
||||
preprocessor = {fg = {127, 127, 0 },},
|
||||
operator = {fg = {0, 0, 0 },},
|
||||
number = {fg = {90, 100, 0 },},
|
||||
|
||||
keywords0 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords1 = {fg = {127, 0, 0}, b = true,},
|
||||
keywords2 = {fg = {0, 127, 0}, b = true,},
|
||||
keywords3 = {fg = {0, 0, 127}, b = true,},
|
||||
keywords4 = {fg = {127, 0, 95}, b = true,},
|
||||
keywords5 = {fg = {35, 95, 175}, b = true,},
|
||||
keywords6 = {fg = {0, 127, 127}, b = true,},
|
||||
keywords7 = {fg = {240, 255, 255}, b = true,},
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = nil, -- let os pick
|
||||
linenumber = {fg = {90, 90, 80},},
|
||||
bracematch = {fg = {0, 0, 255}, b = true},
|
||||
bracemiss = {fg = {255, 0, 0 }, b = true},
|
||||
ctrlchar = nil,
|
||||
indent = {fg = {192, 192, 192},bg = {255, 255, 255},},
|
||||
calltip = nil,
|
||||
|
||||
-- common special (need custom fg & bg)
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = nil,
|
||||
|
||||
fncall = {fg = {175,175,255}, st= wxstc.wxSTC_INDIC_BOX},
|
||||
}
|
||||
@@ -1,114 +1,113 @@
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Create the Help menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
|
||||
local helpMenu = wx.wxMenu{
|
||||
{ ID_ABOUT, "&About\tF1", "About Estrela Editor" },
|
||||
}
|
||||
menuBar:Append(helpMenu, "&Help")
|
||||
|
||||
local function DisplayAbout(event)
|
||||
local page = [[
|
||||
<html>
|
||||
<body bgcolor = "#ffffff" text='#ffffff'>
|
||||
<table border='0' width="100%">
|
||||
<tr><td><img src = "estrela/res/estrela.png"></center></td><td>
|
||||
<table cellspacing = 4 cellpadding = 4 width = "400">
|
||||
<tr>
|
||||
<td bgcolor = "#010156">
|
||||
<center>
|
||||
<font size = +2 color = "#FFFFFF"><br><b>]]..
|
||||
wxlua.wxLUA_VERSION_STRING..[[</b></font>
|
||||
<font size = +1 color = "#FFFFFF">built with</font>
|
||||
<font size = +2 color = "#FFFFFF"><b>]]..
|
||||
wx.wxVERSION_STRING..[[</b></font>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor = "#4747A1">
|
||||
<b>Estrela Editor</b><br>
|
||||
<b><font color='#ffffff'>Copyright © 2008-2011 Luxinia DevTeam</font></b>
|
||||
<p>
|
||||
<font size=-1>
|
||||
<table cellpadding = 0 cellspacing = 0 width = "100%">
|
||||
<tr>
|
||||
<td width = "65%">
|
||||
Christoph Kubisch<br>
|
||||
Eike Decker<p>
|
||||
</td>
|
||||
<td valign = top>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<font size = 1>
|
||||
Licenced under The MIT License.
|
||||
</font>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor = "#4747A1">
|
||||
<b>based on wxLua editor sample</b><br>
|
||||
<b>Copyright © 2002-2005 Lomtick Software</b>
|
||||
<p>
|
||||
<font size=-1>
|
||||
<table cellpadding = 0 cellspacing = 0 width = "100%">
|
||||
<tr>
|
||||
<td width = "65%">
|
||||
J. Winwood (luascript@thersgb.net)<br>
|
||||
John Labenski<p>
|
||||
</td>
|
||||
<td valign = top>
|
||||
<img src = "estrela/res/wxlualogo2.png">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<font size = 1>
|
||||
wxLua binding licenced under wxWindows Library Licence, Version 3.
|
||||
</font>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr></table>
|
||||
</body>
|
||||
</html>
|
||||
]]
|
||||
|
||||
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About Estrela Editor")
|
||||
|
||||
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(500, 270),
|
||||
wx.wxHW_SCROLLBAR_NEVER)
|
||||
local line = wx.wxStaticLine(dlg, wx.wxID_ANY)
|
||||
local button = wx.wxButton(dlg, wx.wxID_OK, "OK")
|
||||
|
||||
button:SetDefault()
|
||||
|
||||
html:SetBorders(0)
|
||||
html:SetPage(page)
|
||||
html:SetSize(html:GetInternalRepresentation():GetWidth(),
|
||||
html:GetInternalRepresentation():GetHeight())
|
||||
|
||||
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
|
||||
topsizer:Add(html, 1, wx.wxALL, 10)
|
||||
topsizer:Add(line, 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
|
||||
topsizer:Add(button, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
|
||||
|
||||
dlg:SetAutoLayout(true)
|
||||
dlg:SetSizer(topsizer)
|
||||
topsizer:Fit(dlg)
|
||||
|
||||
dlg:ShowModal()
|
||||
dlg:Destroy()
|
||||
end
|
||||
|
||||
frame:Connect(ID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, DisplayAbout)
|
||||
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Create the Help menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
|
||||
local helpMenu = wx.wxMenu{
|
||||
{ ID_ABOUT, "&About\tF1", "About Estrela Editor" },
|
||||
}
|
||||
menuBar:Append(helpMenu, "&Help")
|
||||
|
||||
local function DisplayAbout(event)
|
||||
local page = [[
|
||||
<html>
|
||||
<body bgcolor = "#ffffff" text='#ffffff'>
|
||||
<table border='0' width="100%">
|
||||
<tr><td><img src = "estrela/res/estrela.png"></center></td><td>
|
||||
<table cellspacing = 4 cellpadding = 4 width = "400">
|
||||
<tr>
|
||||
<td bgcolor = "#010156">
|
||||
<center>
|
||||
<font size = +2 color = "#FFFFFF"><br><b>]]..
|
||||
wxlua.wxLUA_VERSION_STRING..[[</b></font>
|
||||
<font size = +1 color = "#FFFFFF">built with</font>
|
||||
<font size = +2 color = "#FFFFFF"><b>]]..
|
||||
wx.wxVERSION_STRING..[[</b></font>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor = "#4747A1">
|
||||
<b>Estrela Editor</b><br>
|
||||
<b><font color='#ffffff'>Copyright © 2008-2011 Luxinia DevTeam</font></b>
|
||||
<p>
|
||||
<font size=-1>
|
||||
<table cellpadding = 0 cellspacing = 0 width = "100%">
|
||||
<tr>
|
||||
<td width = "65%">
|
||||
Christoph Kubisch<br>
|
||||
Eike Decker<p>
|
||||
</td>
|
||||
<td valign = top>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<font size = 1>
|
||||
Licensed under The MIT License.
|
||||
</font>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor = "#4747A1">
|
||||
<b>based on wxLua editor sample</b><br>
|
||||
<b>Copyright © 2002-2005 Lomtick Software</b>
|
||||
<p>
|
||||
<font size=-1>
|
||||
<table cellpadding = 0 cellspacing = 0 width = "100%">
|
||||
<tr>
|
||||
<td width = "65%">
|
||||
J. Winwood (luascript@thersgb.net)<br>
|
||||
John Labenski<p>
|
||||
</td>
|
||||
<td valign = top>
|
||||
<img src = "estrela/res/wxlualogo2.png">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<font size = 1>
|
||||
wxLua binding licensed under wxWindows Library License, Version 3.
|
||||
</font>
|
||||
</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr></table>
|
||||
</body>
|
||||
</html>
|
||||
]]
|
||||
|
||||
local dlg = wx.wxDialog(frame, wx.wxID_ANY, "About Estrela Editor")
|
||||
|
||||
local html = wx.wxLuaHtmlWindow(dlg, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxSize(500, 270),
|
||||
wx.wxHW_SCROLLBAR_NEVER)
|
||||
local line = wx.wxStaticLine(dlg, wx.wxID_ANY)
|
||||
local button = wx.wxButton(dlg, wx.wxID_OK, "OK")
|
||||
|
||||
button:SetDefault()
|
||||
|
||||
html:SetBorders(0)
|
||||
html:SetPage(page)
|
||||
html:SetSize(html:GetInternalRepresentation():GetWidth(),
|
||||
html:GetInternalRepresentation():GetHeight())
|
||||
|
||||
local topsizer = wx.wxBoxSizer(wx.wxVERTICAL)
|
||||
topsizer:Add(html, 1, wx.wxALL, 10)
|
||||
topsizer:Add(line, 0, wx.wxEXPAND + wx.wxLEFT + wx.wxRIGHT, 10)
|
||||
topsizer:Add(button, 0, wx.wxALL + wx.wxALIGN_RIGHT, 10)
|
||||
|
||||
dlg:SetAutoLayout(true)
|
||||
dlg:SetSizer(topsizer)
|
||||
topsizer:Fit(dlg)
|
||||
|
||||
dlg:ShowModal()
|
||||
dlg:Destroy()
|
||||
end
|
||||
|
||||
frame:Connect(ID_ABOUT, wx.wxEVT_COMMAND_MENU_SELECTED, DisplayAbout)
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
Estrela Editor
|
||||
-----------------
|
||||
Estrela Editor is a wxLua based IDE. It supports multiple
|
||||
fileformats, "api" for autocompletion and tooltips, and custom
|
||||
commandline tools. Focus is extensibility for target applications
|
||||
using Lua. Its main purpose is as IDE for the 3D engine "Luxinia".
|
||||
|
||||
|
||||
|
||||
Commandline:
|
||||
------------
|
||||
|
||||
Open File(s):
|
||||
<exe> <filename> [<filename>...]
|
||||
any non-option will be treated as filename
|
||||
|
||||
Overriding Config:
|
||||
<exe> [...] -cfg "<luacode overriding config>" [...]
|
||||
e.g.: estrela.exe -cfg "singleinstance=false;" somefile.lua
|
||||
|
||||
Estrela Editor
|
||||
-----------------
|
||||
Estrela Editor is a wxLua based IDE. It supports multiple
|
||||
fileformats, "api" for autocompletion and tooltips, and custom
|
||||
commandline tools. Focus is extensibility for target applications
|
||||
using Lua. Its main purpose is as IDE for the 3D engine "Luxinia".
|
||||
|
||||
|
||||
|
||||
Commandline:
|
||||
------------
|
||||
|
||||
Open File(s):
|
||||
<exe> <filename> [<filename>...]
|
||||
any non-option will be treated as filename
|
||||
|
||||
Overriding Config:
|
||||
<exe> [...] -cfg "<luacode overriding config>" [...]
|
||||
e.g.: estrela.exe -cfg "singleinstance=false;" somefile.lua
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
icon ICON "../res/estrela.ico"
|
||||
icon ICON "../res/estrela.ico"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@@ -1,132 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="204.22055"
|
||||
height="96.006279"
|
||||
id="svg3513"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46+devel"
|
||||
version="1.0"
|
||||
inkscape:export-filename="D:\dev\c\tools\wxide\res\wxlualogo2.png"
|
||||
inkscape:export-xdpi="59.996075"
|
||||
inkscape:export-ydpi="59.996075"
|
||||
sodipodi:docname="wxlogo.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs3515">
|
||||
<linearGradient
|
||||
id="linearGradient3538">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3540" />
|
||||
<stop
|
||||
style="stop-color:#e3e3eb;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3542" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3521" />
|
||||
<inkscape:perspective
|
||||
id="perspective3530"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3538"
|
||||
id="linearGradient3544"
|
||||
x1="88.214287"
|
||||
y1="0.2142856"
|
||||
x2="88.214287"
|
||||
y2="81.130592"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter4057"
|
||||
x="-0.044305418"
|
||||
width="1.0886108"
|
||||
y="-0.10071105"
|
||||
height="1.2014221">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="2.2929748"
|
||||
id="feGaussianBlur4059" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="98.55416"
|
||||
inkscape:cy="58.784487"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:window-height="719"
|
||||
inkscape:window-x="-4"
|
||||
inkscape:window-y="-4" />
|
||||
<metadata
|
||||
id="metadata3518">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-102.354,-435.00191)">
|
||||
<rect
|
||||
ry="12.142858"
|
||||
y="-1.9285716"
|
||||
x="-5"
|
||||
height="85"
|
||||
width="193.21428"
|
||||
id="rect3546"
|
||||
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4057)"
|
||||
transform="translate(112.85714,442.43362)" />
|
||||
<rect
|
||||
style="opacity:1;fill:url(#linearGradient3544);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="rect3536"
|
||||
width="193.21428"
|
||||
height="85"
|
||||
x="-5"
|
||||
y="-1.9285716"
|
||||
transform="translate(112.85714,442.43362)"
|
||||
ry="12.142858" />
|
||||
<image
|
||||
y="442.43362"
|
||||
x="112.85714"
|
||||
id="image3532"
|
||||
height="77"
|
||||
width="180"
|
||||
sodipodi:absref="D:\dev\c\tools\wxide\res\wxlualogo.png"
|
||||
xlink:href="wxlualogo.png" />
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="204.22055"
|
||||
height="96.006279"
|
||||
id="svg3513"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46+devel"
|
||||
version="1.0"
|
||||
inkscape:export-filename="D:\dev\c\tools\wxide\res\wxlualogo2.png"
|
||||
inkscape:export-xdpi="59.996075"
|
||||
inkscape:export-ydpi="59.996075"
|
||||
sodipodi:docname="wxlogo.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs3515">
|
||||
<linearGradient
|
||||
id="linearGradient3538">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3540" />
|
||||
<stop
|
||||
style="stop-color:#e3e3eb;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3542" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3521" />
|
||||
<inkscape:perspective
|
||||
id="perspective3530"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3538"
|
||||
id="linearGradient3544"
|
||||
x1="88.214287"
|
||||
y1="0.2142856"
|
||||
x2="88.214287"
|
||||
y2="81.130592"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter4057"
|
||||
x="-0.044305418"
|
||||
width="1.0886108"
|
||||
y="-0.10071105"
|
||||
height="1.2014221">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="2.2929748"
|
||||
id="feGaussianBlur4059" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="98.55416"
|
||||
inkscape:cy="58.784487"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1024"
|
||||
inkscape:window-height="719"
|
||||
inkscape:window-x="-4"
|
||||
inkscape:window-y="-4" />
|
||||
<metadata
|
||||
id="metadata3518">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-102.354,-435.00191)">
|
||||
<rect
|
||||
ry="12.142858"
|
||||
y="-1.9285716"
|
||||
x="-5"
|
||||
height="85"
|
||||
width="193.21428"
|
||||
id="rect3546"
|
||||
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4057)"
|
||||
transform="translate(112.85714,442.43362)" />
|
||||
<rect
|
||||
style="opacity:1;fill:url(#linearGradient3544);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="rect3536"
|
||||
width="193.21428"
|
||||
height="85"
|
||||
x="-5"
|
||||
y="-1.9285716"
|
||||
transform="translate(112.85714,442.43362)"
|
||||
ry="12.142858" />
|
||||
<image
|
||||
y="442.43362"
|
||||
x="112.85714"
|
||||
id="image3532"
|
||||
height="77"
|
||||
width="180"
|
||||
sodipodi:absref="D:\dev\c\tools\wxide\res\wxlualogo.png"
|
||||
xlink:href="wxlualogo.png" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 3.9 KiB |
@@ -1,236 +1,236 @@
|
||||
// this is an extremly ugly quick and dirty hack...
|
||||
// maybe it could be refactored to do some error catching and
|
||||
// other things, but right now it does what it should...
|
||||
// (providing a single exe file in our main directory without
|
||||
// polluting it with all these dlls located in the /bin folder)
|
||||
|
||||
#ifdef __MINGW__ /* not sure if this is the *official* define */
|
||||
#define _WIN32_WINNT 0x0502
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* some typedef functions - these are not matching exactly the
|
||||
original definitions, but their signature is supposed to be
|
||||
compatible
|
||||
Currently 10 different functions are needed - each with different signatures... */
|
||||
typedef void *voidfunc ();
|
||||
typedef int *varfunc (void *L,...); // quick and dirty using the varargs
|
||||
typedef void varfuncvoid (void *L,...);
|
||||
|
||||
// from lua.h
|
||||
#define LUA_GLOBALSINDEX (-10002)
|
||||
|
||||
|
||||
static voidfunc *luaL_newstate;
|
||||
static varfunc *luaL_loadbuffer;
|
||||
static varfunc *luaL_openlibs;
|
||||
static varfunc *lua_pcall;
|
||||
static varfunc *lua_pushcclosure;
|
||||
static varfunc *lua_setfield;
|
||||
static varfunc *lua_tolstring;
|
||||
static varfuncvoid *lua_createtable;
|
||||
static varfuncvoid *lua_pushstring;
|
||||
static varfuncvoid *lua_rawseti;
|
||||
|
||||
static int luafunc_mbox (void *L)
|
||||
{
|
||||
const char *title = (const char*)lua_tolstring(L,1,NULL);
|
||||
const char *msg = (const char*)lua_tolstring(L,2,NULL);
|
||||
MessageBox(NULL,msg,title,MB_OK|MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *luacode =
|
||||
"local msg = _ERRMSG; _ERRMSG = nil "
|
||||
"local arg = _ARG or {}; _ARG = nil "
|
||||
"xpcall("
|
||||
"function() "
|
||||
"(loadfile 'src/main.lua')(unpack(arg)) end,"
|
||||
"function(err) msg('Uncaught lua script exception',debug.traceback(err)) end)"
|
||||
;
|
||||
|
||||
#if defined(_WIN32) && defined (_MSC_VER)
|
||||
|
||||
PCHAR* CommandLineToArgvA(PCHAR CmdLine,int* _argc)
|
||||
{
|
||||
PCHAR* argv;
|
||||
PCHAR _argv;
|
||||
size_t len;
|
||||
ULONG argc;
|
||||
CHAR a;
|
||||
size_t i, j;
|
||||
|
||||
BOOLEAN in_QM;
|
||||
BOOLEAN in_TEXT;
|
||||
BOOLEAN in_SPACE;
|
||||
|
||||
len = strlen(CmdLine);
|
||||
i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);
|
||||
|
||||
argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
|
||||
i + (len+2)*sizeof(CHAR));
|
||||
|
||||
_argv = (PCHAR)(((PUCHAR)argv)+i);
|
||||
|
||||
argc = 0;
|
||||
argv[argc] = _argv;
|
||||
in_QM = 0;
|
||||
in_TEXT = 0;
|
||||
in_SPACE = 1;
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
while( a = CmdLine[i] ) {
|
||||
if(in_QM) {
|
||||
if(a == '\"') {
|
||||
in_QM = 0;
|
||||
} else {
|
||||
_argv[j] = a;
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
switch(a) {
|
||||
case '\"':
|
||||
in_QM = 1;
|
||||
in_TEXT = 1;
|
||||
if(in_SPACE) {
|
||||
argv[argc] = _argv+j;
|
||||
argc++;
|
||||
}
|
||||
in_SPACE = 0;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
if(in_TEXT) {
|
||||
_argv[j] = '\0';
|
||||
j++;
|
||||
}
|
||||
in_TEXT = 0;
|
||||
in_SPACE = 1;
|
||||
break;
|
||||
default:
|
||||
in_TEXT = 1;
|
||||
if(in_SPACE) {
|
||||
argv[argc] = _argv+j;
|
||||
argc++;
|
||||
}
|
||||
_argv[j] = a;
|
||||
j++;
|
||||
in_SPACE = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
_argv[j] = '\0';
|
||||
argv[argc] = NULL;
|
||||
|
||||
(*_argc) = argc;
|
||||
return argv;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
int argc;
|
||||
char ** argv = CommandLineToArgvA(GetCommandLineA(),&argc);
|
||||
|
||||
#else
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
#endif
|
||||
HINSTANCE hinstLib;
|
||||
|
||||
|
||||
char buffer[MAX_PATH],*file;
|
||||
|
||||
if (!GetFullPathName(argv[0],MAX_PATH,buffer,&file)) {
|
||||
MessageBox(NULL,
|
||||
TEXT("Couldn't find the correct working directory"),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
if (file!=NULL)
|
||||
*file = 0; // finish the string, I don't need the appname
|
||||
//int i;
|
||||
//for (i=0;i<argc; i++)
|
||||
// printf("%d %s\n",i,argv[i]);
|
||||
|
||||
SetCurrentDirectory(buffer);
|
||||
|
||||
|
||||
SetDllDirectory(".\\bin\\");
|
||||
hinstLib = LoadLibrary("lua5.1.dll");
|
||||
if (hinstLib != NULL)
|
||||
{
|
||||
luaL_newstate = (voidfunc*) GetProcAddress(hinstLib, "luaL_newstate");
|
||||
luaL_loadbuffer = (varfunc*) GetProcAddress(hinstLib, "luaL_loadbuffer");
|
||||
luaL_openlibs = (varfunc*) GetProcAddress(hinstLib, "luaL_openlibs");
|
||||
lua_pcall = (varfunc*)GetProcAddress(hinstLib, "lua_pcall");
|
||||
lua_tolstring = (varfunc*)GetProcAddress(hinstLib, "lua_tolstring");
|
||||
lua_setfield = (varfunc*)GetProcAddress(hinstLib, "lua_setfield");
|
||||
lua_pushcclosure = (varfunc*)GetProcAddress(hinstLib, "lua_pushcclosure");
|
||||
lua_createtable = (varfuncvoid*)GetProcAddress(hinstLib, "lua_createtable");
|
||||
lua_pushstring = (varfuncvoid*)GetProcAddress(hinstLib, "lua_pushstring");
|
||||
lua_rawseti = (varfuncvoid*)GetProcAddress(hinstLib, "lua_rawseti");
|
||||
// If the function address is valid, call the function.
|
||||
|
||||
if (luaL_newstate && luaL_loadbuffer && luaL_openlibs && lua_pcall &&
|
||||
lua_pushcclosure && lua_setfield && lua_tolstring &&
|
||||
lua_createtable && lua_pushstring && lua_rawseti)
|
||||
{
|
||||
// OK, I don't do any error checking here, which COULD
|
||||
// lead to bugs that are hard to find, but considered the simplicity
|
||||
// of the whole process, it SHOULD be pretty unlikely to fail here
|
||||
// but don't come back on me if it does...
|
||||
void *L = luaL_newstate();
|
||||
int i;
|
||||
|
||||
if (L!=NULL) {
|
||||
lua_createtable(L,argc,0);
|
||||
for (i=0;i<argc;i++) {
|
||||
lua_pushstring(L,argv[i]);
|
||||
lua_rawseti(L,-2,i+1);
|
||||
}
|
||||
lua_setfield(L,LUA_GLOBALSINDEX,"_ARG");
|
||||
luaL_openlibs(L);
|
||||
lua_pushcclosure(L,luafunc_mbox,0);
|
||||
lua_setfield(L,LUA_GLOBALSINDEX,"_ERRMSG");
|
||||
if (luaL_loadbuffer(L,luacode,strlen(luacode),"Initializer") == 0)
|
||||
lua_pcall(L,0,0,0);
|
||||
else
|
||||
MessageBox(NULL,
|
||||
TEXT("An unexpected error occured while loading the lua chunk."),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
} else
|
||||
MessageBox(NULL,
|
||||
TEXT("Couldn't initialize a luastate"),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
} else {
|
||||
MessageBox(NULL,
|
||||
TEXT("Could not load all functions that are supposed to be located in the lua5.1.dll\n"
|
||||
"This is not supposed to be happening..."),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
}
|
||||
|
||||
// Free the DLL module.
|
||||
FreeLibrary(hinstLib);
|
||||
} else {
|
||||
MessageBox(NULL,
|
||||
TEXT("The lua5.1.dll could not be found or loaded, please check the working directory of the application.\n"),
|
||||
TEXT("Failed to initialize estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
// this is an extremly ugly quick and dirty hack...
|
||||
// maybe it could be refactored to do some error catching and
|
||||
// other things, but right now it does what it should...
|
||||
// (providing a single exe file in our main directory without
|
||||
// polluting it with all these dlls located in the /bin folder)
|
||||
|
||||
#ifdef __MINGW__ /* not sure if this is the *official* define */
|
||||
#define _WIN32_WINNT 0x0502
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* some typedef functions - these are not matching exactly the
|
||||
original definitions, but their signature is supposed to be
|
||||
compatible
|
||||
Currently 10 different functions are needed - each with different signatures... */
|
||||
typedef void *voidfunc ();
|
||||
typedef int *varfunc (void *L,...); // quick and dirty using the varargs
|
||||
typedef void varfuncvoid (void *L,...);
|
||||
|
||||
// from lua.h
|
||||
#define LUA_GLOBALSINDEX (-10002)
|
||||
|
||||
|
||||
static voidfunc *luaL_newstate;
|
||||
static varfunc *luaL_loadbuffer;
|
||||
static varfunc *luaL_openlibs;
|
||||
static varfunc *lua_pcall;
|
||||
static varfunc *lua_pushcclosure;
|
||||
static varfunc *lua_setfield;
|
||||
static varfunc *lua_tolstring;
|
||||
static varfuncvoid *lua_createtable;
|
||||
static varfuncvoid *lua_pushstring;
|
||||
static varfuncvoid *lua_rawseti;
|
||||
|
||||
static int luafunc_mbox (void *L)
|
||||
{
|
||||
const char *title = (const char*)lua_tolstring(L,1,NULL);
|
||||
const char *msg = (const char*)lua_tolstring(L,2,NULL);
|
||||
MessageBox(NULL,msg,title,MB_OK|MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *luacode =
|
||||
"local msg = _ERRMSG; _ERRMSG = nil "
|
||||
"local arg = _ARG or {}; _ARG = nil "
|
||||
"xpcall("
|
||||
"function() "
|
||||
"(loadfile 'src/main.lua')(unpack(arg)) end,"
|
||||
"function(err) msg('Uncaught lua script exception',debug.traceback(err)) end)"
|
||||
;
|
||||
|
||||
#if defined(_WIN32) && defined (_MSC_VER)
|
||||
|
||||
PCHAR* CommandLineToArgvA(PCHAR CmdLine,int* _argc)
|
||||
{
|
||||
PCHAR* argv;
|
||||
PCHAR _argv;
|
||||
size_t len;
|
||||
ULONG argc;
|
||||
CHAR a;
|
||||
size_t i, j;
|
||||
|
||||
BOOLEAN in_QM;
|
||||
BOOLEAN in_TEXT;
|
||||
BOOLEAN in_SPACE;
|
||||
|
||||
len = strlen(CmdLine);
|
||||
i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID);
|
||||
|
||||
argv = (PCHAR*)GlobalAlloc(GMEM_FIXED,
|
||||
i + (len+2)*sizeof(CHAR));
|
||||
|
||||
_argv = (PCHAR)(((PUCHAR)argv)+i);
|
||||
|
||||
argc = 0;
|
||||
argv[argc] = _argv;
|
||||
in_QM = 0;
|
||||
in_TEXT = 0;
|
||||
in_SPACE = 1;
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
while( a = CmdLine[i] ) {
|
||||
if(in_QM) {
|
||||
if(a == '\"') {
|
||||
in_QM = 0;
|
||||
} else {
|
||||
_argv[j] = a;
|
||||
j++;
|
||||
}
|
||||
} else {
|
||||
switch(a) {
|
||||
case '\"':
|
||||
in_QM = 1;
|
||||
in_TEXT = 1;
|
||||
if(in_SPACE) {
|
||||
argv[argc] = _argv+j;
|
||||
argc++;
|
||||
}
|
||||
in_SPACE = 0;
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
if(in_TEXT) {
|
||||
_argv[j] = '\0';
|
||||
j++;
|
||||
}
|
||||
in_TEXT = 0;
|
||||
in_SPACE = 1;
|
||||
break;
|
||||
default:
|
||||
in_TEXT = 1;
|
||||
if(in_SPACE) {
|
||||
argv[argc] = _argv+j;
|
||||
argc++;
|
||||
}
|
||||
_argv[j] = a;
|
||||
j++;
|
||||
in_SPACE = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
_argv[j] = '\0';
|
||||
argv[argc] = NULL;
|
||||
|
||||
(*_argc) = argc;
|
||||
return argv;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
int argc;
|
||||
char ** argv = CommandLineToArgvA(GetCommandLineA(),&argc);
|
||||
|
||||
#else
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
#endif
|
||||
HINSTANCE hinstLib;
|
||||
|
||||
|
||||
char buffer[MAX_PATH],*file;
|
||||
|
||||
if (!GetFullPathName(argv[0],MAX_PATH,buffer,&file)) {
|
||||
MessageBox(NULL,
|
||||
TEXT("Couldn't find the correct working directory"),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
if (file!=NULL)
|
||||
*file = 0; // finish the string, I don't need the appname
|
||||
//int i;
|
||||
//for (i=0;i<argc; i++)
|
||||
// printf("%d %s\n",i,argv[i]);
|
||||
|
||||
SetCurrentDirectory(buffer);
|
||||
|
||||
|
||||
SetDllDirectory(".\\bin\\");
|
||||
hinstLib = LoadLibrary("lua5.1.dll");
|
||||
if (hinstLib != NULL)
|
||||
{
|
||||
luaL_newstate = (voidfunc*) GetProcAddress(hinstLib, "luaL_newstate");
|
||||
luaL_loadbuffer = (varfunc*) GetProcAddress(hinstLib, "luaL_loadbuffer");
|
||||
luaL_openlibs = (varfunc*) GetProcAddress(hinstLib, "luaL_openlibs");
|
||||
lua_pcall = (varfunc*)GetProcAddress(hinstLib, "lua_pcall");
|
||||
lua_tolstring = (varfunc*)GetProcAddress(hinstLib, "lua_tolstring");
|
||||
lua_setfield = (varfunc*)GetProcAddress(hinstLib, "lua_setfield");
|
||||
lua_pushcclosure = (varfunc*)GetProcAddress(hinstLib, "lua_pushcclosure");
|
||||
lua_createtable = (varfuncvoid*)GetProcAddress(hinstLib, "lua_createtable");
|
||||
lua_pushstring = (varfuncvoid*)GetProcAddress(hinstLib, "lua_pushstring");
|
||||
lua_rawseti = (varfuncvoid*)GetProcAddress(hinstLib, "lua_rawseti");
|
||||
// If the function address is valid, call the function.
|
||||
|
||||
if (luaL_newstate && luaL_loadbuffer && luaL_openlibs && lua_pcall &&
|
||||
lua_pushcclosure && lua_setfield && lua_tolstring &&
|
||||
lua_createtable && lua_pushstring && lua_rawseti)
|
||||
{
|
||||
// OK, I don't do any error checking here, which COULD
|
||||
// lead to bugs that are hard to find, but considered the simplicity
|
||||
// of the whole process, it SHOULD be pretty unlikely to fail here
|
||||
// but don't come back on me if it does...
|
||||
void *L = luaL_newstate();
|
||||
int i;
|
||||
|
||||
if (L!=NULL) {
|
||||
lua_createtable(L,argc,0);
|
||||
for (i=0;i<argc;i++) {
|
||||
lua_pushstring(L,argv[i]);
|
||||
lua_rawseti(L,-2,i+1);
|
||||
}
|
||||
lua_setfield(L,LUA_GLOBALSINDEX,"_ARG");
|
||||
luaL_openlibs(L);
|
||||
lua_pushcclosure(L,luafunc_mbox,0);
|
||||
lua_setfield(L,LUA_GLOBALSINDEX,"_ERRMSG");
|
||||
if (luaL_loadbuffer(L,luacode,strlen(luacode),"Initializer") == 0)
|
||||
lua_pcall(L,0,0,0);
|
||||
else
|
||||
MessageBox(NULL,
|
||||
TEXT("An unexpected error occured while loading the lua chunk."),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
} else
|
||||
MessageBox(NULL,
|
||||
TEXT("Couldn't initialize a luastate"),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
} else {
|
||||
MessageBox(NULL,
|
||||
TEXT("Could not load all functions that are supposed to be located in the lua5.1.dll\n"
|
||||
"This is not supposed to be happening..."),
|
||||
TEXT("Failed to start estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
}
|
||||
|
||||
// Free the DLL module.
|
||||
FreeLibrary(hinstLib);
|
||||
} else {
|
||||
MessageBox(NULL,
|
||||
TEXT("The lua5.1.dll could not be found or loaded, please check the working directory of the application.\n"),
|
||||
TEXT("Failed to initialize estrela"),
|
||||
MB_OK|MB_ICONERROR);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor
|
||||
@@ -1,12 +1,12 @@
|
||||
return {
|
||||
name = "Estrela Editor",
|
||||
description = "Estrela Editor as run target (IDE development)",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename)
|
||||
local cmd = ide.editorFilename and '"'..ide.editorFilename..'" '..(wfilename and wfilename:GetFullPath() or "")..' -cfg "singleinstance=false;"' or nil
|
||||
CommandLineRun(cmd,nil,false,true)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
}
|
||||
return {
|
||||
name = "Estrela Editor",
|
||||
description = "Estrela Editor as run target (IDE development)",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename)
|
||||
local cmd = ide.editorFilename and '"'..ide.editorFilename..'" '..(wfilename and wfilename:GetFullPath() or "")..' -cfg "singleinstance=false;"' or nil
|
||||
CommandLineRun(cmd,nil,false,true)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
}
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
return {
|
||||
name = "Estrela Shell",
|
||||
description = "Estrela Lua Shell",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename)
|
||||
-- set shellbox for focus
|
||||
local bottomnotebook = ide.frame.vsplitter.splitter.bottomnotebook
|
||||
bottomnotebook:SetSelection(1)
|
||||
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
|
||||
local shellLog = bottomnotebook.shellbox.output
|
||||
shellLog:SetReadOnly(false)
|
||||
shellLog:ClearAll()
|
||||
shellLog:SetReadOnly(true)
|
||||
end
|
||||
|
||||
ShellExecuteCode(nil,wfilename)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
}
|
||||
return {
|
||||
name = "Estrela Shell",
|
||||
description = "Estrela Lua Shell",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename)
|
||||
-- set shellbox for focus
|
||||
local bottomnotebook = ide.frame.bottomnotebook
|
||||
bottomnotebook:SetSelection(1)
|
||||
|
||||
ShellExecuteFile(wfilename)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
}
|
||||
|
||||
27
interpreters/love2d.lua
Normal file
27
interpreters/love2d.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
return {
|
||||
name = "Love2d",
|
||||
description = "Love2d game engine",
|
||||
api = {"baselib", "love2d"},
|
||||
frun = function(self,wfilename,rundebug)
|
||||
if rundebug then DebuggerAttachDefault() end
|
||||
local love2d = ide.config.path.love2d
|
||||
or wx.wxFileName(self:fprojdir(wfilename)):GetPath(wx.wxPATH_GET_VOLUME)
|
||||
.. '/love'
|
||||
local cmd = string.gsub(love2d, "\\","/") .. ' "' .. self:fprojdir(wfilename) .. '"'
|
||||
.. (rundebug and ' -debug' or '')
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
fworkdir = function (self,wfilename)
|
||||
return ide.config.path.projectdir
|
||||
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self)
|
||||
DebuggerAttachDefault()
|
||||
end,
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
return {
|
||||
name = "Lua",
|
||||
description = "Commandline Lua interpreter",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename,script)
|
||||
local mainpath = ide.editorFilename:gsub("[^/\\]+$","")
|
||||
local filepath = wfilename:GetFullPath()
|
||||
if not script then script = ([[dofile '%s']]):format(filepath:gsub("\\","/")) end
|
||||
local code = ([[xpcall(function() %s end,function(err) print(debug.traceback(err)) end)]]):format(script)
|
||||
local cmd = '"'..mainpath..'/bin/lua.exe" -e "'..code..'"'
|
||||
CommandLineRun(cmd,self:fworkdir(wfilename),true,false)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return ide.config.path.projectdir
|
||||
end,
|
||||
fworkdir = function (self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
}
|
||||
36
interpreters/luadeb.lua
Normal file
36
interpreters/luadeb.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
return {
|
||||
name = "Lua with Debugger",
|
||||
description = "Lua interpreter with debugger",
|
||||
api = {"wxwidgets","baselib"},
|
||||
frun = function(self,wfilename,rundebug)
|
||||
local mainpath = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
|
||||
local filepath = string.gsub(wfilename:GetFullPath(), "\\","/")
|
||||
local script
|
||||
if rundebug then
|
||||
DebuggerAttachDefault()
|
||||
script = (
|
||||
"package.path=package.path..';"..mainpath.."lualibs/?/?.lua;"..mainpath.."lualibs/?.lua';"..
|
||||
"package.cpath=package.cpath..';"..mainpath.."bin/clibs/?.dll';"..
|
||||
rundebug
|
||||
)
|
||||
else
|
||||
script = ([[dofile '%s']]):format(filepath)
|
||||
end
|
||||
local code = ([[xpcall(function() io.stdout:setvbuf('no'); %s end,function(err) print(debug.traceback(err)) end)]]):format(script)
|
||||
local cmd = '"'..mainpath..'bin/lua" -e "'..code..'"'
|
||||
-- CommandLineRun(cmd,wdir,tooutput,nohide,stringcallback,uid,endcallback)
|
||||
return CommandLineRun(cmd,self:fworkdir(wfilename),true,false,nil,nil,
|
||||
function() ide.debugger.pid = nil end)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
fworkdir = function (self,wfilename)
|
||||
return ide.config.path.projectdir
|
||||
or wfilename:GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
fattachdebug = function(self)
|
||||
DebuggerAttachDefault()
|
||||
end,
|
||||
}
|
||||
@@ -1,27 +1,33 @@
|
||||
return {
|
||||
name = "Luxinia",
|
||||
description = "Luxinia project",
|
||||
api = {"luxiniaapi","baselib"},
|
||||
fcmdline = function(self,wfilename)
|
||||
local projdir = ide.config.path.projectdir
|
||||
local endstr = projdir and projdir:len()>0
|
||||
and " -p "..projdir or ""
|
||||
|
||||
local fname = wfilename:GetFullName()
|
||||
endstr = endstr..(fname and (" -t "..fname) or "")
|
||||
|
||||
local cmd = ide.config.path.luxinia..'luxinia.exe --nologo'..endstr
|
||||
CommandLineRun(cmd,ide.config.path.luxinia,true,true)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
local path = GetPathWithSep(wfilename)
|
||||
fname = wx.wxFileName(path)
|
||||
|
||||
while ((not wx.wxFileExists(path.."main.lua")) and (fname:GetDirCount() > 0)) do
|
||||
fname:RemoveDir(fname:GetDirCount()-1)
|
||||
path = GetPathWithSep(fname)
|
||||
end
|
||||
|
||||
return path:sub(0,-2)
|
||||
end,
|
||||
}
|
||||
if (not(ide.config.path.luxinia and
|
||||
wx.wxFileExists(ide.config.path.luxinia..'luxinia.exe'))) then
|
||||
return
|
||||
end
|
||||
|
||||
return {
|
||||
name = "Luxinia",
|
||||
description = "Luxinia project",
|
||||
api = {"luxiniaapi","baselib"},
|
||||
frun = function(self,wfilename,withdebug)
|
||||
local projdir = ide.config.path.projectdir
|
||||
local endstr = (projdir and projdir:len()>0
|
||||
and " -p "..projdir or "")
|
||||
|
||||
local fname = wfilename:GetFullName()
|
||||
endstr = endstr..(fname and (" -t "..fname) or "")
|
||||
|
||||
local cmd = 'luxinia.exe --nologo'..endstr
|
||||
CommandLineRun(cmd,ide.config.path.luxinia,true,true)
|
||||
end,
|
||||
fuid = function(self,wfilename) return "luxinia "..(ide.config.path.projectdir or "") end,
|
||||
fprojdir = function(self,wfilename)
|
||||
local path = GetPathWithSep(wfilename)
|
||||
fname = wx.wxFileName(path)
|
||||
|
||||
while ((not wx.wxFileExists(path.."main.lua")) and (fname:GetDirCount() > 0)) do
|
||||
fname:RemoveDir(fname:GetDirCount()-1)
|
||||
path = GetPathWithSep(fname)
|
||||
end
|
||||
|
||||
return path:sub(0,-2)
|
||||
end,
|
||||
}
|
||||
|
||||
@@ -1,60 +1,97 @@
|
||||
if (not(ide.config.path.luxinia2 and
|
||||
wx.wxFileExists(ide.config.path.luxinia2..'luajit.exe'))) then
|
||||
return
|
||||
end
|
||||
|
||||
return {
|
||||
name = "Luxinia2",
|
||||
description = "Luxinia2",
|
||||
api = {"baselib","cg30","cggl30","glfw3","glewgl","assimp20","luxmath","luxgfx","luxscene","luajit2",},
|
||||
|
||||
finitclient = function(self)
|
||||
if (not CommandLineRunning(self:fuid(wfilename))) then return end
|
||||
local init = dofile(ide.config.path.luxinia2.."/../comserver/client.lua")
|
||||
local fenv = {}
|
||||
setmetatable(fenv,{__index = _G})
|
||||
fenv.print = function(...) DisplayOutput(...); DisplayOutput("\n"); end
|
||||
|
||||
setfenv(init,fenv)
|
||||
local client = init()
|
||||
|
||||
self.fclient = client
|
||||
return client
|
||||
end,
|
||||
|
||||
frun = function(self,wfilename)
|
||||
local luxdir = ide.config.path.luxinia2
|
||||
local projdir = ide.config.path.projectdir
|
||||
assert(projdir and projdir:len()>0,"no project directory")
|
||||
local args = " -e "..projdir.."/main.lua"
|
||||
|
||||
if (CommandLineRunning(self:fuid(wfilename))) then
|
||||
if (not self.fclient) then
|
||||
self:finitclient()
|
||||
end
|
||||
-- try to communicate with server
|
||||
self.fclient("dofile([["..wfilename:GetFullPath().."]])")
|
||||
return
|
||||
end
|
||||
|
||||
self.fclient = nil
|
||||
local fname = wfilename:GetFullName()
|
||||
args = args..(fname and (" -f "..fname) or "")
|
||||
local jitargs = ide.config.luxinia2jitargs
|
||||
jitargs = jitargs or ""
|
||||
local cmd = luxdir..'/luajit.exe '..jitargs..' ../main.lua -s'..args
|
||||
|
||||
if(CommandLineRun(cmd,ide.config.path.luxinia2,true,true,nil,self:fuid(wfilename),
|
||||
function() ShellSupportRemote(nil) end)) then return end
|
||||
|
||||
local client = self:finitclient()
|
||||
ShellSupportRemote(client,self:fuid(wfilename))
|
||||
end,
|
||||
fuid = function(self,wfilename) return "luxinia2 "..(ide.config.path.projectdir or "") end,
|
||||
fprojdir = function(self,wfilename)
|
||||
local path = GetPathWithSep(wfilename)
|
||||
filepath = wx.wxFileName(path)
|
||||
|
||||
while ((not wx.wxFileExists(path.."main.lua")) and (filepath:GetDirCount() > 0)) do
|
||||
filepath:RemoveDir(filepath:GetDirCount()-1)
|
||||
path = GetPathWithSep(filepath)
|
||||
end
|
||||
|
||||
return path:sub(0,-2)
|
||||
end,
|
||||
}
|
||||
name = "Luxinia2",
|
||||
description = "Luxinia2",
|
||||
api = {"baselib","cg30","cggl30","glfw","glewgl","assimp20","luxmath","luxgfx","luxscene","luajit2",},
|
||||
|
||||
finitclient = function(self)
|
||||
if (not CommandLineRunning(self:fuid(wfilename))) then return end
|
||||
local init = dofile(ide.config.path.luxinia2.."/../comserver/client.lua")
|
||||
local fenv = {}
|
||||
setmetatable(fenv,{__index = _G})
|
||||
fenv.print = function(...) DisplayOutput(...); DisplayOutput("\n"); end
|
||||
|
||||
setfenv(init,fenv)
|
||||
local client = init()
|
||||
|
||||
self.fclient = client
|
||||
return client
|
||||
end,
|
||||
|
||||
frun = function(self,wfilename,rundebug)
|
||||
local luxdir = ide.config.path.luxinia2
|
||||
local projdir = ide.config.path.projectdir
|
||||
assert(projdir and projdir:len()>0,"no project directory")
|
||||
local basedir = luxdir
|
||||
local startfile = projdir.."/main.lua"
|
||||
local startargs = " -e "..startfile
|
||||
|
||||
if (CommandLineRunning(self:fuid(wfilename))) then
|
||||
if (not self.fclient) then
|
||||
self:finitclient()
|
||||
end
|
||||
-- try to communicate with server
|
||||
self.fclient("dofile([["..wfilename:GetFullPath().."]])")
|
||||
return
|
||||
end
|
||||
|
||||
self.fclient = nil
|
||||
local fname = wfilename:GetFullName()
|
||||
local args = (fname and (" -f "..fname) or "")
|
||||
|
||||
if rundebug then
|
||||
DebuggerAttachDefault({
|
||||
basedir=basedir,
|
||||
startfile=startfile,
|
||||
run=true, noshell=true,}
|
||||
)
|
||||
local editorDir = string.gsub(ide.editorFilename:gsub("[^/\\]+$",""),"\\","/")
|
||||
script = ""..
|
||||
"package.path=package.path..';"..editorDir.."lualibs/?/?.lua';"..
|
||||
"io.stdout:setvbuf('no'); require('mobdebug').start('" .. ide.debugger.hostname.."',"..ide.debugger.portnumber..")"
|
||||
|
||||
args = args..' -es "'..script..'"'..startargs
|
||||
else
|
||||
args = " -s "..args..startargs
|
||||
end
|
||||
|
||||
local jitargs = ide.config.luxinia2jitargs
|
||||
jitargs = jitargs or ""
|
||||
local cmd = 'luajit.exe '..jitargs..' ../main.lua '..args
|
||||
|
||||
|
||||
local pid = CommandLineRun(cmd,ide.config.path.luxinia2,true,true,nil,self:fuid(wfilename),
|
||||
function()
|
||||
ShellSupportRemote(nil)
|
||||
if (rundebug) then
|
||||
DebuggerStop()
|
||||
end
|
||||
end)
|
||||
|
||||
if(not pid) then return end
|
||||
|
||||
if not rundebug then
|
||||
local client = self:finitclient()
|
||||
ShellSupportRemote(client,self:fuid(wfilename))
|
||||
end
|
||||
|
||||
return pid
|
||||
end,
|
||||
fuid = function(self,wfilename) return "luxinia2 "..(ide.config.path.projectdir or "") end,
|
||||
fprojdir = function(self,wfilename)
|
||||
local path = GetPathWithSep(wfilename)
|
||||
filepath = wx.wxFileName(path)
|
||||
|
||||
while ((not wx.wxFileExists(path.."main.lua")) and (filepath:GetDirCount() > 0)) do
|
||||
filepath:RemoveDir(filepath:GetDirCount()-1)
|
||||
path = GetPathWithSep(filepath)
|
||||
end
|
||||
|
||||
return path:sub(0,-2)
|
||||
end,
|
||||
hasdebugger = true,
|
||||
}
|
||||
|
||||
@@ -1,291 +1,291 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- LTN12 - Filters, sources, sinks and pumps.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: ltn12.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module
|
||||
-----------------------------------------------------------------------------
|
||||
local string = require("string")
|
||||
local table = require("table")
|
||||
local base = _G
|
||||
module("ltn12")
|
||||
|
||||
filter = {}
|
||||
source = {}
|
||||
sink = {}
|
||||
pump = {}
|
||||
|
||||
-- 2048 seems to be better in windows...
|
||||
BLOCKSIZE = 2048
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Filter stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- returns a high level filter that cycles a low-level filter
|
||||
function filter.cycle(low, ctx, extra)
|
||||
base.assert(low)
|
||||
return function(chunk)
|
||||
local ret
|
||||
ret, ctx = low(ctx, chunk, extra)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
-- chains a bunch of filters together
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function filter.chain(...)
|
||||
local n = table.getn(arg)
|
||||
local top, index = 1, 1
|
||||
local retry = ""
|
||||
return function(chunk)
|
||||
retry = chunk and retry
|
||||
while true do
|
||||
if index == top then
|
||||
chunk = arg[index](chunk)
|
||||
if chunk == "" or top == n then return chunk
|
||||
elseif chunk then index = index + 1
|
||||
else
|
||||
top = top+1
|
||||
index = top
|
||||
end
|
||||
else
|
||||
chunk = arg[index](chunk or "")
|
||||
if chunk == "" then
|
||||
index = index - 1
|
||||
chunk = retry
|
||||
elseif chunk then
|
||||
if index == n then return chunk
|
||||
else index = index + 1 end
|
||||
else base.error("filter returned inappropriate nil") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Source stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- create an empty source
|
||||
local function empty()
|
||||
return nil
|
||||
end
|
||||
|
||||
function source.empty()
|
||||
return empty
|
||||
end
|
||||
|
||||
-- returns a source that just outputs an error
|
||||
function source.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a file source
|
||||
function source.file(handle, io_err)
|
||||
if handle then
|
||||
return function()
|
||||
local chunk = handle:read(BLOCKSIZE)
|
||||
if not chunk then handle:close() end
|
||||
return chunk
|
||||
end
|
||||
else return source.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
-- turns a fancy source into a simple source
|
||||
function source.simplify(src)
|
||||
base.assert(src)
|
||||
return function()
|
||||
local chunk, err_or_new = src()
|
||||
src = err_or_new or src
|
||||
if not chunk then return nil, err_or_new
|
||||
else return chunk end
|
||||
end
|
||||
end
|
||||
|
||||
-- creates string source
|
||||
function source.string(s)
|
||||
if s then
|
||||
local i = 1
|
||||
return function()
|
||||
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
|
||||
i = i + BLOCKSIZE
|
||||
if chunk ~= "" then return chunk
|
||||
else return nil end
|
||||
end
|
||||
else return source.empty() end
|
||||
end
|
||||
|
||||
-- creates rewindable source
|
||||
function source.rewind(src)
|
||||
base.assert(src)
|
||||
local t = {}
|
||||
return function(chunk)
|
||||
if not chunk then
|
||||
chunk = table.remove(t)
|
||||
if not chunk then return src()
|
||||
else return chunk end
|
||||
else
|
||||
table.insert(t, chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function source.chain(src, f)
|
||||
base.assert(src and f)
|
||||
local last_in, last_out = "", ""
|
||||
local state = "feeding"
|
||||
local err
|
||||
return function()
|
||||
if not last_out then
|
||||
base.error('source is empty!', 2)
|
||||
end
|
||||
while true do
|
||||
if state == "feeding" then
|
||||
last_in, err = src()
|
||||
if err then return nil, err end
|
||||
last_out = f(last_in)
|
||||
if not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif last_out ~= "" then
|
||||
state = "eating"
|
||||
if last_in then last_in = "" end
|
||||
return last_out
|
||||
end
|
||||
else
|
||||
last_out = f(last_in)
|
||||
if last_out == "" then
|
||||
if last_in == "" then
|
||||
state = "feeding"
|
||||
else
|
||||
base.error('filter returned ""')
|
||||
end
|
||||
elseif not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return last_out
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a source that produces contents of several sources, one after the
|
||||
-- other, as if they were concatenated
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function source.cat(...)
|
||||
local src = table.remove(arg, 1)
|
||||
return function()
|
||||
while src do
|
||||
local chunk, err = src()
|
||||
if chunk then return chunk end
|
||||
if err then return nil, err end
|
||||
src = table.remove(arg, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Sink stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- creates a sink that stores into a table
|
||||
function sink.table(t)
|
||||
t = t or {}
|
||||
local f = function(chunk, err)
|
||||
if chunk then table.insert(t, chunk) end
|
||||
return 1
|
||||
end
|
||||
return f, t
|
||||
end
|
||||
|
||||
-- turns a fancy sink into a simple sink
|
||||
function sink.simplify(snk)
|
||||
base.assert(snk)
|
||||
return function(chunk, err)
|
||||
local ret, err_or_new = snk(chunk, err)
|
||||
if not ret then return nil, err_or_new end
|
||||
snk = err_or_new or snk
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a file sink
|
||||
function sink.file(handle, io_err)
|
||||
if handle then
|
||||
return function(chunk, err)
|
||||
if not chunk then
|
||||
handle:close()
|
||||
return 1
|
||||
else return handle:write(chunk) end
|
||||
end
|
||||
else return sink.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
-- creates a sink that discards data
|
||||
local function null()
|
||||
return 1
|
||||
end
|
||||
|
||||
function sink.null()
|
||||
return null
|
||||
end
|
||||
|
||||
-- creates a sink that just returns an error
|
||||
function sink.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
-- chains a sink with a filter
|
||||
function sink.chain(f, snk)
|
||||
base.assert(f and snk)
|
||||
return function(chunk, err)
|
||||
if chunk ~= "" then
|
||||
local filtered = f(chunk)
|
||||
local done = chunk and ""
|
||||
while true do
|
||||
local ret, snkerr = snk(filtered, err)
|
||||
if not ret then return nil, snkerr end
|
||||
if filtered == done then return 1 end
|
||||
filtered = f(done)
|
||||
end
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Pump stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- pumps one chunk from the source to the sink
|
||||
function pump.step(src, snk)
|
||||
local chunk, src_err = src()
|
||||
local ret, snk_err = snk(chunk, src_err)
|
||||
if chunk and ret then return 1
|
||||
else return nil, src_err or snk_err end
|
||||
end
|
||||
|
||||
-- pumps all data from a source to a sink, using a step function
|
||||
function pump.all(src, snk, step)
|
||||
base.assert(src and snk)
|
||||
step = step or pump.step
|
||||
while true do
|
||||
local ret, err = step(src, snk)
|
||||
if not ret then
|
||||
if err then return nil, err
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- LTN12 - Filters, sources, sinks and pumps.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: ltn12.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module
|
||||
-----------------------------------------------------------------------------
|
||||
local string = require("string")
|
||||
local table = require("table")
|
||||
local base = _G
|
||||
module("ltn12")
|
||||
|
||||
filter = {}
|
||||
source = {}
|
||||
sink = {}
|
||||
pump = {}
|
||||
|
||||
-- 2048 seems to be better in windows...
|
||||
BLOCKSIZE = 2048
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Filter stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- returns a high level filter that cycles a low-level filter
|
||||
function filter.cycle(low, ctx, extra)
|
||||
base.assert(low)
|
||||
return function(chunk)
|
||||
local ret
|
||||
ret, ctx = low(ctx, chunk, extra)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
-- chains a bunch of filters together
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function filter.chain(...)
|
||||
local n = table.getn(arg)
|
||||
local top, index = 1, 1
|
||||
local retry = ""
|
||||
return function(chunk)
|
||||
retry = chunk and retry
|
||||
while true do
|
||||
if index == top then
|
||||
chunk = arg[index](chunk)
|
||||
if chunk == "" or top == n then return chunk
|
||||
elseif chunk then index = index + 1
|
||||
else
|
||||
top = top+1
|
||||
index = top
|
||||
end
|
||||
else
|
||||
chunk = arg[index](chunk or "")
|
||||
if chunk == "" then
|
||||
index = index - 1
|
||||
chunk = retry
|
||||
elseif chunk then
|
||||
if index == n then return chunk
|
||||
else index = index + 1 end
|
||||
else base.error("filter returned inappropriate nil") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Source stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- create an empty source
|
||||
local function empty()
|
||||
return nil
|
||||
end
|
||||
|
||||
function source.empty()
|
||||
return empty
|
||||
end
|
||||
|
||||
-- returns a source that just outputs an error
|
||||
function source.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a file source
|
||||
function source.file(handle, io_err)
|
||||
if handle then
|
||||
return function()
|
||||
local chunk = handle:read(BLOCKSIZE)
|
||||
if not chunk then handle:close() end
|
||||
return chunk
|
||||
end
|
||||
else return source.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
-- turns a fancy source into a simple source
|
||||
function source.simplify(src)
|
||||
base.assert(src)
|
||||
return function()
|
||||
local chunk, err_or_new = src()
|
||||
src = err_or_new or src
|
||||
if not chunk then return nil, err_or_new
|
||||
else return chunk end
|
||||
end
|
||||
end
|
||||
|
||||
-- creates string source
|
||||
function source.string(s)
|
||||
if s then
|
||||
local i = 1
|
||||
return function()
|
||||
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
|
||||
i = i + BLOCKSIZE
|
||||
if chunk ~= "" then return chunk
|
||||
else return nil end
|
||||
end
|
||||
else return source.empty() end
|
||||
end
|
||||
|
||||
-- creates rewindable source
|
||||
function source.rewind(src)
|
||||
base.assert(src)
|
||||
local t = {}
|
||||
return function(chunk)
|
||||
if not chunk then
|
||||
chunk = table.remove(t)
|
||||
if not chunk then return src()
|
||||
else return chunk end
|
||||
else
|
||||
table.insert(t, chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function source.chain(src, f)
|
||||
base.assert(src and f)
|
||||
local last_in, last_out = "", ""
|
||||
local state = "feeding"
|
||||
local err
|
||||
return function()
|
||||
if not last_out then
|
||||
base.error('source is empty!', 2)
|
||||
end
|
||||
while true do
|
||||
if state == "feeding" then
|
||||
last_in, err = src()
|
||||
if err then return nil, err end
|
||||
last_out = f(last_in)
|
||||
if not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif last_out ~= "" then
|
||||
state = "eating"
|
||||
if last_in then last_in = "" end
|
||||
return last_out
|
||||
end
|
||||
else
|
||||
last_out = f(last_in)
|
||||
if last_out == "" then
|
||||
if last_in == "" then
|
||||
state = "feeding"
|
||||
else
|
||||
base.error('filter returned ""')
|
||||
end
|
||||
elseif not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return last_out
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a source that produces contents of several sources, one after the
|
||||
-- other, as if they were concatenated
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function source.cat(...)
|
||||
local src = table.remove(arg, 1)
|
||||
return function()
|
||||
while src do
|
||||
local chunk, err = src()
|
||||
if chunk then return chunk end
|
||||
if err then return nil, err end
|
||||
src = table.remove(arg, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Sink stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- creates a sink that stores into a table
|
||||
function sink.table(t)
|
||||
t = t or {}
|
||||
local f = function(chunk, err)
|
||||
if chunk then table.insert(t, chunk) end
|
||||
return 1
|
||||
end
|
||||
return f, t
|
||||
end
|
||||
|
||||
-- turns a fancy sink into a simple sink
|
||||
function sink.simplify(snk)
|
||||
base.assert(snk)
|
||||
return function(chunk, err)
|
||||
local ret, err_or_new = snk(chunk, err)
|
||||
if not ret then return nil, err_or_new end
|
||||
snk = err_or_new or snk
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a file sink
|
||||
function sink.file(handle, io_err)
|
||||
if handle then
|
||||
return function(chunk, err)
|
||||
if not chunk then
|
||||
handle:close()
|
||||
return 1
|
||||
else return handle:write(chunk) end
|
||||
end
|
||||
else return sink.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
-- creates a sink that discards data
|
||||
local function null()
|
||||
return 1
|
||||
end
|
||||
|
||||
function sink.null()
|
||||
return null
|
||||
end
|
||||
|
||||
-- creates a sink that just returns an error
|
||||
function sink.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
-- chains a sink with a filter
|
||||
function sink.chain(f, snk)
|
||||
base.assert(f and snk)
|
||||
return function(chunk, err)
|
||||
if chunk ~= "" then
|
||||
local filtered = f(chunk)
|
||||
local done = chunk and ""
|
||||
while true do
|
||||
local ret, snkerr = snk(filtered, err)
|
||||
if not ret then return nil, snkerr end
|
||||
if filtered == done then return 1 end
|
||||
filtered = f(done)
|
||||
end
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Pump stuff
|
||||
-----------------------------------------------------------------------------
|
||||
-- pumps one chunk from the source to the sink
|
||||
function pump.step(src, snk)
|
||||
local chunk, src_err = src()
|
||||
local ret, snk_err = snk(chunk, src_err)
|
||||
if chunk and ret then return 1
|
||||
else return nil, src_err or snk_err end
|
||||
end
|
||||
|
||||
-- pumps all data from a source to a sink, using a step function
|
||||
function pump.all(src, snk, step)
|
||||
base.assert(src and snk)
|
||||
step = step or pump.step
|
||||
while true do
|
||||
local ret, err = step(src, snk)
|
||||
if not ret then
|
||||
if err then return nil, err
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
929
lualibs/luainspect/ast.lua
Normal file
929
lualibs/luainspect/ast.lua
Normal file
@@ -0,0 +1,929 @@
|
||||
-- luainspect.ast - Lua Abstract Syntax Tree (AST) and token list operations.
|
||||
--
|
||||
-- Two main structures are maintained. A Metalua-style AST represents the
|
||||
-- nested syntactic structure obtained from the parse.
|
||||
-- A separate linear ordered list of tokens represents the syntactic structure
|
||||
-- from the lexing, including line information (character positions only not row/columns),
|
||||
-- comments, and keywords, which is originally built from the lineinfo attributes
|
||||
-- injected by Metalua into the AST (IMPROVE: it probably would be simpler
|
||||
-- to obtain this from the lexer directly rather then inferring it from the parsing).
|
||||
-- During AST manipulations, the lineinfo maintained in the AST is ignored
|
||||
-- because it was found more difficult to maintain and not in the optimal format.
|
||||
--
|
||||
-- The contained code deals with
|
||||
-- - Building the AST from source.
|
||||
-- - Building the tokenlist from the AST lineinfo.
|
||||
-- - Querying the AST+tokenlist.
|
||||
-- - Modifying the AST+tokenlist (including incremental parsing source -> AST)
|
||||
-- - Annotating the AST with navigational info (e.g. parent links) to assist queries.
|
||||
-- - Dumping the tokenlist for debugging.
|
||||
--
|
||||
-- (c) 2010 David Manura, MIT License.
|
||||
|
||||
|
||||
--! require 'luainspect.typecheck' (context)
|
||||
|
||||
-- boilerplate/utility
|
||||
-- LUA_PATH="?.lua;/path/to/metalua/src/compiler/?.lua;/path/to/metalua/src/lib/?.lua"
|
||||
-- import modules -- order is important
|
||||
require "lexer"
|
||||
require "gg"
|
||||
require "mlp_lexer"
|
||||
require "mlp_misc"
|
||||
require "mlp_table"
|
||||
require "mlp_meta"
|
||||
require "mlp_expr"
|
||||
require "mlp_stat"
|
||||
--require "mlp_ext"
|
||||
_G.mlc = {} -- make gg happy
|
||||
-- Metalua:IMPROVE: make above imports simpler
|
||||
|
||||
local M = {}
|
||||
|
||||
--[=TESTSUITE
|
||||
-- utilities
|
||||
local ops = {}
|
||||
ops['=='] = function(a,b) return a == b end
|
||||
local function check(opname, a, b)
|
||||
local op = assert(ops[opname])
|
||||
if not op(a,b) then
|
||||
error("fail == " .. tostring(a) .. " " .. tostring(b))
|
||||
end
|
||||
end
|
||||
--]=]
|
||||
|
||||
-- CATEGORY: debug
|
||||
local function DEBUG(...)
|
||||
if LUAINSPECT_DEBUG then
|
||||
print('DEBUG:', ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Converts character position to row,column position in string src.
|
||||
-- Add values are 1-indexed.
|
||||
function M.pos_to_linecol(pos, src)
|
||||
local linenum = 1
|
||||
local lasteolpos = 0
|
||||
for eolpos in src:gmatch"()\n" do
|
||||
if eolpos > pos then break end
|
||||
linenum = linenum + 1
|
||||
lasteolpos = eolpos
|
||||
end
|
||||
local colnum = pos - lasteolpos
|
||||
return linenum, colnum
|
||||
end
|
||||
|
||||
-- Removes any sheband ("#!") line from Lua source string.
|
||||
-- CATEGORY: Lua parsing
|
||||
function M.remove_shebang(src)
|
||||
local shebang = src:match("^#![^\r\n]*")
|
||||
return shebang and (" "):rep(#shebang) .. src:sub(#shebang+1) or src
|
||||
end
|
||||
|
||||
|
||||
-- Custom version of loadstring that parses out line number info
|
||||
-- CATEGORY: Lua parsing
|
||||
function M.loadstring(src)
|
||||
local f, err = loadstring(src, "")
|
||||
if f then
|
||||
return f
|
||||
else
|
||||
err = err:gsub('^%[string ""%]:', "")
|
||||
local linenum = assert(err:match("(%d+):"))
|
||||
local colnum = 0
|
||||
local linenum2 = err:match("^%d+: '[^']+' expected %(to close '[^']+' at line (%d+)")
|
||||
return nil, err, linenum, colnum, linenum2
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- helper for ast_from_string. Raises on error.
|
||||
-- FIX? filename currently ignored in Metalua
|
||||
-- CATEGORY: Lua parsing
|
||||
local function ast_from_string_helper(src, filename)
|
||||
filename = filename or '(string)'
|
||||
local lx = mlp.lexer:newstream (src, filename)
|
||||
local ast = mlp.chunk(lx)
|
||||
return ast
|
||||
end
|
||||
|
||||
|
||||
-- Counts number of lines in text.
|
||||
-- Warning: the decision of whether to count a trailing new-line in a file
|
||||
-- or an empty file as a line is a little subjective. This function currently
|
||||
-- defines the line count as 1 plus the number of new line characters.
|
||||
-- CATEGORY: utility/string
|
||||
local function linecount(text)
|
||||
local n = 1
|
||||
for _ in text:gmatch'\n' do
|
||||
n = n + 1
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
|
||||
-- Converts Lua source string to Lua AST (via mlp/gg).
|
||||
-- CATEGORY: Lua parsing
|
||||
function M.ast_from_string(src, filename)
|
||||
local ok, ast = pcall(ast_from_string_helper, src, filename)
|
||||
if not ok then
|
||||
local err = ast
|
||||
err = err:match('[^\n]*')
|
||||
err = err:gsub("^.-:%s*line", "line")
|
||||
-- mlp.chunk prepending this is undesirable. error(msg,0) would be better in gg.lua. Reported.
|
||||
-- TODO-Metalua: remove when fixed in Metalua.
|
||||
local linenum, colnum = err:match("line (%d+), char (%d+)")
|
||||
if not linenum then
|
||||
-- Metalua libraries may return "...gg.lua:56: .../mlp_misc.lua:179: End-of-file expected"
|
||||
-- without the normal line/char numbers given things like "if x then end end". Should be
|
||||
-- fixed probably with gg.parse_error in _chunk in mlp_misc.lua.
|
||||
-- TODO-Metalua: remove when fixed in Metalua.
|
||||
linenum = linecount(src)
|
||||
colnum = 1
|
||||
end
|
||||
local linenum2 = nil
|
||||
return nil, err, linenum, colnum, linenum2
|
||||
else
|
||||
return ast
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Simple comment parser. Returns Metalua-style comment.
|
||||
-- CATEGORY: Lua lexing
|
||||
local function quick_parse_comment(src)
|
||||
local s = src:match"^%-%-([^\n]*)()\n$"
|
||||
if s then return {s, 1, #src, 'short'} end
|
||||
local _, s = src:match(lexer.lexer.patterns.long_comment .. '\r?\n?$')
|
||||
if s then return {s, 1, #src, 'long'} end
|
||||
return nil
|
||||
end
|
||||
--FIX:check new-line correctness
|
||||
--note: currently requiring \n at end of single line comment to avoid
|
||||
-- incremental compilation with `--x\nf()` and removing \n from still
|
||||
-- recognizing as comment `--x`.
|
||||
-- currently allowing \r\n at end of long comment since Metalua includes
|
||||
-- it in lineinfo of long comment (FIX:Metalua?)
|
||||
|
||||
|
||||
-- Gets length of longest prefix string in both provided strings.
|
||||
-- Returns max n such that text1:sub(1,n) == text2:sub(1,n) and n <= max(#text1,#text2)
|
||||
-- CATEGORY: string utility
|
||||
local function longest_prefix(text1, text2)
|
||||
local nmin = 0
|
||||
local nmax = math.min(#text1, #text2)
|
||||
while nmax > nmin do
|
||||
local nmid = math.ceil((nmin+nmax)/2)
|
||||
if text1:sub(1,nmid) == text2:sub(1,nmid) then
|
||||
nmin = nmid
|
||||
else
|
||||
nmax = nmid-1
|
||||
end
|
||||
end
|
||||
return nmin
|
||||
end
|
||||
|
||||
|
||||
-- Gets length of longest postfix string in both provided strings.
|
||||
-- Returns max n such that text1:sub(-n) == text2:sub(-n) and n <= max(#text1,#text2)
|
||||
-- CATEGORY: string utility
|
||||
local function longest_postfix(text1, text2)
|
||||
local nmin = 0
|
||||
local nmax = math.min(#text1, #text2)
|
||||
while nmax > nmin do
|
||||
local nmid = math.ceil((nmin+nmax)/2)
|
||||
if text1:sub(-nmid) == text2:sub(-nmid) then --[*]
|
||||
nmin = nmid
|
||||
else
|
||||
nmax = nmid-1
|
||||
end
|
||||
end
|
||||
return nmin
|
||||
end -- differs from longest_prefix only on line [*]
|
||||
|
||||
|
||||
|
||||
-- Determines AST node that must be re-evaluated upon changing code string from
|
||||
-- `src` to `bsrc`, given previous top_ast/tokenlist/src.
|
||||
-- Note: decorates top_ast as side-effect.
|
||||
-- If preserve is true, then does not expand AST match even if replacement is invalid.
|
||||
-- CATEGORY: AST/tokenlist manipulation
|
||||
function M.invalidated_code(top_ast, tokenlist, src, bsrc, preserve)
|
||||
-- Converts posiiton range in src to position range in bsrc.
|
||||
local function range_transform(src_fpos, src_lpos)
|
||||
local src_nlpos = #src - src_lpos
|
||||
local bsrc_fpos = src_fpos
|
||||
local bsrc_lpos = #bsrc - src_nlpos
|
||||
return bsrc_fpos, bsrc_lpos
|
||||
end
|
||||
|
||||
if src == bsrc then return end -- up-to-date
|
||||
|
||||
-- Find range of positions in src that differences correspond to.
|
||||
-- Note: for zero byte range, src_pos2 = src_pos1 - 1.
|
||||
local npre = longest_prefix(src, bsrc)
|
||||
local npost = math.min(#src-npre, longest_postfix(src, bsrc))
|
||||
-- note: min avoids overlap ambiguity
|
||||
local src_fpos, src_lpos = 1 + npre, #src - npost
|
||||
|
||||
-- Find smallest AST node containing src range above. May also
|
||||
-- be contained in (smaller) comment or whitespace.
|
||||
local match_ast, match_comment, iswhitespace =
|
||||
M.smallest_ast_containing_range(top_ast, tokenlist, src_fpos, src_lpos)
|
||||
DEBUG('invalidate-smallest:', match_ast and (match_ast.tag or 'notag'), match_comment, iswhitespace)
|
||||
|
||||
-- Determine which (ast, comment, or whitespace) to match, and get its pos range in src and bsrc.
|
||||
local srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype
|
||||
if iswhitespace then
|
||||
mast, mtype = nil, 'whitespace'
|
||||
srcm_fpos, srcm_lpos = src_fpos, src_lpos
|
||||
elseif match_comment then
|
||||
mast, mtype = match_comment, 'comment'
|
||||
srcm_fpos, srcm_lpos = match_comment.fpos, match_comment.lpos
|
||||
else
|
||||
mast, mtype = match_ast, 'ast'
|
||||
repeat
|
||||
srcm_fpos, srcm_lpos = M.ast_pos_range(mast, tokenlist)
|
||||
if not srcm_fpos then
|
||||
if mast == top_ast then
|
||||
srcm_fpos, srcm_lpos = 1, #src
|
||||
break
|
||||
else
|
||||
M.ensure_parents_marked(top_ast)
|
||||
mast = mast.parent
|
||||
end
|
||||
end
|
||||
until srcm_fpos
|
||||
end
|
||||
bsrcm_fpos, bsrcm_lpos = range_transform(srcm_fpos, srcm_lpos)
|
||||
|
||||
-- Never expand match if preserve specified.
|
||||
if preserve then
|
||||
return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype
|
||||
end
|
||||
|
||||
-- Determine if replacement could break parent nodes.
|
||||
local isreplacesafe
|
||||
if mtype == 'whitespace' then
|
||||
if bsrc:sub(bsrcm_fpos, bsrcm_lpos):match'^%s*$' then -- replaced with whitespace
|
||||
if bsrc:sub(bsrcm_fpos-1, bsrcm_lpos+1):match'%s' then -- not eliminating whitespace
|
||||
isreplacesafe = true
|
||||
end
|
||||
end
|
||||
elseif mtype == 'comment' then
|
||||
local m2src = bsrc:sub(bsrcm_fpos, bsrcm_lpos)
|
||||
DEBUG('invalidate-comment[' .. m2src .. ']')
|
||||
if quick_parse_comment(m2src) then -- replaced with comment
|
||||
isreplacesafe = true
|
||||
end
|
||||
end
|
||||
if isreplacesafe then -- return on safe replacement
|
||||
return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, mast, mtype
|
||||
end
|
||||
|
||||
-- Find smallest containing statement block that will compile (or top_ast).
|
||||
while 1 do
|
||||
match_ast = M.get_containing_statementblock(match_ast, top_ast)
|
||||
if match_ast == top_ast then
|
||||
return 1,#src, 1, #bsrc, match_ast, 'statblock'
|
||||
-- entire AST invalidated
|
||||
end
|
||||
local srcm_fpos, srcm_lpos = M.ast_pos_range(match_ast, tokenlist)
|
||||
local bsrcm_fpos, bsrcm_lpos = range_transform(srcm_fpos, srcm_lpos)
|
||||
local msrc = bsrc:sub(bsrcm_fpos, bsrcm_lpos)
|
||||
DEBUG('invalidate-statblock:', match_ast and match_ast.tag, '[' .. msrc .. ']')
|
||||
if loadstring(msrc) then -- compiled
|
||||
return srcm_fpos, srcm_lpos, bsrcm_fpos, bsrcm_lpos, match_ast, 'statblock'
|
||||
end
|
||||
M.ensure_parents_marked(top_ast)
|
||||
match_ast = match_ast.parent
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Walks AST `ast` in arbitrary order, visiting each node `n`, executing `fdown(n)` (if specified)
|
||||
-- when doing down and `fup(n)` (if specified) when going if.
|
||||
-- CATEGORY: AST walk
|
||||
function M.walk(ast, fdown, fup)
|
||||
assert(type(ast) == 'table')
|
||||
if fdown then fdown(ast) end
|
||||
for _,bast in ipairs(ast) do
|
||||
if type(bast) == 'table' then
|
||||
M.walk(bast, fdown, fup)
|
||||
end
|
||||
end
|
||||
if fup then fup(ast) end
|
||||
end
|
||||
|
||||
|
||||
-- Replaces contents of table t1 with contents of table t2.
|
||||
-- Does not change metatable (if any).
|
||||
-- This function is useful for swapping one AST node with another
|
||||
-- while preserving any references to the node.
|
||||
-- CATEGORY: table utility
|
||||
function M.switchtable(t1, t2)
|
||||
for k in pairs(t1) do t1[k] = nil end
|
||||
for k in pairs(t2) do t1[k] = t2[k] end
|
||||
end
|
||||
|
||||
|
||||
-- Inserts all elements in list bt at index i in list t.
|
||||
-- CATEGORY: table utility
|
||||
local function tinsertlist(t, i, bt)
|
||||
local oldtlen, delta = #t, i - 1
|
||||
for ti = #t + 1, #t + #bt do t[ti] = false end -- preallocate (avoid holes)
|
||||
for ti = oldtlen, i, -1 do t[ti + #bt] = t[ti] end -- shift
|
||||
for bi = 1, #bt do t[bi + delta] = bt[bi] end -- fill
|
||||
end
|
||||
--[=[TESTSUITE:
|
||||
local function _tinsertlist(t, i, bt)
|
||||
for bi=#bt,1,-1 do table.insert(t, i, bt[bi]) end
|
||||
end -- equivalent but MUCH less efficient for large tables
|
||||
local function _tinsertlist(t, i, bt)
|
||||
for bi=1,#bt do table.insert(t, i+bi-1, bt[bi]) end
|
||||
end -- equivalent but MUCH less efficient for large tables
|
||||
local t = {}; tinsertlist(t, 1, {}); assert(table.concat(t)=='')
|
||||
local t = {}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='23')
|
||||
local t = {4}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='234')
|
||||
local t = {2}; tinsertlist(t, 2, {3,4}); assert(table.concat(t)=='234')
|
||||
local t = {4,5}; tinsertlist(t, 1, {2,3}); assert(table.concat(t)=='2345')
|
||||
local t = {2,5}; tinsertlist(t, 2, {3,4}); assert(table.concat(t)=='2345')
|
||||
local t = {2,3}; tinsertlist(t, 3, {4,5}); assert(table.concat(t)=='2345')
|
||||
print 'DONE'
|
||||
--]=]
|
||||
|
||||
|
||||
|
||||
-- Gets list of keyword positions related to node ast in source src
|
||||
-- note: ast must be visible, i.e. have lineinfo (e.g. unlike `Id "self" definition).
|
||||
-- Note: includes operators.
|
||||
-- Note: Assumes ast Metalua-style lineinfo is valid.
|
||||
-- CATEGORY: tokenlist build
|
||||
function M.get_keywords(ast, src)
|
||||
local list = {}
|
||||
if not ast.lineinfo then return list end
|
||||
-- examine space between each pair of children i and j.
|
||||
-- special cases: 0 is before first child and #ast+1 is after last child
|
||||
|
||||
-- Put children in lexical order.
|
||||
-- Some binary operations have arguments reversed from lexical order.
|
||||
-- For example, `a > b` becomes `Op{'lt', `Id 'b', `Id 'a'}
|
||||
local oast =
|
||||
(ast.tag == 'Op' and #ast == 3 and ast[2].lineinfo.first[3] > ast[3].lineinfo.first[3])
|
||||
and {ast[1], ast[3], ast[2]} or ast
|
||||
|
||||
local i = 0
|
||||
while i <= #ast do
|
||||
-- j is node following i that has lineinfo
|
||||
local j = i+1; while j < #ast+1 and not oast[j].lineinfo do j=j+1 end
|
||||
|
||||
-- Get position range [fpos,lpos] between subsequent children.
|
||||
local fpos
|
||||
if i == 0 then -- before first child
|
||||
fpos = ast.lineinfo.first[3]
|
||||
else
|
||||
local last = oast[i].lineinfo.last; local c = last.comments
|
||||
fpos = (c and #c > 0 and c[#c][3] or last[3]) + 1
|
||||
end
|
||||
local lpos
|
||||
if j == #ast+1 then -- after last child
|
||||
lpos = ast.lineinfo.last[3]
|
||||
else
|
||||
local first = oast[j].lineinfo.first; local c = first.comments
|
||||
--DEBUG('first', ast.tag, first[3], src:sub(first[3], first[3]+3))
|
||||
lpos = (c and #c > 0 and c[1][2] or first[3]) - 1
|
||||
end
|
||||
|
||||
-- Find keyword in range.
|
||||
local spos = fpos
|
||||
repeat
|
||||
local mfpos, tok, mlppos = src:match("^%s*()(%a+)()", spos)
|
||||
if not mfpos then
|
||||
mfpos, tok, mlppos = src:match("^%s*()(%p+)()", spos)
|
||||
end
|
||||
if mfpos then
|
||||
local mlpos = mlppos-1
|
||||
if mlpos > lpos then mlpos = lpos end
|
||||
--DEBUG('look', ast.tag, #ast,i,j,'*', mfpos, tok, mlppos, fpos, lpos, src:sub(fpos, fpos+5))
|
||||
if mlpos >= mfpos then
|
||||
list[#list+1] = mfpos
|
||||
list[#list+1] = mlpos
|
||||
end
|
||||
end
|
||||
spos = mlppos
|
||||
until not spos or spos > lpos
|
||||
-- note: finds single keyword. in `local function` returns only `local`
|
||||
--DEBUG(i,j ,'test[' .. src:sub(fpos, lpos) .. ']')
|
||||
|
||||
i = j -- next
|
||||
|
||||
--DESIGN:Lua: comment: string.match accepts a start position but not a stop position
|
||||
end
|
||||
return list
|
||||
end
|
||||
-- Q:Metalua: does ast.lineinfo[loc].comments imply #ast.lineinfo[loc].comments > 0 ?
|
||||
|
||||
|
||||
|
||||
-- Generates ordered list of tokens in top_ast/src.
|
||||
-- Note: currently ignores operators and parens.
|
||||
-- Note: Modifies ast.
|
||||
-- Note: Assumes ast Metalua-style lineinfo is valid.
|
||||
-- CATEGORY: AST/tokenlist query
|
||||
local isterminal = {Nil=true, Dots=true, True=true, False=true, Number=true, String=true,
|
||||
Dots=true, Id=true}
|
||||
local function compare_tokens_(atoken, btoken) return atoken.fpos < btoken.fpos end
|
||||
function M.ast_to_tokenlist(top_ast, src)
|
||||
local tokens = {} -- {nbytes=#src}
|
||||
local isseen = {}
|
||||
M.walk(top_ast, function(ast)
|
||||
if isterminal[ast.tag] then -- Extract terminal
|
||||
local token = ast
|
||||
if ast.lineinfo then
|
||||
token.fpos, token.lpos, token.ast = ast.lineinfo.first[3], ast.lineinfo.last[3], ast
|
||||
table.insert(tokens, token)
|
||||
end
|
||||
else -- Extract non-terminal
|
||||
local keywordposlist = M.get_keywords(ast, src)
|
||||
for i=1,#keywordposlist,2 do
|
||||
local fpos, lpos = keywordposlist[i], keywordposlist[i+1]
|
||||
local toksrc = src:sub(fpos, lpos)
|
||||
local token = {tag='Keyword', fpos=fpos, lpos=lpos, ast=ast, toksrc}
|
||||
table.insert(tokens, token)
|
||||
end
|
||||
end
|
||||
-- Extract comments
|
||||
for i=1,2 do
|
||||
local comments = ast.lineinfo and ast.lineinfo[i==1 and 'first' or 'last'].comments
|
||||
if comments then for _, comment in ipairs(comments) do
|
||||
if not isseen[comment] then
|
||||
comment.tag = 'Comment'
|
||||
local token = comment
|
||||
token.fpos, token.lpos, token.ast = comment[2], comment[3], comment
|
||||
table.insert(tokens, token)
|
||||
isseen[comment] = true
|
||||
end
|
||||
end end
|
||||
end
|
||||
end, nil)
|
||||
table.sort(tokens, compare_tokens_)
|
||||
return tokens
|
||||
end
|
||||
|
||||
|
||||
-- Gets tokenlist range [fidx,lidx] covered by ast. Returns nil,nil if not found.
|
||||
--FIX:PERFORMANCE:this is slow on large files.
|
||||
-- CATEGORY: AST/tokenlist query
|
||||
function M.ast_idx_range_in_tokenlist(tokenlist, ast)
|
||||
-- Get list of primary nodes under ast.
|
||||
local isold = {}; M.walk(ast, function(ast) isold[ast] = true end)
|
||||
-- Get range.
|
||||
local fidx, lidx
|
||||
for idx=1,#tokenlist do
|
||||
local token = tokenlist[idx]
|
||||
if isold[token.ast] then
|
||||
lidx = idx
|
||||
if not fidx then fidx = idx end
|
||||
end
|
||||
end
|
||||
return fidx, lidx
|
||||
end
|
||||
|
||||
|
||||
-- Gets index range in tokenlist overlapped by character position range [fpos, lpos].
|
||||
-- For example, `do ff() end` with range ` ff() ` would match tokens `ff()`.
|
||||
-- Tokens partly inside range are counted, so range `f()` would match tokens `ff()`.
|
||||
-- If lidx = fidx - 1, then position range is whitespace between tokens lidx (on left)
|
||||
-- and fidx (on right), and this may include token pseudoindices 0 (start of file) and
|
||||
-- #tokenlist+1 (end of file).
|
||||
-- Note: lpos == fpos - 1 indicates zero-width range between chars lpos and fpos.
|
||||
-- CATEGORY: tokenlist query
|
||||
function M.tokenlist_idx_range_over_pos_range(tokenlist, fpos, lpos)
|
||||
-- Find first/last indices of tokens overlapped (even partly) by position range.
|
||||
local fidx, lidx
|
||||
for idx=1,#tokenlist do
|
||||
local token = tokenlist[idx]
|
||||
--if (token.fpos >= fpos and token.fpos <= lpos) or (token.lpos >= fpos and token.lpos <= lpos) then -- token overlaps range
|
||||
if fpos <= token.lpos and lpos >= token.fpos then -- range overlaps token (even partially)
|
||||
if not fidx then fidx = idx end
|
||||
lidx = idx
|
||||
end
|
||||
end
|
||||
if not fidx then -- on fail, check between tokens
|
||||
for idx=1,#tokenlist+1 do -- between idx-1 and idx
|
||||
local tokfpos, toklpos = tokenlist[idx-1] and tokenlist[idx-1].lpos, tokenlist[idx] and tokenlist[idx].fpos
|
||||
if (not tokfpos or fpos > tokfpos) and (not toklpos or lpos < toklpos) then -- range between tokens
|
||||
return idx, idx-1
|
||||
end
|
||||
end
|
||||
end
|
||||
return fidx, lidx
|
||||
end
|
||||
--[=[TESTSUITE
|
||||
local function test(...)
|
||||
return table.concat({M.tokenlist_idx_range_over_pos_range(...)}, ',')
|
||||
end
|
||||
check('==', test({}, 2, 2), "1,0") -- no tokens
|
||||
check('==', test({{tag='Id', fpos=1, lpos=1}}, 2, 2), "2,1") -- right of one token
|
||||
check('==', test({{tag='Id', fpos=3, lpos=3}}, 2, 2), "1,0") -- left of one token
|
||||
check('==', test({{tag='Id', fpos=3, lpos=4}}, 2, 3), "1,1") -- left partial overlap one token
|
||||
check('==', test({{tag='Id', fpos=3, lpos=4}}, 4, 5), "1,1") -- right partial overlap one token
|
||||
check('==', test({{tag='Id', fpos=3, lpos=6}}, 4, 5), "1,1") -- partial inner overlap one token
|
||||
check('==', test({{tag='Id', fpos=3, lpos=6}}, 3, 6), "1,1") -- exact overlap one token
|
||||
check('==', test({{tag='Id', fpos=4, lpos=5}}, 3, 6), "1,1") -- extra overlap one token
|
||||
check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 4, 4), "2,1") -- between tokens, " " exact
|
||||
check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 4, 3), "2,1") -- between tokens, "" on left
|
||||
check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=5, lpos=6}}, 5, 4), "2,1") -- between tokens, "" on right
|
||||
check('==', test({{tag='Id', fpos=2, lpos=3}, {tag='Id', fpos=4, lpos=5}}, 4, 3), "2,1") -- between tokens, "" exact
|
||||
--]=]
|
||||
|
||||
-- Removes tokens in tokenlist covered by ast.
|
||||
-- CATEGORY: tokenlist manipulation
|
||||
local function remove_ast_in_tokenlist(tokenlist, ast)
|
||||
local fidx, lidx = M.ast_idx_range_in_tokenlist(tokenlist, ast)
|
||||
if fidx then -- note: fidx implies lidx
|
||||
for idx=lidx,fidx,-1 do table.remove(tokenlist, idx) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Inserts tokens from btokenlist into tokenlist. Preserves sort.
|
||||
-- CATEGORY: tokenlist manipulation
|
||||
local function insert_tokenlist(tokenlist, btokenlist)
|
||||
local ftoken = btokenlist[1]
|
||||
if ftoken then
|
||||
-- Get index in tokenlist in which to insert tokens in btokenlist.
|
||||
local fidx
|
||||
for idx=1,#tokenlist do
|
||||
if tokenlist[idx].fpos > ftoken.fpos then fidx = idx; break end
|
||||
end
|
||||
fidx = fidx or #tokenlist + 1 -- else append
|
||||
|
||||
-- Insert tokens.
|
||||
tinsertlist(tokenlist, fidx, btokenlist)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Get character position range covered by ast in tokenlist. Returns nil,nil on not found.
|
||||
-- CATEGORY: AST/tokenlist query
|
||||
function M.ast_pos_range(ast, tokenlist) -- IMPROVE:style: ast_idx_range_in_tokenlist has params reversed
|
||||
local fidx, lidx = M.ast_idx_range_in_tokenlist(tokenlist, ast)
|
||||
if fidx then
|
||||
return tokenlist[fidx].fpos, tokenlist[lidx].lpos
|
||||
else
|
||||
return nil, nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Gets string representation of AST node. nil if none.
|
||||
-- IMPROVE: what if node is empty block?
|
||||
-- CATEGORY: AST/tokenlist query
|
||||
function M.ast_to_text(ast, tokenlist, src) -- IMPROVE:style: ast_idx_range_in_tokenlist has params reversed
|
||||
local fpos, lpos = M.ast_pos_range(ast, tokenlist)
|
||||
if fpos then
|
||||
return src:sub(fpos, lpos)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Gets smallest AST node in top_ast/tokenlist/src
|
||||
-- completely containing position range [pos1, pos2].
|
||||
-- careful: "function" is not part of the `Function node.
|
||||
-- If range is inside comment, returns comment also.
|
||||
-- If range is inside whitespace, then returns true in third return value.
|
||||
-- CATEGORY: AST/tokenlist query
|
||||
function M.smallest_ast_containing_range(top_ast, tokenlist, pos1, pos2)
|
||||
local f0idx, l0idx = M.tokenlist_idx_range_over_pos_range(tokenlist, pos1, pos2)
|
||||
|
||||
-- Find enclosing AST.
|
||||
M.ensure_parents_marked(top_ast)
|
||||
local fidx, lidx = f0idx, l0idx
|
||||
while tokenlist[fidx] and not tokenlist[fidx].ast.parent do fidx = fidx - 1 end
|
||||
while tokenlist[lidx] and not tokenlist[lidx].ast.parent do lidx = lidx + 1 end
|
||||
-- DEBUG(fidx, lidx, f0idx, l0idx, #tokenlist, pos1, pos2, tokenlist[fidx], tokenlist[lidx])
|
||||
local ast = not (tokenlist[fidx] and tokenlist[lidx]) and top_ast or
|
||||
M.common_ast_parent(tokenlist[fidx].ast, tokenlist[lidx].ast, top_ast)
|
||||
-- DEBUG('m2', tokenlist[fidx], tokenlist[lidx], top_ast, ast, ast and ast.tag)
|
||||
if l0idx == f0idx - 1 then -- whitespace
|
||||
return ast, nil, true
|
||||
elseif l0idx == f0idx and tokenlist[l0idx].tag == 'Comment' then
|
||||
return ast, tokenlist[l0idx], nil
|
||||
else
|
||||
return ast, nil, nil
|
||||
end
|
||||
end
|
||||
--IMPROVE: handle string edits and maybe others
|
||||
|
||||
|
||||
-- Gets smallest statement block containing position pos or
|
||||
-- nearest statement block before pos, whichever is smaller, given ast/tokenlist.
|
||||
function M.current_statementblock(ast, tokenlist, pos)
|
||||
local fidx,lidx = M.tokenlist_idx_range_over_pos_range(tokenlist, pos, pos)
|
||||
if fidx > lidx then fidx = lidx end -- use nearest backward
|
||||
|
||||
-- Find closest AST node backward
|
||||
while fidx >= 1 and tokenlist[fidx].tag == 'Comment' do fidx=fidx-1 end
|
||||
|
||||
if fidx < 1 then return ast, false end
|
||||
local mast = tokenlist[fidx].ast
|
||||
if not mast then return ast, false end
|
||||
mast = M.get_containing_statementblock(mast, ast)
|
||||
local isafter = false
|
||||
if mast.tag2 ~= 'Block' then
|
||||
local mfidx,mlidx = M.ast_idx_range_in_tokenlist(tokenlist, mast)
|
||||
if pos > mlidx then
|
||||
isafter = true
|
||||
end
|
||||
end
|
||||
|
||||
return mast, isafter
|
||||
end
|
||||
|
||||
-- Gets index of bast in ast (nil if not found).
|
||||
-- CATEGORY: AST query
|
||||
function M.ast_idx(ast, bast)
|
||||
for idx=1,#ast do
|
||||
if ast[idx] == bast then return idx end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- Gets parent of ast and index of ast in parent.
|
||||
-- Root node top_ast must also be provided. Returns nil, nil if ast is root.
|
||||
-- Note: may call mark_parents.
|
||||
-- CATEGORY: AST query
|
||||
function M.ast_parent_idx(top_ast, ast)
|
||||
if ast == top_ast then return nil, nil end
|
||||
M.ensure_parents_marked(top_ast); assert(ast.parent)
|
||||
local idx = M.ast_idx(ast.parent, ast)
|
||||
return ast.parent, idx
|
||||
end
|
||||
|
||||
|
||||
-- Gets common parent of aast and bast. Always returns value.
|
||||
-- Must provide root top_ast too.
|
||||
-- CATEGORY: AST query
|
||||
function M.common_ast_parent(aast, bast, top_ast)
|
||||
M.ensure_parents_marked(top_ast)
|
||||
local isparent = {}
|
||||
local tast = bast; repeat isparent[tast] = true; tast = tast.parent until not tast
|
||||
local uast = aast; repeat if isparent[uast] then return uast end; uast = uast.parent until not uast
|
||||
assert(false)
|
||||
end
|
||||
|
||||
|
||||
-- Replaces old_ast with new_ast/new_tokenlist in top_ast/tokenlist.
|
||||
-- Note: assumes new_ast is a block. assumes old_ast is a statement or block.
|
||||
-- CATEGORY: AST/tokenlist
|
||||
function M.replace_statements(top_ast, tokenlist, old_ast, new_ast, new_tokenlist)
|
||||
remove_ast_in_tokenlist(tokenlist, old_ast)
|
||||
insert_tokenlist(tokenlist, new_tokenlist)
|
||||
if old_ast == top_ast then -- special case: no parent
|
||||
M.switchtable(old_ast, new_ast) -- note: safe since block is not in tokenlist.
|
||||
else
|
||||
local parent_ast, idx = M.ast_parent_idx(top_ast, old_ast)
|
||||
table.remove(parent_ast, idx)
|
||||
tinsertlist(parent_ast, idx, new_ast)
|
||||
end
|
||||
|
||||
-- fixup annotations
|
||||
for _,bast in ipairs(new_ast) do
|
||||
if top_ast.tag2 then M.mark_tag2(bast, bast.tag == 'Do' and 'StatBlock' or 'Block') end
|
||||
if old_ast.parent then M.mark_parents(bast, old_ast.parent) end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Adjusts lineinfo in tokenlist.
|
||||
-- All char positions starting at pos1 are shifted by delta number of chars.
|
||||
-- CATEGORY: tokenlist
|
||||
function M.adjust_lineinfo(tokenlist, pos1, delta)
|
||||
for _,token in ipairs(tokenlist) do
|
||||
if token.fpos >= pos1 then
|
||||
token.fpos = token.fpos + delta
|
||||
end
|
||||
if token.lpos >= pos1 then
|
||||
token.lpos = token.lpos + delta
|
||||
end
|
||||
end
|
||||
--tokenlist.nbytes = tokenlist.nbytes + delta
|
||||
end
|
||||
|
||||
|
||||
-- For each node n in ast, sets n.parent to parent node of n.
|
||||
-- Assumes ast.parent will be parent_ast (may be nil)
|
||||
-- CATEGORY: AST query
|
||||
function M.mark_parents(ast, parent_ast)
|
||||
ast.parent = parent_ast
|
||||
for _,ast2 in ipairs(ast) do
|
||||
if type(ast2) == 'table' then
|
||||
M.mark_parents(ast2, ast)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Calls mark_parents(ast) if ast not marked.
|
||||
-- CATEGORY: AST query
|
||||
function M.ensure_parents_marked(ast)
|
||||
if ast[1] and not ast[1].parent then M.mark_parents(ast) end
|
||||
end
|
||||
|
||||
|
||||
-- For each node n in ast, sets n.tag2 to context string:
|
||||
-- 'Block' - node is block
|
||||
-- 'Stat' - node is statement
|
||||
-- 'StatBlock' - node is statement and block (i.e. `Do)
|
||||
-- 'Exp' - node is expression
|
||||
-- 'Explist' - node is expression list (or identifier list)
|
||||
-- 'Pair' - node is key-value pair in table constructor
|
||||
-- note: ast.tag2 will be set to context.
|
||||
-- CATEGORY: AST query
|
||||
local iscertainstat = {Do=true, Set=true, While=true, Repeat=true, If=true,
|
||||
Fornum=true, Forin=true, Local=true, Localrec=true, Return=true, Break=true}
|
||||
function M.mark_tag2(ast, context)
|
||||
context = context or 'Block'
|
||||
ast.tag2 = context
|
||||
for i,bast in ipairs(ast) do
|
||||
if type(bast) == 'table' then
|
||||
local nextcontext
|
||||
if bast.tag == 'Do' then
|
||||
nextcontext = 'StatBlock'
|
||||
elseif iscertainstat[bast.tag] then
|
||||
nextcontext = 'Stat'
|
||||
elseif bast.tag == 'Call' or bast.tag == 'Invoke' then
|
||||
nextcontext = context == 'Block' and 'Stat' or 'Exp'
|
||||
--DESIGN:Metalua: these calls actually contain expression lists,
|
||||
-- but the expression list is not represented as a complete node
|
||||
-- by Metalua (as blocks are in `Do statements)
|
||||
elseif bast.tag == 'Pair' then
|
||||
nextcontext = 'Pair'
|
||||
elseif not bast.tag then
|
||||
if ast.tag == 'Set' or ast.tag == 'Local' or ast.tag == 'Localrec'
|
||||
or ast.tag == 'Forin' and i <= 2
|
||||
or ast.tag == 'Function' and i == 1
|
||||
then
|
||||
nextcontext = 'Explist'
|
||||
else
|
||||
nextcontext = 'Block'
|
||||
end
|
||||
else
|
||||
nextcontext = 'Exp'
|
||||
end
|
||||
M.mark_tag2(bast, nextcontext)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Gets smallest statement or block containing or being `ast`.
|
||||
-- The AST root node `top_ast` must also be provided.
|
||||
-- Note: may decorate AST as side-effect (mark_tag2/mark_parents).
|
||||
-- top_ast is assumed a block, so this is always successful.
|
||||
-- CATEGORY: AST query
|
||||
function M.get_containing_statementblock(ast, top_ast)
|
||||
if not top_ast.tag2 then M.mark_tag2(top_ast) end
|
||||
if ast.tag2 == 'Stat' or ast.tag2 == 'StatBlock' or ast.tag2 == 'Block' then
|
||||
return ast
|
||||
else
|
||||
M.ensure_parents_marked(top_ast)
|
||||
return M.get_containing_statementblock(ast.parent, top_ast)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Finds smallest statement, block, or comment AST in ast/tokenlist containing position
|
||||
-- range [fpos, lpos]. If allowexpand is true (default nil) and located AST
|
||||
-- coincides with position range, then next containing statement is used
|
||||
-- instead (this allows multiple calls to further expand the statement selection).
|
||||
-- CATEGORY: AST query
|
||||
function M.select_statementblockcomment(ast, tokenlist, fpos, lpos, allowexpand)
|
||||
--IMPROVE: rename ast to top_ast
|
||||
local match_ast, comment_ast = M.smallest_ast_containing_range(ast, tokenlist, fpos, lpos)
|
||||
local select_ast = comment_ast or M.get_containing_statementblock(match_ast, ast)
|
||||
local nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist)
|
||||
--DEBUG('s', nfpos, nlpos, fpos, lpos, match_ast.tag, select_ast.tag)
|
||||
if allowexpand and fpos == nfpos and lpos == nlpos then
|
||||
if comment_ast then
|
||||
-- Select enclosing statement.
|
||||
select_ast = match_ast
|
||||
nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist)
|
||||
else
|
||||
-- note: multiple times may be needed to expand selection. For example, in
|
||||
-- `for x=1,2 do f() end` both the statement `f()` and block `f()` have
|
||||
-- the same position range.
|
||||
M.ensure_parents_marked(ast)
|
||||
while select_ast.parent and fpos == nfpos and lpos == nlpos do
|
||||
select_ast = M.get_containing_statementblock(select_ast.parent, ast)
|
||||
nfpos, nlpos = M.ast_pos_range(select_ast, tokenlist)
|
||||
end
|
||||
end
|
||||
end
|
||||
return nfpos, nlpos
|
||||
end
|
||||
|
||||
|
||||
-- Converts tokenlist to string representation for debugging.
|
||||
-- CATEGORY: tokenlist debug
|
||||
function M.dump_tokenlist(tokenlist)
|
||||
local ts = {}
|
||||
for i,token in ipairs(tokenlist) do
|
||||
ts[#ts+1] = 'tok.' .. i .. ': [' .. token.fpos .. ',' .. token.lpos .. '] '
|
||||
.. tostring(token[1]) .. ' ' .. tostring(token.ast.tag)
|
||||
end
|
||||
return table.concat(ts, '\n') -- .. 'nbytes=' .. tokenlist.nbytes .. '\n'
|
||||
end
|
||||
|
||||
|
||||
--FIX:Q: does this handle Unicode ok?
|
||||
|
||||
--FIX?:Metalua: fails on string with escape sequence '\/'. The Reference Manual
|
||||
-- doesn't say this sequence is valid though.
|
||||
|
||||
--FIX:Metalua: In `local --[[x]] function --[[y]] f() end`,
|
||||
-- 'x' comment omitted from AST.
|
||||
|
||||
--FIX:Metalua: `do --[[x]] end` doesn't generate comments in AST.
|
||||
-- `if x then --[[x]] end` and `while 1 do --[[x]] end` generates
|
||||
-- comments in first/last of block
|
||||
|
||||
--FIX:Metalua: `--[[x]] f() --[[y]]` returns lineinfo around `f()`.
|
||||
-- `--[[x]] --[[y]]` returns lineinfo around everything.
|
||||
|
||||
--FIX:Metalua: `while 1 do --[[x]] --[[y]] end` returns first > last
|
||||
-- lineinfo for contained block
|
||||
|
||||
--FIX:Metalua: search for "PATCHED:LuaInspect" in the metalualib folder.
|
||||
|
||||
--FIX?:Metalua: loadstring parses "--x" but metalua omits the comment in the AST
|
||||
|
||||
--FIX?:Metalua: `local x` is generating `Local{{`Id{x}}, {}}`, which
|
||||
-- has no lineinfo on {}. This is contrary to the Metalua
|
||||
-- spec: `Local{ {ident+} {expr+}? }.
|
||||
-- Other things like `self` also generate no lineinfo.
|
||||
-- The ast2.lineinfo above avoids this.
|
||||
|
||||
--FIX:Metalua: Metalua shouldn't overwrite ipairs/pairs. Note: Metalua version
|
||||
-- doesn't set errorlevel correctly.
|
||||
|
||||
--Q:Metalua: Why does `return --[[y]] z --[[x]]` have
|
||||
-- lineinfo.first.comments, lineinfo.last.comments,
|
||||
-- plus lineinfo.comments (which is the same as lineinfo.first.comments) ?
|
||||
|
||||
--CAUTION:Metalua: `do f() end` returns lineinfo around `do f() end`, while
|
||||
-- `while 1 do f() end` returns lineinfo around `f()` for inner block.
|
||||
|
||||
--CAUTION:Metalua: The lineinfo on Metalua comments is inconsistent with other
|
||||
-- nodes
|
||||
|
||||
--CAUTION:Metalua: lineinfo of table in `f{}` is [3,2], of `f{ x,y }` it's [4,6].
|
||||
-- This is inconsistent with `x={}` which is [3,4] and `f""` which is [1,2]
|
||||
-- for the string.
|
||||
|
||||
--CAUTION:Metalua: only the `function()` form of `Function includes `function`
|
||||
-- in lineinfo. 'function' is part of `Localrec and `Set in syntactic sugar form.
|
||||
|
||||
|
||||
--[=[TESTSUITE
|
||||
-- test longest_prefix/longest_postfix
|
||||
local function pr(text1, text2)
|
||||
local lastv
|
||||
local function same(v)
|
||||
assert(not lastv or v == lastv); lastv = v; return v
|
||||
end
|
||||
local function test1(text1, text2) -- test prefix/postfix
|
||||
same(longest_prefix(text1, text2))
|
||||
same(longest_postfix(text1:reverse(), text2:reverse()))
|
||||
end
|
||||
local function test2(text1, text2) -- test swap
|
||||
test1(text1, text2)
|
||||
test1(text2, text1)
|
||||
end
|
||||
for _,extra in ipairs{"", "x", "xy", "xyz"} do -- test extra chars
|
||||
test2(text1, text2..extra)
|
||||
test2(text2, text1..extra)
|
||||
end
|
||||
return lastv
|
||||
end
|
||||
check('==', pr("",""), 0)
|
||||
check('==', pr("a",""), 0)
|
||||
check('==', pr("a","a"), 1)
|
||||
check('==', pr("ab",""), 0)
|
||||
check('==', pr("ab","a"), 1)
|
||||
check('==', pr("ab","ab"), 2)
|
||||
check('==', pr("abcdefg","abcdefgh"), 7)
|
||||
--]=]
|
||||
|
||||
--[=[TESTSUITE
|
||||
print 'DONE'
|
||||
--]=]
|
||||
|
||||
|
||||
return M
|
||||
390
lualibs/luainspect/compat_env.lua
Normal file
390
lualibs/luainspect/compat_env.lua
Normal file
@@ -0,0 +1,390 @@
|
||||
--[[
|
||||
|
||||
compat_env v$(_VERSION) - Lua 5.1/5.2 environment compatibility functions
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
-- Get load/loadfile compatibility functions only if using 5.1.
|
||||
local CL = pcall(load, '') and _G or require 'compat_env'
|
||||
local load = CL.load
|
||||
local loadfile = CL.loadfile
|
||||
|
||||
-- The following now works in both Lua 5.1 and 5.2:
|
||||
assert(load('return 2*pi', nil, 't', {pi=math.pi}))()
|
||||
assert(loadfile('ex.lua', 't', {print=print}))()
|
||||
|
||||
-- Get getfenv/setfenv compatibility functions only if using 5.2.
|
||||
local getfenv = _G.getfenv or require 'compat_env'.getfenv
|
||||
local setfenv = _G.setfenv or require 'compat_env'.setfenv
|
||||
local function f() return x end
|
||||
setfenv(f, {x=2})
|
||||
print(x, getfenv(f).x) --> 2, 2
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
This module provides Lua 5.1/5.2 environment related compatibility functions.
|
||||
This includes implementations of Lua 5.2 style `load` and `loadfile`
|
||||
for use in Lua 5.1. It also includes Lua 5.1 style `getfenv` and `setfenv`
|
||||
for use in Lua 5.2.
|
||||
|
||||
API
|
||||
|
||||
local CL = require 'compat_env'
|
||||
|
||||
CL.load (ld [, source [, mode [, env] ] ]) --> f [, err]
|
||||
|
||||
This behaves the same as the Lua 5.2 `load` in both
|
||||
Lua 5.1 and 5.2.
|
||||
http://www.lua.org/manual/5.2/manual.html#pdf-load
|
||||
|
||||
CL.loadfile ([filename [, mode [, env] ] ]) --> f [, err]
|
||||
|
||||
This behaves the same as the Lua 5.2 `loadfile` in both
|
||||
Lua 5.1 and 5.2.
|
||||
http://www.lua.org/manual/5.2/manual.html#pdf-loadfile
|
||||
|
||||
CL.getfenv ([f]) --> t
|
||||
|
||||
This is identical to the Lua 5.1 `getfenv` in Lua 5.1.
|
||||
This behaves similar to the Lua 5.1 `getfenv` in Lua 5.2.
|
||||
When a global environment is to be returned, or when `f` is a
|
||||
C function, this returns `_G` since Lua 5.2 doesn't have
|
||||
(thread) global and C function environments. This will also
|
||||
return `_G` if the Lua function `f` lacks an `_ENV`
|
||||
upvalue, but it will raise an error if uncertain due to lack of
|
||||
debug info. It is not normally considered good design to use
|
||||
this function; when possible, use `load` or `loadfile` instead.
|
||||
http://www.lua.org/manual/5.1/manual.html#pdf-getfenv
|
||||
|
||||
CL.setfenv (f, t)
|
||||
|
||||
This is identical to the Lua 5.1 `setfenv` in Lua 5.1.
|
||||
This behaves similar to the Lua 5.1 `setfenv` in Lua 5.2.
|
||||
This will do nothing if `f` is a Lua function that
|
||||
lacks an `_ENV` upvalue, but it will raise an error if uncertain
|
||||
due to lack of debug info. See also Design Notes below.
|
||||
It is not normally considered good design to use
|
||||
this function; when possible, use `load` or `loadfile` instead.
|
||||
http://www.lua.org/manual/5.1/manual.html#pdf-setfenv
|
||||
|
||||
DESIGN NOTES
|
||||
|
||||
This module intends to provide robust and fairly complete reimplementations
|
||||
of the environment related Lua 5.1 and Lua 5.2 functions.
|
||||
No effort is made, however, to simulate rare or difficult to simulate features,
|
||||
such as thread environments, although this is liable to change in the future.
|
||||
Such 5.1 capabilities are discouraged and ideally
|
||||
removed from 5.1 code, thereby allowing your code to work in both 5.1 and 5.2.
|
||||
|
||||
In Lua 5.2, a `setfenv(f, {})`, where `f` lacks any upvalues, will be silently
|
||||
ignored since there is no `_ENV` in this function to write to, and the
|
||||
environment will have no effect inside the function anyway. However,
|
||||
this does mean that `getfenv(setfenv(f, t))` does not necessarily equal `t`,
|
||||
which is incompatible with 5.1 code (a possible workaround would be [1]).
|
||||
If `setfenv(f, {})` has an upvalue but no debug info, then this will raise
|
||||
an error to prevent inadvertently executing potentially untrusted code in the
|
||||
global environment.
|
||||
|
||||
It is not normally considered good design to use `setfenv` and `getfenv`
|
||||
(one reason they were removed in 5.2). When possible, consider replacing
|
||||
these with `load` or `loadfile`, which are more restrictive and have native
|
||||
implementations in 5.2.
|
||||
|
||||
This module might be merged into a more general Lua 5.1/5.2 compatibility
|
||||
library (e.g. a full reimplementation of Lua 5.2 `_G`). However,
|
||||
`load/loadfile/getfenv/setfenv` perhaps are among the more cumbersome
|
||||
functions not to have.
|
||||
|
||||
INSTALLATION
|
||||
|
||||
Download compat_env.lua:
|
||||
|
||||
wget https://raw.github.com/gist/1654007/compat_env.lua
|
||||
|
||||
Copy compat_env.lua into your LUA_PATH.
|
||||
|
||||
Alternately, unpack, test, and install into LuaRocks:
|
||||
|
||||
wget https://raw.github.com/gist/1422205/sourceunpack.lua
|
||||
lua sourceunpack.lua compat_env.lua
|
||||
(cd out && luarocks make)
|
||||
|
||||
Related work
|
||||
|
||||
http://lua-users.org/wiki/LuaVersionCompatibility
|
||||
https://github.com/stevedonovan/Penlight/blob/master/lua/pl/utils.lua
|
||||
- penlight implementations of getfenv/setfenv
|
||||
http://lua-users.org/lists/lua-l/2010-06/msg00313.html
|
||||
- initial getfenv/setfenv implementation
|
||||
|
||||
References
|
||||
|
||||
[1] http://lua-users.org/lists/lua-l/2010-06/msg00315.html
|
||||
|
||||
Copyright
|
||||
|
||||
(c) 2012 David Manura. Licensed under the same terms as Lua 5.1/5.2 (MIT license).
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
--]]---------------------------------------------------------------------
|
||||
|
||||
local M = {_TYPE='module', _NAME='compat_env', _VERSION='0.2.20120124'}
|
||||
|
||||
local function check_chunk_type(s, mode)
|
||||
local nmode = mode or 'bt'
|
||||
local is_binary = s and #s > 0 and s:byte(1) == 27
|
||||
if is_binary and not nmode:match'b' then
|
||||
return nil, ("attempt to load a binary chunk (mode is '%s')"):format(mode)
|
||||
elseif not is_binary and not nmode:match't' then
|
||||
return nil, ("attempt to load a text chunk (mode is '%s')"):format(mode)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local IS_52_LOAD = pcall(load, '')
|
||||
if IS_52_LOAD then
|
||||
M.load = _G.load
|
||||
M.loadfile = _G.loadfile
|
||||
else
|
||||
-- 5.2 style `load` implemented in 5.1
|
||||
function M.load(ld, source, mode, env)
|
||||
local f
|
||||
if type(ld) == 'string' then
|
||||
local s = ld
|
||||
local ok, err = check_chunk_type(s, mode); if not ok then return ok, err end
|
||||
local err; f, err = loadstring(s, source); if not f then return f, err end
|
||||
elseif type(ld) == 'function' then
|
||||
local ld2 = ld
|
||||
if (mode or 'bt') ~= 'bt' then
|
||||
local first = ld()
|
||||
local ok, err = check_chunk_type(first, mode); if not ok then return ok, err end
|
||||
ld2 = function()
|
||||
if first then
|
||||
local chunk=first; first=nil; return chunk
|
||||
else return ld() end
|
||||
end
|
||||
end
|
||||
local err; f, err = load(ld2, source); if not f then return f, err end
|
||||
else
|
||||
error(("bad argument #1 to 'load' (function expected, got %s)"):format(type(ld)), 2)
|
||||
end
|
||||
if env then setfenv(f, env) end
|
||||
return f
|
||||
end
|
||||
|
||||
-- 5.2 style `loadfile` implemented in 5.1
|
||||
function M.loadfile(filename, mode, env)
|
||||
if (mode or 'bt') ~= 'bt' then
|
||||
local ioerr
|
||||
local fh, err = io.open(filename, 'rb'); if not fh then return fh, err end
|
||||
local function ld() local chunk; chunk,ioerr = fh:read(4096); return chunk end
|
||||
local f, err = M.load(ld, filename and '@'..filename, mode, env)
|
||||
fh:close()
|
||||
if not f then return f, err end
|
||||
if ioerr then return nil, ioerr end
|
||||
return f
|
||||
else
|
||||
local f, err = loadfile(filename); if not f then return f, err end
|
||||
if env then setfenv(f, env) end
|
||||
return f
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if _G.setfenv then -- Lua 5.1
|
||||
M.setfenv = _G.setfenv
|
||||
M.getfenv = _G.getfenv
|
||||
else -- >= Lua 5.2
|
||||
-- helper function for `getfenv`/`setfenv`
|
||||
local function envlookup(f)
|
||||
local name, val
|
||||
local up = 0
|
||||
local unknown
|
||||
repeat
|
||||
up=up+1; name, val = debug.getupvalue(f, up)
|
||||
if name == '' then unknown = true end
|
||||
until name == '_ENV' or name == nil
|
||||
if name ~= '_ENV' then
|
||||
up = nil
|
||||
if unknown then error("upvalues not readable in Lua 5.2 when debug info missing", 3) end
|
||||
end
|
||||
return (name == '_ENV') and up, val, unknown
|
||||
end
|
||||
|
||||
-- helper function for `getfenv`/`setfenv`
|
||||
local function envhelper(f, name)
|
||||
if type(f) == 'number' then
|
||||
if f < 0 then
|
||||
error(("bad argument #1 to '%s' (level must be non-negative)"):format(name), 3)
|
||||
elseif f < 1 then
|
||||
error("thread environments unsupported in Lua 5.2", 3) --[*]
|
||||
end
|
||||
f = debug.getinfo(f+2, 'f').func
|
||||
elseif type(f) ~= 'function' then
|
||||
error(("bad argument #1 to '%s' (number expected, got %s)"):format(type(name, f)), 2)
|
||||
end
|
||||
return f
|
||||
end
|
||||
-- [*] might simulate with table keyed by coroutine.running()
|
||||
|
||||
-- 5.1 style `setfenv` implemented in 5.2
|
||||
function M.setfenv(f, t)
|
||||
local f = envhelper(f, 'setfenv')
|
||||
local up, val, unknown = envlookup(f)
|
||||
if up then
|
||||
debug.upvaluejoin(f, up, function() return up end, 1) -- unique upvalue [*]
|
||||
debug.setupvalue(f, up, t)
|
||||
else
|
||||
local what = debug.getinfo(f, 'S').what
|
||||
if what ~= 'Lua' and what ~= 'main' then -- not Lua func
|
||||
error("'setfenv' cannot change environment of given object", 2)
|
||||
end -- else ignore no _ENV upvalue (warning: incompatible with 5.1)
|
||||
end
|
||||
end
|
||||
-- [*] http://lua-users.org/lists/lua-l/2010-06/msg00313.html
|
||||
|
||||
-- 5.1 style `getfenv` implemented in 5.2
|
||||
function M.getfenv(f)
|
||||
if f == 0 or f == nil then return _G end -- simulated behavior
|
||||
local f = envhelper(f, 'setfenv')
|
||||
local up, val = envlookup(f)
|
||||
if not up then return _G end -- simulated behavior [**]
|
||||
return val
|
||||
end
|
||||
-- [**] possible reasons: no _ENV upvalue, C function
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
|
||||
--[[ FILE rockspec.in
|
||||
|
||||
package = 'compat_env'
|
||||
version = '$(_VERSION)-1'
|
||||
source = {
|
||||
url = 'https://raw.github.com/gist/1654007/$(GITID)/compat_env.lua',
|
||||
--url = 'https://raw.github.com/gist/1654007/compat_env.lua', -- latest raw
|
||||
--url = 'https://gist.github.com/gists/1654007/download',
|
||||
md5 = '$(MD5)'
|
||||
}
|
||||
description = {
|
||||
summary = 'Lua 5.1/5.2 environment compatibility functions',
|
||||
detailed = [=[
|
||||
Provides Lua 5.1/5.2 environment related compatibility functions.
|
||||
This includes implementations of Lua 5.2 style `load` and `loadfile`
|
||||
for use in Lua 5.1. It also includes Lua 5.1 style `getfenv` and `setfenv`
|
||||
for use in Lua 5.2.
|
||||
]=],
|
||||
license = 'MIT/X11',
|
||||
homepage = 'https://gist.github.com/1654007',
|
||||
maintainer = 'David Manura'
|
||||
}
|
||||
dependencies = {} -- Lua 5.1 or 5.2
|
||||
build = {
|
||||
type = 'builtin',
|
||||
modules = {
|
||||
['compat_env'] = 'compat_env.lua'
|
||||
}
|
||||
}
|
||||
|
||||
--]]---------------------------------------------------------------------
|
||||
|
||||
--[[ FILE test.lua
|
||||
|
||||
-- test.lua - test suite for compat_env module.
|
||||
|
||||
local CL = require 'compat_env'
|
||||
local load = CL.load
|
||||
local loadfile = CL.loadfile
|
||||
local setfenv = CL.setfenv
|
||||
local getfenv = CL.getfenv
|
||||
|
||||
local function checkeq(a, b, e)
|
||||
if a ~= b then error(
|
||||
'not equal ['..tostring(a)..'] ['..tostring(b)..'] ['..tostring(e)..']')
|
||||
end
|
||||
end
|
||||
local function checkerr(pat, ok, err)
|
||||
assert(not ok, 'checkerr')
|
||||
assert(type(err) == 'string' and err:match(pat), err)
|
||||
end
|
||||
|
||||
-- test `load`
|
||||
checkeq(load('return 2')(), 2)
|
||||
checkerr('expected near', load'return 2 2')
|
||||
checkerr('text chunk', load('return 2', nil, 'b'))
|
||||
checkerr('text chunk', load('', nil, 'b'))
|
||||
checkerr('binary chunk', load('\027', nil, 't'))
|
||||
checkeq(load('return 2*x',nil,'bt',{x=5})(), 10)
|
||||
checkeq(debug.getinfo(load('')).source, '')
|
||||
checkeq(debug.getinfo(load('', 'foo')).source, 'foo')
|
||||
|
||||
-- test `loadfile`
|
||||
local fh = assert(io.open('tmp.lua', 'wb'))
|
||||
fh:write('return (...) or x')
|
||||
fh:close()
|
||||
checkeq(loadfile('tmp.lua')(2), 2)
|
||||
checkeq(loadfile('tmp.lua', 't')(2), 2)
|
||||
checkerr('text chunk', loadfile('tmp.lua', 'b'))
|
||||
checkeq(loadfile('tmp.lua', nil, {x=3})(), 3)
|
||||
checkeq(debug.getinfo(loadfile('tmp.lua')).source, '@tmp.lua')
|
||||
checkeq(debug.getinfo(loadfile('tmp.lua', 't', {})).source, '@tmp.lua')
|
||||
os.remove'tmp.lua'
|
||||
|
||||
-- test `setfenv`/`getfenv`
|
||||
x = 5
|
||||
local a,b=true; local function f(c) if a then return x,b,c end end
|
||||
setfenv(f, {x=3})
|
||||
checkeq(f(), 3)
|
||||
checkeq(getfenv(f).x, 3)
|
||||
checkerr('cannot change', pcall(setfenv, string.len, {})) -- C function
|
||||
checkeq(getfenv(string.len), _G) -- C function
|
||||
local function g()
|
||||
setfenv(1, {x=4})
|
||||
checkeq(getfenv(1).x, 4)
|
||||
return x
|
||||
end
|
||||
checkeq(g(), 4) -- numeric level
|
||||
if _G._VERSION ~= 'Lua 5.1' then
|
||||
checkerr('unsupported', pcall(setfenv, 0, {}))
|
||||
end
|
||||
checkeq(getfenv(0), _G)
|
||||
checkeq(getfenv(), _G) -- no arg
|
||||
checkeq(x, 5) -- main unaltered
|
||||
setfenv(function()end, {}) -- no upvalues, ignore
|
||||
checkeq(getfenv(function()end), _G) -- no upvaluse
|
||||
if _G._VERSION ~= 'Lua 5.1' then
|
||||
checkeq(getfenv(setfenv(function()end, {})), _G) -- warning: incompatible with 5.1
|
||||
end
|
||||
x = nil
|
||||
|
||||
print 'OK'
|
||||
|
||||
--]]---------------------------------------------------------------------
|
||||
|
||||
--[[ FILE CHANGES.txt
|
||||
0.2.20120124
|
||||
Renamed module to compat_env (from compat_load)
|
||||
Add getfenv/setfenv functions
|
||||
|
||||
0.1.20120121
|
||||
Initial public release
|
||||
--]]
|
||||
|
||||
90
lualibs/luainspect/dump.lua
Normal file
90
lualibs/luainspect/dump.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
-- Recursive object dumper, for debugging.
|
||||
-- (c) 2010 David Manura, MIT License.
|
||||
|
||||
local M = {}
|
||||
|
||||
-- My own object dumper.
|
||||
-- Intended for debugging, not serialization, with compact formatting.
|
||||
-- Robust against recursion.
|
||||
-- Renders Metalua table tag fields specially {tag=X, ...} --> "`X{...}".
|
||||
-- On first call, only pass parameter o.
|
||||
-- CATEGORY: AST debug
|
||||
local ignore_keys_ = {lineinfo=true}
|
||||
local norecurse_keys_ = {parent=true, ast=true}
|
||||
local function dumpstring_key_(k, isseen, newindent)
|
||||
local ks = type(k) == 'string' and k:match'^[%a_][%w_]*$' and k or
|
||||
'[' .. M.dumpstring(k, isseen, newindent) .. ']'
|
||||
return ks
|
||||
end
|
||||
local function sort_keys_(a, b)
|
||||
if type(a) == 'number' and type(b) == 'number' then
|
||||
return a < b
|
||||
elseif type(a) == 'number' then
|
||||
return false
|
||||
elseif type(b) == 'number' then
|
||||
return true
|
||||
elseif type(a) == 'string' and type(b) == 'string' then
|
||||
return a < b
|
||||
else
|
||||
return tostring(a) < tostring(b) -- arbitrary
|
||||
end
|
||||
end
|
||||
function M.dumpstring(o, isseen, indent, key)
|
||||
isseen = isseen or {}
|
||||
indent = indent or ''
|
||||
|
||||
if type(o) == 'table' then
|
||||
if isseen[o] or norecurse_keys_[key] then
|
||||
return (type(o.tag) == 'string' and '`' .. o.tag .. ':' or '') .. tostring(o)
|
||||
else isseen[o] = true end -- avoid recursion
|
||||
|
||||
local used = {}
|
||||
|
||||
local tag = o.tag
|
||||
local s = '{'
|
||||
if type(o.tag) == 'string' then
|
||||
s = '`' .. tag .. s; used['tag'] = true
|
||||
end
|
||||
local newindent = indent .. ' '
|
||||
|
||||
local ks = {}; for k in pairs(o) do ks[#ks+1] = k end
|
||||
table.sort(ks, sort_keys_)
|
||||
--for i,k in ipairs(ks) do print ('keys', k) end
|
||||
|
||||
local forcenummultiline
|
||||
for k in pairs(o) do
|
||||
if type(k) == 'number' and type(o[k]) == 'table' then forcenummultiline = true end
|
||||
end
|
||||
|
||||
-- inline elements
|
||||
for _,k in ipairs(ks) do
|
||||
if used[k] then -- skip
|
||||
elseif ignore_keys_[k] then used[k] = true
|
||||
elseif (type(k) ~= 'number' or not forcenummultiline) and
|
||||
type(k) ~= 'table' and (type(o[k]) ~= 'table' or norecurse_keys_[k])
|
||||
then
|
||||
s = s .. dumpstring_key_(k, isseen, newindent) .. '=' .. M.dumpstring(o[k], isseen, newindent, k) .. ', '
|
||||
used[k] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- elements on separate lines
|
||||
local done
|
||||
for _,k in ipairs(ks) do
|
||||
if not used[k] then
|
||||
if not done then s = s .. '\n'; done = true end
|
||||
s = s .. newindent .. dumpstring_key_(k, isseen) .. '=' .. M.dumpstring(o[k], isseen, newindent, k) .. ',\n'
|
||||
end
|
||||
end
|
||||
s = s:gsub(',(%s*)$', '%1')
|
||||
s = s .. (done and indent or '') .. '}'
|
||||
return s
|
||||
elseif type(o) == 'string' then
|
||||
return string.format('%q', o)
|
||||
else
|
||||
return tostring(o)
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
222
lualibs/luainspect/globals.lua
Normal file
222
lualibs/luainspect/globals.lua
Normal file
@@ -0,0 +1,222 @@
|
||||
-- LuaInspect.globals - identifier scope analysis
|
||||
-- Locates locals, globals, and their definitions.
|
||||
--
|
||||
-- (c) D.Manura, 2008-2010, MIT license.
|
||||
|
||||
-- based on http://lua-users.org/wiki/DetectingUndefinedVariables
|
||||
|
||||
local M = {}
|
||||
|
||||
--! require 'luainspect.typecheck' (context)
|
||||
|
||||
local LA = require "luainspect.ast"
|
||||
|
||||
local function definelocal(scope, name, ast)
|
||||
if scope[name] then
|
||||
scope[name].localmasked = true
|
||||
ast.localmasking = scope[name]
|
||||
end
|
||||
scope[name] = ast
|
||||
if name == '_' then ast.isignore = true end
|
||||
end
|
||||
|
||||
-- Resolves scoping and usages of variable in AST.
|
||||
-- Data Notes:
|
||||
-- ast.localdefinition refers to lexically scoped definition of `Id node `ast`.
|
||||
-- If ast.localdefinition == ast then ast is a "lexical definition".
|
||||
-- If ast.localdefinition == nil, then variable is global.
|
||||
-- ast.functionlevel is the number of functions the AST is contained in.
|
||||
-- ast.functionlevel is defined iff ast is a lexical definition.
|
||||
-- ast.isparam is true iff ast is a lexical definition and a function parameter.
|
||||
-- ast.isset is true iff ast is a lexical definition and exists an assignment on it.
|
||||
-- ast.isused is true iff ast is a lexical definition and has been referred to.
|
||||
-- ast.isignore is true if local variable should be ignored (e.g. typically "_")
|
||||
-- ast.localmasking - for a lexical definition, this is set to the lexical definition
|
||||
-- this is masking (i.e. same name). nil if not masking.
|
||||
-- ast.localmasked - true iff lexical definition masked by another lexical definition.
|
||||
-- ast.isfield is true iff `String node ast is used for field access on object,
|
||||
-- e.g. x.y or x['y'].z
|
||||
-- ast.previous - For `Index{o,s} or `Invoke{o,s,...}, s.previous == o
|
||||
local function traverse(ast, scope, globals, level, functionlevel)
|
||||
scope = scope or {}
|
||||
|
||||
local blockrecurse
|
||||
ast.level = level
|
||||
|
||||
-- operations on walking down the AST
|
||||
if ast.tag == 'Local' then
|
||||
blockrecurse = 1
|
||||
-- note: apply new scope after processing values
|
||||
elseif ast.tag == 'Localrec' then
|
||||
local namelist_ast, valuelist_ast = ast[1], ast[2]
|
||||
for _,value_ast in ipairs(namelist_ast) do
|
||||
assert(value_ast.tag == 'Id')
|
||||
local name = value_ast[1]
|
||||
local parentscope = getmetatable(scope).__index
|
||||
definelocal(parentscope, name, value_ast)
|
||||
value_ast.localdefinition = value_ast
|
||||
value_ast.functionlevel = functionlevel
|
||||
value_ast.level = level+1
|
||||
end
|
||||
blockrecurse = 1
|
||||
elseif ast.tag == 'Id' then
|
||||
local name = ast[1]
|
||||
if scope[name] then
|
||||
ast.localdefinition = scope[name]
|
||||
ast.functionlevel = functionlevel
|
||||
scope[name].isused = true
|
||||
else -- global, do nothing
|
||||
end
|
||||
elseif ast.tag == 'Function' then
|
||||
local paramlist_ast, body_ast = ast[1], ast[2]
|
||||
functionlevel = functionlevel + 1
|
||||
for _,param_ast in ipairs(paramlist_ast) do
|
||||
local name = param_ast[1]
|
||||
assert(param_ast.tag == 'Id' or param_ast.tag == 'Dots')
|
||||
if param_ast.tag == 'Id' then
|
||||
definelocal(scope, name, param_ast)
|
||||
param_ast.localdefinition = param_ast
|
||||
param_ast.functionlevel = functionlevel
|
||||
param_ast.isparam = true
|
||||
end
|
||||
param_ast.level = level+1
|
||||
end
|
||||
blockrecurse = 1
|
||||
elseif ast.tag == 'Set' then
|
||||
local reflist_ast, valuelist_ast = ast[1], ast[2]
|
||||
for _,ref_ast in ipairs(reflist_ast) do
|
||||
if ref_ast.tag == 'Id' then
|
||||
local name = ref_ast[1]
|
||||
if scope[name] then
|
||||
scope[name].isset = true
|
||||
else
|
||||
if not globals[name] then
|
||||
globals[name] = {set=ref_ast}
|
||||
end
|
||||
end
|
||||
end
|
||||
ref_ast.level = level+1
|
||||
end
|
||||
--ENHANCE? We could differentiate assignments to x (which indicates that
|
||||
-- x is not const) and assignments to a member of x (which indicates that
|
||||
-- x is not a pointer to const) and assignments to any nested member of x
|
||||
-- (which indicates that x it not a transitive const).
|
||||
elseif ast.tag == 'Fornum' then
|
||||
blockrecurse = 1
|
||||
elseif ast.tag == 'Forin' then
|
||||
blockrecurse = 1
|
||||
end
|
||||
|
||||
-- recurse (depth-first search down the AST)
|
||||
if ast.tag == 'Repeat' then
|
||||
local block_ast, cond_ast = ast[1], ast[2]
|
||||
local scope = scope
|
||||
for _,stat_ast in ipairs(block_ast) do
|
||||
scope = setmetatable({}, {__index = scope})
|
||||
traverse(stat_ast, scope, globals, level+1, functionlevel)
|
||||
end
|
||||
scope = setmetatable({}, {__index = scope})
|
||||
traverse(cond_ast, scope, globals, level+1, functionlevel)
|
||||
elseif ast.tag == 'Fornum' then
|
||||
local name_ast, block_ast = ast[1], ast[#ast]
|
||||
-- eval value list in current scope
|
||||
for i=2, #ast-1 do traverse(ast[i], scope, globals, level+1, functionlevel) end
|
||||
-- eval body in next scope
|
||||
local name = name_ast[1]
|
||||
definelocal(scope, name, name_ast)
|
||||
name_ast.localdefinition = name_ast
|
||||
name_ast.functionlevel = functionlevel
|
||||
traverse(block_ast, scope, globals, level+1, functionlevel)
|
||||
elseif ast.tag == 'Forin' then
|
||||
local namelist_ast, vallist_ast, block_ast = ast[1], ast[2], ast[3]
|
||||
-- eval value list in current scope
|
||||
traverse(vallist_ast, scope, globals, level+1, functionlevel)
|
||||
-- eval body in next scope
|
||||
for _,name_ast in ipairs(namelist_ast) do
|
||||
local name = name_ast[1]
|
||||
definelocal(scope, name, name_ast)
|
||||
name_ast.localdefinition = name_ast
|
||||
name_ast.functionlevel = functionlevel
|
||||
name_ast.level = level+1
|
||||
end
|
||||
traverse(block_ast, scope, globals, level+1, functionlevel)
|
||||
else -- normal
|
||||
for i,v in ipairs(ast) do
|
||||
if i ~= blockrecurse and type(v) == 'table' then
|
||||
local scope = setmetatable({}, {__index = scope})
|
||||
traverse(v, scope, globals, level+1, functionlevel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- operations on walking up the AST
|
||||
if ast.tag == 'Local' then
|
||||
-- Unlike Localrec, variables come into scope after evaluating values.
|
||||
local namelist_ast, valuelist_ast = ast[1], ast[2]
|
||||
for _,name_ast in ipairs(namelist_ast) do
|
||||
assert(name_ast.tag == 'Id')
|
||||
local name = name_ast[1]
|
||||
local parentscope = getmetatable(scope).__index
|
||||
definelocal(parentscope, name, name_ast)
|
||||
name_ast.localdefinition = name_ast
|
||||
name_ast.functionlevel = functionlevel
|
||||
name_ast.level = level+1
|
||||
end
|
||||
elseif ast.tag == 'Index' then
|
||||
if ast[2].tag == 'String' then
|
||||
ast[2].isfield = true
|
||||
ast[2].previous = ast[1]
|
||||
end
|
||||
elseif ast.tag == 'Invoke' then
|
||||
assert(ast[2].tag == 'String')
|
||||
ast[2].isfield = true
|
||||
ast[2].previous = ast[1]
|
||||
end
|
||||
end
|
||||
|
||||
function M.globals(ast)
|
||||
-- Default list of defined variables.
|
||||
local scope = setmetatable({}, {})
|
||||
local globals = {}
|
||||
traverse(ast, scope, globals, 1, 1) -- Start check.
|
||||
|
||||
return globals
|
||||
end
|
||||
|
||||
|
||||
-- Gets locals in scope of statement of block ast. If isafter is true and ast is statement,
|
||||
-- uses scope just after statement ast.
|
||||
-- Assumes 'parent' attributes on ast are marked.
|
||||
-- Returns table mapping name -> AST local definition.
|
||||
function M.variables_in_scope(ast, isafter)
|
||||
local scope = {}
|
||||
local cast = ast
|
||||
while cast.parent do
|
||||
local midx = LA.ast_idx(cast.parent, cast)
|
||||
for idx=1,midx do
|
||||
local bast = cast.parent[idx]
|
||||
if bast.tag == 'Localrec' or bast.tag == 'Local' and (idx < midx or isafter) then
|
||||
local names_ast = bast[1]
|
||||
for bidx=1,#names_ast do
|
||||
local name_ast = names_ast[bidx]
|
||||
local name = name_ast[1]
|
||||
scope[name] = name_ast
|
||||
end
|
||||
elseif cast ~= ast and (bast.tag == 'For' or bast.tag == 'Forin' or bast.tag == 'Function') then
|
||||
local names_ast = bast[1]
|
||||
for bidx=1,#names_ast do
|
||||
local name_ast = names_ast[bidx]
|
||||
if name_ast.tag == 'Id' then --Q: or maybe `Dots should be included
|
||||
local name = name_ast[1]
|
||||
scope[name] = name_ast
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
cast = cast.parent
|
||||
end
|
||||
return scope
|
||||
end
|
||||
|
||||
|
||||
return M
|
||||
1431
lualibs/luainspect/init.lua
Normal file
1431
lualibs/luainspect/init.lua
Normal file
File diff suppressed because it is too large
Load Diff
433
lualibs/luainspect/signatures.lua
Normal file
433
lualibs/luainspect/signatures.lua
Normal file
@@ -0,0 +1,433 @@
|
||||
local M = {}
|
||||
|
||||
local T = require "luainspect.types"
|
||||
|
||||
-- signatures of known globals
|
||||
M.global_signatures = {
|
||||
assert = "assert (v [, message])",
|
||||
collectgarbage = "collectgarbage (opt [, arg])",
|
||||
dofile = "dofile (filename)",
|
||||
error = "error (message [, level])",
|
||||
_G = "(table)",
|
||||
getfenv = "getfenv ([f])",
|
||||
getmetatable = "getmetatable (object)",
|
||||
ipairs = "ipairs (t)",
|
||||
load = "load (func [, chunkname])",
|
||||
loadfile = "loadfile ([filename])",
|
||||
loadstring = "loadstring (string [, chunkname])",
|
||||
next = "next (table [, index])",
|
||||
pairs = "pairs (t)",
|
||||
pcall = "pcall (f, arg1, ...)",
|
||||
print = "print (...)",
|
||||
rawequal = "rawequal (v1, v2)",
|
||||
rawget = "rawget (table, index)",
|
||||
rawset = "rawset (table, index, value)",
|
||||
select = "select (index, ...)",
|
||||
setfenv = "setfenv (f, table)",
|
||||
setmetatable = "setmetatable (table, metatable)",
|
||||
tonumber = "tonumber (e [, base])",
|
||||
tostring = "tostring (e)",
|
||||
type = "type (v)",
|
||||
unpack = "unpack (list [, i [, j]])",
|
||||
_VERSION = "(string)",
|
||||
xpcall = "xpcall (f, err)",
|
||||
module = "module (name [, ...])",
|
||||
require = "require (modname)",
|
||||
coroutine = "(table) coroutine manipulation library",
|
||||
debug = "(table) debug facilities library",
|
||||
io = "(table) I/O library",
|
||||
math = "(table) math functions libary",
|
||||
os = "(table) OS facilities library",
|
||||
package = "(table) package library",
|
||||
string = "(table) string manipulation library",
|
||||
table = "(table) table manipulation library",
|
||||
["coroutine.create"] = "coroutine.create (f)",
|
||||
["coroutine.resume"] = "coroutine.resume (co [, val1, ...])",
|
||||
["coroutine.running"] = "coroutine.running ()",
|
||||
["coroutine.status"] = "coroutine.status (co)",
|
||||
["coroutine.wrap"] = "coroutine.wrap (f)",
|
||||
["coroutine.yield"] = "coroutine.yield (...)",
|
||||
["debug.debug"] = "debug.debug ()",
|
||||
["debug.getfenv"] = "debug.getfenv (o)",
|
||||
["debug.gethook"] = "debug.gethook ([thread])",
|
||||
["debug.getinfo"] = "debug.getinfo ([thread,] function [, what])",
|
||||
["debug.getlocal"] = "debug.getlocal ([thread,] level, local)",
|
||||
["debug.getmetatable"] = "debug.getmetatable (object)",
|
||||
["debug.getregistry"] = "debug.getregistry ()",
|
||||
["debug.getupvalue"] = "debug.getupvalue (func, up)",
|
||||
["debug.setfenv"] = "debug.setfenv (object, table)",
|
||||
["debug.sethook"] = "debug.sethook ([thread,] hook, mask [, count])",
|
||||
["debug.setlocal"] = "debug.setlocal ([thread,] level, local, value)",
|
||||
["debug.setmetatable"] = "debug.setmetatable (object, table)",
|
||||
["debug.setupvalue"] = "debug.setupvalue (func, up, value)",
|
||||
["debug.traceback"] = "debug.traceback ([thread,] [message] [, level])",
|
||||
["io.close"] = "io.close ([file])",
|
||||
["io.flush"] = "io.flush ()",
|
||||
["io.input"] = "io.input ([file])",
|
||||
["io.lines"] = "io.lines ([filename])",
|
||||
["io.open"] = "io.open (filename [, mode])",
|
||||
["io.output"] = "io.output ([file])",
|
||||
["io.popen"] = "io.popen (prog [, mode])",
|
||||
["io.read"] = "io.read (...)",
|
||||
["io.tmpfile"] = "io.tmpfile ()",
|
||||
["io.type"] = "io.type (obj)",
|
||||
["io.write"] = "io.write (...)",
|
||||
["math.abs"] = "math.abs (x)",
|
||||
["math.acos"] = "math.acos (x)",
|
||||
["math.asin"] = "math.asin (x)",
|
||||
["math.atan"] = "math.atan (x)",
|
||||
["math.atan2"] = "math.atan2 (y, x)",
|
||||
["math.ceil"] = "math.ceil (x)",
|
||||
["math.cos"] = "math.cos (x)",
|
||||
["math.cosh"] = "math.cosh (x)",
|
||||
["math.deg"] = "math.deg (x)",
|
||||
["math.exp"] = "math.exp (x)",
|
||||
["math.floor"] = "math.floor (x)",
|
||||
["math.fmod"] = "math.fmod (x, y)",
|
||||
["math.frexp"] = "math.frexp (x)",
|
||||
["math.huge"] = "math.huge",
|
||||
["math.ldexp"] = "math.ldexp (m, e)",
|
||||
["math.log"] = "math.log (x)",
|
||||
["math.log10"] = "math.log10 (x)",
|
||||
["math.max"] = "math.max (x, ...)",
|
||||
["math.min"] = "math.min (x, ...)",
|
||||
["math.modf"] = "math.modf (x)",
|
||||
["math.pi"] = "math.pi",
|
||||
["math.pow"] = "math.pow (x, y)",
|
||||
["math.rad"] = "math.rad (x)",
|
||||
["math.random"] = "math.random ([m [, n]])",
|
||||
["math.randomseed"] = "math.randomseed (x)",
|
||||
["math.sin"] = "math.sin (x)",
|
||||
["math.sinh"] = "math.sinh (x)",
|
||||
["math.sqrt"] = "math.sqrt (x)",
|
||||
["math.tan"] = "math.tan (x)",
|
||||
["math.tanh"] = "math.tanh (x)",
|
||||
["os.clock"] = "os.clock ()",
|
||||
["os.date"] = "os.date ([format [, time]])",
|
||||
["os.difftime"] = "os.difftime (t2, t1)",
|
||||
["os.execute"] = "os.execute ([command])",
|
||||
["os.exit"] = "os.exit ([code])",
|
||||
["os.getenv"] = "os.getenv (varname)",
|
||||
["os.remove"] = "os.remove (filename)",
|
||||
["os.rename"] = "os.rename (oldname, newname)",
|
||||
["os.setlocale"] = "os.setlocale (locale [, category])",
|
||||
["os.time"] = "os.time ([table])",
|
||||
["os.tmpname"] = "os.tmpname ()",
|
||||
["package.cpath"] = "package.cpath",
|
||||
["package.loaded"] = "package.loaded",
|
||||
["package.loaders"] = "package.loaders",
|
||||
["package.loadlib"] = "package.loadlib (libname, funcname)",
|
||||
["package.path"] = "package.path",
|
||||
["package.preload"] = "package.preload",
|
||||
["package.seeall"] = "package.seeall (module)",
|
||||
["string.byte"] = "string.byte (s [, i [, j]])",
|
||||
["string.char"] = "string.char (...)",
|
||||
["string.dump"] = "string.dump (function)",
|
||||
["string.find"] = "string.find (s, pattern [, init [, plain]])",
|
||||
["string.format"] = "string.format (formatstring, ...)",
|
||||
["string.gmatch"] = "string.gmatch (s, pattern)",
|
||||
["string.gsub"] = "string.gsub (s, pattern, repl [, n])",
|
||||
["string.len"] = "string.len (s)",
|
||||
["string.lower"] = "string.lower (s)",
|
||||
["string.match"] = "string.match (s, pattern [, init])",
|
||||
["string.rep"] = "string.rep (s, n)",
|
||||
["string.reverse"] = "string.reverse (s)",
|
||||
["string.sub"] = "string.sub (s, i [, j])",
|
||||
["string.upper"] = "string.upper (s)",
|
||||
["table.concat"] = "table.concat (table [, sep [, i [, j]]])",
|
||||
["table.insert"] = "table.insert (table, [pos,] value)",
|
||||
["table.maxn"] = "table.maxn (table)",
|
||||
["table.remove"] = "table.remove (table [, pos])",
|
||||
["table.sort"] = "table.sort (table [, comp])",
|
||||
}
|
||||
|
||||
-- utility function. Converts e.g. name 'math.sqrt' to its value.
|
||||
local function resolve_global_helper_(name)
|
||||
local o = _G
|
||||
for fieldname in name:gmatch'[^%.]+' do o = o[fieldname] end
|
||||
return o
|
||||
end
|
||||
local function resolve_global(name)
|
||||
local a, b = pcall(resolve_global_helper_, name)
|
||||
if a then return b else return nil, b end
|
||||
end
|
||||
|
||||
-- Same as global_signatures but maps value (not name) to signature.
|
||||
M.value_signatures = {}
|
||||
local isobject = {['function']=true, ['table']=true, ['userdata']=true, ['coroutine']=true}
|
||||
for name,sig in pairs(M.global_signatures) do
|
||||
local val, err = resolve_global(name)
|
||||
if isobject[type(val)] then
|
||||
M.value_signatures[val] = sig
|
||||
end
|
||||
end
|
||||
|
||||
-- min,max argument counts.
|
||||
M.argument_counts = {
|
||||
[assert] = {1,2},
|
||||
[collectgarbage] = {1,2},
|
||||
[dofile] = {1},
|
||||
[error] = {1,2},
|
||||
[getfenv or false] = {0,1},
|
||||
[getmetatable] = {1,1},
|
||||
[ipairs] = {1,1},
|
||||
[load] = {1,2},
|
||||
[loadfile] = {0,1},
|
||||
[loadstring] = {1,2},
|
||||
[next] = {1,2},
|
||||
[pairs] = {1,1},
|
||||
[pcall] = {1,math.huge},
|
||||
[print] = {0,math.huge},
|
||||
[rawequal] = {2,2},
|
||||
[rawget] = {2,2},
|
||||
[rawset] = {3,3},
|
||||
[select] = {1, math.huge},
|
||||
[setfenv or false] = {2,2},
|
||||
[setmetatable] = {2,2},
|
||||
[tonumber] = {1,2},
|
||||
[tostring] = {1},
|
||||
[type] = {1},
|
||||
[unpack] = {1,3},
|
||||
[xpcall] = {2,2},
|
||||
[module] = {1,math.huge},
|
||||
[require] = {1,1},
|
||||
[coroutine.create] = {1,1},
|
||||
[coroutine.resume] = {1, math.huge},
|
||||
[coroutine.running] = {0,0},
|
||||
[coroutine.status] = {1,1},
|
||||
[coroutine.wrap] = {1,1},
|
||||
[coroutine.yield] = {0,math.huge},
|
||||
[debug.debug] = {0,0},
|
||||
[debug.getfenv or false] = {1,1},
|
||||
[debug.gethook] = {0,1},
|
||||
[debug.getinfo] = {1,3},
|
||||
[debug.getlocal] = {2,3},
|
||||
[debug.getmetatable] = {1,1},
|
||||
[debug.getregistry] = {0,0},
|
||||
[debug.getupvalue] = {2,2},
|
||||
[debug.setfenv or false] = {2,2},
|
||||
[debug.sethook] = {2,4},
|
||||
[debug.setlocal] = {3,4},
|
||||
[debug.setmetatable] = {2,2},
|
||||
[debug.setupvalue] = {3,3},
|
||||
[debug.traceback] = {0,3},
|
||||
[io.close] = {0,1},
|
||||
[io.flush] = {0,0},
|
||||
[io.input] = {0,1},
|
||||
[io.lines] = {0,1},
|
||||
[io.open] = {1,2},
|
||||
[io.output] = {0,1},
|
||||
[io.popen] = {1,2},
|
||||
[io.read] = {0,math.huge},
|
||||
[io.tmpfile] = {0},
|
||||
[io.type] = {1},
|
||||
[io.write] = {0,math.huge},
|
||||
[math.abs] = {1},
|
||||
[math.acos] = {1},
|
||||
[math.asin] = {1},
|
||||
[math.atan] = {1},
|
||||
[math.atan2] = {2,2},
|
||||
[math.ceil] = {1,1},
|
||||
[math.cos] = {1,1},
|
||||
[math.cosh] = {1,1},
|
||||
[math.deg] = {1,1},
|
||||
[math.exp] = {1,1},
|
||||
[math.floor] = {1,1},
|
||||
[math.fmod] = {2,2},
|
||||
[math.frexp] = {1,1},
|
||||
[math.ldexp] = {2,2},
|
||||
[math.log] = {1,1},
|
||||
[math.log10] = {1,1},
|
||||
[math.max] = {1,math.huge},
|
||||
[math.min] = {1,math.huge},
|
||||
[math.modf] = {1,1},
|
||||
[math.pow] = {2,2},
|
||||
[math.rad] = {1,1},
|
||||
[math.random] = {0,2},
|
||||
[math.randomseed] = {1,1},
|
||||
[math.sin] = {1,1},
|
||||
[math.sinh] = {1,1},
|
||||
[math.sqrt] = {1,1},
|
||||
[math.tan] = {1,1},
|
||||
[math.tanh] = {1,1},
|
||||
[os.clock] = {0,0},
|
||||
[os.date] = {0,2},
|
||||
[os.difftime] = {2,2},
|
||||
[os.execute] = {0,1},
|
||||
[os.exit] = {0,1},
|
||||
[os.getenv] = {1,1},
|
||||
[os.remove] = {1,1},
|
||||
[os.rename] = {2,2},
|
||||
[os.setlocale] = {1,2},
|
||||
[os.time] = {0,1},
|
||||
[os.tmpname] = {0,0},
|
||||
[package.loadlib] = {2,2},
|
||||
[package.seeall] = {1,1},
|
||||
[string.byte] = {1,3},
|
||||
[string.char] = {0,math.huge},
|
||||
[string.dump] = {1,1},
|
||||
[string.find] = {2,4},
|
||||
[string.format] = {1,math.huge},
|
||||
[string.gmatch] = {2,2},
|
||||
[string.gsub] = {3,4},
|
||||
[string.len] = {1,1},
|
||||
[string.lower] = {1,1},
|
||||
[string.match] = {2,3},
|
||||
[string.rep] = {2,2},
|
||||
[string.reverse] = {1,1},
|
||||
[string.sub] = {2,3},
|
||||
[string.upper] = {1,1},
|
||||
[table.concat] = {1,4},
|
||||
[table.insert] = {2,3},
|
||||
[table.maxn] = {1,1},
|
||||
[table.remove] = {1,2},
|
||||
[table.sort] = {1,2},
|
||||
[false] = nil -- trick (relies on potentially undefined behavior)
|
||||
}
|
||||
|
||||
|
||||
-- functions with zero or nearly zero side-effects, and with deterministic results, that may be evaluated by the analyzer.
|
||||
M.safe_function = {
|
||||
[require] = true,
|
||||
[rawequal] = true,
|
||||
[rawget] = true,
|
||||
[require] = true, -- sort of
|
||||
[select] = true,
|
||||
[tonumber] = true,
|
||||
[tostring] = true,
|
||||
[type] = true,
|
||||
[unpack] = true,
|
||||
[coroutine.create] = true,
|
||||
-- [coroutine.resume]
|
||||
[coroutine.running] = true,
|
||||
[coroutine.status] = true,
|
||||
[coroutine.wrap] = true,
|
||||
--[coroutine.yield]
|
||||
-- [debug.debug]
|
||||
--[debug.getfenv] = true,
|
||||
[debug.gethook] = true,
|
||||
[debug.getinfo] = true,
|
||||
[debug.getlocal] = true,
|
||||
[debug.getmetatable] = true,
|
||||
[debug.getregistry] = true,
|
||||
[debug.getupvalue] = true,
|
||||
-- [debug.setfenv]
|
||||
-- [debug.sethook]
|
||||
-- [debug.setlocal]
|
||||
-- [debug.setmetatable]
|
||||
-- [debug.setupvalue]
|
||||
-- [debug.traceback] = true,
|
||||
[io.type] = true,
|
||||
-- skip all other io.*
|
||||
[math.abs] = true,
|
||||
[math.acos] = true,
|
||||
[math.asin] = true,
|
||||
[math.atan] = true,
|
||||
[math.atan2] = true,
|
||||
[math.ceil] = true,
|
||||
[math.cos] = true,
|
||||
[math.cosh] = true,
|
||||
[math.deg] = true,
|
||||
[math.exp] = true,
|
||||
[math.floor] = true,
|
||||
[math.fmod] = true,
|
||||
[math.frexp] = true,
|
||||
[math.ldexp] = true,
|
||||
[math.log] = true,
|
||||
[math.log10] = true,
|
||||
[math.max] = true,
|
||||
[math.min] = true,
|
||||
[math.modf] = true,
|
||||
[math.pow] = true,
|
||||
[math.rad] = true,
|
||||
--[math.random]
|
||||
--[math.randomseed]
|
||||
[math.sin] = true,
|
||||
[math.sinh] = true,
|
||||
[math.sqrt] = true,
|
||||
[math.tan] = true,
|
||||
[math.tanh] = true,
|
||||
[os.clock] = true, -- safe but non-deterministic
|
||||
[os.date] = true,-- safe but non-deterministic
|
||||
[os.difftime] = true,
|
||||
--[os.execute]
|
||||
--[os.exit]
|
||||
[os.getenv] = true, -- though depends on environment
|
||||
--[os.remove]
|
||||
--[os.rename]
|
||||
--[os.setlocale]
|
||||
[os.time] = true, -- safe but non-deterministic
|
||||
--[os.tmpname]
|
||||
[string.byte] = true,
|
||||
[string.char] = true,
|
||||
[string.dump] = true,
|
||||
[string.find] = true,
|
||||
[string.format] = true,
|
||||
[string.gmatch] = true,
|
||||
[string.gsub] = true,
|
||||
[string.len] = true,
|
||||
[string.lower] = true,
|
||||
[string.match] = true,
|
||||
[string.rep] = true,
|
||||
[string.reverse] = true,
|
||||
[string.sub] = true,
|
||||
[string.upper] = true,
|
||||
[table.maxn] = true,
|
||||
}
|
||||
|
||||
M.mock_functions = {}
|
||||
|
||||
-- TODO:IMPROVE
|
||||
local function mockfunction(func, ...)
|
||||
local inputs = {n=0}
|
||||
local outputs = {n=0}
|
||||
local isoutputs
|
||||
for i=1,select('#', ...) do
|
||||
local v = select(i, ...)
|
||||
if type(v) == 'table' then v = v[1] end
|
||||
if v == 'N' or v == 'I' then v = T.number end
|
||||
if v == '->' then
|
||||
isoutputs = true
|
||||
elseif isoutputs then
|
||||
outputs[#outputs+1] = v; outputs.n = outputs.n + 1
|
||||
else
|
||||
inputs[#inputs+1] = v; inputs.n = inputs.n + 1
|
||||
end
|
||||
end
|
||||
M.mock_functions[func] = {inputs=inputs, outputs=outputs}
|
||||
end
|
||||
|
||||
|
||||
mockfunction(math.abs, 'N', '->', {'N',0,math.huge})
|
||||
mockfunction(math.acos, {'N',-1,1}, '->', {'N',0,math.pi/2})
|
||||
mockfunction(math.asin, {'N',-1,1}, '->', {'N',-math.pi/2,math.pi/2})
|
||||
mockfunction(math.atan, {'N',-math.huge,math.huge}, '->',
|
||||
{'N',-math.pi/2,math.pi/2})
|
||||
--FIX atan2
|
||||
mockfunction(math.ceil, 'N','->','I')
|
||||
mockfunction(math.cos, 'N','->',{'N',-1,1})
|
||||
mockfunction(math.cosh, 'N','->',{'N',1,math.huge})
|
||||
mockfunction(math.deg, 'N','->','N')
|
||||
mockfunction(math.exp, 'N','->',{'N',0,math.huge})
|
||||
mockfunction(math.floor, 'N','->','I')
|
||||
mockfunction(math.fmod, 'N','N','->','N')
|
||||
mockfunction(math.frexp, 'N','->',{'N',-1,1},'->','I')
|
||||
mockfunction(math.ldexp, {'N','I'},'->','N')
|
||||
mockfunction(math.log, {'N',0,math.huge},'->','N')
|
||||
mockfunction(math.log10, {'N',0,math.huge},'->','N')
|
||||
-- function max(...) print 'NOT IMPL'end
|
||||
-- function min(...) print 'NOT IMPL'end
|
||||
mockfunction(math.modf, 'N','->','I',{'N',-1,1})
|
||||
|
||||
mockfunction(math.pow, 'N','N','->','N') -- improve?
|
||||
mockfunction(math.rad, 'N','->','N')
|
||||
-- random = function() print 'NOT IMPL' end
|
||||
mockfunction(math.randomseed, 'N')
|
||||
mockfunction(math.sin, 'N','->',{'N',-1,1})
|
||||
mockfunction(math.sinh, 'N','->','N')
|
||||
mockfunction(math.sqrt, {'N',0,math.huge},'->',{'N',0,math.huge})
|
||||
mockfunction(math.tan, 'N','->','N') -- improve?
|
||||
mockfunction(math.tanh, 'N','->',{'N',-1,1})
|
||||
|
||||
|
||||
return M
|
||||
40
lualibs/luainspect/typecheck.lua
Normal file
40
lualibs/luainspect/typecheck.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
-- luainspect.typecheck - Type definitions used to check LuaInspect itself.
|
||||
--
|
||||
-- (c) 2010 David Manura, MIT License.
|
||||
|
||||
local T = require "luainspect.types"
|
||||
|
||||
local ast_mt = {__tostring = function(s) return 'AST' end}
|
||||
|
||||
return function(context)
|
||||
-- AST type.
|
||||
local ast = T.table {
|
||||
tag = T.string,
|
||||
lineinfo=T.table{first=T.table{comments=T.table{T.table{T.string,T.number,T.number}},T.number,T.number,T.number,T.string},
|
||||
ast=T.table{comments=T.table{T.table{T.string,T.number,T.number}},T.number,T.number,T.number,T.string}},
|
||||
isfield=T.boolean, tag2=T.string,
|
||||
value=T.universal, valueself=T.number, valuelist=T.table{n=T.number, isvaluepegged=T.boolean},
|
||||
resolvedname=T.string, definedglobal=T.boolean, id=T.number, isparam=T.boolean, isset=T.boolean, isused=T.boolean,
|
||||
isignore=T.boolean,
|
||||
functionlevel=T.number, localmasked=T.boolean, note=T.string, nocollect=T.table{}, isdead=T.boolean}
|
||||
-- FIX: some of these are "boolean or nil" actually
|
||||
ast.localdefinition=ast; ast.localmasking = ast
|
||||
ast.previous = ast; ast.parent = ast
|
||||
ast.seevalue = ast; ast.seenote=ast
|
||||
setmetatable(ast, ast_mt)
|
||||
|
||||
ast[1] = ast; ast[2] = ast
|
||||
context.apply_value('ast$', ast)
|
||||
|
||||
-- Token type.
|
||||
context.apply_value('token$', T.table{
|
||||
tag=T.string, fpos=T.number, lpos=T.number, keywordid=T.number, ast=ast, [1]=T.string
|
||||
})
|
||||
|
||||
-- Lua source code string type.
|
||||
context.apply_value('src$', '')
|
||||
|
||||
-- SciTE syler object type.
|
||||
local nf = function()end
|
||||
context.apply_value('^styler$', T.table{SetState=nf, More=nf, Current=nf, Forward=nf, StartStyling=nf, EndStyling=nf, language=T.string})
|
||||
end
|
||||
130
lualibs/luainspect/types.lua
Normal file
130
lualibs/luainspect/types.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
local T = {} -- types
|
||||
|
||||
-- istype[o] iff o represents a type (i.e. set of values)
|
||||
T.istype = {}
|
||||
|
||||
-- iserror[o] iff o represents an error type (created via T.error).
|
||||
T.iserror = {}
|
||||
|
||||
-- istabletype[o] iff o represents a table type (created by T.table).
|
||||
T.istabletype = {}
|
||||
|
||||
-- Number type
|
||||
T.number = {}
|
||||
setmetatable(T.number, T.number)
|
||||
function T.number.__tostring(self)
|
||||
return 'number'
|
||||
end
|
||||
T.istype[T.number] = true
|
||||
|
||||
-- String type
|
||||
T.string = {}
|
||||
setmetatable(T.string, T.string)
|
||||
function T.string.__tostring(self)
|
||||
return 'string'
|
||||
end
|
||||
T.istype[T.string] = true
|
||||
|
||||
-- Boolean type
|
||||
T.boolean = {}
|
||||
setmetatable(T.boolean, T.boolean)
|
||||
function T.boolean.__tostring(self)
|
||||
return 'boolean'
|
||||
end
|
||||
T.istype[T.boolean] = true
|
||||
|
||||
-- Table type
|
||||
function T.table(t)
|
||||
T.istype[t] = true
|
||||
T.istabletype[t] = true
|
||||
return t
|
||||
end
|
||||
|
||||
-- Universal type. This is a superset of all other types.
|
||||
T.universal = {}
|
||||
setmetatable(T.universal, T.universal)
|
||||
function T.universal.__tostring(self)
|
||||
return 'unknown'
|
||||
end
|
||||
T.istype[T.universal] = true
|
||||
|
||||
-- nil type. Represents `nil` but can be stored in tables.
|
||||
T['nil'] = {}
|
||||
setmetatable(T['nil'], T['nil'])
|
||||
T['nil'].__tostring = function(self)
|
||||
return 'nil'
|
||||
end
|
||||
T.istype[T['nil']] = true
|
||||
|
||||
-- None type. Represents a non-existent value, in a similar way
|
||||
-- that `none` is used differently from `nil` in the Lua C API.
|
||||
T.none = {}
|
||||
setmetatable(T.none, T.none)
|
||||
function T.none.__tostring(self)
|
||||
return 'none'
|
||||
end
|
||||
T.istype[T.none] = true
|
||||
|
||||
-- Error type
|
||||
local CError = {}; CError.__index = CError
|
||||
function CError.__tostring(self) return "error:" .. tostring(self.value) end
|
||||
function T.error(val)
|
||||
local self = setmetatable({value=val}, CError)
|
||||
T.istype[self] = true
|
||||
T.iserror[self] = true
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
-- Gets a type that is a superset of the two given types.
|
||||
function T.superset_types(a, b)
|
||||
if T.iserror[a] then return a end
|
||||
if T.iserror[b] then return b end
|
||||
if rawequal(a, b) then -- note: including nil == nil
|
||||
return a
|
||||
elseif type(a) == 'string' or a == T.string then
|
||||
if type(b) == 'string' or b == T.string then
|
||||
return T.string
|
||||
else
|
||||
return T.universal
|
||||
end
|
||||
elseif type(a) == 'number' or a == T.number then
|
||||
if type(b) == 'number' or b == T.number then
|
||||
return T.number
|
||||
else
|
||||
return T.universal
|
||||
end
|
||||
elseif type(a) == 'boolean' or a == T.boolean then
|
||||
if type(b) == 'boolean' or b == T.boolean then
|
||||
return T.boolean
|
||||
else
|
||||
return T.universal
|
||||
end
|
||||
else
|
||||
return T.universal -- IMPROVE
|
||||
end
|
||||
end
|
||||
--[[TESTS:
|
||||
assert(T.superset_types(2, 2) == 2)
|
||||
assert(T.superset_types(2, 3) == T.number)
|
||||
assert(T.superset_types(2, T.number) == T.number)
|
||||
assert(T.superset_types(T.number, T.string) == T.universal)
|
||||
print 'DONE'
|
||||
--]]
|
||||
|
||||
-- Determines whether type `o` certainly evaluates to true (true),
|
||||
-- certainly evaluates to false (false) or could evaluate to either
|
||||
-- true of false ('?').
|
||||
function T.boolean_cast(o)
|
||||
if T.iserror[o] then -- special case
|
||||
return '?'
|
||||
elseif o == nil or o == false or o == T['nil'] then -- all subsets of {nil, false}
|
||||
return false
|
||||
elseif o == T.universal or o == T.boolean then -- all supersets of boolean
|
||||
return '?'
|
||||
else -- all subsets of universal - {nil, false}
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return T
|
||||
1271
lualibs/metalua/compile.lua
Normal file
1271
lualibs/metalua/compile.lua
Normal file
File diff suppressed because it is too large
Load Diff
756
lualibs/metalua/gg.lua
Normal file
756
lualibs/metalua/gg.lua
Normal file
@@ -0,0 +1,756 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua.
|
||||
--
|
||||
-- Summary: parser generator. Collection of higher order functors,
|
||||
-- which allow to build and combine parsers. Relies on a lexer
|
||||
-- that supports the same API as the one exposed in mll.lua.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006-2008, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
--
|
||||
-- Parser generators:
|
||||
-- * [gg.sequence()]
|
||||
-- * [gg.multisequence()]
|
||||
-- * [gg.expr()]
|
||||
-- * [gg.list()]
|
||||
-- * [gg.onkeyword()]
|
||||
-- * [gg.optkeyword()]
|
||||
--
|
||||
-- Other functions:
|
||||
-- * [gg.parse_error()]
|
||||
-- * [gg.make_parser()]
|
||||
-- * [gg.is_parser()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module("gg", package.seeall)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- parser metatable, which maps __call to method parse, and adds some
|
||||
-- error tracing boilerplate.
|
||||
-------------------------------------------------------------------------------
|
||||
local parser_metatable = { }
|
||||
function parser_metatable.__call (parser, lx, ...)
|
||||
--printf ("Call parser %q of type %q", parser.name or "?", parser.kind)
|
||||
if mlc.metabugs then
|
||||
return parser:parse (lx, ...)
|
||||
--local x = parser:parse (lx, ...)
|
||||
--printf ("Result of parser %q: %s",
|
||||
-- parser.name or "?",
|
||||
-- _G.table.tostring(x, "nohash", 80))
|
||||
--return x
|
||||
else
|
||||
local li = lx:lineinfo_right() or { "?", "?", "?", "?" }
|
||||
local status, ast = pcall (parser.parse, parser, lx, ...)
|
||||
if status then return ast else
|
||||
-- Try to replace the gg.lua location, in the error msg, with
|
||||
-- the place where the current parser started handling the
|
||||
-- lexstream.
|
||||
-- Since the error is rethrown, these places are stacked.
|
||||
error (string.format ("%s\n - (l.%s, c.%s, k.%s) in parser %s",
|
||||
ast :strmatch "gg.lua:%d+: (.*)" or ast,
|
||||
li[1], li[2], li[3], parser.name or parser.kind))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Turn a table into a parser, mainly by setting the metatable.
|
||||
-------------------------------------------------------------------------------
|
||||
function make_parser(kind, p)
|
||||
p.kind = kind
|
||||
if not p.transformers then p.transformers = { } end
|
||||
function p.transformers:add (x)
|
||||
table.insert (self, x)
|
||||
end
|
||||
setmetatable (p, parser_metatable)
|
||||
return p
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Return true iff [x] is a parser.
|
||||
-- If it's a gg-generated parser, return the name of its kind.
|
||||
-------------------------------------------------------------------------------
|
||||
function is_parser (x)
|
||||
return type(x)=="function" or getmetatable(x)==parser_metatable and x.kind
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Parse a sequence, without applying builder nor transformers
|
||||
-------------------------------------------------------------------------------
|
||||
local function raw_parse_sequence (lx, p)
|
||||
local r = { }
|
||||
for i=1, #p do
|
||||
e=p[i]
|
||||
if type(e) == "string" then
|
||||
if not lx:is_keyword (lx:next(), e) then
|
||||
parse_error (lx, "A keyword was expected, probably `%s'.", e) end
|
||||
elseif is_parser (e) then
|
||||
table.insert (r, e (lx))
|
||||
else
|
||||
gg.parse_error (lx,"Sequence `%s': element #%i is neither a string "..
|
||||
"nor a parser: %s",
|
||||
p.name, i, table.tostring(e))
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Parse a multisequence, without applying multisequence transformers.
|
||||
-- The sequences are completely parsed.
|
||||
-------------------------------------------------------------------------------
|
||||
local function raw_parse_multisequence (lx, sequence_table, default)
|
||||
local seq_parser = sequence_table[lx:is_keyword(lx:peek())]
|
||||
if seq_parser then return seq_parser (lx)
|
||||
elseif default then return default (lx)
|
||||
else return false end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Applies all transformers listed in parser on ast.
|
||||
-------------------------------------------------------------------------------
|
||||
local function transform (ast, parser, fli, lli)
|
||||
if parser.transformers then
|
||||
for _, t in ipairs (parser.transformers) do ast = t(ast) or ast end
|
||||
end
|
||||
if type(ast) == 'table'then
|
||||
local ali = ast.lineinfo
|
||||
if not ali or ali.first~=fli or ali.last~=lli then
|
||||
ast.lineinfo = { first = fli, last = lli }
|
||||
end
|
||||
end
|
||||
return ast
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Generate a tracable parsing error (not implemented yet)
|
||||
-------------------------------------------------------------------------------
|
||||
function parse_error(lx, fmt, ...)
|
||||
local li = lx:lineinfo_left() or {-1,-1,-1, "<unknown file>"}
|
||||
local msg = string.format("line %i, char %i: "..fmt, li[1], li[2], ...)
|
||||
local src = lx.src
|
||||
if li[3]>0 and src then
|
||||
local i, j = li[3], li[3]
|
||||
while src:sub(i,i) ~= '\n' and i>=0 do i=i-1 end
|
||||
while src:sub(j,j) ~= '\n' and j<=#src do j=j+1 end
|
||||
local srcline = src:sub (i+1, j-1)
|
||||
local idx = string.rep (" ", li[2]).."^"
|
||||
msg = string.format("%s\n>>> %s\n>>> %s", msg, srcline, idx)
|
||||
end
|
||||
error(msg)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Sequence parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- Input fields:
|
||||
--
|
||||
-- * [builder]: how to build an AST out of sequence parts. let [x] be the list
|
||||
-- of subparser results (keywords are simply omitted). [builder] can be:
|
||||
-- - [nil], in which case the result of parsing is simply [x]
|
||||
-- - a string, which is then put as a tag on [x]
|
||||
-- - a function, which takes [x] as a parameter and returns an AST.
|
||||
--
|
||||
-- * [name]: the name of the parser. Used for debug messages
|
||||
--
|
||||
-- * [transformers]: a list of AST->AST functions, applied in order on ASTs
|
||||
-- returned by the parser.
|
||||
--
|
||||
-- * Table-part entries corresponds to keywords (strings) and subparsers
|
||||
-- (function and callable objects).
|
||||
--
|
||||
-- After creation, the following fields are added:
|
||||
-- * [parse] the parsing function lexer->AST
|
||||
-- * [kind] == "sequence"
|
||||
-- * [name] is set, if it wasn't in the input.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function sequence (p)
|
||||
make_parser ("sequence", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
-- Raw parsing:
|
||||
local fli = lx:lineinfo_right()
|
||||
local seq = raw_parse_sequence (lx, self)
|
||||
local lli = lx:lineinfo_left()
|
||||
|
||||
-- Builder application:
|
||||
local builder, tb = self.builder, type (self.builder)
|
||||
if tb == "string" then seq.tag = builder
|
||||
elseif tb == "function" or builder and builder.__call then seq = builder(seq)
|
||||
elseif builder == nil then -- nothing
|
||||
else error ("Invalid builder of type "..tb.." in sequence") end
|
||||
seq = transform (seq, self, fli, lli)
|
||||
assert (not seq or seq.lineinfo)
|
||||
return seq
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Construction
|
||||
-------------------------------------------------------------------
|
||||
-- Try to build a proper name
|
||||
if p.name then
|
||||
-- don't touch existing name
|
||||
elseif type(p[1])=="string" then -- find name based on 1st keyword
|
||||
if #p==1 then p.name=p[1]
|
||||
elseif type(p[#p])=="string" then
|
||||
p.name = p[1] .. " ... " .. p[#p]
|
||||
else p.name = p[1] .. " ..." end
|
||||
else -- can't find a decent name
|
||||
p.name = "<anonymous>"
|
||||
end
|
||||
|
||||
return p
|
||||
end --</sequence>
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Multiple, keyword-driven, sequence parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- in [p], useful fields are:
|
||||
--
|
||||
-- * [transformers]: as usual
|
||||
--
|
||||
-- * [name]: as usual
|
||||
--
|
||||
-- * Table-part entries must be sequence parsers, or tables which can
|
||||
-- be turned into a sequence parser by [gg.sequence]. These
|
||||
-- sequences must start with a keyword, and this initial keyword
|
||||
-- must be different for each sequence. The table-part entries will
|
||||
-- be removed after [gg.multisequence] returns.
|
||||
--
|
||||
-- * [default]: the parser to run if the next keyword in the lexer is
|
||||
-- none of the registered initial keywords. If there's no default
|
||||
-- parser and no suitable initial keyword, the multisequence parser
|
||||
-- simply returns [false].
|
||||
--
|
||||
-- After creation, the following fields are added:
|
||||
--
|
||||
-- * [parse] the parsing function lexer->AST
|
||||
--
|
||||
-- * [sequences] the table of sequences, indexed by initial keywords.
|
||||
--
|
||||
-- * [add] method takes a sequence parser or a config table for
|
||||
-- [gg.sequence], and adds/replaces the corresponding sequence
|
||||
-- parser. If the keyword was already used, the former sequence is
|
||||
-- removed and a warning is issued.
|
||||
--
|
||||
-- * [get] method returns a sequence by its initial keyword
|
||||
--
|
||||
-- * [kind] == "multisequence"
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function multisequence (p)
|
||||
make_parser ("multisequence", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Add a sequence (might be just a config table for [gg.sequence])
|
||||
-------------------------------------------------------------------
|
||||
function p:add (s)
|
||||
-- compile if necessary:
|
||||
local keyword = type(s)=='table' and s[1]
|
||||
if type(s)=='table' and not is_parser(s) then sequence(s) end
|
||||
if is_parser(s)~='sequence' or type(keyword)~='string' then
|
||||
if self.default then -- two defaults
|
||||
error ("In a multisequence parser, all but one sequences "..
|
||||
"must start with a keyword")
|
||||
else self.default = s end -- first default
|
||||
elseif self.sequences[keyword] then -- duplicate keyword
|
||||
eprintf (" *** Warning: keyword %q overloaded in multisequence ***",
|
||||
keyword)
|
||||
self.sequences[keyword] = s
|
||||
else -- newly caught keyword
|
||||
self.sequences[keyword] = s
|
||||
end
|
||||
end -- </multisequence.add>
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Get the sequence starting with this keyword. [kw :: string]
|
||||
-------------------------------------------------------------------
|
||||
function p:get (kw) return self.sequences [kw] end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Remove the sequence starting with keyword [kw :: string]
|
||||
-------------------------------------------------------------------
|
||||
function p:del (kw)
|
||||
if not self.sequences[kw] then
|
||||
eprintf("*** Warning: trying to delete sequence starting "..
|
||||
"with %q from a multisequence having no such "..
|
||||
"entry ***", kw) end
|
||||
local removed = self.sequences[kw]
|
||||
self.sequences[kw] = nil
|
||||
return removed
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
local fli = lx:lineinfo_right()
|
||||
local x = raw_parse_multisequence (lx, self.sequences, self.default)
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (x, self, fli, lli)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Construction
|
||||
-------------------------------------------------------------------
|
||||
-- Register the sequences passed to the constructor. They're going
|
||||
-- from the array part of the parser to the hash part of field
|
||||
-- [sequences]
|
||||
p.sequences = { }
|
||||
for i=1, #p do p:add (p[i]); p[i] = nil end
|
||||
|
||||
-- FIXME: why is this commented out?
|
||||
--if p.default and not is_parser(p.default) then sequence(p.default) end
|
||||
return p
|
||||
end --</multisequence>
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Expression parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Expression configuration relies on three tables: [prefix], [infix]
|
||||
-- and [suffix]. Moreover, the primary parser can be replaced by a
|
||||
-- table: in this case the [primary] table will be passed to
|
||||
-- [gg.multisequence] to create a parser.
|
||||
--
|
||||
-- Each of these tables is a modified multisequence parser: the
|
||||
-- differences with respect to regular multisequence config tables are:
|
||||
--
|
||||
-- * the builder takes specific parameters:
|
||||
-- - for [prefix], it takes the result of the prefix sequence parser,
|
||||
-- and the prefixed expression
|
||||
-- - for [infix], it takes the left-hand-side expression, the results
|
||||
-- of the infix sequence parser, and the right-hand-side expression.
|
||||
-- - for [suffix], it takes the suffixed expression, and theresult
|
||||
-- of the suffix sequence parser.
|
||||
--
|
||||
-- * the default field is a list, with parameters:
|
||||
-- - [parser] the raw parsing function
|
||||
-- - [transformers], as usual
|
||||
-- - [prec], the operator's precedence
|
||||
-- - [assoc] for [infix] table, the operator's associativity, which
|
||||
-- can be "left", "right" or "flat" (default to left)
|
||||
--
|
||||
-- In [p], useful fields are:
|
||||
-- * [transformers]: as usual
|
||||
-- * [name]: as usual
|
||||
-- * [primary]: the atomic expression parser, or a multisequence config
|
||||
-- table (mandatory)
|
||||
-- * [prefix]: prefix operators config table, see above.
|
||||
-- * [infix]: infix operators config table, see above.
|
||||
-- * [suffix]: suffix operators config table, see above.
|
||||
--
|
||||
-- After creation, these fields are added:
|
||||
-- * [kind] == "expr"
|
||||
-- * [parse] as usual
|
||||
-- * each table is turned into a multisequence, and therefore has an
|
||||
-- [add] method
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function expr (p)
|
||||
make_parser ("expr", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- parser method.
|
||||
-- In addition to the lexer, it takes an optional precedence:
|
||||
-- it won't read expressions whose precedence is lower or equal
|
||||
-- to [prec].
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx, prec)
|
||||
prec = prec or 0
|
||||
|
||||
------------------------------------------------------
|
||||
-- Extract the right parser and the corresponding
|
||||
-- options table, for (pre|in|suff)fix operators.
|
||||
-- Options include prec, assoc, transformers.
|
||||
------------------------------------------------------
|
||||
local function get_parser_info (tab)
|
||||
local p2 = tab:get (lx:is_keyword (lx:peek()))
|
||||
if p2 then -- keyword-based sequence found
|
||||
local function parser(lx) return raw_parse_sequence(lx, p2) end
|
||||
return parser, p2
|
||||
else -- Got to use the default parser
|
||||
local d = tab.default
|
||||
if d then return d.parse or d.parser, d
|
||||
else return false, false end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------
|
||||
-- Look for a prefix sequence. Multiple prefixes are
|
||||
-- handled through the recursive [p.parse] call.
|
||||
-- Notice the double-transform: one for the primary
|
||||
-- expr, and one for the one with the prefix op.
|
||||
------------------------------------------------------
|
||||
local function handle_prefix ()
|
||||
local fli = lx:lineinfo_right()
|
||||
local p2_func, p2 = get_parser_info (self.prefix)
|
||||
local op = p2_func and p2_func (lx)
|
||||
if op then -- Keyword-based sequence found
|
||||
local ili = lx:lineinfo_right() -- Intermediate LineInfo
|
||||
local e = p2.builder (op, self:parse (lx, p2.prec))
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (transform (e, p2, ili, lli), self, fli, lli)
|
||||
else -- No prefix found, get a primary expression
|
||||
local e = self.primary(lx)
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (e, self, fli, lli)
|
||||
end
|
||||
end --</expr.parse.handle_prefix>
|
||||
|
||||
------------------------------------------------------
|
||||
-- Look for an infix sequence+right-hand-side operand.
|
||||
-- Return the whole binary expression result,
|
||||
-- or false if no operator was found.
|
||||
------------------------------------------------------
|
||||
local function handle_infix (e)
|
||||
local p2_func, p2 = get_parser_info (self.infix)
|
||||
if not p2 then return false end
|
||||
|
||||
-----------------------------------------
|
||||
-- Handle flattening operators: gather all operands
|
||||
-- of the series in [list]; when a different operator
|
||||
-- is found, stop, build from [list], [transform] and
|
||||
-- return.
|
||||
-----------------------------------------
|
||||
if (not p2.prec or p2.prec>prec) and p2.assoc=="flat" then
|
||||
local fli = lx:lineinfo_right()
|
||||
local pflat, list = p2, { e }
|
||||
repeat
|
||||
local op = p2_func(lx)
|
||||
if not op then break end
|
||||
table.insert (list, self:parse (lx, p2.prec))
|
||||
local _ -- We only care about checking that p2==pflat
|
||||
_, p2 = get_parser_info (self.infix)
|
||||
until p2 ~= pflat
|
||||
local e2 = pflat.builder (list)
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (transform (e2, pflat, fli, lli), self, fli, lli)
|
||||
|
||||
-----------------------------------------
|
||||
-- Handle regular infix operators: [e] the LHS is known,
|
||||
-- just gather the operator and [e2] the RHS.
|
||||
-- Result goes in [e3].
|
||||
-----------------------------------------
|
||||
elseif p2.prec and p2.prec>prec or
|
||||
p2.prec==prec and p2.assoc=="right" then
|
||||
local fli = e.lineinfo.first -- lx:lineinfo_right()
|
||||
local op = p2_func(lx)
|
||||
if not op then return false end
|
||||
local e2 = self:parse (lx, p2.prec)
|
||||
local e3 = p2.builder (e, op, e2)
|
||||
local lli = lx:lineinfo_left()
|
||||
return transform (transform (e3, p2, fli, lli), self, fli, lli)
|
||||
|
||||
-----------------------------------------
|
||||
-- Check for non-associative operators, and complain if applicable.
|
||||
-----------------------------------------
|
||||
elseif p2.assoc=="none" and p2.prec==prec then
|
||||
parse_error (lx, "non-associative operator!")
|
||||
|
||||
-----------------------------------------
|
||||
-- No infix operator suitable at that precedence
|
||||
-----------------------------------------
|
||||
else return false end
|
||||
|
||||
end --</expr.parse.handle_infix>
|
||||
|
||||
------------------------------------------------------
|
||||
-- Look for a suffix sequence.
|
||||
-- Return the result of suffix operator on [e],
|
||||
-- or false if no operator was found.
|
||||
------------------------------------------------------
|
||||
local function handle_suffix (e)
|
||||
-- FIXME bad fli, must take e.lineinfo.first
|
||||
local p2_func, p2 = get_parser_info (self.suffix)
|
||||
if not p2 then return false end
|
||||
if not p2.prec or p2.prec>=prec then
|
||||
--local fli = lx:lineinfo_right()
|
||||
local fli = e.lineinfo.first
|
||||
local op = p2_func(lx)
|
||||
if not op then return false end
|
||||
local lli = lx:lineinfo_left()
|
||||
e = p2.builder (e, op)
|
||||
e = transform (transform (e, p2, fli, lli), self, fli, lli)
|
||||
return e
|
||||
end
|
||||
return false
|
||||
end --</expr.parse.handle_suffix>
|
||||
|
||||
------------------------------------------------------
|
||||
-- Parser body: read suffix and (infix+operand)
|
||||
-- extensions as long as we're able to fetch more at
|
||||
-- this precedence level.
|
||||
------------------------------------------------------
|
||||
local e = handle_prefix()
|
||||
repeat
|
||||
local x = handle_suffix (e); e = x or e
|
||||
local y = handle_infix (e); e = y or e
|
||||
until not (x or y)
|
||||
|
||||
-- No transform: it already happened in operators handling
|
||||
return e
|
||||
end --</expr.parse>
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Construction
|
||||
-------------------------------------------------------------------
|
||||
if not p.primary then p.primary=p[1]; p[1]=nil end
|
||||
for _, t in ipairs{ "primary", "prefix", "infix", "suffix" } do
|
||||
if not p[t] then p[t] = { } end
|
||||
if not is_parser(p[t]) then multisequence(p[t]) end
|
||||
end
|
||||
function p:add(...) return self.primary:add(...) end
|
||||
return p
|
||||
end --</expr>
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- List parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- In [p], the following fields can be provided in input:
|
||||
--
|
||||
-- * [builder]: takes list of subparser results, returns AST
|
||||
-- * [transformers]: as usual
|
||||
-- * [name]: as usual
|
||||
--
|
||||
-- * [terminators]: list of strings representing the keywords which
|
||||
-- might mark the end of the list. When non-empty, the list is
|
||||
-- allowed to be empty. A string is treated as a single-element
|
||||
-- table, whose element is that string, e.g. ["do"] is the same as
|
||||
-- [{"do"}].
|
||||
--
|
||||
-- * [separators]: list of strings representing the keywords which can
|
||||
-- separate elements of the list. When non-empty, one of these
|
||||
-- keyword has to be found between each element. Lack of a separator
|
||||
-- indicates the end of the list. A string is treated as a
|
||||
-- single-element table, whose element is that string, e.g. ["do"]
|
||||
-- is the same as [{"do"}]. If [terminators] is empty/nil, then
|
||||
-- [separators] has to be non-empty.
|
||||
--
|
||||
-- After creation, the following fields are added:
|
||||
-- * [parse] the parsing function lexer->AST
|
||||
-- * [kind] == "list"
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function list (p)
|
||||
make_parser ("list", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse (lx)
|
||||
|
||||
------------------------------------------------------
|
||||
-- Used to quickly check whether there's a terminator
|
||||
-- or a separator immediately ahead
|
||||
------------------------------------------------------
|
||||
local function peek_is_in (keywords)
|
||||
return keywords and lx:is_keyword(lx:peek(), unpack(keywords)) end
|
||||
|
||||
local x = { }
|
||||
local fli = lx:lineinfo_right()
|
||||
|
||||
-- if there's a terminator to start with, don't bother trying
|
||||
if not peek_is_in (self.terminators) then
|
||||
repeat table.insert (x, self.primary (lx)) -- read one element
|
||||
until
|
||||
-- First reason to stop: There's a separator list specified,
|
||||
-- and next token isn't one. Otherwise, consume it with [lx:next()]
|
||||
self.separators and not(peek_is_in (self.separators) and lx:next()) or
|
||||
-- Other reason to stop: terminator token ahead
|
||||
peek_is_in (self.terminators) or
|
||||
-- Last reason: end of file reached
|
||||
lx:peek().tag=="Eof"
|
||||
end
|
||||
|
||||
local lli = lx:lineinfo_left()
|
||||
|
||||
-- Apply the builder. It can be a string, or a callable value,
|
||||
-- or simply nothing.
|
||||
local b = self.builder
|
||||
if b then
|
||||
if type(b)=="string" then x.tag = b -- b is a string, use it as a tag
|
||||
elseif type(b)=="function" then x=b(x)
|
||||
else
|
||||
local bmt = getmetatable(b)
|
||||
if bmt and bmt.__call then x=b(x) end
|
||||
end
|
||||
end
|
||||
return transform (x, self, fli, lli)
|
||||
end --</list.parse>
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Construction
|
||||
-------------------------------------------------------------------
|
||||
if not p.primary then p.primary = p[1]; p[1] = nil end
|
||||
if type(p.terminators) == "string" then p.terminators = { p.terminators }
|
||||
elseif p.terminators and #p.terminators == 0 then p.terminators = nil end
|
||||
if type(p.separators) == "string" then p.separators = { p.separators }
|
||||
elseif p.separators and #p.separators == 0 then p.separators = nil end
|
||||
|
||||
return p
|
||||
end --</list>
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Keyword-conditionned parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Only apply a parser if a given keyword is found. The result of
|
||||
-- [gg.onkeyword] parser is the result of the subparser (modulo
|
||||
-- [transformers] applications).
|
||||
--
|
||||
-- lineinfo: the keyword is *not* included in the boundaries of the
|
||||
-- resulting lineinfo. A review of all usages of gg.onkeyword() in the
|
||||
-- implementation of metalua has shown that it was the appropriate choice
|
||||
-- in every case.
|
||||
--
|
||||
-- Input fields:
|
||||
--
|
||||
-- * [name]: as usual
|
||||
--
|
||||
-- * [transformers]: as usual
|
||||
--
|
||||
-- * [peek]: if non-nil, the conditionning keyword is left in the lexeme
|
||||
-- stream instead of being consumed.
|
||||
--
|
||||
-- * [primary]: the subparser.
|
||||
--
|
||||
-- * [keywords]: list of strings representing triggering keywords.
|
||||
--
|
||||
-- * Table-part entries can contain strings, and/or exactly one parser.
|
||||
-- Strings are put in [keywords], and the parser is put in [primary].
|
||||
--
|
||||
-- After the call, the following fields will be set:
|
||||
--
|
||||
-- * [parse] the parsing method
|
||||
-- * [kind] == "onkeyword"
|
||||
-- * [primary]
|
||||
-- * [keywords]
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function onkeyword (p)
|
||||
make_parser ("onkeyword", p)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Parsing method
|
||||
-------------------------------------------------------------------
|
||||
function p:parse(lx)
|
||||
if lx:is_keyword (lx:peek(), unpack(self.keywords)) then
|
||||
--local fli = lx:lineinfo_right()
|
||||
if not self.peek then lx:next() end
|
||||
local content = self.primary (lx)
|
||||
--local lli = lx:lineinfo_left()
|
||||
local fli, lli = content.lineinfo.first, content.lineinfo.last
|
||||
return transform (content, p, fli, lli)
|
||||
else return false end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Construction
|
||||
-------------------------------------------------------------------
|
||||
if not p.keywords then p.keywords = { } end
|
||||
for _, x in ipairs(p) do
|
||||
if type(x)=="string" then table.insert (p.keywords, x)
|
||||
else assert (not p.primary and is_parser (x)); p.primary = x end
|
||||
end
|
||||
if not next (p.keywords) then
|
||||
eprintf("Warning, no keyword to trigger gg.onkeyword") end
|
||||
assert (p.primary, 'no primary parser in gg.onkeyword')
|
||||
return p
|
||||
end --</onkeyword>
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Optional keyword consummer pseudo-parser generator
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- This doesn't return a real parser, just a function. That function parses
|
||||
-- one of the keywords passed as parameters, and returns it. It returns
|
||||
-- [false] if no matching keyword is found.
|
||||
--
|
||||
-- Notice that tokens returned by lexer already carry lineinfo, therefore
|
||||
-- there's no need to add them, as done usually through transform() calls.
|
||||
-------------------------------------------------------------------------------
|
||||
function optkeyword (...)
|
||||
local args = {...}
|
||||
if type (args[1]) == "table" then
|
||||
assert (#args == 1)
|
||||
args = args[1]
|
||||
end
|
||||
for _, v in ipairs(args) do assert (type(v)=="string") end
|
||||
return function (lx)
|
||||
local x = lx:is_keyword (lx:peek(), unpack (args))
|
||||
if x then lx:next(); return x
|
||||
else return false end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- Run a parser with a special lexer
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- This doesn't return a real parser, just a function.
|
||||
-- First argument is the lexer class to be used with the parser,
|
||||
-- 2nd is the parser itself.
|
||||
-- The resulting parser returns whatever the argument parser does.
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
function with_lexer(new_lexer, parser)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Most gg functions take their parameters in a table, so it's
|
||||
-- better to silently accept when with_lexer{ } is called with
|
||||
-- its arguments in a list:
|
||||
-------------------------------------------------------------------
|
||||
if not parser and #new_lexer==2 and type(new_lexer[1])=='table' then
|
||||
return with_lexer(unpack(new_lexer))
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Save the current lexer, switch it for the new one, run the parser,
|
||||
-- restore the previous lexer, even if the parser caused an error.
|
||||
-------------------------------------------------------------------
|
||||
return function (lx)
|
||||
local old_lexer = getmetatable(lx)
|
||||
lx:sync()
|
||||
setmetatable(lx, new_lexer)
|
||||
local status, result = pcall(parser, lx)
|
||||
lx:sync()
|
||||
setmetatable(lx, old_lexer)
|
||||
if status then return result else error(result) end
|
||||
end
|
||||
end
|
||||
1034
lualibs/metalua/lcode.lua
Normal file
1034
lualibs/metalua/lcode.lua
Normal file
File diff suppressed because it is too large
Load Diff
441
lualibs/metalua/ldump.lua
Normal file
441
lualibs/metalua/ldump.lua
Normal file
@@ -0,0 +1,441 @@
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- WARNING! You're entering a hackish area, proceed at your own risks!
|
||||
--
|
||||
-- This code results from the borrowing, then ruthless abuse, of
|
||||
-- Yueliang's implementation of Lua 5.0 compiler. I claim
|
||||
-- responsibility for all of the ugly, dirty stuff that you might spot
|
||||
-- in it.
|
||||
--
|
||||
-- Eventually, this code will be rewritten, either in Lua or more
|
||||
-- probably in C. Meanwhile, if you're interested into digging
|
||||
-- metalua's sources, this is not the best part to invest your time
|
||||
-- on.
|
||||
--
|
||||
-- End of warning.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
ldump.lua
|
||||
Save bytecodes in Lua
|
||||
This file is part of Yueliang.
|
||||
|
||||
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
|
||||
The COPYRIGHT file describes the conditions
|
||||
under which this software may be distributed.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
|
||||
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Notes:
|
||||
-- * LUA_NUMBER (double), byte order (little endian) and some other
|
||||
-- header values hard-coded; see other notes below...
|
||||
-- * One significant difference is that instructions are still in table
|
||||
-- form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
|
||||
-- convert them into 4-char strings
|
||||
-- * Deleted:
|
||||
-- luaU:DumpVector: folded into DumpLines, DumpCode
|
||||
-- * Added:
|
||||
-- luaU:endianness() (from lundump.c)
|
||||
-- luaU:make_setS: create a chunk writer that writes to a string
|
||||
-- luaU:make_setF: create a chunk writer that writes to a file
|
||||
-- (lua.h contains a typedef for a Chunkwriter pointer, and
|
||||
-- a Lua-based implementation exists, writer() in lstrlib.c)
|
||||
-- luaU:from_double(x): encode double value for writing
|
||||
-- luaU:from_int(x): encode integer value for writing
|
||||
-- (error checking is limited for these conversion functions)
|
||||
-- (double conversion does not support denormals or NaNs)
|
||||
-- luaU:ttype(o) (from lobject.h)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
module("bytecode", package.seeall)
|
||||
|
||||
format = { }
|
||||
format.header = string.dump(function()end):sub(1, 12)
|
||||
format.little_endian, format.int_size,
|
||||
format.size_t_size, format.instr_size,
|
||||
format.number_size, format.integral = format.header:byte(7, 12)
|
||||
format.little_endian = format.little_endian~=0
|
||||
format.integral = format.integral ~=0
|
||||
|
||||
assert(format.integral or format.number_size==8, "Number format not supported by dumper")
|
||||
assert(format.little_endian, "Big endian architectures not supported by dumper")
|
||||
|
||||
--requires luaP
|
||||
luaU = {}
|
||||
|
||||
-- constants used by dumper
|
||||
luaU.LUA_TNIL = 0
|
||||
luaU.LUA_TBOOLEAN = 1
|
||||
luaU.LUA_TNUMBER = 3 -- (all in lua.h)
|
||||
luaU.LUA_TSTRING = 4
|
||||
luaU.LUA_TNONE = -1
|
||||
|
||||
-- definitions for headers of binary files
|
||||
--luaU.LUA_SIGNATURE = "\27Lua" -- binary files start with "<esc>Lua"
|
||||
--luaU.VERSION = 81 -- 0x50; last format change was in 5.0
|
||||
--luaU.FORMAT_VERSION = 0 -- 0 is official version. yeah I know I'm a liar.
|
||||
|
||||
-- a multiple of PI for testing native format
|
||||
-- multiplying by 1E7 gives non-trivial integer values
|
||||
--luaU.TEST_NUMBER = 3.14159265358979323846E7
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Additional functions to handle chunk writing
|
||||
-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- works like the lobject.h version except that TObject used in these
|
||||
-- scripts only has a 'value' field, no 'tt' field (native types used)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:ttype(o)
|
||||
local tt = type(o.value)
|
||||
if tt == "number" then return self.LUA_TNUMBER
|
||||
elseif tt == "string" then return self.LUA_TSTRING
|
||||
elseif tt == "nil" then return self.LUA_TNIL
|
||||
elseif tt == "boolean" then return self.LUA_TBOOLEAN
|
||||
else
|
||||
return self.LUA_TNONE -- the rest should not appear
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- create a chunk writer that writes to a string
|
||||
-- * returns the writer function and a table containing the string
|
||||
-- * to get the final result, look in buff.data
|
||||
------------------------------------------------------------------------
|
||||
function luaU:make_setS()
|
||||
local buff = {}
|
||||
buff.data = ""
|
||||
local writer =
|
||||
function(s, buff) -- chunk writer
|
||||
if not s then return end
|
||||
buff.data = buff.data..s
|
||||
end
|
||||
return writer, buff
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- create a chunk writer that writes to a file
|
||||
-- * returns the writer function and a table containing the file handle
|
||||
-- * if a nil is passed, then writer should close the open file
|
||||
------------------------------------------------------------------------
|
||||
function luaU:make_setF(filename)
|
||||
local buff = {}
|
||||
buff.h = io.open(filename, "wb")
|
||||
if not buff.h then return nil end
|
||||
local writer =
|
||||
function(s, buff) -- chunk writer
|
||||
if not buff.h then return end
|
||||
if not s then buff.h:close(); return end
|
||||
buff.h:write(s)
|
||||
end
|
||||
return writer, buff
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- converts a IEEE754 double number to an 8-byte little-endian string
|
||||
-- * luaU:from_double() and luaU:from_int() are from ChunkBake project
|
||||
-- * supports +/- Infinity, but not denormals or NaNs
|
||||
-----------------------------------------------------------------------
|
||||
function luaU:from_double(x)
|
||||
local function grab_byte(v)
|
||||
return math.floor(v / 256),
|
||||
string.char(math.mod(math.floor(v), 256))
|
||||
end
|
||||
local sign = 0
|
||||
if x < 0 then sign = 1; x = -x end
|
||||
local mantissa, exponent = math.frexp(x)
|
||||
if x == 0 then -- zero
|
||||
mantissa, exponent = 0, 0
|
||||
elseif x == 1/0 then
|
||||
mantissa, exponent = 0, 2047
|
||||
else
|
||||
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
|
||||
exponent = exponent + 1022
|
||||
end
|
||||
local v, byte = "" -- convert to bytes
|
||||
x = mantissa
|
||||
for i = 1,6 do
|
||||
x, byte = grab_byte(x); v = v..byte -- 47:0
|
||||
end
|
||||
x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
|
||||
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
|
||||
return v
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- converts a number to a little-endian 32-bit integer string
|
||||
-- * input value assumed to not overflow, can be signed/unsigned
|
||||
-----------------------------------------------------------------------
|
||||
function luaU:from_int(x, size)
|
||||
local v = ""
|
||||
x = math.floor(x)
|
||||
if x >= 0 then
|
||||
for i = 1, size do
|
||||
v = v..string.char(math.mod(x, 256)); x = math.floor(x / 256)
|
||||
end
|
||||
else -- x < 0
|
||||
x = -x
|
||||
local carry = 1
|
||||
for i = 1, size do
|
||||
local c = 255 - math.mod(x, 256) + carry
|
||||
if c == 256 then c = 0; carry = 1 else carry = 0 end
|
||||
v = v..string.char(c); x = math.floor(x / 256)
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Functions to make a binary chunk
|
||||
-- * many functions have the size parameter removed, since output is
|
||||
-- in the form of a string and some sizes are implicit or hard-coded
|
||||
-- * luaU:DumpVector has been deleted (used in DumpCode & DumpLines)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump a block of literal bytes
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLiteral(s, D) self:DumpBlock(s, D) end
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- struct DumpState:
|
||||
-- L -- lua_State (not used in this script)
|
||||
-- write -- lua_Chunkwriter (chunk writer function)
|
||||
-- data -- void* (chunk writer context or data already written)
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a block of bytes
|
||||
-- * lua_unlock(D.L), lua_lock(D.L) deleted
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpBlock(b, D) D.write(b, D.data) end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a single byte
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpByte(y, D)
|
||||
self:DumpBlock(string.char(y), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a 32-bit signed integer (for int)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpInt(x, D)
|
||||
self:DumpBlock(self:from_int(x, format.int_size), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a 32-bit unsigned integer (for size_t)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpSize(x, D)
|
||||
self:DumpBlock(self:from_int(x, format.size_t_size), D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a LUA_NUMBER (hard-coded as a double)
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpNumber(x, D)
|
||||
if format.integral then
|
||||
self:DumpBlock(self:from_int(x, format.number_size), D)
|
||||
else
|
||||
self:DumpBlock(self:from_double(x), D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps a Lua string
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpString(s, D)
|
||||
if s == nil then
|
||||
self:DumpSize(0, D)
|
||||
else
|
||||
s = s.."\0" -- include trailing '\0'
|
||||
self:DumpSize(string.len(s), D)
|
||||
self:DumpBlock(s, D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps instruction block from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpCode(f, D)
|
||||
local n = f.sizecode
|
||||
self:DumpInt(n, D)
|
||||
--was DumpVector
|
||||
for i = 0, n - 1 do
|
||||
self:DumpBlock(luaP:Instruction(f.code[i]), D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps local variable names from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLocals(f, D)
|
||||
local n = f.sizelocvars
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
-- Dirty temporary fix:
|
||||
-- `Stat{ } keeps properly count of the number of local vars,
|
||||
-- but fails to keep score of their debug info (names).
|
||||
-- It therefore might happen that #f.localvars < f.sizelocvars, or
|
||||
-- that a variable's startpc and endpc fields are left unset.
|
||||
-- FIXME: This might not be needed anymore, check the bug report
|
||||
-- by J. Belmonte.
|
||||
local var = f.locvars[i]
|
||||
if not var then break end
|
||||
-- printf("[DUMPLOCALS] dumping local var #%i = %s", i, table.tostring(var))
|
||||
self:DumpString(var.varname, D)
|
||||
self:DumpInt(var.startpc or 0, D)
|
||||
self:DumpInt(var.endpc or 0, D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dumps line information from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpLines(f, D)
|
||||
local n = f.sizelineinfo
|
||||
self:DumpInt(n, D)
|
||||
--was DumpVector
|
||||
for i = 0, n - 1 do
|
||||
self:DumpInt(f.lineinfo[i], D) -- was DumpBlock
|
||||
--print(i, f.lineinfo[i])
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump upvalue names from function prototype
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpUpvalues(f, D)
|
||||
local n = f.sizeupvalues
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
self:DumpString(f.upvalues[i], D)
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump constant pool from function prototype
|
||||
-- * nvalue(o) and tsvalue(o) macros removed
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpConstants(f, D)
|
||||
local n = f.sizek
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
local o = f.k[i] -- TObject
|
||||
local tt = self:ttype(o)
|
||||
assert (tt >= 0)
|
||||
self:DumpByte(tt, D)
|
||||
if tt == self.LUA_TNUMBER then
|
||||
self:DumpNumber(o.value, D)
|
||||
elseif tt == self.LUA_TSTRING then
|
||||
self:DumpString(o.value, D)
|
||||
elseif tt == self.LUA_TBOOLEAN then
|
||||
self:DumpByte (o.value and 1 or 0, D)
|
||||
elseif tt == self.LUA_TNIL then
|
||||
else
|
||||
assert(false) -- cannot happen
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function luaU:DumpProtos (f, D)
|
||||
local n = f.sizep
|
||||
assert (n)
|
||||
self:DumpInt(n, D)
|
||||
for i = 0, n - 1 do
|
||||
self:DumpFunction(f.p[i], f.source, D)
|
||||
end
|
||||
end
|
||||
|
||||
function luaU:DumpDebug(f, D)
|
||||
self:DumpLines(f, D)
|
||||
self:DumpLocals(f, D)
|
||||
self:DumpUpvalues(f, D)
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump child function prototypes from function prototype
|
||||
--FF completely reworked for 5.1 format
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpFunction(f, p, D)
|
||||
-- print "Dumping function:"
|
||||
-- table.print(f, 60)
|
||||
|
||||
local source = f.source
|
||||
if source == p then source = nil end
|
||||
self:DumpString(source, D)
|
||||
self:DumpInt(f.lineDefined, D)
|
||||
self:DumpInt(f.lastLineDefined or 42, D)
|
||||
self:DumpByte(f.nups, D)
|
||||
self:DumpByte(f.numparams, D)
|
||||
self:DumpByte(f.is_vararg, D)
|
||||
self:DumpByte(f.maxstacksize, D)
|
||||
self:DumpCode(f, D)
|
||||
self:DumpConstants(f, D)
|
||||
self:DumpProtos( f, D)
|
||||
self:DumpDebug(f, D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump Lua header section (some sizes hard-coded)
|
||||
--FF: updated for version 5.1
|
||||
------------------------------------------------------------------------
|
||||
function luaU:DumpHeader(D)
|
||||
self:DumpLiteral(format.header, D)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- dump function as precompiled chunk
|
||||
-- * w, data are created from make_setS, make_setF
|
||||
--FF: suppressed extraneous [L] param
|
||||
------------------------------------------------------------------------
|
||||
function luaU:dump (Main, w, data)
|
||||
local D = {} -- DumpState
|
||||
D.write = w
|
||||
D.data = data
|
||||
self:DumpHeader(D)
|
||||
self:DumpFunction(Main, nil, D)
|
||||
-- added: for a chunk writer writing to a file, this final call with
|
||||
-- nil data is to indicate to the writer to close the file
|
||||
D.write(nil, D.data)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- find byte order (from lundump.c)
|
||||
-- * hard-coded to little-endian
|
||||
------------------------------------------------------------------------
|
||||
function luaU:endianness()
|
||||
return 1
|
||||
end
|
||||
|
||||
-- FIXME: ugly concat-base generation in [make_setS], bufferize properly!
|
||||
function dump_string (proto)
|
||||
local writer, buff = luaU:make_setS()
|
||||
luaU:dump (proto, writer, buff)
|
||||
return buff.data
|
||||
end
|
||||
|
||||
-- FIXME: [make_setS] sucks, perform synchronous file writing
|
||||
-- Now unused
|
||||
function dump_file (proto, filename)
|
||||
local writer, buff = luaU:make_setS()
|
||||
luaU:dump (proto, writer, buff)
|
||||
local file = io.open (filename, "wb")
|
||||
file:write (buff.data)
|
||||
io.close(file)
|
||||
if UNIX_SHARPBANG then os.execute ("chmod a+x "..filename) end
|
||||
end
|
||||
511
lualibs/metalua/lexer.lua
Normal file
511
lualibs/metalua/lexer.lua
Normal file
@@ -0,0 +1,511 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: generic Lua-style lexer definition. You need this plus
|
||||
-- some keyword additions to create the complete Lua lexer,
|
||||
-- as is done in mlp_lexer.lua.
|
||||
--
|
||||
-- TODO:
|
||||
--
|
||||
-- * Make it easy to define new flavors of strings. Replacing the
|
||||
-- lexer.patterns.long_string regexp by an extensible list, with
|
||||
-- customizable token tag, would probably be enough. Maybe add:
|
||||
-- + an index of capture for the regexp, that would specify
|
||||
-- which capture holds the content of the string-like token
|
||||
-- + a token tag
|
||||
-- + or a string->string transformer function.
|
||||
--
|
||||
-- * There are some _G.table to prevent a namespace clash which has
|
||||
-- now disappered. remove them.
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
module ("lexer", package.seeall)
|
||||
|
||||
-- don't load metalua.runtime as it loads metalua.base, which pollutes
|
||||
-- global namespace and overwrites pairs/ipairs -- PK 6/4/2012
|
||||
require 'metalua.table2'
|
||||
|
||||
lexer = { alpha={ }, sym={ } }
|
||||
lexer.__index=lexer
|
||||
|
||||
local debugf = function() end
|
||||
--local debugf=printf
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Patterns used by [lexer:extract] to decompose the raw string into
|
||||
-- correctly tagged tokens.
|
||||
----------------------------------------------------------------------
|
||||
lexer.patterns = {
|
||||
spaces = "^[ \r\n\t]*()",
|
||||
short_comment = "^%-%-([^\n]*)()\n",
|
||||
final_short_comment = "^%-%-([^\n]*)()$",
|
||||
long_comment = "^%-%-%[(=*)%[\n?(.-)%]%1%]()",
|
||||
long_string = "^%[(=*)%[\n?(.-)%]%1%]()",
|
||||
number_mantissa = { "^%d+%.?%d*()", "^%d*%.%d+()" },
|
||||
number_exponant = "^[eE][%+%-]?%d+()",
|
||||
number_hex = "^0[xX]%x+()",
|
||||
word = "^([%a_][%w_]*)()"
|
||||
}
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- unescape a whole string, applying [unesc_digits] and
|
||||
-- [unesc_letter] as many times as required.
|
||||
----------------------------------------------------------------------
|
||||
local function unescape_string (s)
|
||||
|
||||
-- Turn the digits of an escape sequence into the corresponding
|
||||
-- character, e.g. [unesc_digits("123") == string.char(123)].
|
||||
local function unesc_digits (backslashes, digits)
|
||||
if #backslashes%2==0 then
|
||||
-- Even number of backslashes, they escape each other, not the digits.
|
||||
-- Return them so that unesc_letter() can treaat them
|
||||
return backslashes..digits
|
||||
else
|
||||
-- Remove the odd backslash, which escapes the number sequence.
|
||||
-- The rest will be returned and parsed by unesc_letter()
|
||||
backslashes = backslashes :sub (1,-2)
|
||||
end
|
||||
local k, j, i = digits:reverse():byte(1, 3)
|
||||
local z = _G.string.byte "0"
|
||||
local code = (k or z) + 10*(j or z) + 100*(i or z) - 111*z
|
||||
if code > 255 then
|
||||
error ("Illegal escape sequence '\\"..digits..
|
||||
"' in string: ASCII codes must be in [0..255]")
|
||||
end
|
||||
return backslashes .. string.char (code)
|
||||
end
|
||||
|
||||
-- Take a letter [x], and returns the character represented by the
|
||||
-- sequence ['\\'..x], e.g. [unesc_letter "n" == "\n"].
|
||||
local function unesc_letter(x)
|
||||
local t = {
|
||||
a = "\a", b = "\b", f = "\f",
|
||||
n = "\n", r = "\r", t = "\t", v = "\v",
|
||||
["\\"] = "\\", ["'"] = "'", ['"'] = '"', ["\n"] = "\n" }
|
||||
return t[x] or error([[Unknown escape sequence '\]]..x..[[']])
|
||||
end
|
||||
|
||||
return s
|
||||
:gsub ("(\\+)([0-9][0-9]?[0-9]?)", unesc_digits)
|
||||
:gsub ("\\(%D)",unesc_letter)
|
||||
end
|
||||
|
||||
lexer.extractors = {
|
||||
"skip_whitespaces_and_comments",
|
||||
"extract_short_string", "extract_word", "extract_number",
|
||||
"extract_long_string", "extract_symbol" }
|
||||
|
||||
lexer.token_metatable = {
|
||||
-- __tostring = function(a)
|
||||
-- return string.format ("`%s{'%s'}",a.tag, a[1])
|
||||
-- end
|
||||
}
|
||||
|
||||
lexer.lineinfo_metatable = { }
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Really extract next token fron the raw string
|
||||
-- (and update the index).
|
||||
-- loc: offset of the position just after spaces and comments
|
||||
-- previous_i: offset in src before extraction began
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract ()
|
||||
local previous_i = self.i
|
||||
local loc = self.i
|
||||
local eof, token
|
||||
|
||||
-- Put line info, comments and metatable around the tag and content
|
||||
-- provided by extractors, thus returning a complete lexer token.
|
||||
-- first_line: line # at the beginning of token
|
||||
-- first_column_offset: char # of the last '\n' before beginning of token
|
||||
-- i: scans from beginning of prefix spaces/comments to end of token.
|
||||
local function build_token (tag, content)
|
||||
assert (tag and content)
|
||||
local i, first_line, first_column_offset, previous_line_length =
|
||||
previous_i, self.line, self.column_offset, nil
|
||||
|
||||
-- update self.line and first_line. i := indexes of '\n' chars
|
||||
while true do
|
||||
i = self.src :find ("\n", i+1, true)
|
||||
if not i or i>self.i then break end -- no more '\n' until end of token
|
||||
previous_line_length = i - self.column_offset
|
||||
if loc and i <= loc then -- '\n' before beginning of token
|
||||
first_column_offset = i
|
||||
first_line = first_line+1
|
||||
end
|
||||
self.line = self.line+1
|
||||
self.column_offset = i
|
||||
end
|
||||
|
||||
-- lineinfo entries: [1]=line, [2]=column, [3]=char, [4]=filename
|
||||
local fli = { first_line, loc-first_column_offset, loc, self.src_name }
|
||||
local lli = { self.line, self.i-self.column_offset-1, self.i-1, self.src_name }
|
||||
--Pluto barfes when the metatable is set:(
|
||||
setmetatable(fli, lexer.lineinfo_metatable)
|
||||
setmetatable(lli, lexer.lineinfo_metatable)
|
||||
local a = { tag = tag, lineinfo = { first=fli, last=lli }, content }
|
||||
if lli[2]==-1 then lli[1], lli[2] = lli[1]-1, previous_line_length-1 end
|
||||
if #self.attached_comments > 0 then
|
||||
a.lineinfo.comments = self.attached_comments
|
||||
fli.comments = self.attached_comments
|
||||
if self.lineinfo_last then
|
||||
self.lineinfo_last.comments = self.attached_comments
|
||||
end
|
||||
end
|
||||
self.attached_comments = { }
|
||||
return setmetatable (a, self.token_metatable)
|
||||
end --</function build_token>
|
||||
|
||||
for ext_idx, extractor in ipairs(self.extractors) do
|
||||
-- printf("method = %s", method)
|
||||
local tag, content = self [extractor] (self)
|
||||
-- [loc] is placed just after the leading whitespaces and comments;
|
||||
-- for this to work, the whitespace extractor *must be* at index 1.
|
||||
if ext_idx==1 then loc = self.i end
|
||||
|
||||
if tag then
|
||||
--printf("`%s{ %q }\t%i", tag, content, loc);
|
||||
return build_token (tag, content)
|
||||
end
|
||||
end
|
||||
|
||||
error "None of the lexer extractors returned anything!"
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- skip whites and comments
|
||||
-- FIXME: doesn't take into account:
|
||||
-- - unterminated long comments
|
||||
-- - short comments at last line without a final \n
|
||||
----------------------------------------------------------------------
|
||||
function lexer:skip_whitespaces_and_comments()
|
||||
local table_insert = _G.table.insert
|
||||
repeat -- loop as long as a space or comment chunk is found
|
||||
local _, j
|
||||
local again = false
|
||||
local last_comment_content = nil
|
||||
-- skip spaces
|
||||
self.i = self.src:match (self.patterns.spaces, self.i)
|
||||
-- skip a long comment if any
|
||||
_, last_comment_content, j =
|
||||
self.src :match (self.patterns.long_comment, self.i)
|
||||
if j then
|
||||
table_insert(self.attached_comments,
|
||||
{last_comment_content, self.i, j, "long"})
|
||||
self.i=j; again=true
|
||||
end
|
||||
-- skip a short comment if any
|
||||
last_comment_content, j = self.src:match (self.patterns.short_comment, self.i)
|
||||
if j then
|
||||
table_insert(self.attached_comments,
|
||||
{last_comment_content, self.i, j, "short"})
|
||||
self.i=j; again=true
|
||||
end
|
||||
if self.i>#self.src then return "Eof", "eof" end
|
||||
until not again
|
||||
|
||||
if self.src:match (self.patterns.final_short_comment, self.i) then
|
||||
return "Eof", "eof" end
|
||||
--assert (not self.src:match(self.patterns.short_comment, self.i))
|
||||
--assert (not self.src:match(self.patterns.long_comment, self.i))
|
||||
-- --assert (not self.src:match(self.patterns.spaces, self.i))
|
||||
return
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- extract a '...' or "..." short string
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_short_string()
|
||||
-- [k] is the first unread char, [self.i] points to [k] in [self.src]
|
||||
local j, k = self.i, self.src :sub (self.i,self.i)
|
||||
if k~="'" and k~='"' then return end
|
||||
local i = self.i + 1
|
||||
local j = i
|
||||
while true do
|
||||
-- k = opening char: either simple-quote or double-quote
|
||||
-- i = index of beginning-of-string
|
||||
-- x = next "interesting" character
|
||||
-- j = position after interesting char
|
||||
-- y = char just after x
|
||||
local x, y
|
||||
x, j, y = self.src :match ("([\\\r\n"..k.."])()(.?)", j)
|
||||
if x == '\\' then j=j+1 -- don't parse escaped char
|
||||
elseif x == k then break -- unescaped end of string
|
||||
else -- eof or '\r' or '\n' reached before end of string
|
||||
assert (not x or x=="\r" or x=="\n")
|
||||
error "Unterminated string"
|
||||
end
|
||||
end
|
||||
self.i = j
|
||||
|
||||
return "String", unescape_string (self.src:sub (i,j-2))
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_word()
|
||||
-- Id / keyword
|
||||
local word, j = self.src:match (self.patterns.word, self.i)
|
||||
if word then
|
||||
self.i = j
|
||||
if self.alpha [word] then return "Keyword", word
|
||||
else return "Id", word end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_number()
|
||||
-- Number
|
||||
local j = self.src:match(self.patterns.number_hex, self.i)
|
||||
if not j then
|
||||
j = self.src:match (self.patterns.number_mantissa[1], self.i) or
|
||||
self.src:match (self.patterns.number_mantissa[2], self.i)
|
||||
if j then
|
||||
j = self.src:match (self.patterns.number_exponant, j) or j;
|
||||
end
|
||||
end
|
||||
if not j then return end
|
||||
-- Number found, interpret with tonumber() and return it
|
||||
local n = tonumber (self.src:sub (self.i, j-1))
|
||||
self.i = j
|
||||
return "Number", n
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_long_string()
|
||||
-- Long string
|
||||
local _, content, j = self.src:match (self.patterns.long_string, self.i)
|
||||
if j then self.i = j; return "String", content end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:extract_symbol()
|
||||
-- compound symbol
|
||||
local k = self.src:sub (self.i,self.i)
|
||||
local symk = self.sym [k]
|
||||
if not symk then
|
||||
self.i = self.i + 1
|
||||
return "Keyword", k
|
||||
end
|
||||
for _, sym in pairs (symk) do
|
||||
if sym == self.src:sub (self.i, self.i + #sym - 1) then
|
||||
self.i = self.i + #sym;
|
||||
return "Keyword", sym
|
||||
end
|
||||
end
|
||||
-- single char symbol
|
||||
self.i = self.i+1
|
||||
return "Keyword", k
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Add a keyword to the list of keywords recognized by the lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:add (w, ...)
|
||||
assert(not ..., "lexer:add() takes only one arg, although possibly a table")
|
||||
if type (w) == "table" then
|
||||
for _, x in ipairs (w) do self:add (x) end
|
||||
else
|
||||
if w:match (self.patterns.word .. "$") then self.alpha [w] = true
|
||||
elseif w:match "^%p%p+$" then
|
||||
local k = w:sub(1,1)
|
||||
local list = self.sym [k]
|
||||
if not list then list = { }; self.sym [k] = list end
|
||||
_G.table.insert (list, w)
|
||||
elseif w:match "^%p$" then return
|
||||
else error "Invalid keyword" end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, without consumming it.
|
||||
-- [n] defaults to 1. If it goes pass the end of the stream, an EOF
|
||||
-- token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:peek (n)
|
||||
if not n then n=1 end
|
||||
if n > #self.peeked then
|
||||
for i = #self.peeked+1, n do
|
||||
self.peeked [i] = self:extract()
|
||||
end
|
||||
end
|
||||
return self.peeked [n]
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the [n]th next token, removing it as well as the 0..n-1
|
||||
-- previous tokens. [n] defaults to 1. If it goes pass the end of the
|
||||
-- stream, an EOF token is returned.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:next (n)
|
||||
n = n or 1
|
||||
self:peek (n)
|
||||
local a
|
||||
for i=1,n do
|
||||
a = _G.table.remove (self.peeked, 1)
|
||||
if a then
|
||||
--debugf ("lexer:next() ==> %s %s",
|
||||
-- table.tostring(a), tostring(a))
|
||||
end
|
||||
self.lastline = a.lineinfo.last[1]
|
||||
end
|
||||
self.lineinfo_last = a.lineinfo.last
|
||||
return a or eof_token
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Returns an object which saves the stream's current state.
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to save
|
||||
function lexer:save () return { self.i; _G.table.cat(self.peeked) } end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Restore the stream's state, as saved by method [save].
|
||||
----------------------------------------------------------------------
|
||||
-- FIXME there are more fields than that to restore
|
||||
function lexer:restore (s) self.i=s[1]; self.peeked=s[2] end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Resynchronize: cancel any token in self.peeked, by emptying the
|
||||
-- list and resetting the indexes
|
||||
----------------------------------------------------------------------
|
||||
function lexer:sync()
|
||||
local p1 = self.peeked[1]
|
||||
if p1 then
|
||||
li = p1.lineinfo.first
|
||||
self.line, self.i = li[1], li[3]
|
||||
self.column_offset = self.i - li[2]
|
||||
self.peeked = { }
|
||||
self.attached_comments = p1.lineinfo.first.comments or { }
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Take the source and offset of an old lexer.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:takeover(old)
|
||||
self:sync()
|
||||
self.line, self.column_offset, self.i, self.src, self.attached_comments =
|
||||
old.line, old.column_offset, old.i, old.src, old.attached_comments
|
||||
return self
|
||||
end
|
||||
|
||||
-- function lexer:lineinfo()
|
||||
-- if self.peeked[1] then return self.peeked[1].lineinfo.first
|
||||
-- else return { self.line, self.i-self.column_offset, self.i } end
|
||||
-- end
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Return the current position in the sources. This position is between
|
||||
-- two tokens, and can be within a space / comment area, and therefore
|
||||
-- have a non-null width. :lineinfo_left() returns the beginning of the
|
||||
-- separation area, :lineinfo_right() returns the end of that area.
|
||||
--
|
||||
-- ____ last consummed token ____ first unconsummed token
|
||||
-- / /
|
||||
-- XXXXX <spaces and comments> YYYYY
|
||||
-- \____ \____
|
||||
-- :lineinfo_left() :lineinfo_right()
|
||||
----------------------------------------------------------------------
|
||||
function lexer:lineinfo_right()
|
||||
return self:peek(1).lineinfo.first
|
||||
end
|
||||
|
||||
function lexer:lineinfo_left()
|
||||
return self.lineinfo_last
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Create a new lexstream.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:newstream (src_or_stream, name)
|
||||
name = name or "?"
|
||||
if type(src_or_stream)=='table' then -- it's a stream
|
||||
return setmetatable ({ }, self) :takeover (src_or_stream)
|
||||
elseif type(src_or_stream)=='string' then -- it's a source string
|
||||
local src = src_or_stream
|
||||
local stream = {
|
||||
src_name = name; -- Name of the file
|
||||
src = src; -- The source, as a single string
|
||||
peeked = { }; -- Already peeked, but not discarded yet, tokens
|
||||
i = 1; -- Character offset in src
|
||||
line = 1; -- Current line number
|
||||
column_offset = 0; -- distance from beginning of file to last '\n'
|
||||
attached_comments = { },-- comments accumulator
|
||||
lineinfo_last = { 1, 1, 1, name }
|
||||
}
|
||||
setmetatable (stream, self)
|
||||
|
||||
-- skip initial sharp-bang for unix scripts
|
||||
-- FIXME: redundant with mlp.chunk()
|
||||
if src and src :match "^#" then stream.i = src :find "\n" + 1 end
|
||||
return stream
|
||||
else
|
||||
assert(false, ":newstream() takes a source string or a stream, not a "..
|
||||
type(src_or_stream))
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- if there's no ... args, return the token a (whose truth value is
|
||||
-- true) if it's a `Keyword{ }, or nil. If there are ... args, they
|
||||
-- have to be strings. if the token a is a keyword, and it's content
|
||||
-- is one of the ... args, then returns it (it's truth value is
|
||||
-- true). If no a keyword or not in ..., return nil.
|
||||
----------------------------------------------------------------------
|
||||
function lexer:is_keyword (a, ...)
|
||||
if not a or a.tag ~= "Keyword" then return false end
|
||||
local words = {...}
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Cause an error if the next token isn't a keyword whose content
|
||||
-- is listed among ... args (which have to be strings).
|
||||
----------------------------------------------------------------------
|
||||
function lexer:check (...)
|
||||
local words = {...}
|
||||
local a = self:next()
|
||||
local function err ()
|
||||
error ("Got " .. tostring (a) ..
|
||||
", expected one of these keywords : '" ..
|
||||
_G.table.concat (words,"', '") .. "'") end
|
||||
|
||||
if not a or a.tag ~= "Keyword" then err () end
|
||||
if #words == 0 then return a[1] end
|
||||
for _, w in ipairs (words) do
|
||||
if w == a[1] then return w end
|
||||
end
|
||||
err ()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
function lexer:clone()
|
||||
local clone = {
|
||||
alpha = table.deep_copy(self.alpha),
|
||||
sym = table.deep_copy(self.sym) }
|
||||
setmetatable(clone, self)
|
||||
clone.__index = clone
|
||||
return clone
|
||||
end
|
||||
440
lualibs/metalua/lopcodes.lua
Normal file
440
lualibs/metalua/lopcodes.lua
Normal file
@@ -0,0 +1,440 @@
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- WARNING! You're entering a hackish area, proceed at your own risks!
|
||||
--
|
||||
-- This code results from the borrowing, then ruthless abuse, of
|
||||
-- Yueliang's implementation of Lua 5.0 compiler. I claim
|
||||
-- responsibility for all of the ugly, dirty stuff that you might spot
|
||||
-- in it.
|
||||
--
|
||||
-- Eventually, this code will be rewritten, either in Lua or more
|
||||
-- probably in C. Meanwhile, if you're interested into digging
|
||||
-- metalua's sources, this is not the best part to invest your time
|
||||
-- on.
|
||||
--
|
||||
-- End of warning.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
|
||||
$Id$
|
||||
|
||||
lopcodes.lua
|
||||
Lua 5 virtual machine opcodes in Lua
|
||||
This file is part of Yueliang.
|
||||
|
||||
Copyright (c) 2005 Kein-Hong Man <khman@users.sf.net>
|
||||
The COPYRIGHT file describes the conditions
|
||||
under which this software may be distributed.
|
||||
|
||||
See the ChangeLog for more information.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
[FF] Slightly modified, mainly to produce Lua 5.1 bytecode.
|
||||
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
-- Notes:
|
||||
-- * an Instruction is a table with OP, A, B, C, Bx elements; this
|
||||
-- should allow instruction handling to work with doubles and ints
|
||||
-- * Added:
|
||||
-- luaP:Instruction(i): convert field elements to a 4-char string
|
||||
-- luaP:DecodeInst(x): convert 4-char string into field elements
|
||||
-- * WARNING luaP:Instruction outputs instructions encoded in little-
|
||||
-- endian form and field size and positions are hard-coded
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
module("bytecode", package.seeall)
|
||||
|
||||
local function debugf() end
|
||||
|
||||
luaP = { }
|
||||
|
||||
--[[
|
||||
===========================================================================
|
||||
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
|
||||
'Bx' : 18 bits ('B' and 'C' together)
|
||||
'sBx' : signed Bx
|
||||
|
||||
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.
|
||||
===========================================================================
|
||||
--]]
|
||||
|
||||
luaP.OpMode = {"iABC", "iABx", "iAsBx"} -- basic instruction format
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- size and position of opcode arguments.
|
||||
-- * WARNING size and position is hard-coded elsewhere in this script
|
||||
------------------------------------------------------------------------
|
||||
luaP.SIZE_C = 9
|
||||
luaP.SIZE_B = 9
|
||||
luaP.SIZE_Bx = luaP.SIZE_C + luaP.SIZE_B
|
||||
luaP.SIZE_A = 8
|
||||
|
||||
luaP.SIZE_OP = 6
|
||||
|
||||
luaP.POS_C = luaP.SIZE_OP
|
||||
luaP.POS_B = luaP.POS_C + luaP.SIZE_C
|
||||
luaP.POS_Bx = luaP.POS_C
|
||||
luaP.POS_A = luaP.POS_B + luaP.SIZE_B
|
||||
|
||||
--FF from 5.1
|
||||
luaP.BITRK = 2^(luaP.SIZE_B - 1)
|
||||
function luaP:ISK(x) return x >= self.BITRK end
|
||||
luaP.MAXINDEXRK = luaP.BITRK - 1
|
||||
function luaP:RKASK(x)
|
||||
if x < self.BITRK then return x+self.BITRK else return x end
|
||||
end
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- limits for opcode arguments.
|
||||
-- we use (signed) int to manipulate most arguments,
|
||||
-- so they must fit in BITS_INT-1 bits (-1 for sign)
|
||||
------------------------------------------------------------------------
|
||||
-- removed "#if SIZE_Bx < BITS_INT-1" test, assume this script is
|
||||
-- running on a Lua VM with double or int as LUA_NUMBER
|
||||
|
||||
luaP.MAXARG_Bx = math.ldexp(1, luaP.SIZE_Bx) - 1
|
||||
luaP.MAXARG_sBx = math.floor(luaP.MAXARG_Bx / 2) -- 'sBx' is signed
|
||||
|
||||
luaP.MAXARG_A = math.ldexp(1, luaP.SIZE_A) - 1
|
||||
luaP.MAXARG_B = math.ldexp(1, luaP.SIZE_B) - 1
|
||||
luaP.MAXARG_C = math.ldexp(1, luaP.SIZE_C) - 1
|
||||
|
||||
-- creates a mask with 'n' 1 bits at position 'p'
|
||||
-- MASK1(n,p) deleted
|
||||
-- creates a mask with 'n' 0 bits at position 'p'
|
||||
-- MASK0(n,p) deleted
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Visual representation for reference:
|
||||
|
||||
31 | | | 0 bit position
|
||||
+-----+-----+-----+----------+
|
||||
| B | C | A | Opcode | iABC format
|
||||
+-----+-----+-----+----------+
|
||||
- 9 - 9 - 8 - 6 - field sizes
|
||||
+-----+-----+-----+----------+
|
||||
| [s]Bx | A | Opcode | iABx | iAsBx format
|
||||
+-----+-----+-----+----------+
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- the following macros help to manipulate instructions
|
||||
-- * changed to a table object representation, very clean compared to
|
||||
-- the [nightmare] alternatives of using a number or a string
|
||||
------------------------------------------------------------------------
|
||||
|
||||
-- these accept or return opcodes in the form of string names
|
||||
function luaP:GET_OPCODE(i) return self.ROpCode[i.OP] end
|
||||
function luaP:SET_OPCODE(i, o) i.OP = self.OpCode[o] end
|
||||
|
||||
function luaP:GETARG_A(i) return i.A end
|
||||
function luaP:SETARG_A(i, u) i.A = u end
|
||||
|
||||
function luaP:GETARG_B(i) return i.B end
|
||||
function luaP:SETARG_B(i, b) i.B = b end
|
||||
|
||||
function luaP:GETARG_C(i) return i.C end
|
||||
function luaP:SETARG_C(i, b) i.C = b end
|
||||
|
||||
function luaP:GETARG_Bx(i) return i.Bx end
|
||||
function luaP:SETARG_Bx(i, b) i.Bx = b end
|
||||
|
||||
function luaP:GETARG_sBx(i) return i.Bx - self.MAXARG_sBx end
|
||||
function luaP:SETARG_sBx(i, b) i.Bx = b + self.MAXARG_sBx end
|
||||
|
||||
function luaP:CREATE_ABC(o,a,b,c)
|
||||
return {OP = self.OpCode[o], A = a, B = b, C = c}
|
||||
end
|
||||
|
||||
function luaP:CREATE_ABx(o,a,bc)
|
||||
return {OP = self.OpCode[o], A = a, Bx = bc}
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Bit shuffling stuffs
|
||||
------------------------------------------------------------------------
|
||||
|
||||
if false and pcall (require, 'bit') then
|
||||
------------------------------------------------------------------------
|
||||
-- Return a 4-char string little-endian encoded form of an instruction
|
||||
------------------------------------------------------------------------
|
||||
function luaP:Instruction(i)
|
||||
--FIXME
|
||||
end
|
||||
else
|
||||
------------------------------------------------------------------------
|
||||
-- Version without bit manipulation library.
|
||||
------------------------------------------------------------------------
|
||||
local p2 = {1,2,4,8,16,32,64,128,256, 512, 1024, 2048, 4096}
|
||||
-- keeps [n] bits from [x]
|
||||
local function keep (x, n) return x % p2[n+1] end
|
||||
-- shifts bits of [x] [n] places to the right
|
||||
local function srb (x,n) return math.floor (x / p2[n+1]) end
|
||||
-- shifts bits of [x] [n] places to the left
|
||||
local function slb (x,n) return x * p2[n+1] end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- Return a 4-char string little-endian encoded form of an instruction
|
||||
------------------------------------------------------------------------
|
||||
function luaP:Instruction(i)
|
||||
-- printf("Instr->string: %s %s", self.opnames[i.OP], table.tostring(i))
|
||||
local c0, c1, c2, c3
|
||||
-- change to OP/A/B/C format if needed
|
||||
if i.Bx then i.C = keep (i.Bx, 9); i.B = srb (i.Bx, 9) end
|
||||
-- c0 = 6B from opcode + 2LSB from A (flushed to MSB)
|
||||
c0 = i.OP + slb (keep (i.A, 2), 6)
|
||||
-- c1 = 6MSB from A + 2LSB from C (flushed to MSB)
|
||||
c1 = srb (i.A, 2) + slb (keep (i.C, 2), 6)
|
||||
-- c2 = 7MSB from C + 1LSB from B (flushed to MSB)
|
||||
c2 = srb (i.C, 2) + slb (keep (i.B, 1), 7)
|
||||
-- c3 = 8MSB from B
|
||||
c3 = srb (i.B, 1)
|
||||
--printf ("Instruction: %s %s", self.opnames[i.OP], tostringv (i))
|
||||
--printf ("Bin encoding: %x %x %x %x", c0, c1, c2, c3)
|
||||
return string.char(c0, c1, c2, c3)
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------
|
||||
-- decodes a 4-char little-endian string into an instruction struct
|
||||
------------------------------------------------------------------------
|
||||
function luaP:DecodeInst(x)
|
||||
error "Not implemented"
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- invalid register that fits in 8 bits
|
||||
------------------------------------------------------------------------
|
||||
luaP.NO_REG = luaP.MAXARG_A
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- R(x) - register
|
||||
-- Kst(x) - constant (in constant table)
|
||||
-- RK(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
|
||||
------------------------------------------------------------------------
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- grep "ORDER OP" if you change these enums
|
||||
------------------------------------------------------------------------
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Lua virtual machine opcodes (enum OpCode):
|
||||
------------------------------------------------------------------------
|
||||
name args description
|
||||
------------------------------------------------------------------------
|
||||
OP_MOVE A B R(A) := R(B)
|
||||
OP_LOADK A Bx R(A) := Kst(Bx)
|
||||
OP_LOADBOOL A B C R(A) := (Bool)B; if (C) PC++
|
||||
OP_LOADNIL A B R(A) := ... := R(B) := nil
|
||||
OP_GETUPVAL A B R(A) := UpValue[B]
|
||||
OP_GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)]
|
||||
OP_GETTABLE A B C R(A) := R(B)[RK(C)]
|
||||
OP_SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A)
|
||||
OP_SETUPVAL A B UpValue[B] := R(A)
|
||||
OP_SETTABLE A B C R(A)[RK(B)] := RK(C)
|
||||
OP_NEWTABLE A B C R(A) := {} (size = B,C)
|
||||
OP_SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)]
|
||||
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_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_CONCAT A B C R(A) := R(B).. ... ..R(C)
|
||||
OP_JMP sBx PC += sBx
|
||||
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_TEST A B C if (R(B) <=> C) then R(A) := R(B) else pc++
|
||||
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_FORLOOP A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBx
|
||||
OP_TFORLOOP A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||
if R(A+2) ~= nil then pc++
|
||||
OP_TFORPREP A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next;
|
||||
PC += sBx
|
||||
OP_SETLIST A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1
|
||||
OP_SETLISTO A Bx (see note)
|
||||
OP_CLOSE A close all variables in the stack up to (>=) R(A)
|
||||
OP_CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
luaP.opnames = {} -- opcode names
|
||||
luaP.OpCode = {} -- lookup name -> number
|
||||
luaP.ROpCode = {} -- lookup number -> name
|
||||
|
||||
local i = 0
|
||||
for v in string.gfind([[
|
||||
MOVE -- 0
|
||||
LOADK
|
||||
LOADBOOL
|
||||
LOADNIL
|
||||
GETUPVAL
|
||||
GETGLOBAL -- 5
|
||||
GETTABLE
|
||||
SETGLOBAL
|
||||
SETUPVAL
|
||||
SETTABLE
|
||||
NEWTABLE -- 10
|
||||
SELF
|
||||
ADD
|
||||
SUB
|
||||
MUL
|
||||
DIV -- 15
|
||||
MOD
|
||||
POW
|
||||
UNM
|
||||
NOT
|
||||
LEN -- 20
|
||||
CONCAT
|
||||
JMP
|
||||
EQ
|
||||
LT
|
||||
LE -- 25
|
||||
TEST
|
||||
TESTSET
|
||||
CALL
|
||||
TAILCALL
|
||||
RETURN -- 30
|
||||
FORLOOP
|
||||
FORPREP
|
||||
TFORLOOP
|
||||
SETLIST
|
||||
CLOSE -- 35
|
||||
CLOSURE
|
||||
VARARG
|
||||
]], "[%a]+") do
|
||||
local n = "OP_"..v
|
||||
luaP.opnames[i] = v
|
||||
luaP.OpCode[n] = i
|
||||
luaP.ROpCode[i] = n
|
||||
i = i + 1
|
||||
end
|
||||
luaP.NUM_OPCODES = i
|
||||
|
||||
--[[
|
||||
===========================================================================
|
||||
Notes:
|
||||
(1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||
and can be 0: OP_CALL then sets 'top' to last_result+1, so
|
||||
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'.
|
||||
|
||||
(2) In OP_RETURN, if (B == 0) then return up to 'top'
|
||||
|
||||
(3) For comparisons, B specifies what conditions the test should accept.
|
||||
|
||||
(4) All 'skips' (pc++) assume that next instruction is a jump
|
||||
|
||||
(5) OP_SETLISTO is used when the last item in a table constructor is a
|
||||
function, so the number of elements set is up to top of stack
|
||||
===========================================================================
|
||||
--]]
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- masks for instruction properties
|
||||
------------------------------------------------------------------------
|
||||
-- was enum OpModeMask:
|
||||
luaP.OpModeBreg = 2 -- B is a register
|
||||
luaP.OpModeBrk = 3 -- B is a register/constant
|
||||
luaP.OpModeCrk = 4 -- C is a register/constant
|
||||
luaP.OpModesetA = 5 -- instruction set register A
|
||||
luaP.OpModeK = 6 -- Bx is a constant
|
||||
luaP.OpModeT = 1 -- operator is a test
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- get opcode mode, e.g. "iABC"
|
||||
------------------------------------------------------------------------
|
||||
function luaP:getOpMode(m)
|
||||
--printv(m)
|
||||
--printv(self.OpCode[m])
|
||||
--printv(self.opmodes [self.OpCode[m]+1])
|
||||
return self.OpMode[tonumber(string.sub(self.opmodes[self.OpCode[m] + 1], 7, 7))]
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- test an instruction property flag
|
||||
-- * b is a string, e.g. "OpModeBreg"
|
||||
------------------------------------------------------------------------
|
||||
function luaP:testOpMode(m, b)
|
||||
return (string.sub(self.opmodes[self.OpCode[m] + 1], self[b], self[b]) == "1")
|
||||
end
|
||||
|
||||
-- number of list items to accumulate before a SETLIST instruction
|
||||
-- (must be a power of 2)
|
||||
-- * used in lparser, lvm, ldebug, ltests
|
||||
luaP.LFIELDS_PER_FLUSH = 50 --FF updated to match 5.1
|
||||
|
||||
-- luaP_opnames[] is set above, as the luaP.opnames table
|
||||
-- opmode(t,b,bk,ck,sa,k,m) deleted
|
||||
|
||||
--[[--------------------------------------------------------------------
|
||||
Legend for luaP:opmodes:
|
||||
1 T -> T (is a test?)
|
||||
2 B -> B is a register
|
||||
3 b -> B is an RK register/constant combination
|
||||
4 C -> C is an RK register/constant combination
|
||||
5 A -> register A is set by the opcode
|
||||
6 K -> Bx is a constant
|
||||
7 m -> 1 if iABC layout,
|
||||
2 if iABx layout,
|
||||
3 if iAsBx layout
|
||||
----------------------------------------------------------------------]]
|
||||
|
||||
luaP.opmodes = {
|
||||
-- TBbCAKm opcode
|
||||
"0100101", -- OP_MOVE 0
|
||||
"0000112", -- OP_LOADK
|
||||
"0000101", -- OP_LOADBOOL
|
||||
"0100101", -- OP_LOADNIL
|
||||
"0000101", -- OP_GETUPVAL
|
||||
"0000112", -- OP_GETGLOBAL 5
|
||||
"0101101", -- OP_GETTABLE
|
||||
"0000012", -- OP_SETGLOBAL
|
||||
"0000001", -- OP_SETUPVAL
|
||||
"0011001", -- OP_SETTABLE
|
||||
"0000101", -- OP_NEWTABLE 10
|
||||
"0101101", -- OP_SELF
|
||||
"0011101", -- OP_ADD
|
||||
"0011101", -- OP_SUB
|
||||
"0011101", -- OP_MUL
|
||||
"0011101", -- OP_DIV 15
|
||||
"0011101", -- OP_MOD
|
||||
"0011101", -- OP_POW
|
||||
"0100101", -- OP_UNM
|
||||
"0100101", -- OP_NOT
|
||||
"0100101", -- OP_LEN 20
|
||||
"0101101", -- OP_CONCAT
|
||||
"0000003", -- OP_JMP
|
||||
"1011001", -- OP_EQ
|
||||
"1011001", -- OP_LT
|
||||
"1011001", -- OP_LE 25
|
||||
"1000101", -- OP_TEST
|
||||
"1100101", -- OP_TESTSET
|
||||
"0000001", -- OP_CALL
|
||||
"0000001", -- OP_TAILCALL
|
||||
"0000001", -- OP_RETURN 30
|
||||
"0000003", -- OP_FORLOOP
|
||||
"0000103", -- OP_FORPREP
|
||||
"1000101", -- OP_TFORLOOP
|
||||
"0000001", -- OP_SETLIST
|
||||
"0000001", -- OP_CLOSE 35
|
||||
"0000102", -- OP_CLOSURE
|
||||
"0000101" -- OP_VARARG
|
||||
}
|
||||
60
lualibs/metalua/metalua.lua
Normal file
60
lualibs/metalua/metalua.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
-- construct proper path to load metalua modules to build
|
||||
-- an abstract syntax tree (AST)
|
||||
local file = debug.getinfo(1, "S").source
|
||||
if string.find(file, "@") == 1 then file = string.sub(file, 2) end
|
||||
package.path = package.path .. ';' .. string.gsub(file, "metalua%.lua$", "?.lua")
|
||||
|
||||
-- these modules are sufficient to build an AST from a source file/string
|
||||
require "lexer"
|
||||
require "gg"
|
||||
require "mlp_lexer"
|
||||
require "mlp_misc"
|
||||
require "mlp_table"
|
||||
require "mlp_meta"
|
||||
require "mlp_expr"
|
||||
require "mlp_stat"
|
||||
|
||||
-- these modules are needed to convert an AST into bytecode to execute
|
||||
require "lcode"
|
||||
require "ldump"
|
||||
require "lopcodes"
|
||||
require "compile"
|
||||
|
||||
-- this is the compiler module that builds bytecode from an AST
|
||||
local mlc = { }
|
||||
|
||||
function mlc.function_of_ast (ast)
|
||||
local proto = bytecode.metalua_compile(ast)
|
||||
local dump = bytecode.dump_string(proto)
|
||||
local func = string.undump(dump)
|
||||
return func
|
||||
end
|
||||
|
||||
function mlc.ast_of_luastring (src, file)
|
||||
local lx = mlp.lexer:newstream(src, file or "(string)")
|
||||
local ast = mlp.chunk(lx)
|
||||
return ast
|
||||
end
|
||||
|
||||
function mlc.function_of_luastring (src, file)
|
||||
local ast = mlc.ast_of_luastring(src, file)
|
||||
local func = mlc.function_of_ast(ast)
|
||||
return func
|
||||
end
|
||||
|
||||
function mlc.function_of_luafile (name)
|
||||
local f = io.open(name, 'r')
|
||||
local src = f:read('*a')
|
||||
f:close()
|
||||
return mlc.function_of_luastring(src, "@"..name)
|
||||
end
|
||||
|
||||
_G.mlc = mlc
|
||||
|
||||
--[[
|
||||
-- Can be used with the following code:
|
||||
require "metalua"
|
||||
local ast = mlc.ast_of_luastring(src)
|
||||
local f = mlc.function_of_ast(ast)
|
||||
f()
|
||||
]]
|
||||
104
lualibs/metalua/metalua/base.lua
Normal file
104
lualibs/metalua/metalua/base.lua
Normal file
@@ -0,0 +1,104 @@
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Base library extension
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
if not metalua then rawset(getfenv(), 'metalua', { }) end
|
||||
metalua.version = "v-0.5"
|
||||
|
||||
if not rawpairs then
|
||||
rawpairs, rawipairs, rawtype = pairs, ipairs, type
|
||||
end
|
||||
|
||||
function pairs(x)
|
||||
assert(type(x)=='table', 'pairs() expects a table')
|
||||
local mt = getmetatable(x)
|
||||
if mt then
|
||||
local mtp = mt.__pairs
|
||||
if mtp then return mtp(x) end
|
||||
end
|
||||
return rawpairs(x)
|
||||
end
|
||||
|
||||
function ipairs(x)
|
||||
assert(type(x)=='table', 'ipairs() expects a table')
|
||||
local mt = getmetatable(x)
|
||||
if mt then
|
||||
local mti = mt.__ipairs
|
||||
if mti then return mti(x) end
|
||||
end
|
||||
return rawipairs(x)
|
||||
end
|
||||
|
||||
--[[
|
||||
function type(x)
|
||||
local mt = getmetatable(x)
|
||||
if mt then
|
||||
local mtt = mt.__type
|
||||
if mtt then return mtt end
|
||||
end
|
||||
return rawtype(x)
|
||||
end
|
||||
]]
|
||||
|
||||
function min (a, ...)
|
||||
for n in values{...} do if n<a then a=n end end
|
||||
return a
|
||||
end
|
||||
|
||||
function max (a, ...)
|
||||
for n in values{...} do if n>a then a=n end end
|
||||
return a
|
||||
end
|
||||
|
||||
function o (...)
|
||||
local args = {...}
|
||||
local function g (...)
|
||||
local result = {...}
|
||||
for i=#args, 1, -1 do result = {args[i](unpack(result))} end
|
||||
return unpack (result)
|
||||
end
|
||||
return g
|
||||
end
|
||||
|
||||
function id (...) return ... end
|
||||
function const (k) return function () return k end end
|
||||
|
||||
function printf(...) return print(string.format(...)) end
|
||||
function eprintf(...)
|
||||
io.stderr:write(string.format(...).."\n")
|
||||
end
|
||||
|
||||
function ivalues (x)
|
||||
assert(type(x)=='table', 'ivalues() expects a table')
|
||||
local i = 1
|
||||
local function iterator ()
|
||||
local r = x[i]; i=i+1; return r
|
||||
end
|
||||
return iterator
|
||||
end
|
||||
|
||||
|
||||
function values (x)
|
||||
assert(type(x)=='table', 'values() expects a table')
|
||||
local function iterator (state)
|
||||
local it
|
||||
state.content, it = next(state.list, state.content)
|
||||
return it
|
||||
end
|
||||
return iterator, { list = x }
|
||||
end
|
||||
|
||||
function keys (x)
|
||||
assert(type(x)=='table', 'keys() expects a table')
|
||||
local function iterator (state)
|
||||
local it = next(state.list, state.content)
|
||||
state.content = it
|
||||
return it
|
||||
end
|
||||
return iterator, { list = x }
|
||||
end
|
||||
|
||||
3
lualibs/metalua/metalua/runtime.lua
Normal file
3
lualibs/metalua/metalua/runtime.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
require 'metalua.base'
|
||||
require 'metalua.table2'
|
||||
require 'metalua.string2'
|
||||
43
lualibs/metalua/metalua/string2.lua
Normal file
43
lualibs/metalua/metalua/string2.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- String module extension
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- Courtesy of lua-users.org
|
||||
function string.split(str, pat)
|
||||
local t = {}
|
||||
local fpat = "(.-)" .. pat
|
||||
local last_end = 1
|
||||
local s, e, cap = string.find(str, fpat, 1)
|
||||
while s do
|
||||
if s ~= 1 or cap ~= "" then
|
||||
table.insert(t,cap)
|
||||
end
|
||||
last_end = e+1
|
||||
s, e, cap = string.find(str, fpat, last_end)
|
||||
end
|
||||
if last_end <= string.len(str) then
|
||||
cap = string.sub(str, last_end)
|
||||
table.insert(t, cap)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
-- "match" is regularly used as a keyword for pattern matching,
|
||||
-- so here is an always available substitute.
|
||||
string.strmatch = string["match"]
|
||||
|
||||
-- change a compiled string into a function
|
||||
function string.undump(str)
|
||||
if str:strmatch '^\027LuaQ' or str:strmatch '^#![^\n]+\n\027LuaQ' then
|
||||
local f = (lua_loadstring or loadstring)(str)
|
||||
return f
|
||||
else
|
||||
error "Not a chunk dump"
|
||||
end
|
||||
end
|
||||
|
||||
return string
|
||||
380
lualibs/metalua/metalua/table2.lua
Normal file
380
lualibs/metalua/metalua/table2.lua
Normal file
@@ -0,0 +1,380 @@
|
||||
---------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Table module extension
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- todo: table.scan (scan1?) fold1? flip?
|
||||
|
||||
function table.transpose(t)
|
||||
local tt = { }
|
||||
for a, b in pairs(t) do tt[b] = a end
|
||||
return tt
|
||||
end
|
||||
|
||||
function table.iforeach(f, ...)
|
||||
-- assert (type (f) == "function") [wouldn't allow metamethod __call]
|
||||
local nargs = select("#", ...)
|
||||
if nargs==1 then -- Quick iforeach (most common case), just one table arg
|
||||
local t = ...
|
||||
assert (type (t) == "table")
|
||||
for i = 1, #t do
|
||||
local result = f (t[i])
|
||||
-- If the function returns non-false, stop iteration
|
||||
if result then return result end
|
||||
end
|
||||
else -- advanced case: boundaries and/or multiple tables
|
||||
|
||||
-- fargs: arguments fot a single call to f
|
||||
-- first, last: indexes of the first & last elements mapped in each table
|
||||
-- arg1: index of the first table in args
|
||||
|
||||
-- 1 - find boundaries if any
|
||||
local args, fargs, first, last, arg1 = {...}, { }
|
||||
if type(args[1]) ~= "number" then first, arg1 = 1, 1 -- no boundary
|
||||
elseif type(args[2]) ~= "number" then first, last, arg1 = 1, args[1], 2
|
||||
else first, last, arg1 = args[1], args[2], 3 end
|
||||
assert (nargs >= arg1) -- at least one table
|
||||
-- 2 - determine upper boundary if not given
|
||||
if not last then for i = arg1, nargs do
|
||||
assert (type (args[i]) == "table")
|
||||
last = max (#args[i], last)
|
||||
end end
|
||||
-- 3 - remove non-table arguments from args, adjust nargs
|
||||
if arg1>1 then args = { select(arg1, unpack(args)) }; nargs = #args end
|
||||
|
||||
-- 4 - perform the iteration
|
||||
for i = first, last do
|
||||
for j = 1, nargs do fargs[j] = args[j][i] end -- build args list
|
||||
local result = f (unpack (fargs)) -- here is the call
|
||||
-- If the function returns non-false, stop iteration
|
||||
if result then return result end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function table.imap (f, ...)
|
||||
local result, idx = { }, 1
|
||||
local function g(...) result[idx] = f(...); idx=idx+1 end
|
||||
table.iforeach(g, ...)
|
||||
return result
|
||||
end
|
||||
|
||||
function table.ifold (f, acc, ...)
|
||||
local function g(...) acc = f (acc,...) end
|
||||
table.iforeach (g, ...)
|
||||
return acc
|
||||
end
|
||||
|
||||
-- function table.ifold1 (f, ...)
|
||||
-- return table.ifold (f, acc, 2, false, ...)
|
||||
-- end
|
||||
|
||||
function table.izip(...)
|
||||
local function g(...) return {...} end
|
||||
return table.imap(g, ...)
|
||||
end
|
||||
|
||||
function table.ifilter(f, t)
|
||||
local yes, no = { }, { }
|
||||
for i=1,#t do table.insert (f(t[i]) and yes or no, t[i]) end
|
||||
return yes, no
|
||||
end
|
||||
|
||||
function table.icat(...)
|
||||
local result = { }
|
||||
for t in values {...} do
|
||||
for x in values (t) do
|
||||
table.insert (result, x)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function table.iflatten (x) return table.icat (unpack (x)) end
|
||||
|
||||
function table.irev (t)
|
||||
local result, nt = { }, #t
|
||||
for i=0, nt-1 do result[nt-i] = t[i+1] end
|
||||
return result
|
||||
end
|
||||
|
||||
function table.isub (t, ...)
|
||||
local ti, u = table.insert, { }
|
||||
local args, nargs = {...}, select("#", ...)
|
||||
for i=1, nargs/2 do
|
||||
local a, b = args[2*i-1], args[2*i]
|
||||
for i=a, b, a<=b and 1 or -1 do ti(u, t[i]) end
|
||||
end
|
||||
return u
|
||||
end
|
||||
|
||||
function table.iall (f, ...)
|
||||
local result = true
|
||||
local function g(...) return not f(...) end
|
||||
return not table.iforeach(g, ...)
|
||||
--return result
|
||||
end
|
||||
|
||||
function table.iany (f, ...)
|
||||
local function g(...) return not f(...) end
|
||||
return not table.iall(g, ...)
|
||||
end
|
||||
|
||||
function table.shallow_copy(x)
|
||||
local y={ }
|
||||
for k, v in pairs(x) do y[k]=v end
|
||||
return y
|
||||
end
|
||||
|
||||
-- Warning, this is implementation dependent: it relies on
|
||||
-- the fact the [next()] enumerates the array-part before the hash-part.
|
||||
function table.cat(...)
|
||||
local y={ }
|
||||
for x in values{...} do
|
||||
-- cat array-part
|
||||
for _, v in ipairs(x) do table.insert(y,v) end
|
||||
-- cat hash-part
|
||||
local lx, k = #x
|
||||
if lx>0 then k=next(x,lx) else k=next(x) end
|
||||
while k do y[k]=x[k]; k=next(x,k) end
|
||||
end
|
||||
return y
|
||||
end
|
||||
|
||||
function table.deep_copy(x)
|
||||
local tracker = { }
|
||||
local function aux (x)
|
||||
if type(x) == "table" then
|
||||
local y=tracker[x]
|
||||
if y then return y end
|
||||
y = { }; tracker[x] = y
|
||||
setmetatable (y, getmetatable (x))
|
||||
for k,v in pairs(x) do y[aux(k)] = aux(v) end
|
||||
return y
|
||||
else return x end
|
||||
end
|
||||
return aux(x)
|
||||
end
|
||||
|
||||
function table.override(dst, src)
|
||||
for k, v in pairs(src) do dst[k] = v end
|
||||
for i = #src+1, #dst do dst[i] = nil end
|
||||
return dst
|
||||
end
|
||||
|
||||
|
||||
function table.range(a,b,c)
|
||||
if not b then assert(not(c)); b=a; a=1
|
||||
elseif not c then c = (b>=a) and 1 or -1 end
|
||||
local result = { }
|
||||
for i=a, b, c do table.insert(result, i) end
|
||||
return result
|
||||
end
|
||||
|
||||
-- FIXME: new_indent seems to be always nil?!
|
||||
-- FIXME: accumulator function should be configurable,
|
||||
-- so that print() doesn't need to bufferize the whole string
|
||||
-- before starting to print.
|
||||
function table.tostring(t, ...)
|
||||
local PRINT_HASH, HANDLE_TAG, FIX_INDENT, LINE_MAX, INITIAL_INDENT = true, true
|
||||
for _, x in ipairs {...} do
|
||||
if type(x) == "number" then
|
||||
if not LINE_MAX then LINE_MAX = x
|
||||
else INITIAL_INDENT = x end
|
||||
elseif x=="nohash" then PRINT_HASH = false
|
||||
elseif x=="notag" then HANDLE_TAG = false
|
||||
else
|
||||
local n = string['match'](x, "^indent%s*(%d*)$")
|
||||
if n then FIX_INDENT = tonumber(n) or 3 end
|
||||
end
|
||||
end
|
||||
LINE_MAX = LINE_MAX or math.huge
|
||||
INITIAL_INDENT = INITIAL_INDENT or 1
|
||||
|
||||
local current_offset = 0 -- indentation level
|
||||
local xlen_cache = { } -- cached results for xlen()
|
||||
local acc_list = { } -- Generated bits of string
|
||||
local function acc(...) -- Accumulate a bit of string
|
||||
local x = table.concat{...}
|
||||
current_offset = current_offset + #x
|
||||
table.insert(acc_list, x)
|
||||
end
|
||||
local function valid_id(x)
|
||||
-- FIXME: we should also reject keywords; but the list of
|
||||
-- current keywords is not fixed in metalua...
|
||||
return type(x) == "string"
|
||||
and string['match'](x, "^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
end
|
||||
|
||||
-- Compute the number of chars it would require to display the table
|
||||
-- on a single line. Helps to decide whether some carriage returns are
|
||||
-- required. Since the size of each sub-table is required many times,
|
||||
-- it's cached in [xlen_cache].
|
||||
local xlen_type = { }
|
||||
local function xlen(x, nested)
|
||||
nested = nested or { }
|
||||
if x==nil then return #"nil" end
|
||||
--if nested[x] then return #tostring(x) end -- already done in table
|
||||
local len = xlen_cache[x]
|
||||
if len then return len end
|
||||
local f = xlen_type[type(x)]
|
||||
if not f then return #tostring(x) end
|
||||
len = f (x, nested)
|
||||
xlen_cache[x] = len
|
||||
return len
|
||||
end
|
||||
|
||||
-- optim: no need to compute lengths if I'm not going to use them
|
||||
-- anyway.
|
||||
if LINE_MAX == math.huge then xlen = function() return 0 end end
|
||||
|
||||
xlen_type["nil"] = function () return 3 end
|
||||
function xlen_type.number (x) return #tostring(x) end
|
||||
function xlen_type.boolean (x) return x and 4 or 5 end
|
||||
function xlen_type.string (x) return #string.format("%q",x) end
|
||||
function xlen_type.table (adt, nested)
|
||||
|
||||
-- Circular references detection
|
||||
if nested [adt] then return #tostring(adt) end
|
||||
nested [adt] = true
|
||||
|
||||
local has_tag = HANDLE_TAG and valid_id(adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
local x = 0
|
||||
|
||||
if PRINT_HASH then
|
||||
-- first pass: count hash-part
|
||||
for k, v in pairs(adt) do
|
||||
if k=="tag" and has_tag then
|
||||
-- this is the tag -> do nothing!
|
||||
elseif type(k)=="number" and k<=alen and math.fmod(k,1)==0 then
|
||||
-- array-part pair -> do nothing!
|
||||
else
|
||||
has_hash = true
|
||||
if valid_id(k) then x=x+#k
|
||||
else x = x + xlen (k, nested) + 2 end -- count surrounding brackets
|
||||
x = x + xlen (v, nested) + 5 -- count " = " and ", "
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, alen do x = x + xlen (adt[i], nested) + 2 end -- count ", "
|
||||
|
||||
nested[adt] = false -- No more nested calls
|
||||
|
||||
if not (has_tag or has_arr or has_hash) then return 3 end
|
||||
if has_tag then x=x+#adt.tag+1 end
|
||||
if not (has_arr or has_hash) then return x end
|
||||
if not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
return x-2 -- substract extraneous ", "
|
||||
end
|
||||
return x+2 -- count "{ " and " }", substract extraneous ", "
|
||||
end
|
||||
|
||||
-- Recursively print a (sub) table at given indentation level.
|
||||
-- [newline] indicates whether newlines should be inserted.
|
||||
local function rec (adt, nested, indent)
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
local function acc_newline()
|
||||
acc ("\n"); acc (string.rep (" ", indent))
|
||||
current_offset = indent
|
||||
end
|
||||
local x = { }
|
||||
x["nil"] = function() acc "nil" end
|
||||
function x.number() acc (tostring (adt)) end
|
||||
--function x.string() acc (string.format ("%q", adt)) end
|
||||
function x.string() acc ((string.format ("%q", adt):gsub("\\\n", "\\n"))) end
|
||||
function x.boolean() acc (adt and "true" or "false") end
|
||||
function x.table()
|
||||
if nested[adt] then acc(tostring(adt)); return end
|
||||
nested[adt] = true
|
||||
|
||||
|
||||
local has_tag = HANDLE_TAG and valid_id(adt.tag)
|
||||
local alen = #adt
|
||||
local has_arr = alen>0
|
||||
local has_hash = false
|
||||
|
||||
if has_tag then acc("`"); acc(adt.tag) end
|
||||
|
||||
-- First pass: handle hash-part
|
||||
if PRINT_HASH then
|
||||
for k, v in pairs(adt) do
|
||||
-- pass if the key belongs to the array-part or is the "tag" field
|
||||
if not (k=="tag" and HANDLE_TAG) and
|
||||
not (type(k)=="number" and k<=alen and math.fmod(k,1)==0) then
|
||||
|
||||
-- Is it the first time we parse a hash pair?
|
||||
if not has_hash then
|
||||
acc "{ "
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
else acc ", " end
|
||||
|
||||
-- Determine whether a newline is required
|
||||
local is_id, expected_len = valid_id(k)
|
||||
if is_id then expected_len = #k + xlen (v, nested) + #" = , "
|
||||
else expected_len = xlen (k, nested) +
|
||||
xlen (v, nested) + #"[] = , " end
|
||||
if has_hash and expected_len + current_offset > LINE_MAX
|
||||
then acc_newline() end
|
||||
|
||||
-- Print the key
|
||||
if is_id then acc(k); acc " = "
|
||||
else acc "["; rec (k, nested, indent+(FIX_INDENT or 0)); acc "] = " end
|
||||
|
||||
-- Print the value
|
||||
rec (v, nested, indent+(FIX_INDENT or 0))
|
||||
has_hash = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now we know whether there's a hash-part, an array-part, and a tag.
|
||||
-- Tag and hash-part are already printed if they're present.
|
||||
if not has_tag and not has_hash and not has_arr then acc "{ }";
|
||||
elseif has_tag and not has_hash and not has_arr then -- nothing, tag already in acc
|
||||
else
|
||||
assert (has_hash or has_arr)
|
||||
local no_brace = false
|
||||
if has_hash and has_arr then acc ", "
|
||||
elseif has_tag and not has_hash and alen==1 and type(adt[1])~="table" then
|
||||
-- No brace required; don't print "{", remember not to print "}"
|
||||
acc (" "); rec (adt[1], nested, indent+(FIX_INDENT or 0))
|
||||
no_brace = true
|
||||
elseif not has_hash then
|
||||
-- Braces required, but not opened by hash-part handler yet
|
||||
acc "{ "
|
||||
if not FIX_INDENT then indent = current_offset end
|
||||
end
|
||||
|
||||
-- 2nd pass: array-part
|
||||
if not no_brace and has_arr then
|
||||
rec (adt[1], nested, indent+(FIX_INDENT or 0))
|
||||
for i=2, alen do
|
||||
acc ", ";
|
||||
if current_offset + xlen (adt[i], { }) > LINE_MAX
|
||||
then acc_newline() end
|
||||
rec (adt[i], nested, indent+(FIX_INDENT or 0))
|
||||
end
|
||||
end
|
||||
if not no_brace then acc " }" end
|
||||
end
|
||||
nested[adt] = false -- No more nested calls
|
||||
end
|
||||
local y = x[type(adt)]
|
||||
if y then y() else acc(tostring(adt)) end
|
||||
end
|
||||
--printf("INITIAL_INDENT = %i", INITIAL_INDENT)
|
||||
current_offset = INITIAL_INDENT or 0
|
||||
rec(t, { }, 0)
|
||||
return table.concat (acc_list)
|
||||
end
|
||||
|
||||
function table.print(...) return print(table.tostring(...)) end
|
||||
|
||||
return table
|
||||
213
lualibs/metalua/mlp_expr.lua
Normal file
213
lualibs/metalua/mlp_expr.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_expr.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, expression parser. This is part of the
|
||||
-- definition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_expr.lua,v $
|
||||
-- Revision 1.7 2006/11/15 09:07:50 fab13n
|
||||
-- debugged meta operators.
|
||||
-- Added command line options handling.
|
||||
--
|
||||
-- Revision 1.6 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.5 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.4 2006/11/07 21:29:02 fab13n
|
||||
-- improved quasi-quoting
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.expr()]
|
||||
-- * [mlp.expr_list()]
|
||||
-- * [mlp.func_val()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mlp_misc"
|
||||
--require "mlp_table"
|
||||
--require "mlp_meta"
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- These function wrappers (eta-expansions ctually) are just here to break
|
||||
-- some circular dependencies between mlp_xxx.lua files.
|
||||
--------------------------------------------------------------------------------
|
||||
local function _expr (lx) return mlp.expr (lx) end
|
||||
local function _table_content (lx) return mlp.table_content (lx) end
|
||||
local function block (lx) return mlp.block (lx) end
|
||||
local function stat (lx) return mlp.stat (lx) end
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Non-empty expression list. Actually, this isn't used here, but that's
|
||||
-- handy to give to users.
|
||||
--------------------------------------------------------------------------------
|
||||
expr_list = gg.list{ _expr, separators = "," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Helpers for function applications / method applications
|
||||
--------------------------------------------------------------------------------
|
||||
func_args_content = gg.list {
|
||||
name = "function arguments",
|
||||
_expr, separators = ",", terminators = ")" }
|
||||
|
||||
-- Used to parse methods
|
||||
method_args = gg.multisequence{
|
||||
name = "function argument(s)",
|
||||
{ "{", table_content, "}" },
|
||||
{ "(", func_args_content, ")", builder = fget(1) },
|
||||
{ "+{", quote_content, "}" },
|
||||
function(lx) local r = opt_string(lx); return r and {r} or { } end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [func_val] parses a function, from opening parameters parenthese to
|
||||
-- "end" keyword included. Used for anonymous functions as well as
|
||||
-- function declaration statements (both local and global).
|
||||
--
|
||||
-- It's wrapped in a [_func_val] eta expansion, so that when expr
|
||||
-- parser uses the latter, they will notice updates of [func_val]
|
||||
-- definitions.
|
||||
--------------------------------------------------------------------------------
|
||||
func_params_content = gg.list{ name="function parameters",
|
||||
gg.multisequence{ { "...", builder = "Dots" }, id },
|
||||
separators = ",", terminators = {")", "|"} }
|
||||
|
||||
local _func_params_content = function (lx) return func_params_content(lx) end
|
||||
|
||||
func_val = gg.sequence { name="function body",
|
||||
"(", func_params_content, ")", block, "end", builder = "Function" }
|
||||
|
||||
local _func_val = function (lx) return func_val(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Default parser for primary expressions
|
||||
--------------------------------------------------------------------------------
|
||||
function id_or_literal (lx)
|
||||
local a = lx:next()
|
||||
if a.tag~="Id" and a.tag~="String" and a.tag~="Number" then
|
||||
local msg
|
||||
if a.tag=='Eof' then
|
||||
msg = "End of file reached when an expression was expected"
|
||||
elseif a.tag=='Keyword' then
|
||||
msg = "An expression was expected, and `"..a[1]..
|
||||
"' can't start an expression"
|
||||
else
|
||||
msg = "Unexpected expr token " .. _G.table.tostring (a, 'nohash')
|
||||
end
|
||||
gg.parse_error (lx, msg)
|
||||
end
|
||||
return a
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Builder generator for operators. Wouldn't be worth it if "|x|" notation
|
||||
-- were allowed, but then lua 5.1 wouldn't compile it
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- opf1 = |op| |_,a| `Op{ op, a }
|
||||
local function opf1 (op) return
|
||||
function (_,a) return { tag="Op", op, a } end end
|
||||
|
||||
-- opf2 = |op| |a,_,b| `Op{ op, a, b }
|
||||
local function opf2 (op) return
|
||||
function (a,_,b) return { tag="Op", op, a, b } end end
|
||||
|
||||
-- opf2r = |op| |a,_,b| `Op{ op, b, a } -- (args reversed)
|
||||
local function opf2r (op) return
|
||||
function (a,_,b) return { tag="Op", op, b, a } end end
|
||||
|
||||
local function op_ne(a, _, b)
|
||||
-- The first version guarantees to return the same code as Lua,
|
||||
-- but it relies on the non-standard 'ne' operator, which has been
|
||||
-- suppressed from the official AST grammar (although still supported
|
||||
-- in practice by the compiler).
|
||||
-- return { tag="Op", "ne", a, b }
|
||||
return { tag="Op", "not", { tag="Op", "eq", a, b, lineinfo= {
|
||||
first = a.lineinfo.first, last = b.lineinfo.last } } }
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- complete expression
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- FIXME: set line number. In [expr] transformers probably
|
||||
|
||||
expr = gg.expr { name = "expression",
|
||||
|
||||
primary = gg.multisequence{ name="expr primary",
|
||||
{ "(", _expr, ")", builder = "Paren" },
|
||||
{ "function", _func_val, builder = fget(1) },
|
||||
{ "-{", splice_content, "}", builder = fget(1) },
|
||||
{ "+{", quote_content, "}", builder = fget(1) },
|
||||
{ "nil", builder = "Nil" },
|
||||
{ "true", builder = "True" },
|
||||
{ "false", builder = "False" },
|
||||
{ "...", builder = "Dots" },
|
||||
table,
|
||||
id_or_literal },
|
||||
|
||||
infix = { name="expr infix op",
|
||||
{ "+", prec = 60, builder = opf2 "add" },
|
||||
{ "-", prec = 60, builder = opf2 "sub" },
|
||||
{ "*", prec = 70, builder = opf2 "mul" },
|
||||
{ "/", prec = 70, builder = opf2 "div" },
|
||||
{ "%", prec = 70, builder = opf2 "mod" },
|
||||
{ "^", prec = 90, builder = opf2 "pow", assoc = "right" },
|
||||
{ "..", prec = 40, builder = opf2 "concat", assoc = "right" },
|
||||
{ "==", prec = 30, builder = opf2 "eq" },
|
||||
{ "~=", prec = 30, builder = op_ne },
|
||||
{ "<", prec = 30, builder = opf2 "lt" },
|
||||
{ "<=", prec = 30, builder = opf2 "le" },
|
||||
{ ">", prec = 30, builder = opf2r "lt" },
|
||||
{ ">=", prec = 30, builder = opf2r "le" },
|
||||
{ "and",prec = 20, builder = opf2 "and" },
|
||||
{ "or", prec = 10, builder = opf2 "or" } },
|
||||
|
||||
prefix = { name="expr prefix op",
|
||||
{ "not", prec = 80, builder = opf1 "not" },
|
||||
{ "#", prec = 80, builder = opf1 "len" },
|
||||
{ "-", prec = 80, builder = opf1 "unm" } },
|
||||
|
||||
suffix = { name="expr suffix op",
|
||||
{ "[", _expr, "]", builder = function (tab, idx)
|
||||
return {tag="Index", tab, idx[1]} end},
|
||||
{ ".", id, builder = function (tab, field)
|
||||
return {tag="Index", tab, id2string(field[1])} end },
|
||||
{ "(", func_args_content, ")", builder = function(f, args)
|
||||
return {tag="Call", f, unpack(args[1])} end },
|
||||
{ "{", _table_content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1]} end},
|
||||
{ ":", id, method_args, builder = function (obj, post)
|
||||
return {tag="Invoke", obj, id2string(post[1]), unpack(post[2])} end},
|
||||
{ "+{", quote_content, "}", builder = function (f, arg)
|
||||
return {tag="Call", f, arg[1] } end },
|
||||
default = { name="opt_string_arg", parse = mlp.opt_string, builder = function(f, arg)
|
||||
return {tag="Call", f, arg } end } } }
|
||||
89
lualibs/metalua/mlp_ext.lua
Normal file
89
lualibs/metalua/mlp_ext.lua
Normal file
@@ -0,0 +1,89 @@
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Non-Lua syntax extensions
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Alebraic Datatypes
|
||||
--------------------------------------------------------------------------------
|
||||
local function adt (lx)
|
||||
local tagval = id (lx) [1]
|
||||
local tagkey = {tag="Pair", {tag="String", "tag"}, {tag="String", tagval} }
|
||||
if lx:peek().tag == "String" or lx:peek().tag == "Number" then
|
||||
return { tag="Table", tagkey, lx:next() }
|
||||
elseif lx:is_keyword (lx:peek(), "{") then
|
||||
local x = table (lx)
|
||||
_G.table.insert (x, 1, tagkey)
|
||||
return x
|
||||
else return { tag="Table", tagkey } end
|
||||
end
|
||||
|
||||
expr:add{ "`", adt, builder = fget(1) }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Anonymous lambda
|
||||
--------------------------------------------------------------------------------
|
||||
local lambda_expr = gg.sequence{
|
||||
"|", func_params_content, "|", expr,
|
||||
builder= function (x)
|
||||
local li = x[2].lineinfo
|
||||
return { tag="Function", x[1],
|
||||
{ {tag="Return", x[2], lineinfo=li }, lineinfo=li } }
|
||||
end }
|
||||
|
||||
-- In an earlier version, lambda_expr took an expr_list rather than an expr
|
||||
-- after the 2nd bar. However, it happened to be much more of a burden than an
|
||||
-- help, So finally I disabled it. If you want to return several results,
|
||||
-- use the long syntax.
|
||||
--------------------------------------------------------------------------------
|
||||
-- local lambda_expr = gg.sequence{
|
||||
-- "|", func_params_content, "|", expr_list,
|
||||
-- builder= function (x)
|
||||
-- return {tag="Function", x[1], { {tag="Return", unpack(x[2]) } } } end }
|
||||
|
||||
expr:add (lambda_expr)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Allows to write "a `f` b" instead of "f(a, b)". Taken from Haskell.
|
||||
-- This is not part of Lua 5.1 syntax, so it's added to the expression
|
||||
-- afterwards, so that it's easier to disable.
|
||||
--------------------------------------------------------------------------------
|
||||
local function expr_in_backquotes (lx) return expr(lx, 35) end
|
||||
|
||||
expr.infix:add{ name = "infix function",
|
||||
"`", expr_in_backquotes, "`", prec = 35, assoc="left",
|
||||
builder = function(a, op, b) return {tag="Call", op[1], a, b} end }
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- table.override assignment
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
mlp.lexer:add "<-"
|
||||
stat.assignments["<-"] = function (a, b)
|
||||
assert( #a==1 and #b==1, "No multi-args for '<-'")
|
||||
return { tag="Call", { tag="Index", { tag="Id", "table" },
|
||||
{ tag="String", "override" } },
|
||||
a[1], b[1]}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- C-style op+assignments
|
||||
--------------------------------------------------------------------------------
|
||||
local function op_assign(kw, op)
|
||||
local function rhs(a, b)
|
||||
return { tag="Op", op, a, b }
|
||||
end
|
||||
local function f(a,b)
|
||||
return { tag="Set", a, _G.table.imap(rhs, a, b) }
|
||||
end
|
||||
mlp.lexer:add (kw)
|
||||
mlp.stat.assignments[kw] = f
|
||||
end
|
||||
|
||||
_G.table.iforeach (op_assign,
|
||||
{"+=", "-=", "*=", "/="},
|
||||
{"add", "sub", "mul", "div"})
|
||||
32
lualibs/metalua/mlp_lexer.lua
Normal file
32
lualibs/metalua/mlp_lexer.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mll.lua,v 1.3 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: Source file lexer. ~~Currently only works on strings.
|
||||
-- Some API refactoring is needed.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006-2007, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
require "lexer"
|
||||
|
||||
local mlp_lexer = lexer.lexer:clone()
|
||||
|
||||
local keywords = {
|
||||
"and", "break", "do", "else", "elseif",
|
||||
"end", "false", "for", "function", "if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"...", "..", "==", ">=", "<=", "~=",
|
||||
"+{", "-{" }
|
||||
|
||||
for _,w in pairs(keywords) do mlp_lexer:add(w) end -- PK 6/4/2012
|
||||
|
||||
_M.lexer = mlp_lexer
|
||||
118
lualibs/metalua/mlp_meta.lua
Normal file
118
lualibs/metalua/mlp_meta.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_meta.lua,v 1.4 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: Meta-operations: AST quasi-quoting and splicing
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.splice_content()]
|
||||
-- * [mlp.quote_content()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- External splicing: compile an AST into a chunk, load and evaluate
|
||||
-- that chunk, and replace the chunk by its result (which must also be
|
||||
-- an AST).
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function splice (ast)
|
||||
local f = mlc.function_of_ast(ast, '=splice')
|
||||
local result=f()
|
||||
return result
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Going from an AST to an AST representing that AST
|
||||
-- the only key being lifted in this version is ["tag"]
|
||||
--------------------------------------------------------------------------------
|
||||
function quote (t)
|
||||
--print("QUOTING:", _G.table.tostring(t, 60))
|
||||
local cases = { }
|
||||
function cases.table (t)
|
||||
local mt = { tag = "Table" }
|
||||
--_G.table.insert (mt, { tag = "Pair", quote "quote", { tag = "True" } })
|
||||
if t.tag == "Splice" then
|
||||
assert (#t==1, "Invalid splice")
|
||||
local sp = t[1]
|
||||
return sp
|
||||
elseif t.tag then
|
||||
_G.table.insert (mt, { tag = "Pair", quote "tag", quote (t.tag) })
|
||||
end
|
||||
for _, v in ipairs (t) do
|
||||
_G.table.insert (mt, quote(v))
|
||||
end
|
||||
return mt
|
||||
end
|
||||
function cases.number (t) return { tag = "Number", t, quote = true } end
|
||||
function cases.string (t) return { tag = "String", t, quote = true } end
|
||||
return cases [ type (t) ] (t)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- when this variable is false, code inside [-{...}] is compiled and
|
||||
-- avaluated immediately. When it's true (supposedly when we're
|
||||
-- parsing data inside a quasiquote), [-{foo}] is replaced by
|
||||
-- [`Splice{foo}], which will be unpacked by [quote()].
|
||||
--------------------------------------------------------------------------------
|
||||
in_a_quote = false
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "-{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function splice_content (lx)
|
||||
local parser_name = "expr"
|
||||
if lx:is_keyword (lx:peek(2), ":") then
|
||||
local a = lx:next()
|
||||
lx:next() -- skip ":"
|
||||
assert (a.tag=="Id", "Invalid splice parser name")
|
||||
parser_name = a[1]
|
||||
end
|
||||
local ast = mlp[parser_name](lx)
|
||||
if in_a_quote then
|
||||
--printf("SPLICE_IN_QUOTE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return { tag="Splice", ast }
|
||||
else
|
||||
if parser_name == "expr" then ast = { { tag="Return", ast } }
|
||||
elseif parser_name == "stat" then ast = { ast }
|
||||
elseif parser_name ~= "block" then
|
||||
error ("splice content must be an expr, stat or block") end
|
||||
--printf("EXEC THIS SPLICE:\n%s", _G.table.tostring(ast, "nohash", 60))
|
||||
return splice (ast)
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Parse the inside of a "+{ ... }"
|
||||
--------------------------------------------------------------------------------
|
||||
function quote_content (lx)
|
||||
local parser
|
||||
if lx:is_keyword (lx:peek(2), ":") then -- +{parser: content }
|
||||
parser = mlp[id(lx)[1]]
|
||||
lx:next()
|
||||
else -- +{ content }
|
||||
parser = mlp.expr
|
||||
end
|
||||
|
||||
local prev_iq = in_a_quote
|
||||
in_a_quote = true
|
||||
--print("IN_A_QUOTE")
|
||||
local content = parser (lx)
|
||||
local q_content = quote (content)
|
||||
in_a_quote = prev_iq
|
||||
return q_content
|
||||
end
|
||||
|
||||
185
lualibs/metalua/mlp_misc.lua
Normal file
185
lualibs/metalua/mlp_misc.lua
Normal file
@@ -0,0 +1,185 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_misc.lua,v 1.6 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, miscellaneous utility functions.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_misc.lua,v $
|
||||
-- Revision 1.6 2006/11/15 09:07:50 fab13n
|
||||
-- debugged meta operators.
|
||||
-- Added command line options handling.
|
||||
--
|
||||
-- Revision 1.5 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.4 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.fget()]
|
||||
-- * [mlp.id()]
|
||||
-- * [mlp.opt_id()]
|
||||
-- * [mlp.id_list()]
|
||||
-- * [mlp.gensym()]
|
||||
-- * [mlp.string()]
|
||||
-- * [mlp.opt_string()]
|
||||
-- * [mlp.id2string()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mll"
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- returns a function that takes the [n]th element of a table.
|
||||
-- if [tag] is provided, then this element is expected to be a
|
||||
-- table, and this table receives a "tag" field whose value is
|
||||
-- set to [tag].
|
||||
--
|
||||
-- The primary purpose of this is to generate builders for
|
||||
-- grammar generators. It has little purpose in metalua, as lambda has
|
||||
-- a lightweight syntax.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function fget (n, tag)
|
||||
assert (type (n) == "number")
|
||||
if tag then
|
||||
assert (type (tag) == "string")
|
||||
return function (x)
|
||||
assert (type (x[n]) == "table")
|
||||
return {tag=tag, unpack(x[n])} end
|
||||
else
|
||||
return function (x) return x[n] end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read an identifier (possibly as a splice), or return [false] if no
|
||||
-- id is found.
|
||||
--------------------------------------------------------------------------------
|
||||
function opt_id (lx)
|
||||
local a = lx:peek();
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
|
||||
if v.tag ~= "Id" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx,"Bad id splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "Id" then return lx:next()
|
||||
else return false end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Mandatory reading of an id: causes an error if it can't read one.
|
||||
--------------------------------------------------------------------------------
|
||||
function id (lx)
|
||||
return opt_id (lx) or gg.parse_error(lx,"Identifier expected")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Common helper function
|
||||
--------------------------------------------------------------------------------
|
||||
id_list = gg.list { primary = mlp.id, separators = "," }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Symbol generator: [gensym()] returns a guaranteed-to-be-unique identifier.
|
||||
-- The main purpose is to avoid variable capture in macros.
|
||||
--
|
||||
-- If a string is passed as an argument, theis string will be part of the
|
||||
-- id name (helpful for macro debugging)
|
||||
--------------------------------------------------------------------------------
|
||||
local gensymidx = 0
|
||||
|
||||
function gensym (arg)
|
||||
gensymidx = gensymidx + 1
|
||||
return { tag="Id", _G.string.format(".%i.%s", gensymidx, arg or "")}
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Converts an identifier into a string. Hopefully one day it'll handle
|
||||
-- splices gracefully, but that proves quite tricky.
|
||||
--------------------------------------------------------------------------------
|
||||
function id2string (id)
|
||||
--print("id2string:", disp.ast(id))
|
||||
if id.tag == "Id" then id.tag = "String"; return id
|
||||
elseif id.tag == "Splice" then
|
||||
assert (in_a_quote, "can't do id2string on an outermost splice")
|
||||
error ("id2string on splice not implemented")
|
||||
-- Evaluating id[1] will produce `Id{ xxx },
|
||||
-- and we want it to produce `String{ xxx }
|
||||
-- Morally, this is what I want:
|
||||
-- return `String{ `Index{ `Splice{ id[1] }, `Number 1 } }
|
||||
-- That is, without sugar:
|
||||
return {tag="String", {tag="Index", {tag="Splice", id[1] },
|
||||
{tag="Number", 1 } } }
|
||||
else error ("Identifier expected: ".._G.table.tostring(id, 'nohash')) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Read a string, possibly spliced, or return an error if it can't
|
||||
--------------------------------------------------------------------------------
|
||||
function string (lx)
|
||||
local a = lx:peek()
|
||||
if lx:is_keyword (a, "-{") then
|
||||
local v = gg.sequence{ "-{", splice_content, "}" } (lx) [1]
|
||||
if v.tag ~= "" and v.tag ~= "Splice" then
|
||||
gg.parse_error(lx,"Bad string splice")
|
||||
end
|
||||
return v
|
||||
elseif a.tag == "String" then return lx:next()
|
||||
else error "String expected" end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Try to read a string, or return false if it can't. No splice allowed.
|
||||
--------------------------------------------------------------------------------
|
||||
function opt_string (lx)
|
||||
return lx:peek().tag == "String" and lx:next()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Chunk reader: block + Eof
|
||||
--------------------------------------------------------------------------------
|
||||
function skip_initial_sharp_comment (lx)
|
||||
-- Dirty hack: I'm happily fondling lexer's private parts
|
||||
-- FIXME: redundant with lexer:newstream()
|
||||
lx :sync()
|
||||
local i = lx.src:match ("^#.-\n()", lx.i)
|
||||
if i then lx.i, lx.column_offset, lx.line = i, i, lx.line+1 end
|
||||
end
|
||||
|
||||
local function _chunk (lx)
|
||||
if lx:peek().tag == 'Eof' then return { } -- handle empty files
|
||||
else
|
||||
skip_initial_sharp_comment (lx)
|
||||
local chunk = block (lx)
|
||||
if lx:peek().tag ~= "Eof" then error "End-of-file expected" end
|
||||
return chunk
|
||||
end
|
||||
end
|
||||
|
||||
-- chunk is wrapped in a sequence so that it has a "transformer" field.
|
||||
chunk = gg.sequence { _chunk, builder = unpack }
|
||||
226
lualibs/metalua/mlp_stat.lua
Normal file
226
lualibs/metalua/mlp_stat.lua
Normal file
@@ -0,0 +1,226 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_stat.lua,v 1.7 2006/11/15 09:07:50 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, statement/block parser. This is part of
|
||||
-- the definition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exports API:
|
||||
-- * [mlp.stat()]
|
||||
-- * [mlp.block()]
|
||||
-- * [mlp.for_header()]
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- eta-expansions to break circular dependency
|
||||
--------------------------------------------------------------------------------
|
||||
local expr = function (lx) return mlp.expr (lx) end
|
||||
local func_val = function (lx) return mlp.func_val (lx) end
|
||||
local expr_list = function (lx) return mlp.expr_list(lx) end
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- List of all keywords that indicate the end of a statement block. Users are
|
||||
-- likely to extend this list when designing extensions.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
local block_terminators = { "else", "elseif", "end", "until", ")", "}", "]" }
|
||||
|
||||
-- FIXME: this must be handled from within GG!!!
|
||||
function block_terminators:add(x)
|
||||
if type (x) == "table" then for _, y in ipairs(x) do self:add (y) end
|
||||
else _G.table.insert (self, x) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- list of statements, possibly followed by semicolons
|
||||
--------------------------------------------------------------------------------
|
||||
block = gg.list {
|
||||
name = "statements block",
|
||||
terminators = block_terminators,
|
||||
primary = function (lx)
|
||||
-- FIXME use gg.optkeyword()
|
||||
local x = stat (lx)
|
||||
if lx:is_keyword (lx:peek(), ";") then lx:next() end
|
||||
return x
|
||||
end }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Helper function for "return <expr_list>" parsing.
|
||||
-- Called when parsing return statements.
|
||||
-- The specific test for initial ";" is because it's not a block terminator,
|
||||
-- so without itgg.list would choke on "return ;" statements.
|
||||
-- We don't make a modified copy of block_terminators because this list
|
||||
-- is sometimes modified at runtime, and the return parser would get out of
|
||||
-- sync if it was relying on a copy.
|
||||
--------------------------------------------------------------------------------
|
||||
local return_expr_list_parser = gg.multisequence{
|
||||
{ ";" , builder = function() return { } end },
|
||||
default = gg.list {
|
||||
expr, separators = ",", terminators = block_terminators } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- for header, between [for] and [do] (exclusive).
|
||||
-- Return the `Forxxx{...} AST, without the body element (the last one).
|
||||
--------------------------------------------------------------------------------
|
||||
function for_header (lx)
|
||||
local var = mlp.id (lx)
|
||||
if lx:is_keyword (lx:peek(), "=") then
|
||||
-- Fornum: only 1 variable
|
||||
lx:next() -- skip "="
|
||||
local e = expr_list (lx)
|
||||
assert (2 <= #e and #e <= 3, "2 or 3 values in a fornum")
|
||||
return { tag="Fornum", var, unpack (e) }
|
||||
else
|
||||
-- Forin: there might be several vars
|
||||
local a = lx:is_keyword (lx:next(), ",", "in")
|
||||
if a=="in" then var_list = { var, lineinfo = var.lineinfo } else
|
||||
-- several vars; first "," skipped, read other vars
|
||||
var_list = gg.list{
|
||||
primary = id, separators = ",", terminators = "in" } (lx)
|
||||
_G.table.insert (var_list, 1, var) -- put back the first variable
|
||||
lx:next() -- skip "in"
|
||||
end
|
||||
local e = expr_list (lx)
|
||||
return { tag="Forin", var_list, e }
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def parser helper: id ( . id ) *
|
||||
--------------------------------------------------------------------------------
|
||||
local function fn_builder (list)
|
||||
local r = list[1]
|
||||
for i = 2, #list do r = { tag="Index", r, id2string(list[i]) } end
|
||||
return r
|
||||
end
|
||||
local func_name = gg.list{ id, separators = ".", builder = fn_builder }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def parser helper: ( : id )?
|
||||
--------------------------------------------------------------------------------
|
||||
local method_name = gg.onkeyword{ name = "method invocation", ":", id,
|
||||
transformers = { function(x) return x and id2string(x) end } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Function def builder
|
||||
--------------------------------------------------------------------------------
|
||||
local function funcdef_builder(x)
|
||||
local name, method, func = x[1], x[2], x[3]
|
||||
if method then
|
||||
name = { tag="Index", name, method, lineinfo = {
|
||||
first = name.lineinfo.first,
|
||||
last = method.lineinfo.last } }
|
||||
_G.table.insert (func[1], 1, {tag="Id", "self"})
|
||||
end
|
||||
local r = { tag="Set", {name}, {func} }
|
||||
r[1].lineinfo = name.lineinfo
|
||||
r[2].lineinfo = func.lineinfo
|
||||
return r
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- if statement builder
|
||||
--------------------------------------------------------------------------------
|
||||
local function if_builder (x)
|
||||
local cb_pairs, else_block, r = x[1], x[2], {tag="If"}
|
||||
for i=1,#cb_pairs do r[2*i-1]=cb_pairs[i][1]; r[2*i]=cb_pairs[i][2] end
|
||||
if else_block then r[#r+1] = else_block end
|
||||
return r
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- produce a list of (expr,block) pairs
|
||||
--------------------------------------------------------------------------------
|
||||
local elseifs_parser = gg.list {
|
||||
gg.sequence { expr, "then", block },
|
||||
separators = "elseif",
|
||||
terminators = { "else", "end" } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- assignments and calls: statements that don't start with a keyword
|
||||
--------------------------------------------------------------------------------
|
||||
local function assign_or_call_stat_parser (lx)
|
||||
local e = expr_list (lx)
|
||||
local a = lx:is_keyword(lx:peek())
|
||||
local op = a and stat.assignments[a]
|
||||
if op then
|
||||
--FIXME: check that [e] is a LHS
|
||||
lx:next()
|
||||
local v = expr_list (lx)
|
||||
if type(op)=="string" then return { tag=op, e, v }
|
||||
else return op (e, v) end
|
||||
else
|
||||
assert (#e > 0)
|
||||
if #e > 1 then
|
||||
gg.parse_error (lx,
|
||||
"comma is not a valid statement separator; statement can be "..
|
||||
"separated by semicolons, or not separated at all") end
|
||||
if e[1].tag ~= "Call" and e[1].tag ~= "Invoke" then
|
||||
local typename
|
||||
if e[1].tag == 'Id' then
|
||||
typename = '("'..e[1][1]..'") is an identifier'
|
||||
elseif e[1].tag == 'Op' then
|
||||
typename = "is an arithmetic operation"
|
||||
else typename = "is of type '"..(e[1].tag or "<list>").."'" end
|
||||
|
||||
gg.parse_error (lx, "This expression " .. typename ..
|
||||
"; a statement was expected, and only function and method call "..
|
||||
"expressions can be used as statements");
|
||||
end
|
||||
return e[1]
|
||||
end
|
||||
end
|
||||
|
||||
local_stat_parser = gg.multisequence{
|
||||
-- local function <name> <func_val>
|
||||
{ "function", id, func_val, builder =
|
||||
function(x)
|
||||
local vars = { x[1], lineinfo = x[1].lineinfo }
|
||||
local vals = { x[2], lineinfo = x[2].lineinfo }
|
||||
return { tag="Localrec", vars, vals }
|
||||
end },
|
||||
-- local <id_list> ( = <expr_list> )?
|
||||
default = gg.sequence{ id_list, gg.onkeyword{ "=", expr_list },
|
||||
builder = function(x) return {tag="Local", x[1], x[2] or { } } end } }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- statement
|
||||
--------------------------------------------------------------------------------
|
||||
stat = gg.multisequence {
|
||||
name="statement",
|
||||
{ "do", block, "end", builder =
|
||||
function (x) return { tag="Do", unpack (x[1]) } end },
|
||||
{ "for", for_header, "do", block, "end", builder =
|
||||
function (x) x[1][#x[1]+1] = x[2]; return x[1] end },
|
||||
{ "function", func_name, method_name, func_val, builder=funcdef_builder },
|
||||
{ "while", expr, "do", block, "end", builder = "While" },
|
||||
{ "repeat", block, "until", expr, builder = "Repeat" },
|
||||
{ "local", local_stat_parser, builder = fget (1) },
|
||||
{ "return", return_expr_list_parser, builder = fget (1, "Return") },
|
||||
{ "break", builder = function() return { tag="Break" } end },
|
||||
{ "-{", splice_content, "}", builder = fget(1) },
|
||||
{ "if", elseifs_parser, gg.onkeyword{ "else", block }, "end",
|
||||
builder = if_builder },
|
||||
default = assign_or_call_stat_parser }
|
||||
|
||||
stat.assignments = {
|
||||
["="] = "Set" }
|
||||
|
||||
function stat.assignments:add(k, v) self[k] = v end
|
||||
92
lualibs/metalua/mlp_table.lua
Normal file
92
lualibs/metalua/mlp_table.lua
Normal file
@@ -0,0 +1,92 @@
|
||||
----------------------------------------------------------------------
|
||||
-- Metalua: $Id: mlp_table.lua,v 1.5 2006/11/10 02:11:17 fab13n Exp $
|
||||
--
|
||||
-- Summary: metalua parser, table constructor parser. This is part
|
||||
-- of thedefinition of module [mlp].
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (c) 2006, Fabien Fleutot <metalua@gmail.com>.
|
||||
--
|
||||
-- This software is released under the MIT Licence, see licence.txt
|
||||
-- for details.
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
-- History:
|
||||
-- $Log: mlp_table.lua,v $
|
||||
-- Revision 1.5 2006/11/10 02:11:17 fab13n
|
||||
-- compiler faithfulness to 5.1 improved
|
||||
-- gg.expr extended
|
||||
-- mlp.expr refactored
|
||||
--
|
||||
-- Revision 1.4 2006/11/09 09:39:57 fab13n
|
||||
-- some cleanup
|
||||
--
|
||||
-- Revision 1.3 2006/11/07 04:38:00 fab13n
|
||||
-- first bootstrapping version.
|
||||
--
|
||||
-- Revision 1.2 2006/11/05 15:08:34 fab13n
|
||||
-- updated code generation, to be compliant with 5.1
|
||||
--
|
||||
----------------------------------------------------------------------
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--
|
||||
-- Exported API:
|
||||
-- * [mlp.table_field()]
|
||||
-- * [mlp.table_content()]
|
||||
-- * [mlp.table()]
|
||||
--
|
||||
-- KNOWN BUG: doesn't handle final ";" or "," before final "}"
|
||||
--
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
--require "gg"
|
||||
--require "mll"
|
||||
--require "mlp_misc"
|
||||
|
||||
module ("mlp", package.seeall)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- eta expansion to break circular dependencies:
|
||||
--------------------------------------------------------------------------------
|
||||
local function _expr (lx) return expr(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [[key] = value] table field definition
|
||||
--------------------------------------------------------------------------------
|
||||
local bracket_field = gg.sequence{ "[", _expr, "]", "=", _expr, builder = "Pair" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [id = value] or [value] table field definition;
|
||||
-- [[key]=val] are delegated to [bracket_field()]
|
||||
--------------------------------------------------------------------------------
|
||||
function table_field (lx)
|
||||
if lx:is_keyword (lx:peek(), "[") then return bracket_field (lx) end
|
||||
local e = _expr (lx)
|
||||
if lx:is_keyword (lx:peek(), "=") then
|
||||
lx:next(); -- skip the "="
|
||||
local key = id2string(e)
|
||||
local val = _expr(lx)
|
||||
local r = { tag="Pair", key, val }
|
||||
r.lineinfo = { first = key.lineinfo.first, last = val.lineinfo.last }
|
||||
return r
|
||||
else return e end
|
||||
end
|
||||
|
||||
local function _table_field(lx) return table_field(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- table constructor, without enclosing braces; returns a full table object
|
||||
--------------------------------------------------------------------------------
|
||||
table_content = gg.list { _table_field,
|
||||
separators = { ",", ";" }, terminators = "}", builder = "Table" }
|
||||
|
||||
local function _table_content(lx) return table_content(lx) end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- complete table constructor including [{...}]
|
||||
--------------------------------------------------------------------------------
|
||||
table = gg.sequence{ "{", _table_content, "}", builder = fget(1) }
|
||||
|
||||
|
||||
@@ -1,86 +1,86 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- MIME support for the Lua language.
|
||||
-- Author: Diego Nehab
|
||||
-- Conforming to RFCs 2045-2049
|
||||
-- RCS ID: $Id: mime.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime.core")
|
||||
local io = require("io")
|
||||
local string = require("string")
|
||||
module("mime")
|
||||
|
||||
-- encode, decode and wrap algorithm tables
|
||||
encodet = {}
|
||||
decodet = {}
|
||||
wrapt = {}
|
||||
|
||||
-- creates a function that chooses a filter by name from a given table
|
||||
local function choose(table)
|
||||
return function(name, opt1, opt2)
|
||||
if base.type(name) ~= "string" then
|
||||
name, opt1, opt2 = "default", name, opt1
|
||||
end
|
||||
local f = table[name or "nil"]
|
||||
if not f then error("unknown key (" .. base.tostring(name) .. ")", 3)
|
||||
else return f(opt1, opt2) end
|
||||
end
|
||||
end
|
||||
|
||||
-- define the encoding filters
|
||||
encodet['base64'] = function()
|
||||
return ltn12.filter.cycle(b64, "")
|
||||
end
|
||||
|
||||
encodet['quoted-printable'] = function(mode)
|
||||
return ltn12.filter.cycle(qp, "",
|
||||
(mode == "binary") and "=0D=0A" or "\r\n")
|
||||
end
|
||||
|
||||
-- define the decoding filters
|
||||
decodet['base64'] = function()
|
||||
return ltn12.filter.cycle(unb64, "")
|
||||
end
|
||||
|
||||
decodet['quoted-printable'] = function()
|
||||
return ltn12.filter.cycle(unqp, "")
|
||||
end
|
||||
|
||||
local function format(chunk)
|
||||
if chunk then
|
||||
if chunk == "" then return "''"
|
||||
else return string.len(chunk) end
|
||||
else return "nil" end
|
||||
end
|
||||
|
||||
-- define the line-wrap filters
|
||||
wrapt['text'] = function(length)
|
||||
length = length or 76
|
||||
return ltn12.filter.cycle(wrp, length, length)
|
||||
end
|
||||
wrapt['base64'] = wrapt['text']
|
||||
wrapt['default'] = wrapt['text']
|
||||
|
||||
wrapt['quoted-printable'] = function()
|
||||
return ltn12.filter.cycle(qpwrp, 76, 76)
|
||||
end
|
||||
|
||||
-- function that choose the encoding, decoding or wrap algorithm
|
||||
encode = choose(encodet)
|
||||
decode = choose(decodet)
|
||||
wrap = choose(wrapt)
|
||||
|
||||
-- define the end-of-line normalization filter
|
||||
function normalize(marker)
|
||||
return ltn12.filter.cycle(eol, 0, marker)
|
||||
end
|
||||
|
||||
-- high level stuffing filter
|
||||
function stuff()
|
||||
return ltn12.filter.cycle(dot, 2)
|
||||
end
|
||||
-----------------------------------------------------------------------------
|
||||
-- MIME support for the Lua language.
|
||||
-- Author: Diego Nehab
|
||||
-- Conforming to RFCs 2045-2049
|
||||
-- RCS ID: $Id: mime.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime.core")
|
||||
local io = require("io")
|
||||
local string = require("string")
|
||||
module("mime")
|
||||
|
||||
-- encode, decode and wrap algorithm tables
|
||||
encodet = {}
|
||||
decodet = {}
|
||||
wrapt = {}
|
||||
|
||||
-- creates a function that chooses a filter by name from a given table
|
||||
local function choose(table)
|
||||
return function(name, opt1, opt2)
|
||||
if base.type(name) ~= "string" then
|
||||
name, opt1, opt2 = "default", name, opt1
|
||||
end
|
||||
local f = table[name or "nil"]
|
||||
if not f then error("unknown key (" .. base.tostring(name) .. ")", 3)
|
||||
else return f(opt1, opt2) end
|
||||
end
|
||||
end
|
||||
|
||||
-- define the encoding filters
|
||||
encodet['base64'] = function()
|
||||
return ltn12.filter.cycle(b64, "")
|
||||
end
|
||||
|
||||
encodet['quoted-printable'] = function(mode)
|
||||
return ltn12.filter.cycle(qp, "",
|
||||
(mode == "binary") and "=0D=0A" or "\r\n")
|
||||
end
|
||||
|
||||
-- define the decoding filters
|
||||
decodet['base64'] = function()
|
||||
return ltn12.filter.cycle(unb64, "")
|
||||
end
|
||||
|
||||
decodet['quoted-printable'] = function()
|
||||
return ltn12.filter.cycle(unqp, "")
|
||||
end
|
||||
|
||||
local function format(chunk)
|
||||
if chunk then
|
||||
if chunk == "" then return "''"
|
||||
else return string.len(chunk) end
|
||||
else return "nil" end
|
||||
end
|
||||
|
||||
-- define the line-wrap filters
|
||||
wrapt['text'] = function(length)
|
||||
length = length or 76
|
||||
return ltn12.filter.cycle(wrp, length, length)
|
||||
end
|
||||
wrapt['base64'] = wrapt['text']
|
||||
wrapt['default'] = wrapt['text']
|
||||
|
||||
wrapt['quoted-printable'] = function()
|
||||
return ltn12.filter.cycle(qpwrp, 76, 76)
|
||||
end
|
||||
|
||||
-- function that choose the encoding, decoding or wrap algorithm
|
||||
encode = choose(encodet)
|
||||
decode = choose(decodet)
|
||||
wrap = choose(wrapt)
|
||||
|
||||
-- define the end-of-line normalization filter
|
||||
function normalize(marker)
|
||||
return ltn12.filter.cycle(eol, 0, marker)
|
||||
end
|
||||
|
||||
-- high level stuffing filter
|
||||
function stuff()
|
||||
return ltn12.filter.cycle(dot, 2)
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,133 +1,133 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- LuaSocket helper module
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: socket.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local socket = require("socket.core")
|
||||
module("socket")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Exported auxiliar functions
|
||||
-----------------------------------------------------------------------------
|
||||
function connect(address, port, laddress, lport)
|
||||
local sock, err = socket.tcp()
|
||||
if not sock then return nil, err end
|
||||
if laddress then
|
||||
local res, err = sock:bind(laddress, lport, -1)
|
||||
if not res then return nil, err end
|
||||
end
|
||||
local res, err = sock:connect(address, port)
|
||||
if not res then return nil, err end
|
||||
return sock
|
||||
end
|
||||
|
||||
function bind(host, port, backlog)
|
||||
local sock, err = socket.tcp()
|
||||
if not sock then return nil, err end
|
||||
sock:setoption("reuseaddr", true)
|
||||
local res, err = sock:bind(host, port)
|
||||
if not res then return nil, err end
|
||||
res, err = sock:listen(backlog)
|
||||
if not res then return nil, err end
|
||||
return sock
|
||||
end
|
||||
|
||||
try = newtry()
|
||||
|
||||
function choose(table)
|
||||
return function(name, opt1, opt2)
|
||||
if base.type(name) ~= "string" then
|
||||
name, opt1, opt2 = "default", name, opt1
|
||||
end
|
||||
local f = table[name or "nil"]
|
||||
if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
|
||||
else return f(opt1, opt2) end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Socket sources and sinks, conforming to LTN12
|
||||
-----------------------------------------------------------------------------
|
||||
-- create namespaces inside LuaSocket namespace
|
||||
sourcet = {}
|
||||
sinkt = {}
|
||||
|
||||
BLOCKSIZE = 2048
|
||||
|
||||
sinkt["close-when-done"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if not chunk then
|
||||
sock:close()
|
||||
return 1
|
||||
else return sock:send(chunk) end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sinkt["keep-open"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if chunk then return sock:send(chunk)
|
||||
else return 1 end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sinkt["default"] = sinkt["keep-open"]
|
||||
|
||||
sink = choose(sinkt)
|
||||
|
||||
sourcet["by-length"] = function(sock, length)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
if length <= 0 then return nil end
|
||||
local size = math.min(socket.BLOCKSIZE, length)
|
||||
local chunk, err = sock:receive(size)
|
||||
if err then return nil, err end
|
||||
length = length - string.len(chunk)
|
||||
return chunk
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sourcet["until-closed"] = function(sock)
|
||||
local done
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
if done then return nil end
|
||||
local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
|
||||
if not err then return chunk
|
||||
elseif err == "closed" then
|
||||
sock:close()
|
||||
done = 1
|
||||
return partial
|
||||
else return nil, err end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
sourcet["default"] = sourcet["until-closed"]
|
||||
|
||||
source = choose(sourcet)
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- LuaSocket helper module
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: socket.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local socket = require("socket.core")
|
||||
module("socket")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Exported auxiliar functions
|
||||
-----------------------------------------------------------------------------
|
||||
function connect(address, port, laddress, lport)
|
||||
local sock, err = socket.tcp()
|
||||
if not sock then return nil, err end
|
||||
if laddress then
|
||||
local res, err = sock:bind(laddress, lport, -1)
|
||||
if not res then return nil, err end
|
||||
end
|
||||
local res, err = sock:connect(address, port)
|
||||
if not res then return nil, err end
|
||||
return sock
|
||||
end
|
||||
|
||||
function bind(host, port, backlog)
|
||||
local sock, err = socket.tcp()
|
||||
if not sock then return nil, err end
|
||||
sock:setoption("reuseaddr", true)
|
||||
local res, err = sock:bind(host, port)
|
||||
if not res then return nil, err end
|
||||
res, err = sock:listen(backlog)
|
||||
if not res then return nil, err end
|
||||
return sock
|
||||
end
|
||||
|
||||
try = newtry()
|
||||
|
||||
function choose(table)
|
||||
return function(name, opt1, opt2)
|
||||
if base.type(name) ~= "string" then
|
||||
name, opt1, opt2 = "default", name, opt1
|
||||
end
|
||||
local f = table[name or "nil"]
|
||||
if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
|
||||
else return f(opt1, opt2) end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Socket sources and sinks, conforming to LTN12
|
||||
-----------------------------------------------------------------------------
|
||||
-- create namespaces inside LuaSocket namespace
|
||||
sourcet = {}
|
||||
sinkt = {}
|
||||
|
||||
BLOCKSIZE = 2048
|
||||
|
||||
sinkt["close-when-done"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if not chunk then
|
||||
sock:close()
|
||||
return 1
|
||||
else return sock:send(chunk) end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sinkt["keep-open"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if chunk then return sock:send(chunk)
|
||||
else return 1 end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sinkt["default"] = sinkt["keep-open"]
|
||||
|
||||
sink = choose(sinkt)
|
||||
|
||||
sourcet["by-length"] = function(sock, length)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
if length <= 0 then return nil end
|
||||
local size = math.min(socket.BLOCKSIZE, length)
|
||||
local chunk, err = sock:receive(size)
|
||||
if err then return nil, err end
|
||||
length = length - string.len(chunk)
|
||||
return chunk
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
sourcet["until-closed"] = function(sock)
|
||||
local done
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
if done then return nil end
|
||||
local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
|
||||
if not err then return chunk
|
||||
elseif err == "closed" then
|
||||
sock:close()
|
||||
done = 1
|
||||
return partial
|
||||
else return nil, err end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
sourcet["default"] = sourcet["until-closed"]
|
||||
|
||||
source = choose(sourcet)
|
||||
|
||||
@@ -1,280 +1,280 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- FTP support for the Lua language
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: ftp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local socket = require("socket")
|
||||
local url = require("socket.url")
|
||||
local tp = require("socket.tp")
|
||||
local ltn12 = require("ltn12")
|
||||
module("socket.ftp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- timeout in seconds before the program gives up on a connection
|
||||
TIMEOUT = 60
|
||||
-- default port for ftp service
|
||||
PORT = 21
|
||||
-- this is the default anonymous password. used when no password is
|
||||
-- provided in url. should be changed to your e-mail.
|
||||
USER = "ftp"
|
||||
PASSWORD = "anonymous@anonymous.org"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Low level FTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function open(server, port, create)
|
||||
local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT))
|
||||
local f = base.setmetatable({ tp = tp }, metat)
|
||||
-- make sure everything gets closed in an exception
|
||||
f.try = socket.newtry(function() f:close() end)
|
||||
return f
|
||||
end
|
||||
|
||||
function metat.__index:portconnect()
|
||||
self.try(self.server:settimeout(TIMEOUT))
|
||||
self.data = self.try(self.server:accept())
|
||||
self.try(self.data:settimeout(TIMEOUT))
|
||||
end
|
||||
|
||||
function metat.__index:pasvconnect()
|
||||
self.data = self.try(socket.tcp())
|
||||
self.try(self.data:settimeout(TIMEOUT))
|
||||
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
|
||||
end
|
||||
|
||||
function metat.__index:login(user, password)
|
||||
self.try(self.tp:command("user", user or USER))
|
||||
local code, reply = self.try(self.tp:check{"2..", 331})
|
||||
if code == 331 then
|
||||
self.try(self.tp:command("pass", password or PASSWORD))
|
||||
self.try(self.tp:check("2.."))
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:pasv()
|
||||
self.try(self.tp:command("pasv"))
|
||||
local code, reply = self.try(self.tp:check("2.."))
|
||||
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
|
||||
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
|
||||
self.try(a and b and c and d and p1 and p2, reply)
|
||||
self.pasvt = {
|
||||
ip = string.format("%d.%d.%d.%d", a, b, c, d),
|
||||
port = p1*256 + p2
|
||||
}
|
||||
if self.server then
|
||||
self.server:close()
|
||||
self.server = nil
|
||||
end
|
||||
return self.pasvt.ip, self.pasvt.port
|
||||
end
|
||||
|
||||
function metat.__index:port(ip, port)
|
||||
self.pasvt = nil
|
||||
if not ip then
|
||||
ip, port = self.try(self.tp:getcontrol():getsockname())
|
||||
self.server = self.try(socket.bind(ip, 0))
|
||||
ip, port = self.try(self.server:getsockname())
|
||||
self.try(server:settimeout(TIMEOUT))
|
||||
end
|
||||
local pl = math.mod(port, 256)
|
||||
local ph = (port - pl)/256
|
||||
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
|
||||
self.try(self.tp:command("port", arg))
|
||||
self.try(self.tp:check("2.."))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:send(sendt)
|
||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
||||
-- if there is a pasvt table, we already sent a PASV command
|
||||
-- we just get the data connection into self.data
|
||||
if self.pasvt then self:pasvconnect() end
|
||||
-- get the transfer argument and command
|
||||
local argument = sendt.argument or
|
||||
url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
|
||||
if argument == "" then argument = nil end
|
||||
local command = sendt.command or "stor"
|
||||
-- send the transfer command and check the reply
|
||||
self.try(self.tp:command(command, argument))
|
||||
local code, reply = self.try(self.tp:check{"2..", "1.."})
|
||||
-- if there is not a a pasvt table, then there is a server
|
||||
-- and we already sent a PORT command
|
||||
if not self.pasvt then self:portconnect() end
|
||||
-- get the sink, source and step for the transfer
|
||||
local step = sendt.step or ltn12.pump.step
|
||||
local checkstep = function(src, snk)
|
||||
-- check status in control connection while downloading
|
||||
local readyt = socket.select(readt, nil, 0)
|
||||
if readyt[tp] then self.try(self.tp:check("2..")) end
|
||||
return step(src, snk)
|
||||
end
|
||||
local sink = socket.sink("close-when-done", self.data)
|
||||
-- transfer all data and check error
|
||||
self.try(ltn12.pump.all(sendt.source, sink, checkstep))
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
-- done with data connection
|
||||
self.data:close()
|
||||
-- find out how many bytes were sent
|
||||
local sent = socket.skip(1, self.data:getstats())
|
||||
self.data = nil
|
||||
return sent
|
||||
end
|
||||
|
||||
function metat.__index:receive(recvt)
|
||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
||||
if self.pasvt then self:pasvconnect() end
|
||||
local argument = recvt.argument or
|
||||
url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
|
||||
if argument == "" then argument = nil end
|
||||
local command = recvt.command or "retr"
|
||||
self.try(self.tp:command(command, argument))
|
||||
local code = self.try(self.tp:check{"1..", "2.."})
|
||||
if not self.pasvt then self:portconnect() end
|
||||
local source = socket.source("until-closed", self.data)
|
||||
local step = recvt.step or ltn12.pump.step
|
||||
self.try(ltn12.pump.all(source, recvt.sink, step))
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
self.data:close()
|
||||
self.data = nil
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:cwd(dir)
|
||||
self.try(self.tp:command("cwd", dir))
|
||||
self.try(self.tp:check(250))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:type(type)
|
||||
self.try(self.tp:command("type", type))
|
||||
self.try(self.tp:check(200))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:greet()
|
||||
local code = self.try(self.tp:check{"1..", "2.."})
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:quit()
|
||||
self.try(self.tp:command("quit"))
|
||||
self.try(self.tp:check("2.."))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
if self.data then self.data:close() end
|
||||
if self.server then self.server:close() end
|
||||
return self.tp:close()
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- High level FTP API
|
||||
-----------------------------------------------------------------------------
|
||||
function override(t)
|
||||
if t.url then
|
||||
u = url.parse(t.url)
|
||||
for i,v in base.pairs(t) do
|
||||
u[i] = v
|
||||
end
|
||||
return u
|
||||
else return t end
|
||||
end
|
||||
|
||||
local function tput(putt)
|
||||
putt = override(putt)
|
||||
socket.try(putt.host, "missing hostname")
|
||||
local f = open(putt.host, putt.port, putt.create)
|
||||
f:greet()
|
||||
f:login(putt.user, putt.password)
|
||||
if putt.type then f:type(putt.type) end
|
||||
f:pasv()
|
||||
local sent = f:send(putt)
|
||||
f:quit()
|
||||
f:close()
|
||||
return sent
|
||||
end
|
||||
|
||||
local default = {
|
||||
path = "/",
|
||||
scheme = "ftp"
|
||||
}
|
||||
|
||||
local function parse(u)
|
||||
local t = socket.try(url.parse(u, default))
|
||||
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
|
||||
socket.try(t.host, "missing hostname")
|
||||
local pat = "^type=(.)$"
|
||||
if t.params then
|
||||
t.type = socket.skip(2, string.find(t.params, pat))
|
||||
socket.try(t.type == "a" or t.type == "i",
|
||||
"invalid type '" .. t.type .. "'")
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function sput(u, body)
|
||||
local putt = parse(u)
|
||||
putt.source = ltn12.source.string(body)
|
||||
return tput(putt)
|
||||
end
|
||||
|
||||
put = socket.protect(function(putt, body)
|
||||
if base.type(putt) == "string" then return sput(putt, body)
|
||||
else return tput(putt) end
|
||||
end)
|
||||
|
||||
local function tget(gett)
|
||||
gett = override(gett)
|
||||
socket.try(gett.host, "missing hostname")
|
||||
local f = open(gett.host, gett.port, gett.create)
|
||||
f:greet()
|
||||
f:login(gett.user, gett.password)
|
||||
if gett.type then f:type(gett.type) end
|
||||
f:pasv()
|
||||
f:receive(gett)
|
||||
f:quit()
|
||||
return f:close()
|
||||
end
|
||||
|
||||
local function sget(u)
|
||||
local gett = parse(u)
|
||||
local t = {}
|
||||
gett.sink = ltn12.sink.table(t)
|
||||
tget(gett)
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
command = socket.protect(function(cmdt)
|
||||
cmdt = override(cmdt)
|
||||
socket.try(cmdt.host, "missing hostname")
|
||||
socket.try(cmdt.command, "missing command")
|
||||
local f = open(cmdt.host, cmdt.port, cmdt.create)
|
||||
f:greet()
|
||||
f:login(cmdt.user, cmdt.password)
|
||||
f.try(f.tp:command(cmdt.command, cmdt.argument))
|
||||
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
|
||||
f:quit()
|
||||
return f:close()
|
||||
end)
|
||||
|
||||
get = socket.protect(function(gett)
|
||||
if base.type(gett) == "string" then return sget(gett)
|
||||
else return tget(gett) end
|
||||
end)
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- FTP support for the Lua language
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: ftp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local socket = require("socket")
|
||||
local url = require("socket.url")
|
||||
local tp = require("socket.tp")
|
||||
local ltn12 = require("ltn12")
|
||||
module("socket.ftp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- timeout in seconds before the program gives up on a connection
|
||||
TIMEOUT = 60
|
||||
-- default port for ftp service
|
||||
PORT = 21
|
||||
-- this is the default anonymous password. used when no password is
|
||||
-- provided in url. should be changed to your e-mail.
|
||||
USER = "ftp"
|
||||
PASSWORD = "anonymous@anonymous.org"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Low level FTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function open(server, port, create)
|
||||
local tp = socket.try(tp.connect(server, port or PORT, create, TIMEOUT))
|
||||
local f = base.setmetatable({ tp = tp }, metat)
|
||||
-- make sure everything gets closed in an exception
|
||||
f.try = socket.newtry(function() f:close() end)
|
||||
return f
|
||||
end
|
||||
|
||||
function metat.__index:portconnect()
|
||||
self.try(self.server:settimeout(TIMEOUT))
|
||||
self.data = self.try(self.server:accept())
|
||||
self.try(self.data:settimeout(TIMEOUT))
|
||||
end
|
||||
|
||||
function metat.__index:pasvconnect()
|
||||
self.data = self.try(socket.tcp())
|
||||
self.try(self.data:settimeout(TIMEOUT))
|
||||
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
|
||||
end
|
||||
|
||||
function metat.__index:login(user, password)
|
||||
self.try(self.tp:command("user", user or USER))
|
||||
local code, reply = self.try(self.tp:check{"2..", 331})
|
||||
if code == 331 then
|
||||
self.try(self.tp:command("pass", password or PASSWORD))
|
||||
self.try(self.tp:check("2.."))
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:pasv()
|
||||
self.try(self.tp:command("pasv"))
|
||||
local code, reply = self.try(self.tp:check("2.."))
|
||||
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
|
||||
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
|
||||
self.try(a and b and c and d and p1 and p2, reply)
|
||||
self.pasvt = {
|
||||
ip = string.format("%d.%d.%d.%d", a, b, c, d),
|
||||
port = p1*256 + p2
|
||||
}
|
||||
if self.server then
|
||||
self.server:close()
|
||||
self.server = nil
|
||||
end
|
||||
return self.pasvt.ip, self.pasvt.port
|
||||
end
|
||||
|
||||
function metat.__index:port(ip, port)
|
||||
self.pasvt = nil
|
||||
if not ip then
|
||||
ip, port = self.try(self.tp:getcontrol():getsockname())
|
||||
self.server = self.try(socket.bind(ip, 0))
|
||||
ip, port = self.try(self.server:getsockname())
|
||||
self.try(server:settimeout(TIMEOUT))
|
||||
end
|
||||
local pl = math.mod(port, 256)
|
||||
local ph = (port - pl)/256
|
||||
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
|
||||
self.try(self.tp:command("port", arg))
|
||||
self.try(self.tp:check("2.."))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:send(sendt)
|
||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
||||
-- if there is a pasvt table, we already sent a PASV command
|
||||
-- we just get the data connection into self.data
|
||||
if self.pasvt then self:pasvconnect() end
|
||||
-- get the transfer argument and command
|
||||
local argument = sendt.argument or
|
||||
url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
|
||||
if argument == "" then argument = nil end
|
||||
local command = sendt.command or "stor"
|
||||
-- send the transfer command and check the reply
|
||||
self.try(self.tp:command(command, argument))
|
||||
local code, reply = self.try(self.tp:check{"2..", "1.."})
|
||||
-- if there is not a a pasvt table, then there is a server
|
||||
-- and we already sent a PORT command
|
||||
if not self.pasvt then self:portconnect() end
|
||||
-- get the sink, source and step for the transfer
|
||||
local step = sendt.step or ltn12.pump.step
|
||||
local checkstep = function(src, snk)
|
||||
-- check status in control connection while downloading
|
||||
local readyt = socket.select(readt, nil, 0)
|
||||
if readyt[tp] then self.try(self.tp:check("2..")) end
|
||||
return step(src, snk)
|
||||
end
|
||||
local sink = socket.sink("close-when-done", self.data)
|
||||
-- transfer all data and check error
|
||||
self.try(ltn12.pump.all(sendt.source, sink, checkstep))
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
-- done with data connection
|
||||
self.data:close()
|
||||
-- find out how many bytes were sent
|
||||
local sent = socket.skip(1, self.data:getstats())
|
||||
self.data = nil
|
||||
return sent
|
||||
end
|
||||
|
||||
function metat.__index:receive(recvt)
|
||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
||||
if self.pasvt then self:pasvconnect() end
|
||||
local argument = recvt.argument or
|
||||
url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
|
||||
if argument == "" then argument = nil end
|
||||
local command = recvt.command or "retr"
|
||||
self.try(self.tp:command(command, argument))
|
||||
local code = self.try(self.tp:check{"1..", "2.."})
|
||||
if not self.pasvt then self:portconnect() end
|
||||
local source = socket.source("until-closed", self.data)
|
||||
local step = recvt.step or ltn12.pump.step
|
||||
self.try(ltn12.pump.all(source, recvt.sink, step))
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
self.data:close()
|
||||
self.data = nil
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:cwd(dir)
|
||||
self.try(self.tp:command("cwd", dir))
|
||||
self.try(self.tp:check(250))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:type(type)
|
||||
self.try(self.tp:command("type", type))
|
||||
self.try(self.tp:check(200))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:greet()
|
||||
local code = self.try(self.tp:check{"1..", "2.."})
|
||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:quit()
|
||||
self.try(self.tp:command("quit"))
|
||||
self.try(self.tp:check("2.."))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
if self.data then self.data:close() end
|
||||
if self.server then self.server:close() end
|
||||
return self.tp:close()
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- High level FTP API
|
||||
-----------------------------------------------------------------------------
|
||||
function override(t)
|
||||
if t.url then
|
||||
u = url.parse(t.url)
|
||||
for i,v in base.pairs(t) do
|
||||
u[i] = v
|
||||
end
|
||||
return u
|
||||
else return t end
|
||||
end
|
||||
|
||||
local function tput(putt)
|
||||
putt = override(putt)
|
||||
socket.try(putt.host, "missing hostname")
|
||||
local f = open(putt.host, putt.port, putt.create)
|
||||
f:greet()
|
||||
f:login(putt.user, putt.password)
|
||||
if putt.type then f:type(putt.type) end
|
||||
f:pasv()
|
||||
local sent = f:send(putt)
|
||||
f:quit()
|
||||
f:close()
|
||||
return sent
|
||||
end
|
||||
|
||||
local default = {
|
||||
path = "/",
|
||||
scheme = "ftp"
|
||||
}
|
||||
|
||||
local function parse(u)
|
||||
local t = socket.try(url.parse(u, default))
|
||||
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
|
||||
socket.try(t.host, "missing hostname")
|
||||
local pat = "^type=(.)$"
|
||||
if t.params then
|
||||
t.type = socket.skip(2, string.find(t.params, pat))
|
||||
socket.try(t.type == "a" or t.type == "i",
|
||||
"invalid type '" .. t.type .. "'")
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function sput(u, body)
|
||||
local putt = parse(u)
|
||||
putt.source = ltn12.source.string(body)
|
||||
return tput(putt)
|
||||
end
|
||||
|
||||
put = socket.protect(function(putt, body)
|
||||
if base.type(putt) == "string" then return sput(putt, body)
|
||||
else return tput(putt) end
|
||||
end)
|
||||
|
||||
local function tget(gett)
|
||||
gett = override(gett)
|
||||
socket.try(gett.host, "missing hostname")
|
||||
local f = open(gett.host, gett.port, gett.create)
|
||||
f:greet()
|
||||
f:login(gett.user, gett.password)
|
||||
if gett.type then f:type(gett.type) end
|
||||
f:pasv()
|
||||
f:receive(gett)
|
||||
f:quit()
|
||||
return f:close()
|
||||
end
|
||||
|
||||
local function sget(u)
|
||||
local gett = parse(u)
|
||||
local t = {}
|
||||
gett.sink = ltn12.sink.table(t)
|
||||
tget(gett)
|
||||
return table.concat(t)
|
||||
end
|
||||
|
||||
command = socket.protect(function(cmdt)
|
||||
cmdt = override(cmdt)
|
||||
socket.try(cmdt.host, "missing hostname")
|
||||
socket.try(cmdt.command, "missing command")
|
||||
local f = open(cmdt.host, cmdt.port, cmdt.create)
|
||||
f:greet()
|
||||
f:login(cmdt.user, cmdt.password)
|
||||
f.try(f.tp:command(cmdt.command, cmdt.argument))
|
||||
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
|
||||
f:quit()
|
||||
return f:close()
|
||||
end)
|
||||
|
||||
get = socket.protect(function(gett)
|
||||
if base.type(gett) == "string" then return sget(gett)
|
||||
else return tget(gett) end
|
||||
end)
|
||||
|
||||
@@ -1,326 +1,326 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- HTTP/1.1 client support for the Lua language.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: http.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-------------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
local url = require("socket.url")
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime")
|
||||
local string = require("string")
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
module("socket.http")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- connection timeout in seconds
|
||||
TIMEOUT = 60
|
||||
-- default port for document retrieval
|
||||
PORT = 80
|
||||
-- user agent field sent in request
|
||||
USERAGENT = socket._VERSION
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Reads MIME headers from a connection, unfolding where needed
|
||||
-----------------------------------------------------------------------------
|
||||
local function receiveheaders(sock, headers)
|
||||
local line, name, value, err
|
||||
headers = headers or {}
|
||||
-- get first line
|
||||
line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
-- headers go until a blank line is found
|
||||
while line ~= "" do
|
||||
-- get field-name and value
|
||||
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
|
||||
if not (name and value) then return nil, "malformed reponse headers" end
|
||||
name = string.lower(name)
|
||||
-- get next line (value might be folded)
|
||||
line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
-- unfold any folded values
|
||||
while string.find(line, "^%s") do
|
||||
value = value .. line
|
||||
line = sock:receive()
|
||||
if err then return nil, err end
|
||||
end
|
||||
-- save pair in table
|
||||
if headers[name] then headers[name] = headers[name] .. ", " .. value
|
||||
else headers[name] = value end
|
||||
end
|
||||
return headers
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Extra sources and sinks
|
||||
-----------------------------------------------------------------------------
|
||||
socket.sourcet["http-chunked"] = function(sock, headers)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
-- get chunk size, skip extention
|
||||
local line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
|
||||
if not size then return nil, "invalid chunk size" end
|
||||
-- was it the last chunk?
|
||||
if size > 0 then
|
||||
-- if not, get chunk and skip terminating CRLF
|
||||
local chunk, err, part = sock:receive(size)
|
||||
if chunk then sock:receive() end
|
||||
return chunk, err
|
||||
else
|
||||
-- if it was, read trailers into headers table
|
||||
headers, err = receiveheaders(sock, headers)
|
||||
if not headers then return nil, err end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
socket.sinkt["http-chunked"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if not chunk then return sock:send("0\r\n\r\n") end
|
||||
local size = string.format("%X\r\n", string.len(chunk))
|
||||
return sock:send(size .. chunk .. "\r\n")
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Low level HTTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function open(host, port, create)
|
||||
-- create socket with user connect function, or with default
|
||||
local c = socket.try(create or socket.tcp)()
|
||||
local h = base.setmetatable({ c = c }, metat)
|
||||
-- create finalized try
|
||||
h.try = socket.newtry(function() h:close() end)
|
||||
-- set timeout before connecting
|
||||
h.try(c:settimeout(TIMEOUT))
|
||||
h.try(c:connect(host, port or PORT))
|
||||
-- here everything worked
|
||||
return h
|
||||
end
|
||||
|
||||
function metat.__index:sendrequestline(method, uri)
|
||||
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
|
||||
return self.try(self.c:send(reqline))
|
||||
end
|
||||
|
||||
function metat.__index:sendheaders(headers)
|
||||
local h = "\r\n"
|
||||
for i, v in base.pairs(headers) do
|
||||
h = i .. ": " .. v .. "\r\n" .. h
|
||||
end
|
||||
self.try(self.c:send(h))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:sendbody(headers, source, step)
|
||||
source = source or ltn12.source.empty()
|
||||
step = step or ltn12.pump.step
|
||||
-- if we don't know the size in advance, send chunked and hope for the best
|
||||
local mode = "http-chunked"
|
||||
if headers["content-length"] then mode = "keep-open" end
|
||||
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
|
||||
end
|
||||
|
||||
function metat.__index:receivestatusline()
|
||||
local status = self.try(self.c:receive())
|
||||
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
||||
return self.try(base.tonumber(code), status)
|
||||
end
|
||||
|
||||
function metat.__index:receiveheaders()
|
||||
return self.try(receiveheaders(self.c))
|
||||
end
|
||||
|
||||
function metat.__index:receivebody(headers, sink, step)
|
||||
sink = sink or ltn12.sink.null()
|
||||
step = step or ltn12.pump.step
|
||||
local length = base.tonumber(headers["content-length"])
|
||||
local t = headers["transfer-encoding"] -- shortcut
|
||||
local mode = "default" -- connection close
|
||||
if t and t ~= "identity" then mode = "http-chunked"
|
||||
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
|
||||
return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
|
||||
sink, step))
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
return self.c:close()
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- High level HTTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local function adjusturi(reqt)
|
||||
local u = reqt
|
||||
-- if there is a proxy, we need the full url. otherwise, just a part.
|
||||
if not reqt.proxy and not PROXY then
|
||||
u = {
|
||||
path = socket.try(reqt.path, "invalid path 'nil'"),
|
||||
params = reqt.params,
|
||||
query = reqt.query,
|
||||
fragment = reqt.fragment
|
||||
}
|
||||
end
|
||||
return url.build(u)
|
||||
end
|
||||
|
||||
local function adjustproxy(reqt)
|
||||
local proxy = reqt.proxy or PROXY
|
||||
if proxy then
|
||||
proxy = url.parse(proxy)
|
||||
return proxy.host, proxy.port or 3128
|
||||
else
|
||||
return reqt.host, reqt.port
|
||||
end
|
||||
end
|
||||
|
||||
local function adjustheaders(headers, host)
|
||||
-- default headers
|
||||
local lower = {
|
||||
["user-agent"] = USERAGENT,
|
||||
["host"] = host,
|
||||
["connection"] = "close, TE",
|
||||
["te"] = "trailers"
|
||||
}
|
||||
-- override with user headers
|
||||
for i,v in base.pairs(headers or lower) do
|
||||
lower[string.lower(i)] = v
|
||||
end
|
||||
return lower
|
||||
end
|
||||
|
||||
-- default url parts
|
||||
local default = {
|
||||
host = "",
|
||||
port = PORT,
|
||||
path ="/",
|
||||
scheme = "http"
|
||||
}
|
||||
|
||||
local function adjustrequest(reqt)
|
||||
-- parse url if provided
|
||||
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
||||
local t = url.parse(reqt.url, default)
|
||||
-- explicit components override url
|
||||
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
||||
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
|
||||
-- compute uri if user hasn't overriden
|
||||
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
||||
-- ajust host and port if there is a proxy
|
||||
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
||||
-- adjust headers in request
|
||||
nreqt.headers = adjustheaders(nreqt.headers, nreqt.host)
|
||||
return nreqt
|
||||
end
|
||||
|
||||
local function shouldredirect(reqt, code, headers)
|
||||
return headers.location and
|
||||
string.gsub(headers.location, "%s", "") ~= "" and
|
||||
(reqt.redirect ~= false) and
|
||||
(code == 301 or code == 302) and
|
||||
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
||||
and (not reqt.nredirects or reqt.nredirects < 5)
|
||||
end
|
||||
|
||||
local function shouldauthorize(reqt, code)
|
||||
-- if there has been an authorization attempt, it must have failed
|
||||
if reqt.headers and reqt.headers["authorization"] then return nil end
|
||||
-- if last attempt didn't fail due to lack of authentication,
|
||||
-- or we don't have authorization information, we can't retry
|
||||
return code == 401 and reqt.user and reqt.password
|
||||
end
|
||||
|
||||
local function shouldreceivebody(reqt, code)
|
||||
if reqt.method == "HEAD" then return nil end
|
||||
if code == 204 or code == 304 then return nil end
|
||||
if code >= 100 and code < 200 then return nil end
|
||||
return 1
|
||||
end
|
||||
|
||||
-- forward declarations
|
||||
local trequest, tauthorize, tredirect
|
||||
|
||||
function tauthorize(reqt)
|
||||
local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
|
||||
reqt.headers["authorization"] = auth
|
||||
return trequest(reqt)
|
||||
end
|
||||
|
||||
function tredirect(reqt, location)
|
||||
local result, code, headers, status = trequest {
|
||||
-- the RFC says the redirect URL has to be absolute, but some
|
||||
-- servers do not respect that
|
||||
url = url.absolute(reqt, location),
|
||||
source = reqt.source,
|
||||
sink = reqt.sink,
|
||||
headers = reqt.headers,
|
||||
proxy = reqt.proxy,
|
||||
nredirects = (reqt.nredirects or 0) + 1,
|
||||
connect = reqt.connect
|
||||
}
|
||||
-- pass location header back as a hint we redirected
|
||||
headers.location = headers.location or location
|
||||
return result, code, headers, status
|
||||
end
|
||||
|
||||
function trequest(reqt)
|
||||
reqt = adjustrequest(reqt)
|
||||
local h = open(reqt.host, reqt.port, reqt.create)
|
||||
h:sendrequestline(reqt.method, reqt.uri)
|
||||
h:sendheaders(reqt.headers)
|
||||
if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end
|
||||
local code, headers, status
|
||||
code, status = h:receivestatusline()
|
||||
headers = h:receiveheaders()
|
||||
if shouldredirect(reqt, code, headers) then
|
||||
h:close()
|
||||
return tredirect(reqt, headers.location)
|
||||
elseif shouldauthorize(reqt, code) then
|
||||
h:close()
|
||||
return tauthorize(reqt)
|
||||
elseif shouldreceivebody(reqt, code) then
|
||||
h:receivebody(headers, reqt.sink, reqt.step)
|
||||
end
|
||||
h:close()
|
||||
return 1, code, headers, status
|
||||
end
|
||||
|
||||
local function srequest(u, body)
|
||||
local t = {}
|
||||
local reqt = {
|
||||
url = u,
|
||||
sink = ltn12.sink.table(t)
|
||||
}
|
||||
if body then
|
||||
reqt.source = ltn12.source.string(body)
|
||||
reqt.headers = { ["content-length"] = string.len(body) }
|
||||
reqt.method = "POST"
|
||||
end
|
||||
local code, headers, status = socket.skip(1, trequest(reqt))
|
||||
return table.concat(t), code, headers, status
|
||||
end
|
||||
|
||||
request = socket.protect(function(reqt, body)
|
||||
if base.type(reqt) == "string" then return srequest(reqt, body)
|
||||
else return trequest(reqt) end
|
||||
end)
|
||||
-----------------------------------------------------------------------------
|
||||
-- HTTP/1.1 client support for the Lua language.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: http.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-------------------------------------------------------------------------------
|
||||
local socket = require("socket")
|
||||
local url = require("socket.url")
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime")
|
||||
local string = require("string")
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
module("socket.http")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- connection timeout in seconds
|
||||
TIMEOUT = 60
|
||||
-- default port for document retrieval
|
||||
PORT = 80
|
||||
-- user agent field sent in request
|
||||
USERAGENT = socket._VERSION
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Reads MIME headers from a connection, unfolding where needed
|
||||
-----------------------------------------------------------------------------
|
||||
local function receiveheaders(sock, headers)
|
||||
local line, name, value, err
|
||||
headers = headers or {}
|
||||
-- get first line
|
||||
line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
-- headers go until a blank line is found
|
||||
while line ~= "" do
|
||||
-- get field-name and value
|
||||
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
|
||||
if not (name and value) then return nil, "malformed reponse headers" end
|
||||
name = string.lower(name)
|
||||
-- get next line (value might be folded)
|
||||
line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
-- unfold any folded values
|
||||
while string.find(line, "^%s") do
|
||||
value = value .. line
|
||||
line = sock:receive()
|
||||
if err then return nil, err end
|
||||
end
|
||||
-- save pair in table
|
||||
if headers[name] then headers[name] = headers[name] .. ", " .. value
|
||||
else headers[name] = value end
|
||||
end
|
||||
return headers
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Extra sources and sinks
|
||||
-----------------------------------------------------------------------------
|
||||
socket.sourcet["http-chunked"] = function(sock, headers)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function()
|
||||
-- get chunk size, skip extention
|
||||
local line, err = sock:receive()
|
||||
if err then return nil, err end
|
||||
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
|
||||
if not size then return nil, "invalid chunk size" end
|
||||
-- was it the last chunk?
|
||||
if size > 0 then
|
||||
-- if not, get chunk and skip terminating CRLF
|
||||
local chunk, err, part = sock:receive(size)
|
||||
if chunk then sock:receive() end
|
||||
return chunk, err
|
||||
else
|
||||
-- if it was, read trailers into headers table
|
||||
headers, err = receiveheaders(sock, headers)
|
||||
if not headers then return nil, err end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
socket.sinkt["http-chunked"] = function(sock)
|
||||
return base.setmetatable({
|
||||
getfd = function() return sock:getfd() end,
|
||||
dirty = function() return sock:dirty() end
|
||||
}, {
|
||||
__call = function(self, chunk, err)
|
||||
if not chunk then return sock:send("0\r\n\r\n") end
|
||||
local size = string.format("%X\r\n", string.len(chunk))
|
||||
return sock:send(size .. chunk .. "\r\n")
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Low level HTTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function open(host, port, create)
|
||||
-- create socket with user connect function, or with default
|
||||
local c = socket.try(create or socket.tcp)()
|
||||
local h = base.setmetatable({ c = c }, metat)
|
||||
-- create finalized try
|
||||
h.try = socket.newtry(function() h:close() end)
|
||||
-- set timeout before connecting
|
||||
h.try(c:settimeout(TIMEOUT))
|
||||
h.try(c:connect(host, port or PORT))
|
||||
-- here everything worked
|
||||
return h
|
||||
end
|
||||
|
||||
function metat.__index:sendrequestline(method, uri)
|
||||
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
|
||||
return self.try(self.c:send(reqline))
|
||||
end
|
||||
|
||||
function metat.__index:sendheaders(headers)
|
||||
local h = "\r\n"
|
||||
for i, v in base.pairs(headers) do
|
||||
h = i .. ": " .. v .. "\r\n" .. h
|
||||
end
|
||||
self.try(self.c:send(h))
|
||||
return 1
|
||||
end
|
||||
|
||||
function metat.__index:sendbody(headers, source, step)
|
||||
source = source or ltn12.source.empty()
|
||||
step = step or ltn12.pump.step
|
||||
-- if we don't know the size in advance, send chunked and hope for the best
|
||||
local mode = "http-chunked"
|
||||
if headers["content-length"] then mode = "keep-open" end
|
||||
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
|
||||
end
|
||||
|
||||
function metat.__index:receivestatusline()
|
||||
local status = self.try(self.c:receive())
|
||||
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
||||
return self.try(base.tonumber(code), status)
|
||||
end
|
||||
|
||||
function metat.__index:receiveheaders()
|
||||
return self.try(receiveheaders(self.c))
|
||||
end
|
||||
|
||||
function metat.__index:receivebody(headers, sink, step)
|
||||
sink = sink or ltn12.sink.null()
|
||||
step = step or ltn12.pump.step
|
||||
local length = base.tonumber(headers["content-length"])
|
||||
local t = headers["transfer-encoding"] -- shortcut
|
||||
local mode = "default" -- connection close
|
||||
if t and t ~= "identity" then mode = "http-chunked"
|
||||
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
|
||||
return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
|
||||
sink, step))
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
return self.c:close()
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- High level HTTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local function adjusturi(reqt)
|
||||
local u = reqt
|
||||
-- if there is a proxy, we need the full url. otherwise, just a part.
|
||||
if not reqt.proxy and not PROXY then
|
||||
u = {
|
||||
path = socket.try(reqt.path, "invalid path 'nil'"),
|
||||
params = reqt.params,
|
||||
query = reqt.query,
|
||||
fragment = reqt.fragment
|
||||
}
|
||||
end
|
||||
return url.build(u)
|
||||
end
|
||||
|
||||
local function adjustproxy(reqt)
|
||||
local proxy = reqt.proxy or PROXY
|
||||
if proxy then
|
||||
proxy = url.parse(proxy)
|
||||
return proxy.host, proxy.port or 3128
|
||||
else
|
||||
return reqt.host, reqt.port
|
||||
end
|
||||
end
|
||||
|
||||
local function adjustheaders(headers, host)
|
||||
-- default headers
|
||||
local lower = {
|
||||
["user-agent"] = USERAGENT,
|
||||
["host"] = host,
|
||||
["connection"] = "close, TE",
|
||||
["te"] = "trailers"
|
||||
}
|
||||
-- override with user headers
|
||||
for i,v in base.pairs(headers or lower) do
|
||||
lower[string.lower(i)] = v
|
||||
end
|
||||
return lower
|
||||
end
|
||||
|
||||
-- default url parts
|
||||
local default = {
|
||||
host = "",
|
||||
port = PORT,
|
||||
path ="/",
|
||||
scheme = "http"
|
||||
}
|
||||
|
||||
local function adjustrequest(reqt)
|
||||
-- parse url if provided
|
||||
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
||||
local t = url.parse(reqt.url, default)
|
||||
-- explicit components override url
|
||||
for i,v in base.pairs(reqt) do nreqt[i] = v end
|
||||
socket.try(nreqt.host, "invalid host '" .. base.tostring(nreqt.host) .. "'")
|
||||
-- compute uri if user hasn't overriden
|
||||
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
||||
-- ajust host and port if there is a proxy
|
||||
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
||||
-- adjust headers in request
|
||||
nreqt.headers = adjustheaders(nreqt.headers, nreqt.host)
|
||||
return nreqt
|
||||
end
|
||||
|
||||
local function shouldredirect(reqt, code, headers)
|
||||
return headers.location and
|
||||
string.gsub(headers.location, "%s", "") ~= "" and
|
||||
(reqt.redirect ~= false) and
|
||||
(code == 301 or code == 302) and
|
||||
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
||||
and (not reqt.nredirects or reqt.nredirects < 5)
|
||||
end
|
||||
|
||||
local function shouldauthorize(reqt, code)
|
||||
-- if there has been an authorization attempt, it must have failed
|
||||
if reqt.headers and reqt.headers["authorization"] then return nil end
|
||||
-- if last attempt didn't fail due to lack of authentication,
|
||||
-- or we don't have authorization information, we can't retry
|
||||
return code == 401 and reqt.user and reqt.password
|
||||
end
|
||||
|
||||
local function shouldreceivebody(reqt, code)
|
||||
if reqt.method == "HEAD" then return nil end
|
||||
if code == 204 or code == 304 then return nil end
|
||||
if code >= 100 and code < 200 then return nil end
|
||||
return 1
|
||||
end
|
||||
|
||||
-- forward declarations
|
||||
local trequest, tauthorize, tredirect
|
||||
|
||||
function tauthorize(reqt)
|
||||
local auth = "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
|
||||
reqt.headers["authorization"] = auth
|
||||
return trequest(reqt)
|
||||
end
|
||||
|
||||
function tredirect(reqt, location)
|
||||
local result, code, headers, status = trequest {
|
||||
-- the RFC says the redirect URL has to be absolute, but some
|
||||
-- servers do not respect that
|
||||
url = url.absolute(reqt, location),
|
||||
source = reqt.source,
|
||||
sink = reqt.sink,
|
||||
headers = reqt.headers,
|
||||
proxy = reqt.proxy,
|
||||
nredirects = (reqt.nredirects or 0) + 1,
|
||||
connect = reqt.connect
|
||||
}
|
||||
-- pass location header back as a hint we redirected
|
||||
headers.location = headers.location or location
|
||||
return result, code, headers, status
|
||||
end
|
||||
|
||||
function trequest(reqt)
|
||||
reqt = adjustrequest(reqt)
|
||||
local h = open(reqt.host, reqt.port, reqt.create)
|
||||
h:sendrequestline(reqt.method, reqt.uri)
|
||||
h:sendheaders(reqt.headers)
|
||||
if reqt.source then h:sendbody(reqt.headers, reqt.source, reqt.step) end
|
||||
local code, headers, status
|
||||
code, status = h:receivestatusline()
|
||||
headers = h:receiveheaders()
|
||||
if shouldredirect(reqt, code, headers) then
|
||||
h:close()
|
||||
return tredirect(reqt, headers.location)
|
||||
elseif shouldauthorize(reqt, code) then
|
||||
h:close()
|
||||
return tauthorize(reqt)
|
||||
elseif shouldreceivebody(reqt, code) then
|
||||
h:receivebody(headers, reqt.sink, reqt.step)
|
||||
end
|
||||
h:close()
|
||||
return 1, code, headers, status
|
||||
end
|
||||
|
||||
local function srequest(u, body)
|
||||
local t = {}
|
||||
local reqt = {
|
||||
url = u,
|
||||
sink = ltn12.sink.table(t)
|
||||
}
|
||||
if body then
|
||||
reqt.source = ltn12.source.string(body)
|
||||
reqt.headers = { ["content-length"] = string.len(body) }
|
||||
reqt.method = "POST"
|
||||
end
|
||||
local code, headers, status = socket.skip(1, trequest(reqt))
|
||||
return table.concat(t), code, headers, status
|
||||
end
|
||||
|
||||
request = socket.protect(function(reqt, body)
|
||||
if base.type(reqt) == "string" then return srequest(reqt, body)
|
||||
else return trequest(reqt) end
|
||||
end)
|
||||
@@ -1,245 +1,245 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- SMTP client support for the Lua language.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: smtp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local coroutine = require("coroutine")
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local os = require("os")
|
||||
local socket = require("socket")
|
||||
local tp = require("socket.tp")
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime")
|
||||
module("socket.smtp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- timeout for connection
|
||||
TIMEOUT = 60
|
||||
-- default server used to send e-mails
|
||||
SERVER = "localhost"
|
||||
-- default port
|
||||
PORT = 25
|
||||
-- domain used in HELO command and default sendmail
|
||||
-- If we are under a CGI, try to get from environment
|
||||
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
|
||||
-- default time zone (means we don't know)
|
||||
ZONE = "-0000"
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Low level SMTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function metat.__index:greet(domain)
|
||||
self.try(self.tp:check("2.."))
|
||||
self.try(self.tp:command("EHLO", domain or DOMAIN))
|
||||
return socket.skip(1, self.try(self.tp:check("2..")))
|
||||
end
|
||||
|
||||
function metat.__index:mail(from)
|
||||
self.try(self.tp:command("MAIL", "FROM:" .. from))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:rcpt(to)
|
||||
self.try(self.tp:command("RCPT", "TO:" .. to))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:data(src, step)
|
||||
self.try(self.tp:command("DATA"))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:source(src, step))
|
||||
self.try(self.tp:send("\r\n.\r\n"))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:quit()
|
||||
self.try(self.tp:command("QUIT"))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
return self.tp:close()
|
||||
end
|
||||
|
||||
function metat.__index:login(user, password)
|
||||
self.try(self.tp:command("AUTH", "LOGIN"))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:command(mime.b64(user)))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:command(mime.b64(password)))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:plain(user, password)
|
||||
local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
|
||||
self.try(self.tp:command("AUTH", auth))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:auth(user, password, ext)
|
||||
if not user or not password then return 1 end
|
||||
if string.find(ext, "AUTH[^\n]+LOGIN") then
|
||||
return self:login(user, password)
|
||||
elseif string.find(ext, "AUTH[^\n]+PLAIN") then
|
||||
return self:plain(user, password)
|
||||
else
|
||||
self.try(nil, "authentication not supported")
|
||||
end
|
||||
end
|
||||
|
||||
-- send message or throw an exception
|
||||
function metat.__index:send(mailt)
|
||||
self:mail(mailt.from)
|
||||
if base.type(mailt.rcpt) == "table" then
|
||||
for i,v in base.ipairs(mailt.rcpt) do
|
||||
self:rcpt(v)
|
||||
end
|
||||
else
|
||||
self:rcpt(mailt.rcpt)
|
||||
end
|
||||
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
|
||||
end
|
||||
|
||||
function open(server, port, create)
|
||||
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
|
||||
create, TIMEOUT))
|
||||
local s = base.setmetatable({tp = tp}, metat)
|
||||
-- make sure tp is closed if we get an exception
|
||||
s.try = socket.newtry(function()
|
||||
s:close()
|
||||
end)
|
||||
return s
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Multipart message source
|
||||
-----------------------------------------------------------------------------
|
||||
-- returns a hopefully unique mime boundary
|
||||
local seqno = 0
|
||||
local function newboundary()
|
||||
seqno = seqno + 1
|
||||
return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
|
||||
math.random(0, 99999), seqno)
|
||||
end
|
||||
|
||||
-- send_message forward declaration
|
||||
local send_message
|
||||
|
||||
-- yield the headers all at once, it's faster
|
||||
local function send_headers(headers)
|
||||
local h = "\r\n"
|
||||
for i,v in base.pairs(headers) do
|
||||
h = i .. ': ' .. v .. "\r\n" .. h
|
||||
end
|
||||
coroutine.yield(h)
|
||||
end
|
||||
|
||||
-- yield multipart message body from a multipart message table
|
||||
local function send_multipart(mesgt)
|
||||
-- make sure we have our boundary and send headers
|
||||
local bd = newboundary()
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
|
||||
headers['content-type'] = headers['content-type'] ..
|
||||
'; boundary="' .. bd .. '"'
|
||||
send_headers(headers)
|
||||
-- send preamble
|
||||
if mesgt.body.preamble then
|
||||
coroutine.yield(mesgt.body.preamble)
|
||||
coroutine.yield("\r\n")
|
||||
end
|
||||
-- send each part separated by a boundary
|
||||
for i, m in base.ipairs(mesgt.body) do
|
||||
coroutine.yield("\r\n--" .. bd .. "\r\n")
|
||||
send_message(m)
|
||||
end
|
||||
-- send last boundary
|
||||
coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
|
||||
-- send epilogue
|
||||
if mesgt.body.epilogue then
|
||||
coroutine.yield(mesgt.body.epilogue)
|
||||
coroutine.yield("\r\n")
|
||||
end
|
||||
end
|
||||
|
||||
-- yield message body from a source
|
||||
local function send_source(mesgt)
|
||||
-- make sure we have a content-type
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or
|
||||
'text/plain; charset="iso-8859-1"'
|
||||
send_headers(headers)
|
||||
-- send body from source
|
||||
while true do
|
||||
local chunk, err = mesgt.body()
|
||||
if err then coroutine.yield(nil, err)
|
||||
elseif chunk then coroutine.yield(chunk)
|
||||
else break end
|
||||
end
|
||||
end
|
||||
|
||||
-- yield message body from a string
|
||||
local function send_string(mesgt)
|
||||
-- make sure we have a content-type
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or
|
||||
'text/plain; charset="iso-8859-1"'
|
||||
send_headers(headers)
|
||||
-- send body from string
|
||||
coroutine.yield(mesgt.body)
|
||||
end
|
||||
|
||||
-- message source
|
||||
function send_message(mesgt)
|
||||
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
|
||||
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
|
||||
else send_string(mesgt) end
|
||||
end
|
||||
|
||||
-- set defaul headers
|
||||
local function adjust_headers(mesgt)
|
||||
local lower = {}
|
||||
for i,v in base.pairs(mesgt.headers or lower) do
|
||||
lower[string.lower(i)] = v
|
||||
end
|
||||
lower["date"] = lower["date"] or
|
||||
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
|
||||
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
|
||||
-- this can't be overriden
|
||||
lower["mime-version"] = "1.0"
|
||||
mesgt.headers = lower
|
||||
end
|
||||
|
||||
function message(mesgt)
|
||||
adjust_headers(mesgt)
|
||||
-- create and return message source
|
||||
local co = coroutine.create(function() send_message(mesgt) end)
|
||||
return function()
|
||||
local ret, a, b = coroutine.resume(co)
|
||||
if ret then return a, b
|
||||
else return nil, a end
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- High level SMTP API
|
||||
-----------------------------------------------------------------------------
|
||||
send = socket.protect(function(mailt)
|
||||
local s = open(mailt.server, mailt.port, mailt.create)
|
||||
local ext = s:greet(mailt.domain)
|
||||
s:auth(mailt.user, mailt.password, ext)
|
||||
s:send(mailt)
|
||||
s:quit()
|
||||
return s:close()
|
||||
end)
|
||||
-----------------------------------------------------------------------------
|
||||
-- SMTP client support for the Lua language.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: smtp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local coroutine = require("coroutine")
|
||||
local string = require("string")
|
||||
local math = require("math")
|
||||
local os = require("os")
|
||||
local socket = require("socket")
|
||||
local tp = require("socket.tp")
|
||||
local ltn12 = require("ltn12")
|
||||
local mime = require("mime")
|
||||
module("socket.smtp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
-- timeout for connection
|
||||
TIMEOUT = 60
|
||||
-- default server used to send e-mails
|
||||
SERVER = "localhost"
|
||||
-- default port
|
||||
PORT = 25
|
||||
-- domain used in HELO command and default sendmail
|
||||
-- If we are under a CGI, try to get from environment
|
||||
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
|
||||
-- default time zone (means we don't know)
|
||||
ZONE = "-0000"
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Low level SMTP API
|
||||
-----------------------------------------------------------------------------
|
||||
local metat = { __index = {} }
|
||||
|
||||
function metat.__index:greet(domain)
|
||||
self.try(self.tp:check("2.."))
|
||||
self.try(self.tp:command("EHLO", domain or DOMAIN))
|
||||
return socket.skip(1, self.try(self.tp:check("2..")))
|
||||
end
|
||||
|
||||
function metat.__index:mail(from)
|
||||
self.try(self.tp:command("MAIL", "FROM:" .. from))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:rcpt(to)
|
||||
self.try(self.tp:command("RCPT", "TO:" .. to))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:data(src, step)
|
||||
self.try(self.tp:command("DATA"))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:source(src, step))
|
||||
self.try(self.tp:send("\r\n.\r\n"))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:quit()
|
||||
self.try(self.tp:command("QUIT"))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:close()
|
||||
return self.tp:close()
|
||||
end
|
||||
|
||||
function metat.__index:login(user, password)
|
||||
self.try(self.tp:command("AUTH", "LOGIN"))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:command(mime.b64(user)))
|
||||
self.try(self.tp:check("3.."))
|
||||
self.try(self.tp:command(mime.b64(password)))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:plain(user, password)
|
||||
local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
|
||||
self.try(self.tp:command("AUTH", auth))
|
||||
return self.try(self.tp:check("2.."))
|
||||
end
|
||||
|
||||
function metat.__index:auth(user, password, ext)
|
||||
if not user or not password then return 1 end
|
||||
if string.find(ext, "AUTH[^\n]+LOGIN") then
|
||||
return self:login(user, password)
|
||||
elseif string.find(ext, "AUTH[^\n]+PLAIN") then
|
||||
return self:plain(user, password)
|
||||
else
|
||||
self.try(nil, "authentication not supported")
|
||||
end
|
||||
end
|
||||
|
||||
-- send message or throw an exception
|
||||
function metat.__index:send(mailt)
|
||||
self:mail(mailt.from)
|
||||
if base.type(mailt.rcpt) == "table" then
|
||||
for i,v in base.ipairs(mailt.rcpt) do
|
||||
self:rcpt(v)
|
||||
end
|
||||
else
|
||||
self:rcpt(mailt.rcpt)
|
||||
end
|
||||
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
|
||||
end
|
||||
|
||||
function open(server, port, create)
|
||||
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
|
||||
create, TIMEOUT))
|
||||
local s = base.setmetatable({tp = tp}, metat)
|
||||
-- make sure tp is closed if we get an exception
|
||||
s.try = socket.newtry(function()
|
||||
s:close()
|
||||
end)
|
||||
return s
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Multipart message source
|
||||
-----------------------------------------------------------------------------
|
||||
-- returns a hopefully unique mime boundary
|
||||
local seqno = 0
|
||||
local function newboundary()
|
||||
seqno = seqno + 1
|
||||
return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
|
||||
math.random(0, 99999), seqno)
|
||||
end
|
||||
|
||||
-- send_message forward declaration
|
||||
local send_message
|
||||
|
||||
-- yield the headers all at once, it's faster
|
||||
local function send_headers(headers)
|
||||
local h = "\r\n"
|
||||
for i,v in base.pairs(headers) do
|
||||
h = i .. ': ' .. v .. "\r\n" .. h
|
||||
end
|
||||
coroutine.yield(h)
|
||||
end
|
||||
|
||||
-- yield multipart message body from a multipart message table
|
||||
local function send_multipart(mesgt)
|
||||
-- make sure we have our boundary and send headers
|
||||
local bd = newboundary()
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
|
||||
headers['content-type'] = headers['content-type'] ..
|
||||
'; boundary="' .. bd .. '"'
|
||||
send_headers(headers)
|
||||
-- send preamble
|
||||
if mesgt.body.preamble then
|
||||
coroutine.yield(mesgt.body.preamble)
|
||||
coroutine.yield("\r\n")
|
||||
end
|
||||
-- send each part separated by a boundary
|
||||
for i, m in base.ipairs(mesgt.body) do
|
||||
coroutine.yield("\r\n--" .. bd .. "\r\n")
|
||||
send_message(m)
|
||||
end
|
||||
-- send last boundary
|
||||
coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
|
||||
-- send epilogue
|
||||
if mesgt.body.epilogue then
|
||||
coroutine.yield(mesgt.body.epilogue)
|
||||
coroutine.yield("\r\n")
|
||||
end
|
||||
end
|
||||
|
||||
-- yield message body from a source
|
||||
local function send_source(mesgt)
|
||||
-- make sure we have a content-type
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or
|
||||
'text/plain; charset="iso-8859-1"'
|
||||
send_headers(headers)
|
||||
-- send body from source
|
||||
while true do
|
||||
local chunk, err = mesgt.body()
|
||||
if err then coroutine.yield(nil, err)
|
||||
elseif chunk then coroutine.yield(chunk)
|
||||
else break end
|
||||
end
|
||||
end
|
||||
|
||||
-- yield message body from a string
|
||||
local function send_string(mesgt)
|
||||
-- make sure we have a content-type
|
||||
local headers = mesgt.headers or {}
|
||||
headers['content-type'] = headers['content-type'] or
|
||||
'text/plain; charset="iso-8859-1"'
|
||||
send_headers(headers)
|
||||
-- send body from string
|
||||
coroutine.yield(mesgt.body)
|
||||
end
|
||||
|
||||
-- message source
|
||||
function send_message(mesgt)
|
||||
if base.type(mesgt.body) == "table" then send_multipart(mesgt)
|
||||
elseif base.type(mesgt.body) == "function" then send_source(mesgt)
|
||||
else send_string(mesgt) end
|
||||
end
|
||||
|
||||
-- set defaul headers
|
||||
local function adjust_headers(mesgt)
|
||||
local lower = {}
|
||||
for i,v in base.pairs(mesgt.headers or lower) do
|
||||
lower[string.lower(i)] = v
|
||||
end
|
||||
lower["date"] = lower["date"] or
|
||||
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
|
||||
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
|
||||
-- this can't be overriden
|
||||
lower["mime-version"] = "1.0"
|
||||
mesgt.headers = lower
|
||||
end
|
||||
|
||||
function message(mesgt)
|
||||
adjust_headers(mesgt)
|
||||
-- create and return message source
|
||||
local co = coroutine.create(function() send_message(mesgt) end)
|
||||
return function()
|
||||
local ret, a, b = coroutine.resume(co)
|
||||
if ret then return a, b
|
||||
else return nil, a end
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- High level SMTP API
|
||||
-----------------------------------------------------------------------------
|
||||
send = socket.protect(function(mailt)
|
||||
local s = open(mailt.server, mailt.port, mailt.create)
|
||||
local ext = s:greet(mailt.domain)
|
||||
s:auth(mailt.user, mailt.password, ext)
|
||||
s:send(mailt)
|
||||
s:quit()
|
||||
return s:close()
|
||||
end)
|
||||
@@ -1,123 +1,123 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- Unified SMTP/FTP subsystem
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: tp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local string = require("string")
|
||||
local socket = require("socket")
|
||||
local ltn12 = require("ltn12")
|
||||
module("socket.tp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
TIMEOUT = 60
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Implementation
|
||||
-----------------------------------------------------------------------------
|
||||
-- gets server reply (works for SMTP and FTP)
|
||||
local function get_reply(c)
|
||||
local code, current, sep
|
||||
local line, err = c:receive()
|
||||
local reply = line
|
||||
if err then return nil, err end
|
||||
code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
||||
if not code then return nil, "invalid server reply" end
|
||||
if sep == "-" then -- reply is multiline
|
||||
repeat
|
||||
line, err = c:receive()
|
||||
if err then return nil, err end
|
||||
current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
||||
reply = reply .. "\n" .. line
|
||||
-- reply ends with same code
|
||||
until code == current and sep == " "
|
||||
end
|
||||
return code, reply
|
||||
end
|
||||
|
||||
-- metatable for sock object
|
||||
local metat = { __index = {} }
|
||||
|
||||
function metat.__index:check(ok)
|
||||
local code, reply = get_reply(self.c)
|
||||
if not code then return nil, reply end
|
||||
if base.type(ok) ~= "function" then
|
||||
if base.type(ok) == "table" then
|
||||
for i, v in base.ipairs(ok) do
|
||||
if string.find(code, v) then
|
||||
return base.tonumber(code), reply
|
||||
end
|
||||
end
|
||||
return nil, reply
|
||||
else
|
||||
if string.find(code, ok) then return base.tonumber(code), reply
|
||||
else return nil, reply end
|
||||
end
|
||||
else return ok(base.tonumber(code), reply) end
|
||||
end
|
||||
|
||||
function metat.__index:command(cmd, arg)
|
||||
if arg then
|
||||
return self.c:send(cmd .. " " .. arg.. "\r\n")
|
||||
else
|
||||
return self.c:send(cmd .. "\r\n")
|
||||
end
|
||||
end
|
||||
|
||||
function metat.__index:sink(snk, pat)
|
||||
local chunk, err = c:receive(pat)
|
||||
return snk(chunk, err)
|
||||
end
|
||||
|
||||
function metat.__index:send(data)
|
||||
return self.c:send(data)
|
||||
end
|
||||
|
||||
function metat.__index:receive(pat)
|
||||
return self.c:receive(pat)
|
||||
end
|
||||
|
||||
function metat.__index:getfd()
|
||||
return self.c:getfd()
|
||||
end
|
||||
|
||||
function metat.__index:dirty()
|
||||
return self.c:dirty()
|
||||
end
|
||||
|
||||
function metat.__index:getcontrol()
|
||||
return self.c
|
||||
end
|
||||
|
||||
function metat.__index:source(source, step)
|
||||
local sink = socket.sink("keep-open", self.c)
|
||||
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
|
||||
return ret, err
|
||||
end
|
||||
|
||||
-- closes the underlying c
|
||||
function metat.__index:close()
|
||||
self.c:close()
|
||||
return 1
|
||||
end
|
||||
|
||||
-- connect with server and return c object
|
||||
function connect(host, port, create, timeout)
|
||||
local c, e = (create or socket.tcp())
|
||||
if not c then return nil, e end
|
||||
c:settimeout(timeout or TIMEOUT)
|
||||
local r, e = c:connect(host, port)
|
||||
if not r then
|
||||
c:close()
|
||||
return nil, e
|
||||
end
|
||||
return base.setmetatable({c = c}, metat)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Unified SMTP/FTP subsystem
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: tp.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module and import dependencies
|
||||
-----------------------------------------------------------------------------
|
||||
local base = _G
|
||||
local string = require("string")
|
||||
local socket = require("socket")
|
||||
local ltn12 = require("ltn12")
|
||||
module("socket.tp")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Program constants
|
||||
-----------------------------------------------------------------------------
|
||||
TIMEOUT = 60
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Implementation
|
||||
-----------------------------------------------------------------------------
|
||||
-- gets server reply (works for SMTP and FTP)
|
||||
local function get_reply(c)
|
||||
local code, current, sep
|
||||
local line, err = c:receive()
|
||||
local reply = line
|
||||
if err then return nil, err end
|
||||
code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
||||
if not code then return nil, "invalid server reply" end
|
||||
if sep == "-" then -- reply is multiline
|
||||
repeat
|
||||
line, err = c:receive()
|
||||
if err then return nil, err end
|
||||
current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
||||
reply = reply .. "\n" .. line
|
||||
-- reply ends with same code
|
||||
until code == current and sep == " "
|
||||
end
|
||||
return code, reply
|
||||
end
|
||||
|
||||
-- metatable for sock object
|
||||
local metat = { __index = {} }
|
||||
|
||||
function metat.__index:check(ok)
|
||||
local code, reply = get_reply(self.c)
|
||||
if not code then return nil, reply end
|
||||
if base.type(ok) ~= "function" then
|
||||
if base.type(ok) == "table" then
|
||||
for i, v in base.ipairs(ok) do
|
||||
if string.find(code, v) then
|
||||
return base.tonumber(code), reply
|
||||
end
|
||||
end
|
||||
return nil, reply
|
||||
else
|
||||
if string.find(code, ok) then return base.tonumber(code), reply
|
||||
else return nil, reply end
|
||||
end
|
||||
else return ok(base.tonumber(code), reply) end
|
||||
end
|
||||
|
||||
function metat.__index:command(cmd, arg)
|
||||
if arg then
|
||||
return self.c:send(cmd .. " " .. arg.. "\r\n")
|
||||
else
|
||||
return self.c:send(cmd .. "\r\n")
|
||||
end
|
||||
end
|
||||
|
||||
function metat.__index:sink(snk, pat)
|
||||
local chunk, err = c:receive(pat)
|
||||
return snk(chunk, err)
|
||||
end
|
||||
|
||||
function metat.__index:send(data)
|
||||
return self.c:send(data)
|
||||
end
|
||||
|
||||
function metat.__index:receive(pat)
|
||||
return self.c:receive(pat)
|
||||
end
|
||||
|
||||
function metat.__index:getfd()
|
||||
return self.c:getfd()
|
||||
end
|
||||
|
||||
function metat.__index:dirty()
|
||||
return self.c:dirty()
|
||||
end
|
||||
|
||||
function metat.__index:getcontrol()
|
||||
return self.c
|
||||
end
|
||||
|
||||
function metat.__index:source(source, step)
|
||||
local sink = socket.sink("keep-open", self.c)
|
||||
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
|
||||
return ret, err
|
||||
end
|
||||
|
||||
-- closes the underlying c
|
||||
function metat.__index:close()
|
||||
self.c:close()
|
||||
return 1
|
||||
end
|
||||
|
||||
-- connect with server and return c object
|
||||
function connect(host, port, create, timeout)
|
||||
local c, e = (create or socket.tcp())
|
||||
if not c then return nil, e end
|
||||
c:settimeout(timeout or TIMEOUT)
|
||||
local r, e = c:connect(host, port)
|
||||
if not r then
|
||||
c:close()
|
||||
return nil, e
|
||||
end
|
||||
return base.setmetatable({c = c}, metat)
|
||||
end
|
||||
|
||||
@@ -1,297 +1,297 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- URI parsing, composition and relative URL resolution
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: url.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module
|
||||
-----------------------------------------------------------------------------
|
||||
local string = require("string")
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
module("socket.url")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Module version
|
||||
-----------------------------------------------------------------------------
|
||||
_VERSION = "URL 1.0"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Encodes a string into its escaped hexadecimal representation
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
function escape(s)
|
||||
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
|
||||
return string.format("%%%02x", string.byte(c))
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Protects a path segment, to prevent it from interfering with the
|
||||
-- url parsing.
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
local function make_set(t)
|
||||
local s = {}
|
||||
for i,v in base.ipairs(t) do
|
||||
s[t[i]] = 1
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
-- these are allowed withing a path segment, along with alphanum
|
||||
-- other characters must be escaped
|
||||
local segment_set = make_set {
|
||||
"-", "_", ".", "!", "~", "*", "'", "(",
|
||||
")", ":", "@", "&", "=", "+", "$", ",",
|
||||
}
|
||||
|
||||
local function protect_segment(s)
|
||||
return string.gsub(s, "([^A-Za-z0-9_])", function (c)
|
||||
if segment_set[c] then return c
|
||||
else return string.format("%%%02x", string.byte(c)) end
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Encodes a string into its escaped hexadecimal representation
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
function unescape(s)
|
||||
return string.gsub(s, "%%(%x%x)", function(hex)
|
||||
return string.char(base.tonumber(hex, 16))
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a path from a base path and a relative path
|
||||
-- Input
|
||||
-- base_path
|
||||
-- relative_path
|
||||
-- Returns
|
||||
-- corresponding absolute path
|
||||
-----------------------------------------------------------------------------
|
||||
local function absolute_path(base_path, relative_path)
|
||||
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
|
||||
local path = string.gsub(base_path, "[^/]*$", "")
|
||||
path = path .. relative_path
|
||||
path = string.gsub(path, "([^/]*%./)", function (s)
|
||||
if s ~= "./" then return s else return "" end
|
||||
end)
|
||||
path = string.gsub(path, "/%.$", "/")
|
||||
local reduced
|
||||
while reduced ~= path do
|
||||
reduced = path
|
||||
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
|
||||
if s ~= "../../" then return "" else return s end
|
||||
end)
|
||||
end
|
||||
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
|
||||
if s ~= "../.." then return "" else return s end
|
||||
end)
|
||||
return path
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Parses a url and returns a table with all its parts according to RFC 2396
|
||||
-- The following grammar describes the names given to the URL parts
|
||||
-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
|
||||
-- <authority> ::= <userinfo>@<host>:<port>
|
||||
-- <userinfo> ::= <user>[:<password>]
|
||||
-- <path> :: = {<segment>/}<segment>
|
||||
-- Input
|
||||
-- url: uniform resource locator of request
|
||||
-- default: table with default values for each field
|
||||
-- Returns
|
||||
-- table with the following fields, where RFC naming conventions have
|
||||
-- been preserved:
|
||||
-- scheme, authority, userinfo, user, password, host, port,
|
||||
-- path, params, query, fragment
|
||||
-- Obs:
|
||||
-- the leading '/' in {/<path>} is considered part of <path>
|
||||
-----------------------------------------------------------------------------
|
||||
function parse(url, default)
|
||||
-- initialize default parameters
|
||||
local parsed = {}
|
||||
for i,v in base.pairs(default or parsed) do parsed[i] = v end
|
||||
-- empty url is parsed to nil
|
||||
if not url or url == "" then return nil, "invalid url" end
|
||||
-- remove whitespace
|
||||
-- url = string.gsub(url, "%s", "")
|
||||
-- get fragment
|
||||
url = string.gsub(url, "#(.*)$", function(f)
|
||||
parsed.fragment = f
|
||||
return ""
|
||||
end)
|
||||
-- get scheme
|
||||
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
|
||||
function(s) parsed.scheme = s; return "" end)
|
||||
-- get authority
|
||||
url = string.gsub(url, "^//([^/]*)", function(n)
|
||||
parsed.authority = n
|
||||
return ""
|
||||
end)
|
||||
-- get query stringing
|
||||
url = string.gsub(url, "%?(.*)", function(q)
|
||||
parsed.query = q
|
||||
return ""
|
||||
end)
|
||||
-- get params
|
||||
url = string.gsub(url, "%;(.*)", function(p)
|
||||
parsed.params = p
|
||||
return ""
|
||||
end)
|
||||
-- path is whatever was left
|
||||
if url ~= "" then parsed.path = url end
|
||||
local authority = parsed.authority
|
||||
if not authority then return parsed end
|
||||
authority = string.gsub(authority,"^([^@]*)@",
|
||||
function(u) parsed.userinfo = u; return "" end)
|
||||
authority = string.gsub(authority, ":([^:]*)$",
|
||||
function(p) parsed.port = p; return "" end)
|
||||
if authority ~= "" then parsed.host = authority end
|
||||
local userinfo = parsed.userinfo
|
||||
if not userinfo then return parsed end
|
||||
userinfo = string.gsub(userinfo, ":([^:]*)$",
|
||||
function(p) parsed.password = p; return "" end)
|
||||
parsed.user = userinfo
|
||||
return parsed
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Rebuilds a parsed URL from its components.
|
||||
-- Components are protected if any reserved or unallowed characters are found
|
||||
-- Input
|
||||
-- parsed: parsed URL, as returned by parse
|
||||
-- Returns
|
||||
-- a stringing with the corresponding URL
|
||||
-----------------------------------------------------------------------------
|
||||
function build(parsed)
|
||||
local ppath = parse_path(parsed.path or "")
|
||||
local url = build_path(ppath)
|
||||
if parsed.params then url = url .. ";" .. parsed.params end
|
||||
if parsed.query then url = url .. "?" .. parsed.query end
|
||||
local authority = parsed.authority
|
||||
if parsed.host then
|
||||
authority = parsed.host
|
||||
if parsed.port then authority = authority .. ":" .. parsed.port end
|
||||
local userinfo = parsed.userinfo
|
||||
if parsed.user then
|
||||
userinfo = parsed.user
|
||||
if parsed.password then
|
||||
userinfo = userinfo .. ":" .. parsed.password
|
||||
end
|
||||
end
|
||||
if userinfo then authority = userinfo .. "@" .. authority end
|
||||
end
|
||||
if authority then url = "//" .. authority .. url end
|
||||
if parsed.scheme then url = parsed.scheme .. ":" .. url end
|
||||
if parsed.fragment then url = url .. "#" .. parsed.fragment end
|
||||
-- url = string.gsub(url, "%s", "")
|
||||
return url
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a absolute URL from a base and a relative URL according to RFC 2396
|
||||
-- Input
|
||||
-- base_url
|
||||
-- relative_url
|
||||
-- Returns
|
||||
-- corresponding absolute url
|
||||
-----------------------------------------------------------------------------
|
||||
function absolute(base_url, relative_url)
|
||||
if base.type(base_url) == "table" then
|
||||
base_parsed = base_url
|
||||
base_url = build(base_parsed)
|
||||
else
|
||||
base_parsed = parse(base_url)
|
||||
end
|
||||
local relative_parsed = parse(relative_url)
|
||||
if not base_parsed then return relative_url
|
||||
elseif not relative_parsed then return base_url
|
||||
elseif relative_parsed.scheme then return relative_url
|
||||
else
|
||||
relative_parsed.scheme = base_parsed.scheme
|
||||
if not relative_parsed.authority then
|
||||
relative_parsed.authority = base_parsed.authority
|
||||
if not relative_parsed.path then
|
||||
relative_parsed.path = base_parsed.path
|
||||
if not relative_parsed.params then
|
||||
relative_parsed.params = base_parsed.params
|
||||
if not relative_parsed.query then
|
||||
relative_parsed.query = base_parsed.query
|
||||
end
|
||||
end
|
||||
else
|
||||
relative_parsed.path = absolute_path(base_parsed.path or "",
|
||||
relative_parsed.path)
|
||||
end
|
||||
end
|
||||
return build(relative_parsed)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Breaks a path into its segments, unescaping the segments
|
||||
-- Input
|
||||
-- path
|
||||
-- Returns
|
||||
-- segment: a table with one entry per segment
|
||||
-----------------------------------------------------------------------------
|
||||
function parse_path(path)
|
||||
local parsed = {}
|
||||
path = path or ""
|
||||
--path = string.gsub(path, "%s", "")
|
||||
string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
|
||||
for i = 1, table.getn(parsed) do
|
||||
parsed[i] = unescape(parsed[i])
|
||||
end
|
||||
if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
|
||||
if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
|
||||
return parsed
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a path component from its segments, escaping protected characters.
|
||||
-- Input
|
||||
-- parsed: path segments
|
||||
-- unsafe: if true, segments are not protected before path is built
|
||||
-- Returns
|
||||
-- path: corresponding path stringing
|
||||
-----------------------------------------------------------------------------
|
||||
function build_path(parsed, unsafe)
|
||||
local path = ""
|
||||
local n = table.getn(parsed)
|
||||
if unsafe then
|
||||
for i = 1, n-1 do
|
||||
path = path .. parsed[i]
|
||||
path = path .. "/"
|
||||
end
|
||||
if n > 0 then
|
||||
path = path .. parsed[n]
|
||||
if parsed.is_directory then path = path .. "/" end
|
||||
end
|
||||
else
|
||||
for i = 1, n-1 do
|
||||
path = path .. protect_segment(parsed[i])
|
||||
path = path .. "/"
|
||||
end
|
||||
if n > 0 then
|
||||
path = path .. protect_segment(parsed[n])
|
||||
if parsed.is_directory then path = path .. "/" end
|
||||
end
|
||||
end
|
||||
if parsed.is_absolute then path = "/" .. path end
|
||||
return path
|
||||
end
|
||||
-----------------------------------------------------------------------------
|
||||
-- URI parsing, composition and relative URL resolution
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id: url.lua 1418 2006-04-25 09:38:15Z 3rdparty $
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module
|
||||
-----------------------------------------------------------------------------
|
||||
local string = require("string")
|
||||
local base = _G
|
||||
local table = require("table")
|
||||
module("socket.url")
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Module version
|
||||
-----------------------------------------------------------------------------
|
||||
_VERSION = "URL 1.0"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Encodes a string into its escaped hexadecimal representation
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
function escape(s)
|
||||
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
|
||||
return string.format("%%%02x", string.byte(c))
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Protects a path segment, to prevent it from interfering with the
|
||||
-- url parsing.
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
local function make_set(t)
|
||||
local s = {}
|
||||
for i,v in base.ipairs(t) do
|
||||
s[t[i]] = 1
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
-- these are allowed withing a path segment, along with alphanum
|
||||
-- other characters must be escaped
|
||||
local segment_set = make_set {
|
||||
"-", "_", ".", "!", "~", "*", "'", "(",
|
||||
")", ":", "@", "&", "=", "+", "$", ",",
|
||||
}
|
||||
|
||||
local function protect_segment(s)
|
||||
return string.gsub(s, "([^A-Za-z0-9_])", function (c)
|
||||
if segment_set[c] then return c
|
||||
else return string.format("%%%02x", string.byte(c)) end
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Encodes a string into its escaped hexadecimal representation
|
||||
-- Input
|
||||
-- s: binary string to be encoded
|
||||
-- Returns
|
||||
-- escaped representation of string binary
|
||||
-----------------------------------------------------------------------------
|
||||
function unescape(s)
|
||||
return string.gsub(s, "%%(%x%x)", function(hex)
|
||||
return string.char(base.tonumber(hex, 16))
|
||||
end)
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a path from a base path and a relative path
|
||||
-- Input
|
||||
-- base_path
|
||||
-- relative_path
|
||||
-- Returns
|
||||
-- corresponding absolute path
|
||||
-----------------------------------------------------------------------------
|
||||
local function absolute_path(base_path, relative_path)
|
||||
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
|
||||
local path = string.gsub(base_path, "[^/]*$", "")
|
||||
path = path .. relative_path
|
||||
path = string.gsub(path, "([^/]*%./)", function (s)
|
||||
if s ~= "./" then return s else return "" end
|
||||
end)
|
||||
path = string.gsub(path, "/%.$", "/")
|
||||
local reduced
|
||||
while reduced ~= path do
|
||||
reduced = path
|
||||
path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
|
||||
if s ~= "../../" then return "" else return s end
|
||||
end)
|
||||
end
|
||||
path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
|
||||
if s ~= "../.." then return "" else return s end
|
||||
end)
|
||||
return path
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Parses a url and returns a table with all its parts according to RFC 2396
|
||||
-- The following grammar describes the names given to the URL parts
|
||||
-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
|
||||
-- <authority> ::= <userinfo>@<host>:<port>
|
||||
-- <userinfo> ::= <user>[:<password>]
|
||||
-- <path> :: = {<segment>/}<segment>
|
||||
-- Input
|
||||
-- url: uniform resource locator of request
|
||||
-- default: table with default values for each field
|
||||
-- Returns
|
||||
-- table with the following fields, where RFC naming conventions have
|
||||
-- been preserved:
|
||||
-- scheme, authority, userinfo, user, password, host, port,
|
||||
-- path, params, query, fragment
|
||||
-- Obs:
|
||||
-- the leading '/' in {/<path>} is considered part of <path>
|
||||
-----------------------------------------------------------------------------
|
||||
function parse(url, default)
|
||||
-- initialize default parameters
|
||||
local parsed = {}
|
||||
for i,v in base.pairs(default or parsed) do parsed[i] = v end
|
||||
-- empty url is parsed to nil
|
||||
if not url or url == "" then return nil, "invalid url" end
|
||||
-- remove whitespace
|
||||
-- url = string.gsub(url, "%s", "")
|
||||
-- get fragment
|
||||
url = string.gsub(url, "#(.*)$", function(f)
|
||||
parsed.fragment = f
|
||||
return ""
|
||||
end)
|
||||
-- get scheme
|
||||
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
|
||||
function(s) parsed.scheme = s; return "" end)
|
||||
-- get authority
|
||||
url = string.gsub(url, "^//([^/]*)", function(n)
|
||||
parsed.authority = n
|
||||
return ""
|
||||
end)
|
||||
-- get query stringing
|
||||
url = string.gsub(url, "%?(.*)", function(q)
|
||||
parsed.query = q
|
||||
return ""
|
||||
end)
|
||||
-- get params
|
||||
url = string.gsub(url, "%;(.*)", function(p)
|
||||
parsed.params = p
|
||||
return ""
|
||||
end)
|
||||
-- path is whatever was left
|
||||
if url ~= "" then parsed.path = url end
|
||||
local authority = parsed.authority
|
||||
if not authority then return parsed end
|
||||
authority = string.gsub(authority,"^([^@]*)@",
|
||||
function(u) parsed.userinfo = u; return "" end)
|
||||
authority = string.gsub(authority, ":([^:]*)$",
|
||||
function(p) parsed.port = p; return "" end)
|
||||
if authority ~= "" then parsed.host = authority end
|
||||
local userinfo = parsed.userinfo
|
||||
if not userinfo then return parsed end
|
||||
userinfo = string.gsub(userinfo, ":([^:]*)$",
|
||||
function(p) parsed.password = p; return "" end)
|
||||
parsed.user = userinfo
|
||||
return parsed
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Rebuilds a parsed URL from its components.
|
||||
-- Components are protected if any reserved or unallowed characters are found
|
||||
-- Input
|
||||
-- parsed: parsed URL, as returned by parse
|
||||
-- Returns
|
||||
-- a stringing with the corresponding URL
|
||||
-----------------------------------------------------------------------------
|
||||
function build(parsed)
|
||||
local ppath = parse_path(parsed.path or "")
|
||||
local url = build_path(ppath)
|
||||
if parsed.params then url = url .. ";" .. parsed.params end
|
||||
if parsed.query then url = url .. "?" .. parsed.query end
|
||||
local authority = parsed.authority
|
||||
if parsed.host then
|
||||
authority = parsed.host
|
||||
if parsed.port then authority = authority .. ":" .. parsed.port end
|
||||
local userinfo = parsed.userinfo
|
||||
if parsed.user then
|
||||
userinfo = parsed.user
|
||||
if parsed.password then
|
||||
userinfo = userinfo .. ":" .. parsed.password
|
||||
end
|
||||
end
|
||||
if userinfo then authority = userinfo .. "@" .. authority end
|
||||
end
|
||||
if authority then url = "//" .. authority .. url end
|
||||
if parsed.scheme then url = parsed.scheme .. ":" .. url end
|
||||
if parsed.fragment then url = url .. "#" .. parsed.fragment end
|
||||
-- url = string.gsub(url, "%s", "")
|
||||
return url
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a absolute URL from a base and a relative URL according to RFC 2396
|
||||
-- Input
|
||||
-- base_url
|
||||
-- relative_url
|
||||
-- Returns
|
||||
-- corresponding absolute url
|
||||
-----------------------------------------------------------------------------
|
||||
function absolute(base_url, relative_url)
|
||||
if base.type(base_url) == "table" then
|
||||
base_parsed = base_url
|
||||
base_url = build(base_parsed)
|
||||
else
|
||||
base_parsed = parse(base_url)
|
||||
end
|
||||
local relative_parsed = parse(relative_url)
|
||||
if not base_parsed then return relative_url
|
||||
elseif not relative_parsed then return base_url
|
||||
elseif relative_parsed.scheme then return relative_url
|
||||
else
|
||||
relative_parsed.scheme = base_parsed.scheme
|
||||
if not relative_parsed.authority then
|
||||
relative_parsed.authority = base_parsed.authority
|
||||
if not relative_parsed.path then
|
||||
relative_parsed.path = base_parsed.path
|
||||
if not relative_parsed.params then
|
||||
relative_parsed.params = base_parsed.params
|
||||
if not relative_parsed.query then
|
||||
relative_parsed.query = base_parsed.query
|
||||
end
|
||||
end
|
||||
else
|
||||
relative_parsed.path = absolute_path(base_parsed.path or "",
|
||||
relative_parsed.path)
|
||||
end
|
||||
end
|
||||
return build(relative_parsed)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Breaks a path into its segments, unescaping the segments
|
||||
-- Input
|
||||
-- path
|
||||
-- Returns
|
||||
-- segment: a table with one entry per segment
|
||||
-----------------------------------------------------------------------------
|
||||
function parse_path(path)
|
||||
local parsed = {}
|
||||
path = path or ""
|
||||
--path = string.gsub(path, "%s", "")
|
||||
string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
|
||||
for i = 1, table.getn(parsed) do
|
||||
parsed[i] = unescape(parsed[i])
|
||||
end
|
||||
if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
|
||||
if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
|
||||
return parsed
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Builds a path component from its segments, escaping protected characters.
|
||||
-- Input
|
||||
-- parsed: path segments
|
||||
-- unsafe: if true, segments are not protected before path is built
|
||||
-- Returns
|
||||
-- path: corresponding path stringing
|
||||
-----------------------------------------------------------------------------
|
||||
function build_path(parsed, unsafe)
|
||||
local path = ""
|
||||
local n = table.getn(parsed)
|
||||
if unsafe then
|
||||
for i = 1, n-1 do
|
||||
path = path .. parsed[i]
|
||||
path = path .. "/"
|
||||
end
|
||||
if n > 0 then
|
||||
path = path .. parsed[n]
|
||||
if parsed.is_directory then path = path .. "/" end
|
||||
end
|
||||
else
|
||||
for i = 1, n-1 do
|
||||
path = path .. protect_segment(parsed[i])
|
||||
path = path .. "/"
|
||||
end
|
||||
if n > 0 then
|
||||
path = path .. protect_segment(parsed[n])
|
||||
if parsed.is_directory then path = path .. "/" end
|
||||
end
|
||||
end
|
||||
if parsed.is_absolute then path = "/" .. path end
|
||||
return path
|
||||
end
|
||||
93
lualibs/ssl.lua
Normal file
93
lualibs/ssl.lua
Normal file
@@ -0,0 +1,93 @@
|
||||
------------------------------------------------------------------------------
|
||||
-- LuaSec 0.4.1
|
||||
-- Copyright (C) 2006-2011 Bruno Silvestre
|
||||
--
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
module("ssl", package.seeall)
|
||||
|
||||
require("ssl.core")
|
||||
require("ssl.context")
|
||||
|
||||
|
||||
_VERSION = "0.4.1"
|
||||
_COPYRIGHT = "LuaSec 0.4.1 - Copyright (C) 2006-2011 Bruno Silvestre\n" ..
|
||||
"LuaSocket 2.0.2 - Copyright (C) 2004-2007 Diego Nehab"
|
||||
|
||||
-- Export functions
|
||||
rawconnection = core.rawconnection
|
||||
rawcontext = context.rawcontext
|
||||
|
||||
--
|
||||
--
|
||||
--
|
||||
local function optexec(func, param, ctx)
|
||||
if param then
|
||||
if type(param) == "table" then
|
||||
return func(ctx, unpack(param))
|
||||
else
|
||||
return func(ctx, param)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
--
|
||||
--
|
||||
function newcontext(cfg)
|
||||
local succ, msg, ctx
|
||||
-- Create the context
|
||||
ctx, msg = context.create(cfg.protocol)
|
||||
if not ctx then return nil, msg end
|
||||
-- Mode
|
||||
succ, msg = context.setmode(ctx, cfg.mode)
|
||||
if not succ then return nil, msg end
|
||||
-- Load the key
|
||||
if cfg.key then
|
||||
succ, msg = context.loadkey(ctx, cfg.key, cfg.password)
|
||||
if not succ then return nil, msg end
|
||||
end
|
||||
-- Load the certificate
|
||||
if cfg.certificate then
|
||||
succ, msg = context.loadcert(ctx, cfg.certificate)
|
||||
if not succ then return nil, msg end
|
||||
end
|
||||
-- Load the CA certificates
|
||||
if cfg.cafile or cfg.capath then
|
||||
succ, msg = context.locations(ctx, cfg.cafile, cfg.capath)
|
||||
if not succ then return nil, msg end
|
||||
end
|
||||
-- Set the verification options
|
||||
succ, msg = optexec(context.setverify, cfg.verify, ctx)
|
||||
if not succ then return nil, msg end
|
||||
-- Set SSL options
|
||||
succ, msg = optexec(context.setoptions, cfg.options, ctx)
|
||||
if not succ then return nil, msg end
|
||||
-- Set the depth for certificate verification
|
||||
if cfg.depth then
|
||||
succ, msg = context.setdepth(ctx, cfg.depth)
|
||||
if not succ then return nil, msg end
|
||||
end
|
||||
return ctx
|
||||
end
|
||||
|
||||
--
|
||||
--
|
||||
--
|
||||
function wrap(sock, cfg)
|
||||
local ctx, msg
|
||||
if type(cfg) == "table" then
|
||||
ctx, msg = newcontext(cfg)
|
||||
if not ctx then return nil, msg end
|
||||
else
|
||||
ctx = cfg
|
||||
end
|
||||
local s, msg = core.create(ctx)
|
||||
if s then
|
||||
core.setfd(s, sock:getfd())
|
||||
sock:setfd(core.invalidfd)
|
||||
return s
|
||||
end
|
||||
return nil, msg
|
||||
end
|
||||
138
lualibs/ssl/https.lua
Normal file
138
lualibs/ssl/https.lua
Normal file
@@ -0,0 +1,138 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- LuaSec 0.4.1
|
||||
-- Copyright (C) 2009-2011 PUC-Rio
|
||||
--
|
||||
-- Author: Pablo Musa
|
||||
-- Author: Tomas Guisasola
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local socket = require("socket")
|
||||
local ssl = require("ssl")
|
||||
local ltn12 = require("ltn12")
|
||||
local http = require("socket.http")
|
||||
local url = require("socket.url")
|
||||
|
||||
local table = require("table")
|
||||
local string = require("string")
|
||||
|
||||
local try = socket.try
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local getmetatable = getmetatable
|
||||
|
||||
module("ssl.https")
|
||||
|
||||
_VERSION = "0.4.1"
|
||||
_COPYRIGHT = "LuaSec 0.4.1 - Copyright (C) 2009-2011 PUC-Rio"
|
||||
|
||||
-- Default settings
|
||||
PORT = 443
|
||||
|
||||
local cfg = {
|
||||
protocol = "tlsv1",
|
||||
options = "all",
|
||||
verify = "none",
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- Auxiliar Functions
|
||||
--------------------------------------------------------------------
|
||||
|
||||
-- Insert default HTTPS port.
|
||||
local function default_https_port(u)
|
||||
return url.build(url.parse(u, {port = PORT}))
|
||||
end
|
||||
|
||||
-- Convert an URL to a table according to Luasocket needs.
|
||||
local function urlstring_totable(url, body, result_table)
|
||||
url = {
|
||||
url = default_https_port(url),
|
||||
method = body and "POST" or "GET",
|
||||
sink = ltn12.sink.table(result_table)
|
||||
}
|
||||
if body then
|
||||
url.source = ltn12.source.string(body)
|
||||
url.headers = {
|
||||
["content-length"] = #body,
|
||||
["content-type"] = "application/x-www-form-urlencoded",
|
||||
}
|
||||
end
|
||||
return url
|
||||
end
|
||||
|
||||
-- Forward calls to the real connection object.
|
||||
local function reg(conn)
|
||||
local mt = getmetatable(conn.sock).__index
|
||||
for name, method in pairs(mt) do
|
||||
if type(method) == "function" then
|
||||
conn[name] = function (self, ...)
|
||||
return method(self.sock, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Return a function which performs the SSL/TLS connection.
|
||||
local function tcp(params)
|
||||
params = params or {}
|
||||
-- Default settings
|
||||
for k, v in pairs(cfg) do
|
||||
params[k] = params[k] or v
|
||||
end
|
||||
-- Force client mode
|
||||
params.mode = "client"
|
||||
-- 'create' function for LuaSocket
|
||||
return function ()
|
||||
local conn = {}
|
||||
conn.sock = try(socket.tcp())
|
||||
local st = getmetatable(conn.sock).__index.settimeout
|
||||
function conn:settimeout(...)
|
||||
return st(self.sock, ...)
|
||||
end
|
||||
-- Replace TCP's connection function
|
||||
function conn:connect(host, port)
|
||||
try(self.sock:connect(host, port))
|
||||
self.sock = try(ssl.wrap(self.sock, params))
|
||||
try(self.sock:dohandshake())
|
||||
reg(self, getmetatable(self.sock))
|
||||
return 1
|
||||
end
|
||||
return conn
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- Main Function
|
||||
--------------------------------------------------------------------
|
||||
|
||||
-- Make a HTTP request over secure connection. This function receives
|
||||
-- the same parameters of LuaSocket's HTTP module (except 'proxy' and
|
||||
-- 'redirect') plus LuaSec parameters.
|
||||
--
|
||||
-- @param url mandatory (string or table)
|
||||
-- @param body optional (string)
|
||||
-- @return (string if url == string or 1), code, headers, status
|
||||
--
|
||||
function request(url, body)
|
||||
local result_table = {}
|
||||
local stringrequest = type(url) == "string"
|
||||
if stringrequest then
|
||||
url = urlstring_totable(url, body, result_table)
|
||||
else
|
||||
url.url = default_https_port(url.url)
|
||||
end
|
||||
if http.PROXY or url.proxy then
|
||||
return nil, "proxy not supported"
|
||||
elseif url.redirect then
|
||||
return nil, "redirect not supported"
|
||||
elseif url.create then
|
||||
return nil, "create function not permitted"
|
||||
end
|
||||
-- New 'create' function to establish a secure connection
|
||||
url.create = tcp(url)
|
||||
local res, code, headers, status = http.request(url)
|
||||
if res and stringrequest then
|
||||
return table.concat(result_table), code, headers, status
|
||||
end
|
||||
return res, code, headers, status
|
||||
end
|
||||
211
spec/cg.lua
211
spec/cg.lua
@@ -1,106 +1,105 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"cg","cgh","fx","fxh","cgfx","cgfxh",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "cg",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
|
||||
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
|
||||
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
|
||||
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
|
||||
int4 bool bool2 bool3 bool4 string struct typedef
|
||||
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY isampler
|
||||
isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY sampler sampler1D
|
||||
sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY texture texture1D texture2D
|
||||
texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY decl do double else
|
||||
usamplerBUF isamplerBUF samplerBUF samplerRBUF sampler2DMS sampler2DMSARRAY usamplerRBUF usampler2DMS usampler2DMSARRAY
|
||||
isamplerRBUF isampler2DMS isampler2DMSARRAY
|
||||
extern false for if in inline inout out pass pixelshader
|
||||
return shared static string technique true uniform vector vertexshader void
|
||||
volatile while asm compile const auto break case catch
|
||||
char class const_cast continue default delete dynamic_cast enum explicit friend
|
||||
goto long mutable namespace new operator private protected public register
|
||||
reinterpret_case short signed sizeof static_cast switch template this throw try
|
||||
typename union unsigned using virtual ]],
|
||||
|
||||
[[abs acos all any asin atan atan2 ceil clamp clip
|
||||
cos cosh cross ddx ddy degrees determinant distance dot exp
|
||||
exp2 faceforward floatToIntBits floatToRawIntBits floor fmod frac frexp fwidth intBitsToFloat
|
||||
isfinite isinf isnan ldexp length lerp lit log log10 log2
|
||||
max min mul normalize pow radians reflect refract round rsqrt
|
||||
saturate sign sin sincos sinh sqrt step tan tanh tex1D
|
||||
tex1DARRAY tex1DARRAYbias tex1DARRAYcmpbias tex1DARRAYcmplod tex1DARRAYfetch tex1DARRAYlod tex1DARRAYproj tex1DARRAYsize tex1Dbias tex1Dcmpbias
|
||||
tex1Dcmplod tex1Dfetch tex1Dlod tex1Dproj tex1Dsize tex2D tex2DARRAY tex2DARRAYbias tex2DARRAYfetch tex2DARRAYlod
|
||||
tex2DARRAYproj tex2DARRAYsize tex2Dbias tex2Dcmpbias tex2Dcmplod tex2Dfetch tex2Dlod tex2Dproj tex2Dsize tex3D
|
||||
tex3Dbias tex3Dfetch tex3Dlod tex3Dproj tex3Dsize texBUF texBUFsize texCUBE texCUBEARRAY texCUBEARRAYsize
|
||||
texCUBEbias texCUBElod texCUBEproj texCUBEsize texRECT texRECTbias texRECTfetch texRECTlod texRECTproj texRECTsize
|
||||
texBUF texBUFsize texRBUF texRBUFsize tex2DMS tex2DMSARRAY tex2DMSsize tex2DMSARRAYsize
|
||||
unpack_4ubyte pack_4ubyte unpack_4byte pack_4byte unpack_2ushort pack_2ushort
|
||||
unpack_2half pack_2half
|
||||
|
||||
transpose trunc POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG FOGP COLOR WPOS
|
||||
COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5
|
||||
TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14 TEXCOORD15
|
||||
NORMAL FACE PRIMITIVEID DEPTH ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5
|
||||
ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
|
||||
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9
|
||||
TEXUNIT10 TEXUNIT11 TEXUNIT12 TEXUNIT13 TEXUNIT14 TEXUNIT15 LAYER INSTANCEID
|
||||
|
||||
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
|
||||
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
|
||||
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
|
||||
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
|
||||
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
|
||||
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
|
||||
VIEWPORTSIZE VIEWPORTDIMENSION
|
||||
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
|
||||
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
|
||||
|
||||
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
|
||||
]],
|
||||
|
||||
},
|
||||
}
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"cg","cgh","fx","fxh","cgfx","cgfxh",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "cg",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int half float float3 float4 float2 float3x3 float3x4 float4x3 float4x4
|
||||
float1x2 float2x1 float2x2 float2x3 float3x2 float1x3 float3x1 float4x1 float1x4
|
||||
float2x4 float4x2 double1x4 double4x4 double4x2 double4x3 double3x4 double2x4 double1x4
|
||||
double half half2 half3 half4 int2 int3 uint uint2 uint3 uint4
|
||||
int4 bool bool2 bool3 bool4 string struct typedef
|
||||
usampler usampler1D usampler2D usampler3D usamplerRECT usamplerCUBE isampler1DARRAY usampler2DARRAY usamplerCUBEARRAY isampler
|
||||
isampler1D isampler2D isampler3D isamplerRECT isamplerCUBE isampler1DARRAY isampler2DARRAY isamplerCUBEARRAY sampler sampler1D
|
||||
sampler2D sampler3D samplerRECT samplerCUBE sampler1DARRAY sampler2DARRAY samplerCUBEARRAY texture texture1D texture2D
|
||||
texture3D textureRECT textureCUBE texture1DARRAY texture2DARRAY textureCUBEARRAY decl do double else
|
||||
usamplerBUF isamplerBUF samplerBUF samplerRBUF sampler2DMS sampler2DMSARRAY usamplerRBUF usampler2DMS usampler2DMSARRAY
|
||||
isamplerRBUF isampler2DMS isampler2DMSARRAY
|
||||
extern false for if in inline inout out pass pixelshader
|
||||
return shared static string technique true uniform vector vertexshader void
|
||||
volatile while asm compile const auto break case catch
|
||||
char class const_cast continue default delete dynamic_cast enum explicit friend
|
||||
goto long mutable namespace new operator private protected public register
|
||||
reinterpret_case short signed sizeof static_cast switch template this throw try
|
||||
typename union unsigned using virtual ]],
|
||||
|
||||
[[abs acos all any asin atan atan2 ceil clamp clip
|
||||
cos cosh cross ddx ddy degrees determinant distance dot exp
|
||||
exp2 faceforward floatToIntBits floatToRawIntBits floor fmod frac frexp fwidth intBitsToFloat
|
||||
isfinite isinf isnan ldexp length lerp lit log log10 log2
|
||||
max min mul normalize pow radians reflect refract round rsqrt
|
||||
saturate sign sin sincos sinh sqrt step tan tanh tex1D
|
||||
tex1DARRAY tex1DARRAYbias tex1DARRAYcmpbias tex1DARRAYcmplod tex1DARRAYfetch tex1DARRAYlod tex1DARRAYproj tex1DARRAYsize tex1Dbias tex1Dcmpbias
|
||||
tex1Dcmplod tex1Dfetch tex1Dlod tex1Dproj tex1Dsize tex2D tex2DARRAY tex2DARRAYbias tex2DARRAYfetch tex2DARRAYlod
|
||||
tex2DARRAYproj tex2DARRAYsize tex2Dbias tex2Dcmpbias tex2Dcmplod tex2Dfetch tex2Dlod tex2Dproj tex2Dsize tex3D
|
||||
tex3Dbias tex3Dfetch tex3Dlod tex3Dproj tex3Dsize texBUF texBUFsize texCUBE texCUBEARRAY texCUBEARRAYsize
|
||||
texCUBEbias texCUBElod texCUBEproj texCUBEsize texRECT texRECTbias texRECTfetch texRECTlod texRECTproj texRECTsize
|
||||
texBUF texBUFsize texRBUF texRBUFsize tex2DMS tex2DMSARRAY tex2DMSsize tex2DMSARRAYsize
|
||||
unpack_4ubyte pack_4ubyte unpack_4byte pack_4byte unpack_2ushort pack_2ushort
|
||||
unpack_2half pack_2half
|
||||
|
||||
transpose trunc POSITION PSIZE DIFFUSE SPECULAR TEXCOORD FOG FOGP COLOR WPOS
|
||||
COLOR0 COLOR1 COLOR2 COLOR3 TEXCOORD0 TEXCOORD1 TEXCOORD2 TEXCOORD3 TEXCOORD4 TEXCOORD5
|
||||
TEXCOORD6 TEXCOORD7 TEXCOORD8 TEXCOORD9 TEXCOORD10 TEXCOORD11 TEXCOORD12 TEXCOORD13 TEXCOORD14 TEXCOORD15
|
||||
NORMAL FACE PRIMITIVEID DEPTH ATTR0 ATTR1 ATTR2 ATTR3 ATTR4 ATTR5
|
||||
ATTR6 ATTR7 ATTR8 ATTR9 ATTR10 ATTR11 ATTR12 ATTR13 ATTR14 ATTR15
|
||||
TEXUNIT0 TEXUNIT1 TEXUNIT2 TEXUNIT3 TEXUNIT4 TEXUNIT5 TEXUNIT6 TEXUNIT7 TEXUNIT8 TEXUNIT9
|
||||
TEXUNIT10 TEXUNIT11 TEXUNIT12 TEXUNIT13 TEXUNIT14 TEXUNIT15 LAYER INSTANCEID
|
||||
|
||||
PROJ PROJECTION PROJECTIONMATRIX PROJMATRIX
|
||||
PROJMATRIXINV PROJINV PROJECTIONINV PROJINVERSE PROJECTIONINVERSE PROJINVMATRIX PROJECTIONINVMATRIX PROJINVERSEMATRIX PROJECTIONINVERSEMATRIX
|
||||
VIEW VIEWMATRIX VIEWMATRIXINV VIEWINV VIEWINVERSE VIEWINVERSEMATRIX VIEWINVMATRIX
|
||||
VIEWPROJECTION VIEWPROJ VIEWPROJMATRIX VIEWPROJECTIONMATRIX
|
||||
WORLD WORLDMATRIX WORLDVIEW WORLDVIEWMATRIX
|
||||
WORLDVIEWPROJ WORLDVIEWPROJECTION WORLDVIEWPROJMATRIX WORLDVIEWPROJECTIONMATRIX
|
||||
VIEWPORTSIZE VIEWPORTDIMENSION
|
||||
VIEWPORTSIZEINV VIEWPORTSIZEINVERSE VIEWPORTDIMENSIONINV VIEWPORTDIMENSIONINVERSE INVERSEVIEWPORTDIMENSIONS
|
||||
FOGCOLOR FOGDISTANCE CAMERAWORLDPOS CAMERAWORLDDIR
|
||||
|
||||
CENTROID FLAT NOPERSPECTIVE FACE PRIMITIVEID VERTEXID
|
||||
]],
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
335
spec/glsl.lua
335
spec/glsl.lua
@@ -2,173 +2,172 @@
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"glsl","vert","frag","geom","cont","eval", "glslv", "glslf"},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "glsl",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int uint half float bool double
|
||||
vec2 vec3 vec4 dvec2 dvec3 dvec4
|
||||
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
|
||||
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
|
||||
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
|
||||
struct typedef void
|
||||
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
|
||||
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
|
||||
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
|
||||
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
|
||||
usamplerBuffer isamplerBuffer samplerBuffer samplerRenderbuffer isamplerRenderbuffer usamplerRenderbuffer
|
||||
in out inout uniform const centroid sample attribute varying patch index true false
|
||||
return switch case for do while if else break continue main inline
|
||||
layout location vertices line_strip triangle_strip max_vertices stream
|
||||
triangles quads equal_spacing isolines fractional_even_spacing lines points
|
||||
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
|
||||
invocations
|
||||
origin_upper_left pixel_center_integer
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
|
||||
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
|
||||
subroutine gl_Position gl_FragCoord
|
||||
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
|
||||
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
|
||||
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
|
||||
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
|
||||
gl_PatchVerticesIn
|
||||
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
|
||||
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
|
||||
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
|
||||
gl_FragData gl_FragDepth gl_SampleMask
|
||||
|
||||
coherent volatile restrict
|
||||
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
|
||||
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
|
||||
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
|
||||
size1x8 size1x16 size1x32 size2x32 size4x32
|
||||
]],
|
||||
exts = {"glsl","vert","frag","geom","cont","eval", "glslv", "glslf"},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "glsl",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
[[discard
|
||||
radians degrees sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh
|
||||
pow exp log exp2 log2 sqrt inversesqrt abs sign floor trunc round
|
||||
roundEven ceil fract mod modf min max mix step isnan isinf clamp smoothstep
|
||||
floatBitsToInt intBitsToFloat uintBitsToFloat fma frexp ldexp
|
||||
packUnorm2x16 packUnorm4x8 packSnorm4x8
|
||||
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
|
||||
packDouble2x32 unpackDouble2x32
|
||||
length distance dot cross normalize ftransform faceforward
|
||||
reflect refract
|
||||
matrixCompMult outerProduct transpose determinant inverse
|
||||
lessThan lessThanEqual greaterThan greaterThanEqual equal
|
||||
notEqual any all not
|
||||
uaddCarry usubBorrow umulExtended imulExtended
|
||||
bitfeldExtract bitfieldInsert bitfeldReverse bitCount
|
||||
findLSB findMSB
|
||||
dFdx dFdy fwidth
|
||||
interpolateAtCentroid interpolateAtSample interpolateAtOffset
|
||||
noise1 noise2 noise3 noise4
|
||||
EmitStreamVertex EndStreamPrimitive EmitVertex EndPrimitive
|
||||
barrier
|
||||
textureSize textureQueryLod texture textureOffset textureProj
|
||||
textureLod textureProjOffset textureLodOffset
|
||||
texelFetchOffset texelFetch textureProjLod textureProjLodOffset
|
||||
textureGrad textureGradOffset textureProjGrad textureProjGradOffset
|
||||
textureGather textureGatherOffset
|
||||
texture2D texture1D texture3D textureCube texture2DRect
|
||||
texture1DProj texture1DLod texture1DProjLod
|
||||
texture2DProj texture2DLod texture2DProjLod
|
||||
texture3DProj texture3DLod texture3DProjLod
|
||||
textureCubeLod
|
||||
shadow1D shadow2D
|
||||
shadow1DProj shadow1DLod shadow1DProjLod
|
||||
shadow2DProj shadow2DLod shadow2DProjLod
|
||||
texelFetch1D texelFetch2D texelFetch3D texelFetch2DRect texelFetch1DArray texelFetch2DArray texelFetchBuffer
|
||||
textureSizeBuffer textureSize1D textureSize2D textureSize3D textureSizeCube textureSize2DRect
|
||||
textureSize1DArray textureSize2DArray
|
||||
texture1DArray texture1DArrayLod
|
||||
texture2DArray texture2DArrayLod
|
||||
shadow1DArray shadow1DArrayLod shadow2DArray shadowCube
|
||||
texture1DGrad texture1DProjGrad texture1DProjGrad texture1DArrayGrad
|
||||
texture2DGrad texture2DProjGrad texture2DProjGrad texture2DArrayGrad
|
||||
texture3DGrad texture3DProjGrad textureCubeGrad
|
||||
shadow1DGrad shadow1DProjGrad shadow1DArrayGrad shadow2DGrad shadow2DProjGrad shadow2DArrayGrad
|
||||
texture2DRectGrad texture2DRectProjGrad texture2DRectProjGrad shadow2DRectGrad shadow2DRectProjGrad
|
||||
shadowCubeGrad
|
||||
texture1DOffset texture1DProjOffset texture1DLodOffset texture1DProjLodOffset
|
||||
texture2DOffset texture2DProjOffset texture2DLodOffset texture2DProjLodOffset
|
||||
texture3DOffset texture3DProjOffset texture3DLodOffset texture3DProjLodOffset
|
||||
|
||||
imageLoad imageStore
|
||||
imageAtomicAdd imageAtomicMin imageAtomicMax
|
||||
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
|
||||
imageAtomicOr imageAtomixXor imageAtomicExchange
|
||||
imageCompSwap memoryBarrier
|
||||
|
||||
x y z w
|
||||
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
|
||||
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
|
||||
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
|
||||
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
|
||||
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
|
||||
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
|
||||
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
|
||||
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
|
||||
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
|
||||
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
|
||||
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
|
||||
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
|
||||
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
|
||||
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
|
||||
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
|
||||
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
|
||||
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
|
||||
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
|
||||
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
|
||||
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
|
||||
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
|
||||
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
|
||||
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
|
||||
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
|
||||
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
|
||||
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
|
||||
xw yw xyw zw xzw yzw xyzw ]],
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
},
|
||||
}
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int uint half float bool double
|
||||
vec2 vec3 vec4 dvec2 dvec3 dvec4
|
||||
ivec2 ivec3 ivec4 uvec2 uvec3 uvec4 bvec2 bvec3 bvec4
|
||||
mat2 mat3 mat4 mat2x2 mat3x3 mat4x4 mat2x3 mat3x2 mat4x2 mat2x4 mat4x3 mat3x4
|
||||
dmat2 dmat3 dmat4 dmat2x2 dmat3x3 dmat4x4 dmat2x3 dmat3x2 dmat4x2 dmat2x4 dmat4x3 dmat3x4
|
||||
struct typedef void
|
||||
usampler1D usampler2D usampler3D usampler2DRect usamplerCube isampler1DArray usampler2DARRAY usamplerCubeArray usampler2DMS usampler2DMSArray
|
||||
isampler1D isampler2D isampler3D isampler2DRect isamplerCube isampler1DArray isampler2DARRAY isamplerCubeArray isampler2DMS isampler2DMSArray
|
||||
sampler1D sampler2D sampler3D sampler2DRect samplerCube sampler1DArray sampler2DArray samplerCubeArray sampler2DMS sampler2DMSArray
|
||||
sampler1DShadow sampler2DShadow sampler2DRectShadow sampler1DArrayShadow sampler2DArrayShadow samplerCubeArrayShadow
|
||||
usamplerBuffer isamplerBuffer samplerBuffer samplerRenderbuffer isamplerRenderbuffer usamplerRenderbuffer
|
||||
in out inout uniform const centroid sample attribute varying patch index true false
|
||||
return switch case for do while if else break continue main inline
|
||||
layout location vertices line_strip triangle_strip max_vertices stream
|
||||
triangles quads equal_spacing isolines fractional_even_spacing lines points
|
||||
fractional_odd_spacing cw ccw point_mode lines_adjacency triangles_adjacency
|
||||
invocations
|
||||
origin_upper_left pixel_center_integer
|
||||
smooth flat noperspective highp mediump lowp shared packed std140 row_major column_major
|
||||
gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_Color gl_SecondaryColor
|
||||
subroutine gl_Position gl_FragCoord
|
||||
gl_VertexID gl_InstanceID gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1
|
||||
gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6
|
||||
gl_MultiTexCoord7 gl_FogCoord gl_PointSize gl_ClipDistance
|
||||
gl_TexCoord gl_FogFragCoord gl_ClipVertex gl_in
|
||||
gl_PatchVerticesIn
|
||||
gl_PrimitiveID gl_InvocationID gl_TessLevelOuter gl_TessLevelInner gl_TessCoord
|
||||
gl_InvocationID gl_PrimitiveIDIn gl_Layer gl_ViewportIndex gl_FrontFacing
|
||||
gl_PointCoord gl_SampleID gl_SamplePosition gl_FragColor
|
||||
gl_FragData gl_FragDepth gl_SampleMask
|
||||
|
||||
coherent volatile restrict
|
||||
image1D image2D image3D image2DRect imageCube imageBuffer image1DArray image2DArray imageCubeArray image2DMS image2DMSArray
|
||||
uimage1D uimage2D uimage3D uimage2DRect uimageCube uimageBuffer uimage1DArray uimage2DArray uimageCubeArray uimage2DMS uimage2DMSArray
|
||||
iimage1D iimage2D iimage3D iimage2DRect iimageCube iimageBuffer iimage1DArray iimage2DArray iimageCubeArray iimage2DMS iimage2DMSArray
|
||||
size1x8 size1x16 size1x32 size2x32 size4x32
|
||||
]],
|
||||
|
||||
[[discard
|
||||
radians degrees sin cos tan asin acos atan sinh cosh tanh asinh acosh atanh
|
||||
pow exp log exp2 log2 sqrt inversesqrt abs sign floor trunc round
|
||||
roundEven ceil fract mod modf min max mix step isnan isinf clamp smoothstep
|
||||
floatBitsToInt intBitsToFloat uintBitsToFloat fma frexp ldexp
|
||||
packUnorm2x16 packUnorm4x8 packSnorm4x8
|
||||
unpackUnorm2x16 unpackUnorm4x8 unpackSnorm4x8
|
||||
packDouble2x32 unpackDouble2x32
|
||||
length distance dot cross normalize ftransform faceforward
|
||||
reflect refract
|
||||
matrixCompMult outerProduct transpose determinant inverse
|
||||
lessThan lessThanEqual greaterThan greaterThanEqual equal
|
||||
notEqual any all not
|
||||
uaddCarry usubBorrow umulExtended imulExtended
|
||||
bitfeldExtract bitfieldInsert bitfeldReverse bitCount
|
||||
findLSB findMSB
|
||||
dFdx dFdy fwidth
|
||||
interpolateAtCentroid interpolateAtSample interpolateAtOffset
|
||||
noise1 noise2 noise3 noise4
|
||||
EmitStreamVertex EndStreamPrimitive EmitVertex EndPrimitive
|
||||
barrier
|
||||
textureSize textureQueryLod texture textureOffset textureProj
|
||||
textureLod textureProjOffset textureLodOffset
|
||||
texelFetchOffset texelFetch textureProjLod textureProjLodOffset
|
||||
textureGrad textureGradOffset textureProjGrad textureProjGradOffset
|
||||
textureGather textureGatherOffset
|
||||
texture2D texture1D texture3D textureCube texture2DRect
|
||||
texture1DProj texture1DLod texture1DProjLod
|
||||
texture2DProj texture2DLod texture2DProjLod
|
||||
texture3DProj texture3DLod texture3DProjLod
|
||||
textureCubeLod
|
||||
shadow1D shadow2D
|
||||
shadow1DProj shadow1DLod shadow1DProjLod
|
||||
shadow2DProj shadow2DLod shadow2DProjLod
|
||||
texelFetch1D texelFetch2D texelFetch3D texelFetch2DRect texelFetch1DArray texelFetch2DArray texelFetchBuffer
|
||||
textureSizeBuffer textureSize1D textureSize2D textureSize3D textureSizeCube textureSize2DRect
|
||||
textureSize1DArray textureSize2DArray
|
||||
texture1DArray texture1DArrayLod
|
||||
texture2DArray texture2DArrayLod
|
||||
shadow1DArray shadow1DArrayLod shadow2DArray shadowCube
|
||||
texture1DGrad texture1DProjGrad texture1DProjGrad texture1DArrayGrad
|
||||
texture2DGrad texture2DProjGrad texture2DProjGrad texture2DArrayGrad
|
||||
texture3DGrad texture3DProjGrad textureCubeGrad
|
||||
shadow1DGrad shadow1DProjGrad shadow1DArrayGrad shadow2DGrad shadow2DProjGrad shadow2DArrayGrad
|
||||
texture2DRectGrad texture2DRectProjGrad texture2DRectProjGrad shadow2DRectGrad shadow2DRectProjGrad
|
||||
shadowCubeGrad
|
||||
texture1DOffset texture1DProjOffset texture1DLodOffset texture1DProjLodOffset
|
||||
texture2DOffset texture2DProjOffset texture2DLodOffset texture2DProjLodOffset
|
||||
texture3DOffset texture3DProjOffset texture3DLodOffset texture3DProjLodOffset
|
||||
|
||||
imageLoad imageStore
|
||||
imageAtomicAdd imageAtomicMin imageAtomicMax
|
||||
imageAtomicIncWrap imageAtomicDecWrap imageAtomicAnd
|
||||
imageAtomicOr imageAtomixXor imageAtomicExchange
|
||||
imageCompSwap memoryBarrier
|
||||
|
||||
x y z w
|
||||
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
|
||||
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
|
||||
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
|
||||
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
|
||||
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
|
||||
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
|
||||
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
|
||||
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
|
||||
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
|
||||
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
|
||||
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
|
||||
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
|
||||
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
|
||||
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
|
||||
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
|
||||
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
|
||||
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
|
||||
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
|
||||
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
|
||||
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
|
||||
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
|
||||
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
|
||||
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
|
||||
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
|
||||
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
|
||||
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
|
||||
xw yw xyw zw xzw yzw xyzw ]],
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
245
spec/html.lua
245
spec/html.lua
@@ -2,133 +2,124 @@
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"htm","html"},
|
||||
lexer = wxstc.wxSTC_LEX_HTML,
|
||||
apitype = "html",
|
||||
|
||||
stylingbits = 7,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {
|
||||
wxstc.wxSTC_H_DEFAULT,
|
||||
wxstc.wxSTC_HJ_DEFAULT,
|
||||
},
|
||||
comment = {wxstc.wxSTC_H_COMMENT,
|
||||
wxstc.wxSTC_HPHP_COMMENT,
|
||||
wxstc.wxSTC_HPHP_COMMENTLINE,
|
||||
wxstc.wxSTC_HJA_COMMENTLINE,
|
||||
wxstc.wxSTC_HJA_COMMENTDOC,
|
||||
wxstc.wxSTC_HJ_COMMENT,
|
||||
wxstc.wxSTC_HJ_COMMENTLINE,
|
||||
wxstc.wxSTC_HJ_COMMENTDOC,},
|
||||
stringeol = {wxstc.wxSTC_HJ_STRINGEOL,},
|
||||
number = {wxstc.wxSTC_H_NUMBER,
|
||||
wxstc.wxSTC_HJ_NUMBER,
|
||||
wxstc.wxSTC_HJA_NUMBER,
|
||||
wxstc.wxSTC_HPHP_NUMBER,},
|
||||
stringtxt = {
|
||||
wxstc.wxSTC_H_DOUBLESTRING,
|
||||
wxstc.wxSTC_H_SINGLESTRING,
|
||||
wxstc.wxSTC_HJ_DOUBLESTRING,
|
||||
wxstc.wxSTC_HJ_SINGLESTRING,
|
||||
wxstc.wxSTC_HJA_DOUBLESTRING,
|
||||
wxstc.wxSTC_HJA_SINGLESTRING,
|
||||
wxstc.wxSTC_HPHP_HSTRING,
|
||||
wxstc.wxSTC_HPHP_SIMPLESTRING,
|
||||
},
|
||||
lexerdef= {
|
||||
|
||||
wxstc.wxSTC_H_OTHER,
|
||||
wxstc.wxSTC_H_ENTITY,
|
||||
wxstc.wxSTC_H_VALUE,
|
||||
|
||||
|
||||
wxstc.wxSTC_HJA_START,
|
||||
wxstc.wxSTC_HJA_DEFAULT,
|
||||
wxstc.wxSTC_HJA_COMMENT,
|
||||
|
||||
wxstc.wxSTC_HJA_SYMBOLS,
|
||||
wxstc.wxSTC_HJA_STRINGEOL,
|
||||
wxstc.wxSTC_HJA_REGEX,
|
||||
exts = {"htm","html"},
|
||||
lexer = wxstc.wxSTC_LEX_HTML,
|
||||
apitype = "html",
|
||||
|
||||
wxstc.wxSTC_HPHP_DEFAULT,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
keywords0 = {
|
||||
wxstc.wxSTC_H_TAG,
|
||||
wxstc.wxSTC_H_ATTRIBUTE,
|
||||
|
||||
wxstc.wxSTC_HPHP_OPERATOR,
|
||||
|
||||
|
||||
wxstc.wxSTC_HJA_KEYWORD,
|
||||
},
|
||||
keywords1 = {wxstc.wxSTC_H_TAGUNKNOWN,
|
||||
wxstc.wxSTC_H_ATTRIBUTEUNKNOWN,
|
||||
wxstc.wxSTC_HJ_WORD,
|
||||
wxstc.wxSTC_HPHP_WORD,
|
||||
wxstc.wxSTC_HJA_WORD,
|
||||
wxstc.wxSTC_HPHP_VARIABLE,
|
||||
wxstc.wxSTC_HPHP_HSTRING_VARIABLE,},
|
||||
keywords2 = {wxstc.wxSTC_H_SCRIPT,
|
||||
wxstc.wxSTC_HJ_KEYWORD,
|
||||
wxstc.wxSTC_HJ_REGEX,},
|
||||
keywords3 = {wxstc.wxSTC_HJ_SYMBOLS,},
|
||||
keywords4 = {
|
||||
wxstc.wxSTC_HJ_START,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
-- HTML tags and attributes
|
||||
[[ a abbr acronym address applet area b base basefont bdo big blockquote
|
||||
body br button caption center cite code col colgroup dd del dfn dir div
|
||||
dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html
|
||||
i iframe img input ins isindex kbd label legend li link map menu meta
|
||||
noframes noscript object ol optgroup option p param pre q s samp script
|
||||
select small span strike strong style sub sup table tbody td textarea
|
||||
tfoot th thead title tr tt u ul var
|
||||
|
||||
class id style title dir lang onclick ondblclick onmousedown onmouseup
|
||||
onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup
|
||||
accesskey charset coords href hreflang name onblur onfocus rel rev
|
||||
shape tabindex target type
|
||||
align alt archive code codebase width height hspace name object vspace
|
||||
nohref color face size cite alink background bgcolor link onload
|
||||
onunload text vlink clear disabled type value char charoff span
|
||||
datetime compact color action accept accept-charset enctype method
|
||||
onreset onsubmit frameborder longdesc marginwidth marginheight
|
||||
noresize scrolling src cols rows profile noshade version
|
||||
border ismap usemap checked maxlength readonly onchange onselect
|
||||
prompt for http-equiv content scheme classid codetype data declare
|
||||
standby start disabled label selected defer event language for
|
||||
multiple media cellpadding cellspacing rules summary
|
||||
axis headers scope image hidden radio]],
|
||||
-- javascript keywords
|
||||
[[break else end false for function if
|
||||
in var null return true while undefined this]],
|
||||
-- VBScript keywords
|
||||
"",
|
||||
-- Python keywords
|
||||
"",
|
||||
-- PHP keywords (used for Lua however)
|
||||
[[and break do else elseif end false for function if
|
||||
in local nil not or repeat return then true until while]],
|
||||
-- XML
|
||||
"",
|
||||
-- SGML
|
||||
"",
|
||||
-- SGML block
|
||||
""
|
||||
},
|
||||
stylingbits = 7,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {
|
||||
wxstc.wxSTC_H_DEFAULT,
|
||||
wxstc.wxSTC_HJ_DEFAULT,
|
||||
},
|
||||
comment = {wxstc.wxSTC_H_COMMENT,
|
||||
wxstc.wxSTC_HPHP_COMMENT,
|
||||
wxstc.wxSTC_HPHP_COMMENTLINE,
|
||||
wxstc.wxSTC_HJA_COMMENTLINE,
|
||||
wxstc.wxSTC_HJA_COMMENTDOC,
|
||||
wxstc.wxSTC_HJ_COMMENT,
|
||||
wxstc.wxSTC_HJ_COMMENTLINE,
|
||||
wxstc.wxSTC_HJ_COMMENTDOC,},
|
||||
stringeol = {wxstc.wxSTC_HJ_STRINGEOL,},
|
||||
number = {wxstc.wxSTC_H_NUMBER,
|
||||
wxstc.wxSTC_HJ_NUMBER,
|
||||
wxstc.wxSTC_HJA_NUMBER,
|
||||
wxstc.wxSTC_HPHP_NUMBER,},
|
||||
stringtxt = {
|
||||
wxstc.wxSTC_H_DOUBLESTRING,
|
||||
wxstc.wxSTC_H_SINGLESTRING,
|
||||
wxstc.wxSTC_HJ_DOUBLESTRING,
|
||||
wxstc.wxSTC_HJ_SINGLESTRING,
|
||||
wxstc.wxSTC_HJA_DOUBLESTRING,
|
||||
wxstc.wxSTC_HJA_SINGLESTRING,
|
||||
wxstc.wxSTC_HPHP_HSTRING,
|
||||
wxstc.wxSTC_HPHP_SIMPLESTRING,
|
||||
},
|
||||
lexerdef= {
|
||||
|
||||
}
|
||||
wxstc.wxSTC_H_OTHER,
|
||||
wxstc.wxSTC_H_ENTITY,
|
||||
wxstc.wxSTC_H_VALUE,
|
||||
|
||||
wxstc.wxSTC_HJA_START,
|
||||
wxstc.wxSTC_HJA_DEFAULT,
|
||||
wxstc.wxSTC_HJA_COMMENT,
|
||||
|
||||
wxstc.wxSTC_HJA_SYMBOLS,
|
||||
wxstc.wxSTC_HJA_STRINGEOL,
|
||||
wxstc.wxSTC_HJA_REGEX,
|
||||
|
||||
wxstc.wxSTC_HPHP_DEFAULT,
|
||||
|
||||
},
|
||||
keywords0 = {
|
||||
wxstc.wxSTC_H_TAG,
|
||||
wxstc.wxSTC_H_ATTRIBUTE,
|
||||
|
||||
wxstc.wxSTC_HPHP_OPERATOR,
|
||||
|
||||
wxstc.wxSTC_HJA_KEYWORD,
|
||||
},
|
||||
keywords1 = {wxstc.wxSTC_H_TAGUNKNOWN,
|
||||
wxstc.wxSTC_H_ATTRIBUTEUNKNOWN,
|
||||
wxstc.wxSTC_HJ_WORD,
|
||||
wxstc.wxSTC_HPHP_WORD,
|
||||
wxstc.wxSTC_HJA_WORD,
|
||||
wxstc.wxSTC_HPHP_VARIABLE,
|
||||
wxstc.wxSTC_HPHP_HSTRING_VARIABLE,},
|
||||
keywords2 = {wxstc.wxSTC_H_SCRIPT,
|
||||
wxstc.wxSTC_HJ_KEYWORD,
|
||||
wxstc.wxSTC_HJ_REGEX,},
|
||||
keywords3 = {wxstc.wxSTC_HJ_SYMBOLS,},
|
||||
keywords4 = {
|
||||
wxstc.wxSTC_HJ_START,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
-- HTML tags and attributes
|
||||
[[ a abbr acronym address applet area b base basefont bdo big blockquote
|
||||
body br button caption center cite code col colgroup dd del dfn dir div
|
||||
dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html
|
||||
i iframe img input ins isindex kbd label legend li link map menu meta
|
||||
noframes noscript object ol optgroup option p param pre q s samp script
|
||||
select small span strike strong style sub sup table tbody td textarea
|
||||
tfoot th thead title tr tt u ul var
|
||||
|
||||
class id style title dir lang onclick ondblclick onmousedown onmouseup
|
||||
onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup
|
||||
accesskey charset coords href hreflang name onblur onfocus rel rev
|
||||
shape tabindex target type
|
||||
align alt archive code codebase width height hspace name object vspace
|
||||
nohref color face size cite alink background bgcolor link onload
|
||||
onunload text vlink clear disabled type value char charoff span
|
||||
datetime compact color action accept accept-charset enctype method
|
||||
onreset onsubmit frameborder longdesc marginwidth marginheight
|
||||
noresize scrolling src cols rows profile noshade version
|
||||
border ismap usemap checked maxlength readonly onchange onselect
|
||||
prompt for http-equiv content scheme classid codetype data declare
|
||||
standby start disabled label selected defer event language for
|
||||
multiple media cellpadding cellspacing rules summary
|
||||
axis headers scope image hidden radio]],
|
||||
-- javascript keywords
|
||||
[[break else end false for function if
|
||||
in var null return true while undefined this]],
|
||||
-- VBScript keywords
|
||||
"",
|
||||
-- Python keywords
|
||||
"",
|
||||
-- PHP keywords (used for Lua however)
|
||||
[[and break do else elseif end false for function if
|
||||
in local nil not or repeat return then true until while]],
|
||||
-- XML
|
||||
"",
|
||||
-- SGML
|
||||
"",
|
||||
-- SGML block
|
||||
""
|
||||
},
|
||||
}
|
||||
|
||||
351
spec/lua.lua
351
spec/lua.lua
@@ -1,175 +1,176 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"lua"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "lua",
|
||||
linecomment = "--",
|
||||
sep = "%.:",
|
||||
isfncall = function(str)
|
||||
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
|
||||
end,
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"function%s+([A-Za-z0-9_]+%s*[%.%:]*%s*[A-Za-z0-9_]*%s*%(.*%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"function%s+([A-Za-z0-9_]+%s*[%.%:]*%s*[A-Za-z0-9_]*)%s*")
|
||||
end
|
||||
if (s) then
|
||||
l = string.find(string.sub(str,1,s-1),"local%s+$")
|
||||
end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
typeassigns = function(editor)
|
||||
local line = editor:GetCurrentLine()
|
||||
line = line-1
|
||||
|
||||
local scopestart = {"if","do","while","function", "local%s+function", "for", "else", "elseif"}
|
||||
local scopeend = {"end"}
|
||||
local iscomment = editor.spec.iscomment
|
||||
|
||||
local assigns = {}
|
||||
|
||||
-- iterate up until a line starts with scopestart
|
||||
-- always ignore lines whose first symbol is styled as comment
|
||||
local endline = line
|
||||
while (line >= 0) do
|
||||
local ls = editor:PositionFromLine(line)
|
||||
local s = bit.band(editor:GetStyleAt(ls),31)
|
||||
|
||||
if (not iscomment[s]) then
|
||||
local tx = editor:GetLine(line)
|
||||
local leftscope
|
||||
|
||||
for i,v in ipairs(scopestart) do
|
||||
if (tx:match("^"..v)) then
|
||||
leftscope = true
|
||||
end
|
||||
end
|
||||
if (leftscope) then
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line -1
|
||||
end
|
||||
|
||||
local added
|
||||
while (line <= endline) do
|
||||
local ls = editor:PositionFromLine(line)
|
||||
local s = bit.band(editor:GetStyleAt(ls),31)
|
||||
|
||||
if (not iscomment[s]) then
|
||||
local tx = editor:GetLine(line) --= string
|
||||
|
||||
-- check for assignments
|
||||
local varname = "([%w_%.]+)"
|
||||
local identifier = "([%w_%.:]+)"
|
||||
|
||||
-- special hint
|
||||
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
|
||||
if (var and typ) then
|
||||
assigns[var] = typ
|
||||
added = true
|
||||
else
|
||||
-- real assignments
|
||||
local var,typ,rest = tx:match("%s*"..identifier.."%s*=%s*"..identifier.."(.*)")
|
||||
local comment = rest and rest:match(".*%-%-=%s*"..varname.."%s*$")
|
||||
local comma = rest and rest:match(".-%s*([,]*)%s*$")
|
||||
if (var and comment) then
|
||||
assigns[var] = comment
|
||||
added = true
|
||||
elseif (var and typ and comma=="") then
|
||||
class,func = typ:match(varname.."[%.:]"..varname)
|
||||
if (func) then
|
||||
local funcnames = {"new","load","create"}
|
||||
for i,v in ipairs(funcnames) do
|
||||
if (func:match("^"..v)) then
|
||||
assigns[var] = class
|
||||
added = true
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif (assigns[typ]) then
|
||||
assigns[var] = assigns[typ]
|
||||
added = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
line = line+1
|
||||
end
|
||||
|
||||
if (added) then
|
||||
DisplayOutput("\nTYPES\n")
|
||||
for i,v in pairs(assigns) do
|
||||
DisplayOutput(i,v,"\n")
|
||||
end
|
||||
end
|
||||
|
||||
return assigns
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_LUA_COMMENT,
|
||||
wxstc.wxSTC_LUA_COMMENTLINE,
|
||||
wxstc.wxSTC_LUA_COMMENTDOC,},
|
||||
stringtxt = {wxstc.wxSTC_LUA_STRING,
|
||||
wxstc.wxSTC_LUA_CHARACTER,
|
||||
wxstc.wxSTC_LUA_LITERALSTRING,},
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_LUA_OPERATOR,},
|
||||
number = {wxstc.wxSTC_LUA_NUMBER,},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_LUA_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
|
||||
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
|
||||
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
|
||||
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[and break do else elseif end false for function if ipairs pairs
|
||||
in local nil not or repeat return then true until while]],
|
||||
|
||||
[[_VERSION assert collectgarbage dofile error gcinfo loadfile loadstring
|
||||
print rawget rawset require tonumber tostring type unpack]],
|
||||
|
||||
[[_G getfenv getmetatable loadlib next pcall
|
||||
rawequal setfenv setmetatable xpcall
|
||||
string table math coroutine io os debug
|
||||
load module select]],
|
||||
|
||||
[[string.byte string.char string.dump string.find string.len
|
||||
string.lower string.rep string.sub string.upper string.format string.gfind string.gsub
|
||||
table.concat table.foreach table.foreachi table.getn table.sort table.insert table.remove table.setn
|
||||
math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.deg math.exp
|
||||
math.floor math.frexp math.ldexp math.log math.log10 math.max math.min math.mod
|
||||
math.pi math.pow math.rad math.random math.randomseed math.sin math.sqrt math.tan
|
||||
string.gmatch string.match string.reverse table.maxn
|
||||
math.cosh math.fmod math.modf math.sinh math.tanh math.huge]],
|
||||
|
||||
[[coroutine.create coroutine.resume coroutine.status
|
||||
coroutine.wrap coroutine.yield
|
||||
io.close io.flush io.input io.lines io.open io.output io.read io.tmpfile io.type io.write
|
||||
io.stdin io.stdout io.stderr
|
||||
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename
|
||||
os.setlocale os.time os.tmpname
|
||||
coroutine.running package.cpath package.loaded package.loadlib package.path
|
||||
package.preload package.seeall io.popen
|
||||
debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal
|
||||
debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv
|
||||
debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback]],
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"lua"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "lua",
|
||||
linecomment = "--",
|
||||
sep = "%.:",
|
||||
isfncall = function(str)
|
||||
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
|
||||
end,
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap,par = string.find(str,"function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*(%(.-%))")
|
||||
-- try to match without brackets now, but only at the beginning of the line
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*function%s+([A-Za-z0-9_]+%s-[%.%:]?%s-[A-Za-z0-9_]*)%s*")
|
||||
end
|
||||
-- try to match "foo = function()"
|
||||
if (not s) then
|
||||
s,e,cap,cap1,cap2,par = string.find(str,"(([A-Za-z0-9_]+%s-[%.%:]?%s-)([A-Za-z0-9_]*))%s*=%s*function%s*(%(.-%))")
|
||||
-- check if we captured 'local foo =' instead of 'foo.bar ='
|
||||
if cap1 and cap2 and string.len(cap2) > 0 and not string.find(cap1,'[%.%:]') then
|
||||
cap = cap2
|
||||
s = s + string.len(cap1)
|
||||
end
|
||||
end
|
||||
if (s) then
|
||||
l = string.find(string.sub(str,1,s-1),"local%s+$")
|
||||
cap = cap .. " " .. (par or "(?)")
|
||||
end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
typeassigns = function(editor)
|
||||
local line = editor:GetCurrentLine()
|
||||
line = line-1
|
||||
|
||||
local scopestart = {"if","do","while","function", "local%s+function", "for", "else", "elseif"}
|
||||
local scopeend = {"end"}
|
||||
local iscomment = editor.spec.iscomment
|
||||
|
||||
local assigns = {}
|
||||
|
||||
-- iterate up until a line starts with scopestart
|
||||
-- always ignore lines whose first symbol is styled as comment
|
||||
local endline = line
|
||||
while (line >= 0) do
|
||||
local ls = editor:PositionFromLine(line)
|
||||
local s = bit.band(editor:GetStyleAt(ls),31)
|
||||
|
||||
if (not iscomment[s]) then
|
||||
local tx = editor:GetLine(line)
|
||||
local leftscope
|
||||
|
||||
for i,v in ipairs(scopestart) do
|
||||
if (tx:match("^"..v)) then
|
||||
leftscope = true
|
||||
end
|
||||
end
|
||||
if (leftscope) then
|
||||
break
|
||||
end
|
||||
end
|
||||
line = line -1
|
||||
end
|
||||
|
||||
local added
|
||||
while (line <= endline) do
|
||||
local ls = editor:PositionFromLine(line)
|
||||
local s = bit.band(editor:GetStyleAt(ls),31)
|
||||
|
||||
if (not iscomment[s]) then
|
||||
local tx = editor:GetLine(line) --= string
|
||||
|
||||
-- check for assignments
|
||||
local varname = "([%w_%.]+)"
|
||||
local identifier = "([%w_%.:]+)"
|
||||
|
||||
-- special hint
|
||||
local typ,var = tx:match("%s*%-%-=%s*"..varname.."%s+"..identifier)
|
||||
if (var and typ) then
|
||||
assigns[var] = typ
|
||||
added = true
|
||||
else
|
||||
-- real assignments
|
||||
local var,typ,rest = tx:match("%s*"..identifier.."%s*=%s*"..identifier.."(.*)")
|
||||
local comment = rest and rest:match(".*%-%-=%s*"..varname.."%s*$")
|
||||
local comma = rest and rest:match(".-%s*([,]*)%s*$")
|
||||
if (var and comment) then
|
||||
assigns[var] = comment
|
||||
added = true
|
||||
elseif (var and typ and comma=="") then
|
||||
class,func = typ:match(varname.."[%.:]"..varname)
|
||||
if (func) then
|
||||
local funcnames = {"new","load","create"}
|
||||
for i,v in ipairs(funcnames) do
|
||||
if (func:match("^"..v)) then
|
||||
assigns[var] = class
|
||||
added = true
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif (assigns[typ]) then
|
||||
assigns[var] = assigns[typ]
|
||||
added = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
line = line+1
|
||||
end
|
||||
|
||||
return assigns
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_LUA_COMMENT,
|
||||
wxstc.wxSTC_LUA_COMMENTLINE,
|
||||
wxstc.wxSTC_LUA_COMMENTDOC,},
|
||||
stringtxt = {wxstc.wxSTC_LUA_STRING,
|
||||
wxstc.wxSTC_LUA_CHARACTER,
|
||||
wxstc.wxSTC_LUA_LITERALSTRING,},
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_LUA_OPERATOR,},
|
||||
number = {wxstc.wxSTC_LUA_NUMBER,},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_LUA_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
|
||||
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
|
||||
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
|
||||
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[and break do else elseif end false for function if ipairs pairs
|
||||
in local nil not or repeat return then true until while]],
|
||||
|
||||
[[_VERSION assert collectgarbage dofile error gcinfo loadfile loadstring
|
||||
print rawget rawset require tonumber tostring type unpack]],
|
||||
|
||||
[[_G getfenv getmetatable loadlib next pcall
|
||||
rawequal setfenv setmetatable xpcall
|
||||
string table math coroutine io os debug
|
||||
load module select]],
|
||||
|
||||
[[string.byte string.char string.dump string.find string.len
|
||||
string.lower string.rep string.sub string.upper string.format string.gfind string.gsub
|
||||
table.concat table.foreach table.foreachi table.getn table.sort table.insert table.remove table.setn
|
||||
math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.deg math.exp
|
||||
math.floor math.frexp math.ldexp math.log math.log10 math.max math.min math.mod
|
||||
math.pi math.pow math.rad math.random math.randomseed math.sin math.sqrt math.tan
|
||||
string.gmatch string.match string.reverse table.maxn
|
||||
math.cosh math.fmod math.modf math.sinh math.tanh math.huge]],
|
||||
|
||||
[[coroutine.create coroutine.resume coroutine.status
|
||||
coroutine.wrap coroutine.yield
|
||||
io.close io.flush io.input io.lines io.open io.output io.read io.tmpfile io.type io.write
|
||||
io.stdin io.stdout io.stderr
|
||||
os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename
|
||||
os.setlocale os.time os.tmpname
|
||||
coroutine.running package.cpath package.loaded package.loadlib package.path
|
||||
package.preload package.seeall io.popen
|
||||
debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal
|
||||
debug.getmetatable debug.getregistry debug.getupvalue debug.setfenv
|
||||
debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.traceback]],
|
||||
},
|
||||
}
|
||||
|
||||
117
spec/luxres.lua
117
spec/luxres.lua
@@ -2,68 +2,67 @@
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"prt","shd","mtl"},
|
||||
lexer = wxstc.wxSTC_LEX_POV,
|
||||
apitype = "luxres",
|
||||
linecomment = "//",
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_POV_IDENTIFIER,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_POV_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_POV_COMMENT,
|
||||
wxstc.wxSTC_POV_COMMENTLINE,},
|
||||
stringtxt = {wxstc.wxSTC_POV_STRING,},
|
||||
stringeol = {wxstc.wxSTC_POV_STRINGEOL,},
|
||||
--preprocessor= {wxstc.wxSTC_POV_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_POV_OPERATOR,},
|
||||
number = {wxstc.wxSTC_POV_NUMBER,},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_POV_WORD2,},
|
||||
keywords1 = {wxstc.wxSTC_POV_WORD3,},
|
||||
keywords2 = {wxstc.wxSTC_POV_WORD4,},
|
||||
keywords3 = {wxstc.wxSTC_POV_WORD5,},
|
||||
keywords4 = {wxstc.wxSTC_POV_WORD6,},
|
||||
keywords5 = {wxstc.wxSTC_POV_WORD7,},
|
||||
keywords6 = {wxstc.wxSTC_POV_WORD8,},
|
||||
},
|
||||
exts = {"prt","shd","mtl"},
|
||||
lexer = wxstc.wxSTC_LEX_POV,
|
||||
apitype = "luxres",
|
||||
linecomment = "//",
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_POV_IDENTIFIER,},
|
||||
|
||||
keywords = {
|
||||
-- word0 doesnt exist in lexer
|
||||
"",
|
||||
[[RenderFlag Color Texture Forces SubSystem Emitter Particle Technique GpuProgram Shader
|
||||
NewPass DrawPass ]],
|
||||
lexerdef = {wxstc.wxSTC_POV_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_POV_COMMENT,
|
||||
wxstc.wxSTC_POV_COMMENTLINE,},
|
||||
stringtxt = {wxstc.wxSTC_POV_STRING,},
|
||||
stringeol = {wxstc.wxSTC_POV_STRINGEOL,},
|
||||
--preprocessor= {wxstc.wxSTC_POV_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_POV_OPERATOR,},
|
||||
number = {wxstc.wxSTC_POV_NUMBER,},
|
||||
|
||||
[[control floatmod texcontrol shdcontrol texconst texcenter texscale texrotate texmove texgenplane texclamp
|
||||
frames delay loop param alpha rfalpha layer alphaTEX alphafunc texmatrixcolum
|
||||
blendmode texcoord count type size width height axis model rate
|
||||
alphaTEX alphamode stateflag velocity endtime maxoffsetdist velocityvar flipdirection spread restarttime
|
||||
restarts life size sizeage3 sizevar lifevar rotate rotatevar rotateoffset rotateage3
|
||||
RGBAvar pointparams speedage3 numcolor numtex originoffset gravity wind trail normal
|
||||
translated instancemesh rotateagetex speedagetex sizeagetex RGBAagetex RGBAvar TEXPROJ TEXCUBE TEXALPHA
|
||||
TEX TEXDOTZ VTEXPROJ VTEXCUBE VTEXALPHA VTEX VTEXDOTZ SHD RGBA BASE
|
||||
SKIN FOGGED TEXCOMBINE1D MATERIAL TEXCOMBINE2D_16 TEXCOMBINE2D_32 ]],
|
||||
keywords0 = {wxstc.wxSTC_POV_WORD2,},
|
||||
keywords1 = {wxstc.wxSTC_POV_WORD3,},
|
||||
keywords2 = {wxstc.wxSTC_POV_WORD4,},
|
||||
keywords3 = {wxstc.wxSTC_POV_WORD5,},
|
||||
keywords4 = {wxstc.wxSTC_POV_WORD6,},
|
||||
keywords5 = {wxstc.wxSTC_POV_WORD7,},
|
||||
keywords6 = {wxstc.wxSTC_POV_WORD8,},
|
||||
},
|
||||
|
||||
[[VID_REPLACE VID_DECAL VID_DECAL_PREV VID_DECAL_VERTEX VID_DECAL_CONST VID_MODULATE VID_ADD VID_AMODADD VID_AMODADD_PREV VID_AMODADD_VERTEX
|
||||
VID_AMODADD_CONST VID_AMODADD_CONSTMOD VID_NORMALMAPTAN VID_DECAL_CONSTMOD VID_LIGHTPOS VID_LIGHTCOLOR VID_LIGHTDIR VID_CAMPOS VID_CAMDIR VID_ARRAY
|
||||
VID_LIGHTAMBIENT VID_VALUE VID_LIGHTRANGE VID_RANDOM VID_TIME VID_TEXCONST VID_TEXSIZE VID_TEXSIZEINV VID_TEXLMSCALE VID_TEXMAT0
|
||||
VID_TEXMAT1 VID_TEXMAT2 VID_TEXMAT3 VID_TEXGEN0 VID_TEXGEN1 VID_TEXGEN2 VID_TEXGEN3 RENDER_BLEND RENDER_NOVERTEXCOLOR RENDER_ALPHATEST
|
||||
RENDER_STENCILTEST RENDER_NODEPTHTEST RENDER_NOCULL RENDER_FRONTCULL RENDER_NOCOLORMASK RENDER_NODEPTHMASK RENDER_STENCILMASK RENDER_LIT ADD SIN
|
||||
COS ZIGZAG USER_TEX LIGHTMAP ATTENUATE3D NORMALIZE SKYBOX SPECULAR DIFFUSE DUMMY
|
||||
VID_DEFAULT VID_LOWDETAIL VID_ARB_V VID_ARB_V_TEX4 VID_ARB_V_TEX8 VID_ARB_TEXCOMB VID_ARB_TEXCOMB_TEX4 VID_ARB_VF VID_ARB_VF_TEX4 VID_ARB_VF_TEX8
|
||||
VID_CG_SM3_TEX8 VID_CG_SM3 VID_CG_SM4 VID_CG_SM4_GS GL_NEVER GL_ALWAYS GL_LESS GL_GREATER GL_LEQUAL GL_GEQUAL
|
||||
GL_EQUAL GL_NOTEQUAL VID_POINT VID_CIRCLE VID_SPHERE VID_RECTANGLE VID_MODEL VID_QUAD VID_TRIANGLE VID_HSPHERE
|
||||
VID_DIR VID_ODIR CAP_MODADD CAP_COMBINE4 CAP_TEX3D CAP_TEXFLOAT ]],
|
||||
keywords = {
|
||||
-- word0 doesnt exist in lexer
|
||||
"",
|
||||
[[RenderFlag Color Texture Forces SubSystem Emitter Particle Technique GpuProgram Shader
|
||||
NewPass DrawPass ]],
|
||||
|
||||
[[reflectmap blendinvertalpha spheremap screenmap interpolate skyreflectmap nocolorarray lit unlit sunlit
|
||||
nocull nodepthmask alphamask eyelinmap normalmap sunreflectmap sunnormalmap vertexcolored tangents normals
|
||||
colorpass nodepthtest sort novistest depthmask nodraw depthcompare depthvalue nomipmap fog
|
||||
rotatevelocity dieonfrontplane camrotfix noagedeath pointsmooth noage eventimed sequence combinedraw skymatrix
|
||||
lightmapscale rgbscale2 rgbscale4 alphascale2 alphascale4 lightreflectmap0 lightreflectmap1 lightreflectmap2 lightreflectmap3 lightnormalmap0
|
||||
lightnormalmap1 lightnormalmap2 lightnormalmap3 lowCgProfile VPROG VCG FCG GCG FPROG FFIXED
|
||||
VFIXED GFIXED ]],
|
||||
[[control floatmod texcontrol shdcontrol texconst texcenter texscale texrotate texmove texgenplane texclamp
|
||||
frames delay loop param alpha rfalpha layer alphaTEX alphafunc texmatrixcolum
|
||||
blendmode texcoord count type size width height axis model rate
|
||||
alphaTEX alphamode stateflag velocity endtime maxoffsetdist velocityvar flipdirection spread restarttime
|
||||
restarts life size sizeage3 sizevar lifevar rotate rotatevar rotateoffset rotateage3
|
||||
RGBAvar pointparams speedage3 numcolor numtex originoffset gravity wind trail normal
|
||||
translated instancemesh rotateagetex speedagetex sizeagetex RGBAagetex RGBAvar TEXPROJ TEXCUBE TEXALPHA
|
||||
TEX TEXDOTZ VTEXPROJ VTEXCUBE VTEXALPHA VTEX VTEXDOTZ SHD RGBA BASE
|
||||
SKIN FOGGED TEXCOMBINE1D MATERIAL TEXCOMBINE2D_16 TEXCOMBINE2D_32 ]],
|
||||
|
||||
[[luxinia_ParticleSys_v120 luxinia_Shader_v310 luxinia_Material_v110 IF ELSEIF ELSE ]],
|
||||
[[VID_REPLACE VID_DECAL VID_DECAL_PREV VID_DECAL_VERTEX VID_DECAL_CONST VID_MODULATE VID_ADD VID_AMODADD VID_AMODADD_PREV VID_AMODADD_VERTEX
|
||||
VID_AMODADD_CONST VID_AMODADD_CONSTMOD VID_NORMALMAPTAN VID_DECAL_CONSTMOD VID_LIGHTPOS VID_LIGHTCOLOR VID_LIGHTDIR VID_CAMPOS VID_CAMDIR VID_ARRAY
|
||||
VID_LIGHTAMBIENT VID_VALUE VID_LIGHTRANGE VID_RANDOM VID_TIME VID_TEXCONST VID_TEXSIZE VID_TEXSIZEINV VID_TEXLMSCALE VID_TEXMAT0
|
||||
VID_TEXMAT1 VID_TEXMAT2 VID_TEXMAT3 VID_TEXGEN0 VID_TEXGEN1 VID_TEXGEN2 VID_TEXGEN3 RENDER_BLEND RENDER_NOVERTEXCOLOR RENDER_ALPHATEST
|
||||
RENDER_STENCILTEST RENDER_NODEPTHTEST RENDER_NOCULL RENDER_FRONTCULL RENDER_NOCOLORMASK RENDER_NODEPTHMASK RENDER_STENCILMASK RENDER_LIT ADD SIN
|
||||
COS ZIGZAG USER_TEX LIGHTMAP ATTENUATE3D NORMALIZE SKYBOX SPECULAR DIFFUSE DUMMY
|
||||
VID_DEFAULT VID_LOWDETAIL VID_ARB_V VID_ARB_V_TEX4 VID_ARB_V_TEX8 VID_ARB_TEXCOMB VID_ARB_TEXCOMB_TEX4 VID_ARB_VF VID_ARB_VF_TEX4 VID_ARB_VF_TEX8
|
||||
VID_CG_SM3_TEX8 VID_CG_SM3 VID_CG_SM4 VID_CG_SM4_GS GL_NEVER GL_ALWAYS GL_LESS GL_GREATER GL_LEQUAL GL_GEQUAL
|
||||
GL_EQUAL GL_NOTEQUAL VID_POINT VID_CIRCLE VID_SPHERE VID_RECTANGLE VID_MODEL VID_QUAD VID_TRIANGLE VID_HSPHERE
|
||||
VID_DIR VID_ODIR CAP_MODADD CAP_COMBINE4 CAP_TEX3D CAP_TEXFLOAT ]],
|
||||
|
||||
},
|
||||
}
|
||||
[[reflectmap blendinvertalpha spheremap screenmap interpolate skyreflectmap nocolorarray lit unlit sunlit
|
||||
nocull nodepthmask alphamask eyelinmap normalmap sunreflectmap sunnormalmap vertexcolored tangents normals
|
||||
colorpass nodepthtest sort novistest depthmask nodraw depthcompare depthvalue nomipmap fog
|
||||
rotatevelocity dieonfrontplane camrotfix noagedeath pointsmooth noage eventimed sequence combinedraw skymatrix
|
||||
lightmapscale rgbscale2 rgbscale4 alphascale2 alphascale4 lightreflectmap0 lightreflectmap1 lightreflectmap2 lightreflectmap3 lightnormalmap0
|
||||
lightnormalmap1 lightnormalmap2 lightnormalmap3 lowCgProfile VPROG VCG FCG GCG FPROG FFIXED
|
||||
VFIXED GFIXED ]],
|
||||
|
||||
[[luxinia_ParticleSys_v120 luxinia_Shader_v310 luxinia_Material_v110 IF ELSEIF ELSE ]],
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,115 +1,114 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
-- unfortunately no good lexer
|
||||
-- ASM comments start with ;
|
||||
-- and TCL doesnt allow coloring
|
||||
-- behind keywords
|
||||
|
||||
exts = {"glp","vp","fp"},
|
||||
lexer = wxstc.wxSTC_LEX_TCL,
|
||||
--apitype = "cg",
|
||||
linecomment = "#",
|
||||
lexerstyleconvert = {
|
||||
text = {4,5,7,8,9,10,11,
|
||||
},
|
||||
|
||||
lexerdef = {0,},
|
||||
comment = {1,2,20,21,
|
||||
},
|
||||
--stringtxt = {wxstc.wxSTC_SQL_STRING,
|
||||
-- wxstc.wxSTC_SQL_CHARACTER,
|
||||
-- },
|
||||
--stringeol = {wxstc.wxSTC_SQL_STRINGEOL,},
|
||||
--preprocessor= {,},
|
||||
operator = {6,},
|
||||
number = {3,
|
||||
},
|
||||
|
||||
|
||||
keywords0 = {12,},
|
||||
keywords1 = {13,},
|
||||
keywords2 = {14,},
|
||||
keywords3 = {15,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[EMIT ENDPRIM
|
||||
ABS ADD AND BRK CAL CEIL CMP CONT COS DIV DP2 DP2A DP3 DP4 DPH DST ELSE
|
||||
ENDIF ENDREP EX2 FLR FRC I2F IF KIL LG2 LIT LRP MAD MAX MIN MOD MOV MUL
|
||||
NOT NRM OR PK2H PK2US PK4B PK4UB POW RCC RCP REP RET RFL ROUND RSQ SAD
|
||||
SCS SEQ SFL SGE SGT SHL SHR SIN SLE SLT SNE SSG STR SUB SWZ TEX TRUNC LOOP
|
||||
TXB TXD TXF TXL TXP TXQ UP2H UP2US UP4B UP4UB X2D XOR XPD REP.S REP.F REP.U
|
||||
ENDLOOP SUBROUTINENUM CALI
|
||||
|
||||
ABS_SAT ADD_SAT CEIL_SAT CMP_SAT COS_SAT DIV_SAT DP2_SAT DP2A_SAT DP3_SAT
|
||||
DP4_SAT DPH_SAT DST_SAT EX2_SAT FLR_SAT FRC_SAT LG2_SAT LIT_SAT LRP_SAT
|
||||
MAD_SAT MAX_SAT MIN_SAT MOV_SAT MUL_SAT NRM_SAT POW_SAT RCC_SAT RCP_SAT
|
||||
RFL_SAT ROUND_SAT RSQ_SAT SCS_SAT SEQ_SAT SFL_SAT SGE_SAT SGT_SAT SIN_SAT
|
||||
SLE_SAT SLT_SAT SNE_SAT SSG_SAT STR_SAT SUB_SAT SWZ_SAT TEX_SAT TRUNC_SAT
|
||||
TXB_SAT TXD_SAT TXF_SAT TXL_SAT TXP_SAT UP2H_SAT UP2US_SAT UP4B_SAT UP4UB_SAT
|
||||
X2D_SAT XPD_SAT
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
ATTRIB PARAM TEMP ADDRESS OUTPUT ALIAS OPTION TEXTURE
|
||||
PRIMITIVE_IN PRIMITIVE_OUT VERTICES_OUT POINTS LINES LINES_ADJACENCY
|
||||
TRIANGLES TRIANGLES_ADJACENCY
|
||||
LINE_STRIP TRIANGLE_STRIP
|
||||
EQ GE GT LE LT NE TR FL EQ0 GE0 GT0 LE0 LT0 NE0 TR0 FL0 EQ1 GE1 GT1 LE1 LT1
|
||||
NE1 TR1 FL1 NAN NAN0 NAN1 LEG LEG0 LEG1 CF CF0 CF1 NCF NCF0 NCF1 OF OF0 OF1
|
||||
NOF NOF0 NOF1 AB AB0 AB1 BLE BLE0 BLE1 SF SF0 SF1 NSF NSF0 NSF1
|
||||
END SUBROUTINETYPE SUBROUTINE
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
vertex position weight normal color primary secondary fogcoord texcoord
|
||||
matrixindex attrib
|
||||
program env local fragment
|
||||
state material ambient diffuse specular emission shininess front back
|
||||
light attenuation spot direction half
|
||||
lightmodel scene lightprod
|
||||
texgen eye object s t r q
|
||||
fog params
|
||||
clip plane
|
||||
point size attenuation
|
||||
matrix modelview projection mvp texture palette row transpose inverse invtrans
|
||||
result pointsize 1D 2D 3D CUBE RECT
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
x y z w xxxx xxxy xxxz xxxw
|
||||
xxyx xxyy xxyz xxyw xxzx xxzy xxzz xxzw xxwx xxwy
|
||||
xxwz xxww xyxx xyxy xyxz xyxw xyyx xyyy xyyz xyyw
|
||||
xyzx xyzy xyzz xyzw xywx xywy xywz xyww xzxx xzxy
|
||||
xzxz xzxw xzyx xzyy xzyz xzyw xzzx xzzy xzzz xzzw
|
||||
xzwx xzwy xzwz xzww xwxx xwxy xwxz xwxw xwyx xwyy
|
||||
xwyz xwyw xwzx xwzy xwzz xwzw xwwx xwwy xwwz xwww
|
||||
yxxx yxxy yxxz yxxw yxyx yxyy yxyz yxyw yxzx yxzy
|
||||
yxzz yxzw yxwx yxwy yxwz yxww yyxx yyxy yyxz yyxw
|
||||
yyyx yyyy yyyz yyyw yyzx yyzy yyzz yyzw yywx yywy
|
||||
yywz yyww yzxx yzxy yzxz yzxw yzyx yzyy yzyz yzyw
|
||||
yzzx yzzy yzzz yzzw yzwx yzwy yzwz yzww ywxx ywxy
|
||||
ywxz ywxw ywyx ywyy ywyz ywyw ywzx ywzy ywzz ywzw
|
||||
ywwx ywwy ywwz ywww zxxx zxxy zxxz zxxw zxyx zxyy
|
||||
zxyz zxyw zxzx zxzy zxzz zxzw zxwx zxwy zxwz zxww
|
||||
zyxx zyxy zyxz zyxw zyyx zyyy zyyz zyyw zyzx zyzy
|
||||
zyzz zyzw zywx zywy zywz zyww zzxx zzxy zzxz zzxw
|
||||
zzyx zzyy zzyz zzyw zzzx zzzy zzzz zzzw zzwx zzwy
|
||||
zzwz zzww zwxx zwxy zwxz zwxw zwyx zwyy zwyz zwyw
|
||||
zwzx zwzy zwzz zwzw zwwx zwwy zwwz zwww wxxx wxxy
|
||||
wxxz wxxw wxyx wxyy wxyz wxyw wxzx wxzy wxzz wxzw
|
||||
wxwx wxwy wxwz wxww wyxx wyxy wyxz wyxw wyyx wyyy
|
||||
wyyz wyyw wyzx wyzy wyzz wyzw wywx wywy wywz wyww
|
||||
wzxx wzxy wzxz wzxw wzyx wzyy wzyz wzyw wzzx wzzy
|
||||
wzzz wzzw wzwx wzwy wzwz wzww wwxx wwxy wwxz wwxw
|
||||
wwyx wwyy wwyz wwyw wwzx wwzy wwzz wwzw wwwx wwwy
|
||||
wwwz wwww xy xz yz xyz xw yw xyw zw
|
||||
xzw yzw xyzw ]],
|
||||
|
||||
},
|
||||
}
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
-- unfortunately no good lexer
|
||||
-- ASM comments start with ;
|
||||
-- and TCL doesnt allow coloring
|
||||
-- behind keywords
|
||||
|
||||
exts = {"glp","vp","fp"},
|
||||
lexer = wxstc.wxSTC_LEX_TCL,
|
||||
--apitype = "cg",
|
||||
linecomment = "#",
|
||||
lexerstyleconvert = {
|
||||
text = {4,5,7,8,9,10,11,
|
||||
},
|
||||
|
||||
lexerdef = {0,},
|
||||
comment = {1,2,20,21,
|
||||
},
|
||||
--stringtxt = {wxstc.wxSTC_SQL_STRING,
|
||||
-- wxstc.wxSTC_SQL_CHARACTER,
|
||||
-- },
|
||||
--stringeol = {wxstc.wxSTC_SQL_STRINGEOL,},
|
||||
--preprocessor= {,},
|
||||
operator = {6,},
|
||||
number = {3,
|
||||
},
|
||||
|
||||
keywords0 = {12,},
|
||||
keywords1 = {13,},
|
||||
keywords2 = {14,},
|
||||
keywords3 = {15,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[EMIT ENDPRIM
|
||||
ABS ADD AND BRK CAL CEIL CMP CONT COS DIV DP2 DP2A DP3 DP4 DPH DST ELSE
|
||||
ENDIF ENDREP EX2 FLR FRC I2F IF KIL LG2 LIT LRP MAD MAX MIN MOD MOV MUL
|
||||
NOT NRM OR PK2H PK2US PK4B PK4UB POW RCC RCP REP RET RFL ROUND RSQ SAD
|
||||
SCS SEQ SFL SGE SGT SHL SHR SIN SLE SLT SNE SSG STR SUB SWZ TEX TRUNC LOOP
|
||||
TXB TXD TXF TXL TXP TXQ UP2H UP2US UP4B UP4UB X2D XOR XPD REP.S REP.F REP.U
|
||||
ENDLOOP SUBROUTINENUM CALI
|
||||
|
||||
ABS_SAT ADD_SAT CEIL_SAT CMP_SAT COS_SAT DIV_SAT DP2_SAT DP2A_SAT DP3_SAT
|
||||
DP4_SAT DPH_SAT DST_SAT EX2_SAT FLR_SAT FRC_SAT LG2_SAT LIT_SAT LRP_SAT
|
||||
MAD_SAT MAX_SAT MIN_SAT MOV_SAT MUL_SAT NRM_SAT POW_SAT RCC_SAT RCP_SAT
|
||||
RFL_SAT ROUND_SAT RSQ_SAT SCS_SAT SEQ_SAT SFL_SAT SGE_SAT SGT_SAT SIN_SAT
|
||||
SLE_SAT SLT_SAT SNE_SAT SSG_SAT STR_SAT SUB_SAT SWZ_SAT TEX_SAT TRUNC_SAT
|
||||
TXB_SAT TXD_SAT TXF_SAT TXL_SAT TXP_SAT UP2H_SAT UP2US_SAT UP4B_SAT UP4UB_SAT
|
||||
X2D_SAT XPD_SAT
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
ATTRIB PARAM TEMP ADDRESS OUTPUT ALIAS OPTION TEXTURE
|
||||
PRIMITIVE_IN PRIMITIVE_OUT VERTICES_OUT POINTS LINES LINES_ADJACENCY
|
||||
TRIANGLES TRIANGLES_ADJACENCY
|
||||
LINE_STRIP TRIANGLE_STRIP
|
||||
EQ GE GT LE LT NE TR FL EQ0 GE0 GT0 LE0 LT0 NE0 TR0 FL0 EQ1 GE1 GT1 LE1 LT1
|
||||
NE1 TR1 FL1 NAN NAN0 NAN1 LEG LEG0 LEG1 CF CF0 CF1 NCF NCF0 NCF1 OF OF0 OF1
|
||||
NOF NOF0 NOF1 AB AB0 AB1 BLE BLE0 BLE1 SF SF0 SF1 NSF NSF0 NSF1
|
||||
END SUBROUTINETYPE SUBROUTINE
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
vertex position weight normal color primary secondary fogcoord texcoord
|
||||
matrixindex attrib
|
||||
program env local fragment
|
||||
state material ambient diffuse specular emission shininess front back
|
||||
light attenuation spot direction half
|
||||
lightmodel scene lightprod
|
||||
texgen eye object s t r q
|
||||
fog params
|
||||
clip plane
|
||||
point size attenuation
|
||||
matrix modelview projection mvp texture palette row transpose inverse invtrans
|
||||
result pointsize 1D 2D 3D CUBE RECT
|
||||
|
||||
]],
|
||||
[[
|
||||
|
||||
x y z w xxxx xxxy xxxz xxxw
|
||||
xxyx xxyy xxyz xxyw xxzx xxzy xxzz xxzw xxwx xxwy
|
||||
xxwz xxww xyxx xyxy xyxz xyxw xyyx xyyy xyyz xyyw
|
||||
xyzx xyzy xyzz xyzw xywx xywy xywz xyww xzxx xzxy
|
||||
xzxz xzxw xzyx xzyy xzyz xzyw xzzx xzzy xzzz xzzw
|
||||
xzwx xzwy xzwz xzww xwxx xwxy xwxz xwxw xwyx xwyy
|
||||
xwyz xwyw xwzx xwzy xwzz xwzw xwwx xwwy xwwz xwww
|
||||
yxxx yxxy yxxz yxxw yxyx yxyy yxyz yxyw yxzx yxzy
|
||||
yxzz yxzw yxwx yxwy yxwz yxww yyxx yyxy yyxz yyxw
|
||||
yyyx yyyy yyyz yyyw yyzx yyzy yyzz yyzw yywx yywy
|
||||
yywz yyww yzxx yzxy yzxz yzxw yzyx yzyy yzyz yzyw
|
||||
yzzx yzzy yzzz yzzw yzwx yzwy yzwz yzww ywxx ywxy
|
||||
ywxz ywxw ywyx ywyy ywyz ywyw ywzx ywzy ywzz ywzw
|
||||
ywwx ywwy ywwz ywww zxxx zxxy zxxz zxxw zxyx zxyy
|
||||
zxyz zxyw zxzx zxzy zxzz zxzw zxwx zxwy zxwz zxww
|
||||
zyxx zyxy zyxz zyxw zyyx zyyy zyyz zyyw zyzx zyzy
|
||||
zyzz zyzw zywx zywy zywz zyww zzxx zzxy zzxz zzxw
|
||||
zzyx zzyy zzyz zzyw zzzx zzzy zzzz zzzw zzwx zzwy
|
||||
zzwz zzww zwxx zwxy zwxz zwxw zwyx zwyy zwyz zwyw
|
||||
zwzx zwzy zwzz zwzw zwwx zwwy zwwz zwww wxxx wxxy
|
||||
wxxz wxxw wxyx wxyy wxyz wxyw wxzx wxzy wxzz wxzw
|
||||
wxwx wxwy wxwz wxww wyxx wyxy wyxz wyxw wyyx wyyy
|
||||
wyyz wyyw wyzx wyzy wyzz wyzw wywx wywy wywz wyww
|
||||
wzxx wzxy wzxz wzxw wzyx wzyy wzyz wzyw wzzx wzzy
|
||||
wzzz wzzw wzwx wzwy wzwz wzww wwxx wwxy wwxz wwxw
|
||||
wwyx wwyy wwyz wwyw wwzx wwzy wwzz wwzw wwwx wwwy
|
||||
wwwz wwww xy xz yz xyz xw yw xyw zw
|
||||
xzw yzw xyzw ]],
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
355
spec/opencl.lua
355
spec/opencl.lua
@@ -4,195 +4,192 @@
|
||||
local convtypes = [[bool char uchar short ushort int uint long ulong float double]]
|
||||
local convout = {}
|
||||
for i in convtypes:gmatch("([%w_]+)") do
|
||||
local suffix = {"","_rte","_rtz","_rtp","_rtn"}
|
||||
for k,t in ipairs(suffix) do
|
||||
table.insert(convout,"convert_"..i..t)
|
||||
table.insert(convout,"convert_"..i.."_sat"..t)
|
||||
local vectors = {2,4,8,16}
|
||||
for n,v in ipairs(vectors) do
|
||||
table.insert(convout,"convert_"..i..v..t)
|
||||
table.insert(convout,"convert_"..i..v.."_sat"..t)
|
||||
end
|
||||
end
|
||||
local suffix = {"","_rte","_rtz","_rtp","_rtn"}
|
||||
for k,t in ipairs(suffix) do
|
||||
table.insert(convout,"convert_"..i..t)
|
||||
table.insert(convout,"convert_"..i.."_sat"..t)
|
||||
local vectors = {2,4,8,16}
|
||||
for n,v in ipairs(vectors) do
|
||||
table.insert(convout,"convert_"..i..v..t)
|
||||
table.insert(convout,"convert_"..i..v.."_sat"..t)
|
||||
end
|
||||
end
|
||||
end
|
||||
convout = table.concat(convout, " ")
|
||||
|
||||
local astypes = [[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
|
||||
long ulong char short unsigned
|
||||
float2 float4 float8 float16
|
||||
double2 double4 double8 double16
|
||||
char2 char4 char8 char16
|
||||
uchar2 uchar4 uchar8 uchar16
|
||||
short2 short4 short8 short16
|
||||
ushort2 ushort4 ushort8 ushort16
|
||||
int2 int4 int8 int16
|
||||
uint2 uint4 uint8 uint16
|
||||
long2 long4 long8 long16
|
||||
ulong2 ulong4 ulong8 ulong16]]
|
||||
long ulong char short unsigned
|
||||
float2 float4 float8 float16
|
||||
double2 double4 double8 double16
|
||||
char2 char4 char8 char16
|
||||
uchar2 uchar4 uchar8 uchar16
|
||||
short2 short4 short8 short16
|
||||
ushort2 ushort4 ushort8 ushort16
|
||||
int2 int4 int8 int16
|
||||
uint2 uint4 uint8 uint16
|
||||
long2 long4 long8 long16
|
||||
ulong2 ulong4 ulong8 ulong16]]
|
||||
|
||||
local astypeout = {}
|
||||
for i in astypes:gmatch("([%w_]+)") do
|
||||
table.insert(astypeout, "as_"..i)
|
||||
table.insert(astypeout, "as_"..i)
|
||||
end
|
||||
astypeout = table.concat(astypeout, " ")
|
||||
|
||||
return {
|
||||
exts = {"cl","ocl","clh",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "opencl",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
|
||||
long ulong char short unsigned
|
||||
|
||||
float2 float4 float8 float16
|
||||
double2 double4 double8 double16
|
||||
char2 char4 char8 char16
|
||||
uchar2 uchar4 uchar8 uchar16
|
||||
short2 short4 short8 short16
|
||||
ushort2 ushort4 ushort8 ushort16
|
||||
int2 int4 int8 int16
|
||||
uint2 uint4 uint8 uint16
|
||||
long2 long4 long8 long16
|
||||
ulong2 ulong4 ulong8 ulong16
|
||||
|
||||
half2 half4 half8 half16
|
||||
void half bool
|
||||
image2d_t image3d_t sampler_t event_t cl_image_format
|
||||
|
||||
struct typedef void const inline
|
||||
return switch case for do while if else break continue volatile
|
||||
CLK_A CLK_R CLK_RG CLK_RGB CLK_RGBA CLK_ARGB CLK_BGRA CLK_INTENSITY CLK_LUMINANCE
|
||||
|
||||
MAXFLOAT HUGE_VALF INFINITY NAN
|
||||
CLK_LOCAL_MEM_FENCE CLK_GLOBAL_MEM_FENCE
|
||||
CLK_SNORM_INT8
|
||||
CLK_SNORM_INT16
|
||||
CLK_UNORM_INT8
|
||||
CLK_UNORM_INT16
|
||||
CLK_UNORM_SHORT_565
|
||||
CLK_UNORM_SHORT_555
|
||||
CLK_UNORM_SHORT_101010
|
||||
CLK_SIGNED_INT8
|
||||
CLK_SIGNED_INT16
|
||||
CLK_SIGNED_INT32
|
||||
CLK_UNSIGNED_INT8
|
||||
CLK_UNSIGNED_INT16
|
||||
CLK_UNSIGNED_INT32
|
||||
CLK_HALF_FLOAT
|
||||
CLK_FLOAT
|
||||
__FILE__ __LINE__ __OPENCL_VERSION__ __ENDIAN_LITTLE__
|
||||
__ROUNDING_MODE__ __IMAGE_SUPPORT__ __FAST_RELAXED_MATH__
|
||||
]],
|
||||
exts = {"cl","ocl","clh",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "opencl",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
[[__kernel kernel __attribute__ __read_only __write_only read_only write_only
|
||||
__constant constant __local local __global global __private private
|
||||
vec_type_hint work_group_size_hint reqd_work_group_size
|
||||
aligned packed endian host device
|
||||
|
||||
async_work_group_copy wait_group_events prefetch
|
||||
clamp min max degrees radians sign smoothstep step mix
|
||||
mem_fence read_mem_fence write_mem_fence
|
||||
cross prod distance dot length normalize fast_distance fast_length fast_normalize
|
||||
get_image_width get_image_height get_image_depth
|
||||
get_image_channel_data_type get_image_channel_order
|
||||
get_image_dim
|
||||
abs abs_diff add_sat clz hadd mad24 mad_hi mad_sat
|
||||
mul24 mul_hi rhadd rotate sub_sat upsample
|
||||
read_imagei write_imagei read_imageui write_imageui
|
||||
read_imagef write_imagef
|
||||
|
||||
isequal isnotequal isgreater isgreaterequal isless islessequal islessgreater
|
||||
isfinite isinf isnan isnormal isordered isunordered signbit any all bitselect select
|
||||
|
||||
acos acosh acospi asin asinh asinpi atan atan2 atanh atanpi atan2pi
|
||||
cbrt ceil copysign cos half_cos native_cos cosh cospi half_divide native_divide
|
||||
erf erfc exp half_exp native_exp exp2 half_exp2 native_exp2 exp10 half_exp10 native_exp10
|
||||
expm1 fabs fdim floor fma fmax fmin fmod fract frexp hypot ilogb
|
||||
ldexp lgamma lgamma_r log half_log native_log log2 half_log2 native_log2
|
||||
log10 half_log10 native_log10 log1p logb mad modf nan nextafter
|
||||
pow pown powr half_powr native_powr half_recip native_recip
|
||||
remainder remquo rint round rootn rsqrt half_rsqrt native_rsqrt
|
||||
sin half_sin native_sin sincos sinh sinpi sqrt half_sqrt native_sqrt
|
||||
tan half_tan native_tan tanh tanpi tgamma trunc
|
||||
|
||||
barrier
|
||||
vload2 vload4 vload8 vload16
|
||||
vload_half vload_half2 vload_half4 vload_half8 vload_half16 vloada_half4 vloada_half8 vloada_half16
|
||||
vstore2 vstore4 vstore8 vstore16
|
||||
vstore_half vstore_half2 vstore_half4 vstore_half8 vstore_half16 vstorea_half4 vstorea_half8 vstorea_half16
|
||||
get_global_id get_global_size get_group_id get_local_id get_local_size get_num_groups get_work_dim
|
||||
|
||||
|
||||
|
||||
x y z w
|
||||
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
|
||||
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
|
||||
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
|
||||
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
|
||||
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
|
||||
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
|
||||
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
|
||||
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
|
||||
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
|
||||
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
|
||||
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
|
||||
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
|
||||
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
|
||||
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
|
||||
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
|
||||
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
|
||||
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
|
||||
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
|
||||
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
|
||||
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
|
||||
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
|
||||
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
|
||||
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
|
||||
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
|
||||
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
|
||||
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
|
||||
xw yw xyw zw xzw yzw xyzw ]]..convout.." "..astypeout,
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
},
|
||||
}
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[int uint uchar ushort float double size_t ptrdiff_t intptr_t uintptr_t
|
||||
long ulong char short unsigned
|
||||
|
||||
float2 float4 float8 float16
|
||||
double2 double4 double8 double16
|
||||
char2 char4 char8 char16
|
||||
uchar2 uchar4 uchar8 uchar16
|
||||
short2 short4 short8 short16
|
||||
ushort2 ushort4 ushort8 ushort16
|
||||
int2 int4 int8 int16
|
||||
uint2 uint4 uint8 uint16
|
||||
long2 long4 long8 long16
|
||||
ulong2 ulong4 ulong8 ulong16
|
||||
|
||||
half2 half4 half8 half16
|
||||
void half bool
|
||||
image2d_t image3d_t sampler_t event_t cl_image_format
|
||||
|
||||
struct typedef void const inline
|
||||
return switch case for do while if else break continue volatile
|
||||
CLK_A CLK_R CLK_RG CLK_RGB CLK_RGBA CLK_ARGB CLK_BGRA CLK_INTENSITY CLK_LUMINANCE
|
||||
|
||||
MAXFLOAT HUGE_VALF INFINITY NAN
|
||||
CLK_LOCAL_MEM_FENCE CLK_GLOBAL_MEM_FENCE
|
||||
CLK_SNORM_INT8
|
||||
CLK_SNORM_INT16
|
||||
CLK_UNORM_INT8
|
||||
CLK_UNORM_INT16
|
||||
CLK_UNORM_SHORT_565
|
||||
CLK_UNORM_SHORT_555
|
||||
CLK_UNORM_SHORT_101010
|
||||
CLK_SIGNED_INT8
|
||||
CLK_SIGNED_INT16
|
||||
CLK_SIGNED_INT32
|
||||
CLK_UNSIGNED_INT8
|
||||
CLK_UNSIGNED_INT16
|
||||
CLK_UNSIGNED_INT32
|
||||
CLK_HALF_FLOAT
|
||||
CLK_FLOAT
|
||||
__FILE__ __LINE__ __OPENCL_VERSION__ __ENDIAN_LITTLE__
|
||||
__ROUNDING_MODE__ __IMAGE_SUPPORT__ __FAST_RELAXED_MATH__
|
||||
]],
|
||||
|
||||
[[__kernel kernel __attribute__ __read_only __write_only read_only write_only
|
||||
__constant constant __local local __global global __private private
|
||||
vec_type_hint work_group_size_hint reqd_work_group_size
|
||||
aligned packed endian host device
|
||||
|
||||
async_work_group_copy wait_group_events prefetch
|
||||
clamp min max degrees radians sign smoothstep step mix
|
||||
mem_fence read_mem_fence write_mem_fence
|
||||
cross prod distance dot length normalize fast_distance fast_length fast_normalize
|
||||
get_image_width get_image_height get_image_depth
|
||||
get_image_channel_data_type get_image_channel_order
|
||||
get_image_dim
|
||||
abs abs_diff add_sat clz hadd mad24 mad_hi mad_sat
|
||||
mul24 mul_hi rhadd rotate sub_sat upsample
|
||||
read_imagei write_imagei read_imageui write_imageui
|
||||
read_imagef write_imagef
|
||||
|
||||
isequal isnotequal isgreater isgreaterequal isless islessequal islessgreater
|
||||
isfinite isinf isnan isnormal isordered isunordered signbit any all bitselect select
|
||||
|
||||
acos acosh acospi asin asinh asinpi atan atan2 atanh atanpi atan2pi
|
||||
cbrt ceil copysign cos half_cos native_cos cosh cospi half_divide native_divide
|
||||
erf erfc exp half_exp native_exp exp2 half_exp2 native_exp2 exp10 half_exp10 native_exp10
|
||||
expm1 fabs fdim floor fma fmax fmin fmod fract frexp hypot ilogb
|
||||
ldexp lgamma lgamma_r log half_log native_log log2 half_log2 native_log2
|
||||
log10 half_log10 native_log10 log1p logb mad modf nan nextafter
|
||||
pow pown powr half_powr native_powr half_recip native_recip
|
||||
remainder remquo rint round rootn rsqrt half_rsqrt native_rsqrt
|
||||
sin half_sin native_sin sincos sinh sinpi sqrt half_sqrt native_sqrt
|
||||
tan half_tan native_tan tanh tanpi tgamma trunc
|
||||
|
||||
barrier
|
||||
vload2 vload4 vload8 vload16
|
||||
vload_half vload_half2 vload_half4 vload_half8 vload_half16 vloada_half4 vloada_half8 vloada_half16
|
||||
vstore2 vstore4 vstore8 vstore16
|
||||
vstore_half vstore_half2 vstore_half4 vstore_half8 vstore_half16 vstorea_half4 vstorea_half8 vstorea_half16
|
||||
get_global_id get_global_size get_group_id get_local_id get_local_size get_num_groups get_work_dim
|
||||
|
||||
x y z w
|
||||
xxxx xxxy xxxz xxxw xxyx xxyy xxyz xxyw xxzx xxzy
|
||||
xxzz xxzw xxwx xxwy xxwz xxww xyxx xyxy xyxz xyxw
|
||||
xyyx xyyy xyyz xyyw xyzx xyzy xyzz xyzw xywx xywy
|
||||
xywz xyww xzxx xzxy xzxz xzxw xzyx xzyy xzyz xzyw
|
||||
xzzx xzzy xzzz xzzw xzwx xzwy xzwz xzww xwxx xwxy
|
||||
xwxz xwxw xwyx xwyy xwyz xwyw xwzx xwzy xwzz xwzw
|
||||
xwwx xwwy xwwz xwww yxxx yxxy yxxz yxxw yxyx yxyy
|
||||
yxyz yxyw yxzx yxzy yxzz yxzw yxwx yxwy yxwz yxww
|
||||
yyxx yyxy yyxz yyxw yyyx yyyy yyyz yyyw yyzx yyzy
|
||||
yyzz yyzw yywx yywy yywz yyww yzxx yzxy yzxz yzxw
|
||||
yzyx yzyy yzyz yzyw yzzx yzzy yzzz yzzw yzwx yzwy
|
||||
yzwz yzww ywxx ywxy ywxz ywxw ywyx ywyy ywyz ywyw
|
||||
ywzx ywzy ywzz ywzw ywwx ywwy ywwz ywww zxxx zxxy
|
||||
zxxz zxxw zxyx zxyy zxyz zxyw zxzx zxzy zxzz zxzw
|
||||
zxwx zxwy zxwz zxww zyxx zyxy zyxz zyxw zyyx zyyy
|
||||
zyyz zyyw zyzx zyzy zyzz zyzw zywx zywy zywz zyww
|
||||
zzxx zzxy zzxz zzxw zzyx zzyy zzyz zzyw zzzx zzzy
|
||||
zzzz zzzw zzwx zzwy zzwz zzww zwxx zwxy zwxz zwxw
|
||||
zwyx zwyy zwyz zwyw zwzx zwzy zwzz zwzw zwwx zwwy
|
||||
zwwz zwww wxxx wxxy wxxz wxxw wxyx wxyy wxyz wxyw
|
||||
wxzx wxzy wxzz wxzw wxwx wxwy wxwz wxww wyxx wyxy
|
||||
wyxz wyxw wyyx wyyy wyyz wyyw wyzx wyzy wyzz wyzw
|
||||
wywx wywy wywz wyww wzxx wzxy wzxz wzxw wzyx wzyy
|
||||
wzyz wzyw wzzx wzzy wzzz wzzw wzwx wzwy wzwz wzww
|
||||
wwxx wwxy wwxz wwxw wwyx wwyy wwyz wwyw wwzx wwzy
|
||||
wwzz wwzw wwwx wwwy wwwz wwww xy xz yz xyz
|
||||
xw yw xyw zw xzw yzw xyzw ]]..convout.." "..astypeout,
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
437
spec/ptx.lua
Normal file
437
spec/ptx.lua
Normal file
@@ -0,0 +1,437 @@
|
||||
-- author: Christoph Kubisch
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"ptx",},
|
||||
lexer = wxstc.wxSTC_LEX_CPP,
|
||||
apitype = "ptx",
|
||||
sep = "%.",
|
||||
linecomment = "//",
|
||||
|
||||
isfndef = function(str)
|
||||
local l
|
||||
local s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+%s*%(.+%))")
|
||||
if (not s) then
|
||||
s,e,cap = string.find(str,"^%s*([A-Za-z0-9_]+%s+[A-Za-z0-9_]+)%s*%(")
|
||||
end
|
||||
if (cap and (string.find(cap,"^return") or string.find(cap,"else"))) then return end
|
||||
return s,e,cap,l
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_C_IDENTIFIER,
|
||||
wxstc.wxSTC_C_VERBATIM,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_REGEX,
|
||||
wxstc.wxSTC_C_GLOBALCLASS,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_C_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_C_COMMENT,
|
||||
wxstc.wxSTC_C_COMMENTLINE,
|
||||
wxstc.wxSTC_C_COMMENTDOC,
|
||||
wxstc.wxSTC_C_COMMENTLINEDOC,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORD,
|
||||
wxstc.wxSTC_C_COMMENTDOCKEYWORDERROR,},
|
||||
stringtxt = {wxstc.wxSTC_C_STRING,
|
||||
wxstc.wxSTC_C_CHARACTER,
|
||||
wxstc.wxSTC_C_UUID,},
|
||||
stringeol = {wxstc.wxSTC_C_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_C_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_C_OPERATOR,},
|
||||
number = {wxstc.wxSTC_C_NUMBER,
|
||||
wxstc.wxSTC_C_WORD},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_C_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_C_WORD2,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[
|
||||
version
|
||||
target
|
||||
address_size
|
||||
|
||||
entry
|
||||
func
|
||||
|
||||
branchtargets
|
||||
calltargets
|
||||
callprototype
|
||||
|
||||
maxnreg
|
||||
maxntid
|
||||
reqntid
|
||||
minnctapersm
|
||||
maxnctapersm
|
||||
pragma
|
||||
|
||||
section
|
||||
file
|
||||
loc
|
||||
|
||||
extern
|
||||
visible
|
||||
|
||||
pragma
|
||||
|
||||
align
|
||||
file
|
||||
maxntid
|
||||
shared
|
||||
branchtargets
|
||||
func
|
||||
minnctapersm
|
||||
sreg
|
||||
callprototype
|
||||
global
|
||||
param
|
||||
target
|
||||
calltargets
|
||||
local
|
||||
pragma
|
||||
tex
|
||||
const
|
||||
loc
|
||||
reg
|
||||
version
|
||||
entry
|
||||
maxnctapersm
|
||||
reqntid
|
||||
visible
|
||||
extern
|
||||
maxnreg
|
||||
section
|
||||
|
||||
s8
|
||||
s16
|
||||
s32
|
||||
s64
|
||||
u8
|
||||
u16
|
||||
u32
|
||||
u64
|
||||
f16
|
||||
f32
|
||||
f64
|
||||
b8
|
||||
b16
|
||||
b32
|
||||
b64
|
||||
pred
|
||||
|
||||
rn
|
||||
rz
|
||||
rm
|
||||
rp
|
||||
|
||||
rni
|
||||
rzi
|
||||
rmi
|
||||
rpi
|
||||
|
||||
ca
|
||||
cg
|
||||
cs
|
||||
lu
|
||||
cv
|
||||
|
||||
wb
|
||||
cg
|
||||
cs
|
||||
wt
|
||||
|
||||
texref
|
||||
samplerref
|
||||
surfref
|
||||
|
||||
sat
|
||||
ftz
|
||||
|
||||
cc
|
||||
|
||||
hi
|
||||
lo
|
||||
wide
|
||||
|
||||
f4e
|
||||
b4e
|
||||
rc8
|
||||
ecl
|
||||
ecr
|
||||
rc16
|
||||
|
||||
finite
|
||||
infinite
|
||||
number
|
||||
notanumber
|
||||
normal
|
||||
subnormal
|
||||
|
||||
approx
|
||||
full
|
||||
|
||||
eq
|
||||
ne
|
||||
lt
|
||||
le
|
||||
gt
|
||||
ge
|
||||
|
||||
equ
|
||||
neu
|
||||
ltu
|
||||
leu
|
||||
gtu
|
||||
geu
|
||||
|
||||
num
|
||||
nan
|
||||
|
||||
ls
|
||||
hs
|
||||
|
||||
volatile
|
||||
|
||||
v2
|
||||
v4
|
||||
|
||||
L1
|
||||
L2
|
||||
|
||||
1d
|
||||
2d
|
||||
3d
|
||||
a1d
|
||||
a2d
|
||||
|
||||
width
|
||||
height
|
||||
depth
|
||||
channel_data_type
|
||||
channel_order
|
||||
normalized_coords
|
||||
|
||||
force_unnormalized_coords
|
||||
filter_mode
|
||||
addr_mode_0
|
||||
addr_mode_1
|
||||
addr_mode_2
|
||||
|
||||
trap
|
||||
clamp
|
||||
zero
|
||||
|
||||
all
|
||||
any
|
||||
uni
|
||||
ballot
|
||||
|
||||
sync
|
||||
arrive
|
||||
red
|
||||
|
||||
cta
|
||||
gl
|
||||
sys
|
||||
|
||||
and
|
||||
or
|
||||
xor
|
||||
cas
|
||||
exch
|
||||
add
|
||||
inc
|
||||
dec
|
||||
min
|
||||
max
|
||||
|
||||
b0
|
||||
b1
|
||||
b2
|
||||
b3
|
||||
h0
|
||||
h1
|
||||
wrap
|
||||
shr7
|
||||
shr15
|
||||
|
||||
byte
|
||||
4byte
|
||||
quad
|
||||
4byte
|
||||
quad
|
||||
|
||||
b8
|
||||
b32
|
||||
b64
|
||||
b32
|
||||
b64
|
||||
]],
|
||||
|
||||
-- functions
|
||||
|
||||
[[
|
||||
add
|
||||
sub
|
||||
add.cc
|
||||
addc
|
||||
sub.cc
|
||||
subc
|
||||
mul
|
||||
mad
|
||||
mul24
|
||||
mad24
|
||||
sad
|
||||
div
|
||||
rem
|
||||
abs
|
||||
neg
|
||||
min
|
||||
max
|
||||
popc
|
||||
clz
|
||||
bfind
|
||||
brev
|
||||
bfe
|
||||
bfi
|
||||
prmt
|
||||
|
||||
rcp
|
||||
sqrt
|
||||
rsqrt
|
||||
sin
|
||||
cos
|
||||
lg2
|
||||
ex2
|
||||
fma
|
||||
|
||||
set
|
||||
setp
|
||||
selp
|
||||
slct
|
||||
|
||||
and
|
||||
or
|
||||
xor
|
||||
not
|
||||
cnot
|
||||
shl
|
||||
shr
|
||||
|
||||
mov
|
||||
ld
|
||||
ldu
|
||||
st
|
||||
prefetch
|
||||
prefetchu
|
||||
isspacep
|
||||
cvta
|
||||
cvt
|
||||
|
||||
tex
|
||||
tld4
|
||||
txq
|
||||
suld
|
||||
sust
|
||||
sured
|
||||
suq
|
||||
|
||||
bra
|
||||
call
|
||||
ret
|
||||
exit
|
||||
|
||||
bar
|
||||
membar
|
||||
atom
|
||||
red
|
||||
vote
|
||||
|
||||
vadd
|
||||
vsub
|
||||
vabsdiff
|
||||
vmin
|
||||
vmax
|
||||
vshl
|
||||
vshr
|
||||
vmad
|
||||
vset
|
||||
|
||||
trap
|
||||
brkpt
|
||||
pmevent
|
||||
|
||||
%clock
|
||||
%laneid
|
||||
%lanemask_gt
|
||||
%pm0
|
||||
%pm1
|
||||
%pm2
|
||||
%pm3
|
||||
%clock64
|
||||
%lanemask_eq
|
||||
%nctaid
|
||||
%smid
|
||||
%ctaid
|
||||
%lanemask_le
|
||||
%ntid
|
||||
%tid
|
||||
%envreg0
|
||||
%envreg1
|
||||
%envreg2
|
||||
%envreg3
|
||||
%envreg4
|
||||
%envreg5
|
||||
%envreg6
|
||||
%envreg7
|
||||
%envreg8
|
||||
%envreg9
|
||||
%envreg10
|
||||
%envreg11
|
||||
%envreg12
|
||||
%envreg13
|
||||
%envreg14
|
||||
%envreg15
|
||||
%envreg16
|
||||
%envreg17
|
||||
%envreg18
|
||||
%envreg19
|
||||
%envreg20
|
||||
%envreg21
|
||||
%envreg22
|
||||
%envreg23
|
||||
%envreg24
|
||||
%envreg25
|
||||
%envreg26
|
||||
%envreg27
|
||||
%envreg28
|
||||
%envreg29
|
||||
%envreg30
|
||||
%envreg31
|
||||
%lanemask_lt
|
||||
%nsmid
|
||||
%warpid
|
||||
%gridid
|
||||
%lanemask_ge
|
||||
%nwarpid
|
||||
WARP_SZ
|
||||
nearest
|
||||
linear
|
||||
wrap
|
||||
mirror
|
||||
clamp_ogl
|
||||
clamp_to_edge
|
||||
clamp_to_border
|
||||
|
||||
sm_20
|
||||
sm_10
|
||||
sm_11
|
||||
sm_12
|
||||
sm_13
|
||||
texmode_unified
|
||||
texmode_independent
|
||||
map_f64_to_f32
|
||||
]],
|
||||
|
||||
},
|
||||
}
|
||||
155
spec/sql.lua
155
spec/sql.lua
@@ -2,87 +2,86 @@
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"sql"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "sql",
|
||||
linecomment = "--",
|
||||
isfncall = function(str)
|
||||
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_LUA_COMMENT,
|
||||
wxstc.wxSTC_LUA_COMMENTLINE,
|
||||
wxstc.wxSTC_LUA_COMMENTDOC,},
|
||||
stringtxt = {wxstc.wxSTC_LUA_STRING,
|
||||
wxstc.wxSTC_LUA_CHARACTER,
|
||||
wxstc.wxSTC_LUA_LITERALSTRING,},
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_LUA_OPERATOR,},
|
||||
number = {wxstc.wxSTC_LUA_NUMBER,},
|
||||
|
||||
|
||||
keywords0 = {wxstc.wxSTC_LUA_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
|
||||
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
|
||||
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
|
||||
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
|
||||
WHEN CHECK CONSTRAINT PRIMARY AUTOINCREMENT
|
||||
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT
|
||||
BEGIN TRANSACTION COMMIT KEY REFERENCES UNIQUE INDEX ON SET RESTRICT
|
||||
CASCADE ]],
|
||||
-- javascript keywords
|
||||
[[ NULL]],
|
||||
[[ TEXT BOOLEAN INTEGER]]
|
||||
},
|
||||
exts = {"sql"},
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
apitype = "sql",
|
||||
linecomment = "--",
|
||||
isfncall = function(str)
|
||||
return string.find(str,"([A-Za-z0-9_]+)%s*%(")
|
||||
end,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wxstc.wxSTC_LUA_IDENTIFIER,},
|
||||
|
||||
lexerdef = {wxstc.wxSTC_LUA_DEFAULT,},
|
||||
comment = {wxstc.wxSTC_LUA_COMMENT,
|
||||
wxstc.wxSTC_LUA_COMMENTLINE,
|
||||
wxstc.wxSTC_LUA_COMMENTDOC,},
|
||||
stringtxt = {wxstc.wxSTC_LUA_STRING,
|
||||
wxstc.wxSTC_LUA_CHARACTER,
|
||||
wxstc.wxSTC_LUA_LITERALSTRING,},
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
preprocessor= {wxstc.wxSTC_LUA_PREPROCESSOR,},
|
||||
operator = {wxstc.wxSTC_LUA_OPERATOR,},
|
||||
number = {wxstc.wxSTC_LUA_NUMBER,},
|
||||
|
||||
keywords0 = {wxstc.wxSTC_LUA_WORD,},
|
||||
keywords1 = {wxstc.wxSTC_LUA_WORD2,},
|
||||
keywords2 = {wxstc.wxSTC_LUA_WORD3,},
|
||||
keywords3 = {wxstc.wxSTC_LUA_WORD4,},
|
||||
keywords4 = {wxstc.wxSTC_LUA_WORD5,},
|
||||
keywords5 = {wxstc.wxSTC_LUA_WORD6,},
|
||||
keywords6 = {wxstc.wxSTC_LUA_WORD7,},
|
||||
keywords7 = {wxstc.wxSTC_LUA_WORD8,},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
|
||||
WHEN CHECK CONSTRAINT PRIMARY AUTOINCREMENT
|
||||
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT
|
||||
BEGIN TRANSACTION COMMIT KEY REFERENCES UNIQUE INDEX ON SET RESTRICT
|
||||
CASCADE ]],
|
||||
-- javascript keywords
|
||||
[[ NULL]],
|
||||
[[ TEXT BOOLEAN INTEGER]]
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
--[==[return {
|
||||
exts = {"sql"},
|
||||
lexer = wxstc.wxSTC_LEX_SQL,
|
||||
apitype = "sql",
|
||||
linecomment = "--",
|
||||
stylingbits = 5,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wx.wxSTC_SQL_DEFAULT},
|
||||
comment = {wx.wxSTC_SQL_COMMENT,wx.wxSTC_SQL_COMMENTLINE},
|
||||
stringeol = {},
|
||||
number = {wx.wxSTC_SQL_NUMBER},
|
||||
stringtxt = {},
|
||||
lexerdef= {},
|
||||
keywords0 = {wx.wxSTC_SQL_IDENTIFIER, wx.wxSTC_SQL_QUOTEDIDENTIFIER},
|
||||
keywords1 = {wx.wxSTC_SQL_STRING},
|
||||
keywords2 = {wx.wxSTC_SQL_COMMENTDOC,wx.wxSTC_SQL_COMMENTDOCKEYWORD},
|
||||
keywords3 = {wx.wxSTC_SQL_COMMENTDOCKEYWORDERROR,wx.wxSTC_SQL_COMMENTLINEDOC},
|
||||
keywords4 = {wx.wxSTC_SQL_WORD,wx.wxSTC_SQL_WORD2,},
|
||||
keywords5 = {wx.wxSTC_SQL_USER1,wx.wxSTC_SQL_USER2,wx.wxSTC_SQL_USER3,wx.wxSTC_SQL_USER4},
|
||||
keywords6 = {},
|
||||
keywords7 = {},
|
||||
preprocessor= {},
|
||||
},
|
||||
|
||||
keywords = {
|
||||
-- HTML tags and attributes
|
||||
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
|
||||
WHEN CHECK CONSTRAINT PRIMARY INTEGER AUTOINCREMENT
|
||||
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT]],
|
||||
-- javascript keywords
|
||||
[[ NULL]]
|
||||
},
|
||||
--[==[
|
||||
return {
|
||||
exts = {"sql"},
|
||||
lexer = wxstc.wxSTC_LEX_SQL,
|
||||
apitype = "sql",
|
||||
linecomment = "--",
|
||||
stylingbits = 5,
|
||||
|
||||
lexerstyleconvert = {
|
||||
text = {wx.wxSTC_SQL_DEFAULT},
|
||||
comment = {wx.wxSTC_SQL_COMMENT,wx.wxSTC_SQL_COMMENTLINE},
|
||||
stringeol = {},
|
||||
number = {wx.wxSTC_SQL_NUMBER},
|
||||
stringtxt = {},
|
||||
lexerdef= {},
|
||||
keywords0 = {wx.wxSTC_SQL_IDENTIFIER, wx.wxSTC_SQL_QUOTEDIDENTIFIER},
|
||||
keywords1 = {wx.wxSTC_SQL_STRING},
|
||||
keywords2 = {wx.wxSTC_SQL_COMMENTDOC,wx.wxSTC_SQL_COMMENTDOCKEYWORD},
|
||||
keywords3 = {wx.wxSTC_SQL_COMMENTDOCKEYWORDERROR,wx.wxSTC_SQL_COMMENTLINEDOC},
|
||||
keywords4 = {wx.wxSTC_SQL_WORD,wx.wxSTC_SQL_WORD2,},
|
||||
keywords5 = {wx.wxSTC_SQL_USER1,wx.wxSTC_SQL_USER2,wx.wxSTC_SQL_USER3,wx.wxSTC_SQL_USER4},
|
||||
keywords6 = {},
|
||||
keywords7 = {},
|
||||
preprocessor= {},
|
||||
},
|
||||
|
||||
}]==]
|
||||
keywords = {
|
||||
-- HTML tags and attributes
|
||||
[[ SELECT FROM CREATE TABLE WHERE ORDER BY CASE
|
||||
WHEN CHECK CONSTRAINT PRIMARY INTEGER AUTOINCREMENT
|
||||
INSERT INTO DELETE DROP DISTINCT GROUP IS DEFAULT]],
|
||||
-- javascript keywords
|
||||
[[ NULL]]
|
||||
},
|
||||
|
||||
}
|
||||
]==]
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"txt"},
|
||||
--lexer = wxstc.wxSTC_LEX_POV,
|
||||
--apitype = "luxres",
|
||||
linecomment = ">",
|
||||
}
|
||||
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
return {
|
||||
exts = {"txt"},
|
||||
--lexer = wxstc.wxSTC_LEX_POV,
|
||||
--apitype = "luxres",
|
||||
linecomment = ">",
|
||||
}
|
||||
|
||||
321
src/defs.lua
Normal file
321
src/defs.lua
Normal file
@@ -0,0 +1,321 @@
|
||||
-- About
|
||||
-- ----------------------------------------------------
|
||||
-- This file contains lua table definitons used by
|
||||
-- automatic loaded files, not part of the
|
||||
-- editor source.
|
||||
--
|
||||
-- /<app>/config.lua
|
||||
-- /cfg/user.lua
|
||||
-- /interpreters/*.lua
|
||||
-- /specs/*.lua
|
||||
-- /tools/*.lua
|
||||
-- /api/<apitype>/*.lua
|
||||
|
||||
-- style definition
|
||||
-- ----------------------------------------------------
|
||||
-- all entries are optional
|
||||
stattr = {
|
||||
fg = {r,g,b}, -- foreground color 0-255
|
||||
bg = {r,g,b}, -- background color
|
||||
i = false, -- italic
|
||||
b = false, -- bold
|
||||
u = false, -- underline
|
||||
fill = true, -- fill to lineend
|
||||
-- fn = "Lucida Console", -- font Face Name
|
||||
-- fx = 11, -- font size
|
||||
-- hs = true or {r,g,b}, -- turn hotspot on
|
||||
-- use the specified color as activeForeground
|
||||
-- use "hs = true", to turn it on without changing the color
|
||||
-- HotspotActiveUnderline and HotspotSingleLine are on automatically
|
||||
-- v = true, -- visibility for symbols of the current style
|
||||
}
|
||||
|
||||
style = {
|
||||
-- lexer specific (inherit fg/bg from text)
|
||||
lexerdef = stattr,
|
||||
comment = stattr,
|
||||
stringtxt = stattr,
|
||||
stringeol = stattr,
|
||||
preprocessor = stattr,
|
||||
operator = stattr,
|
||||
number = stattr,
|
||||
|
||||
keywords0 = stattr,
|
||||
keywords1 = stattr,
|
||||
keywords2 = stattr,
|
||||
keywords3 = stattr,
|
||||
keywords4 = stattr,
|
||||
keywords5 = stattr,
|
||||
keywords6 = stattr,
|
||||
keywords7 = stattr,
|
||||
|
||||
-- common (inherit fg/bg from text)
|
||||
text = stattr,
|
||||
linenumber = stattr,
|
||||
bracematch = stattr,
|
||||
bracemiss = stattr,
|
||||
escapechar = stattr,
|
||||
indent = stattr,
|
||||
calltip = stattr,
|
||||
|
||||
-- common special (need custom fg & bg )
|
||||
calltipbg = nil,
|
||||
sel = nil,
|
||||
caret = nil,
|
||||
caretlinebg = nil,
|
||||
fold = nil,
|
||||
whitespace = nil,
|
||||
|
||||
-- special, functioncall indicator
|
||||
fncall = {
|
||||
fg = {r,g,b},
|
||||
st = wxstc.wxSTC_INDIC_BOX,
|
||||
},
|
||||
}
|
||||
|
||||
-- config definition
|
||||
-- ----------------------------------------------------
|
||||
-- tables must exist
|
||||
-- content is optional
|
||||
-- config is loaded into existing config table
|
||||
config = {
|
||||
appname = "estrela", -- by default the launcher name
|
||||
|
||||
path = {
|
||||
-- path for tools/interpreters
|
||||
luxinia = "C:/luxbin/",
|
||||
-- path to luxinia exe
|
||||
|
||||
projectdir = "",
|
||||
-- the project directory, used by
|
||||
-- some tools/interpreters
|
||||
},
|
||||
editor = {
|
||||
fontname = "Courier New",
|
||||
-- default font
|
||||
fontsize = 10,
|
||||
-- defailt size
|
||||
caretline = true,
|
||||
-- show active line
|
||||
|
||||
-- input/output filtering of strings
|
||||
-- current filters "GermanUtf8Ascii"
|
||||
iofilter = nil,
|
||||
|
||||
-- use indicator to show function calls
|
||||
-- if spec allows
|
||||
showfncall = true,
|
||||
|
||||
tabwidth = 4,
|
||||
usetabs = true, -- if false then spaces are used
|
||||
usewrap = true, -- if true then the text is wrapped in the editor
|
||||
whitespace = false,
|
||||
autotabs = true, -- if true test for tabs after file load,
|
||||
-- sets "usetabs" to true for this file
|
||||
},
|
||||
|
||||
debugger = {
|
||||
verbose = false,
|
||||
}
|
||||
|
||||
outputshell = {
|
||||
-- output and shell settings
|
||||
fontname = "Courier New",
|
||||
-- default font
|
||||
fontsize = 10,
|
||||
-- defult size
|
||||
}
|
||||
|
||||
styles = {},
|
||||
-- styles table as above for editor
|
||||
|
||||
stylesoutshell = {},
|
||||
-- styles for output/shell
|
||||
|
||||
interpreter = "EstrelaEditor",
|
||||
-- the default "project" lua interpreter
|
||||
|
||||
autocomplete = true,
|
||||
-- whether autocomplete is on by default
|
||||
|
||||
acandtip = {
|
||||
shorttip = false,
|
||||
-- tooltips are compact during typing
|
||||
nodynwords = false,
|
||||
-- no dynamic words (user entered words)
|
||||
ignorecase = false,
|
||||
-- ignores case when performing comparison with autocomplete list
|
||||
strategy = 0,
|
||||
-- 0: is string comparison
|
||||
-- 1: substring leading characters (camel case or _ separated)
|
||||
-- 2: leading + any correctly ordered fragments (default)
|
||||
}
|
||||
|
||||
savebak = false,
|
||||
-- if bak files are created on save
|
||||
|
||||
filehistorylength = 20,
|
||||
-- historylength for files
|
||||
|
||||
projecthistorylength = 15,
|
||||
-- historylength for project directories
|
||||
|
||||
singleinstance = true,
|
||||
-- if true creates a UDP server to exchange messages
|
||||
-- for loading commandline passed files
|
||||
|
||||
singleinstanceport = 0xe493,
|
||||
-- UDP port for single instance communication
|
||||
|
||||
activateoutput = false, -- activate output/console on Run/Debug/Compile
|
||||
unhidewxwindow = false, -- try to unhide a wx window
|
||||
allowinteractivescript = false, -- allow interaction in the output window
|
||||
}
|
||||
|
||||
-- application engine
|
||||
-- ----------------------------------------------------
|
||||
|
||||
app = {
|
||||
preinit = function() end, -- post spec/tool loading, but prior subsystems/ui generation
|
||||
postinit = function() end, -- post init, prior starting mainloop
|
||||
loadfilters = {
|
||||
tools = function(file) return true end,
|
||||
specs = function(file) return true end,
|
||||
interpreters = function(file) return true end,
|
||||
}
|
||||
stringtable = { -- optional entries uses defaults otherwise
|
||||
editor = nil, statuswelcome = nil,
|
||||
-- ...
|
||||
}
|
||||
}
|
||||
|
||||
-- api definition
|
||||
-- ----------------------------------------------------
|
||||
-- hierarchy encoded into children
|
||||
|
||||
api = {
|
||||
-- global space words, e.g "table"
|
||||
["blah"] = {
|
||||
-- "function", "class", "keyword", "value", "lib"
|
||||
type = "function",
|
||||
description = "this does something",
|
||||
|
||||
-- value and function:
|
||||
valuetype = "api.ClassName",
|
||||
|
||||
-- function:
|
||||
args = "(blah,blubb)",
|
||||
returns = "(foo)",
|
||||
|
||||
-- autogenerated post load:
|
||||
-- concated hierarchy name (e.g. "lib.class")
|
||||
classname = "blah",
|
||||
|
||||
-- children in the class hierarchy
|
||||
childs = {
|
||||
--.. recursive
|
||||
}
|
||||
},
|
||||
["blubb"] = {
|
||||
--...
|
||||
},
|
||||
}
|
||||
|
||||
-- spec definition
|
||||
-- ----------------------------------------------------
|
||||
-- all entries are optional
|
||||
spec = {
|
||||
exts = {"ext","ext2",..},
|
||||
-- compatible extensions
|
||||
|
||||
lexer = wxstc.wxSTC_LEX_LUA,
|
||||
-- scintilla lexer
|
||||
|
||||
lexerstyleconvert = {
|
||||
-- table mapping each styles to
|
||||
-- appropriate lexer id
|
||||
stringeol = {wxstc.wxSTC_LUA_STRINGEOL,},
|
||||
-- ...
|
||||
}
|
||||
|
||||
linecomment = "//",
|
||||
-- string for linecomments
|
||||
|
||||
sep = "[%.:]",
|
||||
-- class.function separator match string,
|
||||
-- e.g in lua both . and : are allowed
|
||||
-- default is "\1" which should yield no matches
|
||||
-- and therefore disable class.func type autocompletion
|
||||
|
||||
isfncall = function(str) return from,to end
|
||||
-- function that detects positions for a substring that
|
||||
-- stands for a functioncall, ie " call(..)" -> 2,5
|
||||
|
||||
apitype = "api",
|
||||
-- which sub directory of "api" is relevant
|
||||
-- api files handle autocomplete and tooltips
|
||||
-- api won't affect syntax coloring
|
||||
|
||||
keywords = {
|
||||
-- up to 8 strings containing space separated keywords
|
||||
-- used by the lexer for coloring (NOT for autocomplete).
|
||||
-- however each lexer supports varying amount
|
||||
-- of keyword types
|
||||
|
||||
"foo bar word",
|
||||
"more words",
|
||||
}
|
||||
}
|
||||
|
||||
-- tool definition
|
||||
-- ----------------------------------------------------
|
||||
-- main entries are optional
|
||||
tool = {
|
||||
fninit = function(frame,menubar) end,
|
||||
-- guarantees that ide is initialized
|
||||
-- can be used for init
|
||||
-- and adding custom menu
|
||||
|
||||
exec = {
|
||||
-- quick exec action, listed under "Tools" menu
|
||||
name = "",
|
||||
description = "",
|
||||
fn = function(wxfilename,projectdir) end,
|
||||
}
|
||||
}
|
||||
|
||||
-- debuginterface definition
|
||||
-- ----------------------------------------------------
|
||||
debuginterface = {
|
||||
update = function(self) end, -- run in idle when active
|
||||
close = function(self) end, -- run when closed
|
||||
|
||||
-- following are "debugging" actions and must return
|
||||
-- error, running, [filePath, fileLine]
|
||||
run = function(self) end,
|
||||
step = function(self) end,
|
||||
over = function(self) end,
|
||||
out = function(self) end,
|
||||
terminate = function(self) end,
|
||||
breaknow = function(self) end,
|
||||
breakpoint = function(self,file,line,state) end, -- set breakpoint state
|
||||
|
||||
-- returns result table if successful
|
||||
evaluate = function(self, expressions, fnSetValues) end, -- for watches tables expected
|
||||
|
||||
-- NYI getstack = function(self, fnSetValues ) end, -- get stack information
|
||||
}
|
||||
|
||||
-- interpreter definition-- ----------------------------------------------------
|
||||
interpreter = {
|
||||
name = "",
|
||||
description = "",
|
||||
api = {"apifile_without_extension"} -- optional to limit loaded lua apis
|
||||
frun = function(self,wfilename,withdebugger)
|
||||
end,
|
||||
fprojdir = function(self,wfilename)
|
||||
return "projpath_from_filename" -- optional
|
||||
end,
|
||||
fattachdebug = function(self) end, -- optional
|
||||
hasdebugger = false, -- if debugging is available
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,470 +1,523 @@
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
local frame = ide.frame
|
||||
local splitter = ide.frame.vsplitter.splitter
|
||||
local notebook = splitter.notebook
|
||||
local openDocuments = ide.openDocuments
|
||||
|
||||
function NewFile(event)
|
||||
local editor = CreateEditor("untitled.lua")
|
||||
SetupKeywords(editor, "lua")
|
||||
end
|
||||
|
||||
-- Find an editor page that hasn't been used at all, eg. an untouched NewFile()
|
||||
local function findDocumentToReuse()
|
||||
local editor = nil
|
||||
for id, document in pairs(openDocuments) do
|
||||
if (document.editor:GetLength() == 0) and
|
||||
(not document.isModified) and (not document.filePath) and
|
||||
not (document.editor:GetReadOnly() == true) then
|
||||
editor = document.editor
|
||||
break
|
||||
end
|
||||
end
|
||||
return editor
|
||||
end
|
||||
|
||||
function LoadFile(filePath, editor, file_must_exist)
|
||||
filePath = filePath:gsub("\\","/")
|
||||
|
||||
-- prevent files from being reopened again
|
||||
if (not editor) then
|
||||
for id, doc in pairs(openDocuments) do
|
||||
if doc.filePath == filePath then
|
||||
notebook:SetSelection(doc.index)
|
||||
return doc.editor
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if not opened yet, try open now
|
||||
local file_text = ""
|
||||
local handle = io.open(filePath, "rb")
|
||||
if handle then
|
||||
file_text = handle:read("*a")
|
||||
if GetConfigIOFilter("input") then
|
||||
file_text = GetConfigIOFilter("input")(filePath,file_text)
|
||||
end
|
||||
handle:close()
|
||||
elseif file_must_exist then
|
||||
return nil
|
||||
end
|
||||
|
||||
if not editor then
|
||||
editor = findDocumentToReuse()
|
||||
end
|
||||
if not editor then
|
||||
editor = CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
|
||||
end
|
||||
|
||||
editor:Clear()
|
||||
editor:ClearAll()
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
editor:MarkerDeleteAll(BREAKPOINT_MARKER)
|
||||
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
editor:AppendText(file_text)
|
||||
if (ide.config.editor.autotabs) then
|
||||
local found = string.find(file_text,"\t") ~= nil
|
||||
editor:SetUseTabs(found)
|
||||
end
|
||||
|
||||
editor:EmptyUndoBuffer()
|
||||
local id = editor:GetId()
|
||||
openDocuments[id].filePath = filePath
|
||||
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
|
||||
openDocuments[id].modTime = GetFileModTime(filePath)
|
||||
SetDocumentModified(id, false)
|
||||
editor:Colourise(0, -1)
|
||||
|
||||
AddDynamicWords(editor)
|
||||
IndicateFunctions(editor)
|
||||
|
||||
SettingsAppendFileToHistory(filePath)
|
||||
|
||||
return editor
|
||||
end
|
||||
|
||||
local function getExtsString()
|
||||
local knownexts = ""
|
||||
for i,spec in pairs(ide.specs) do
|
||||
if (spec.exts) then
|
||||
for n,ext in ipairs(spec.exts) do
|
||||
knownexts = knownexts.."*."..ext..";"
|
||||
end
|
||||
end
|
||||
end
|
||||
knownexts = knownexts:len() > 0 and knownexts:sub(1,-2) or nil
|
||||
|
||||
local exts = knownexts and "Known Files ("..knownexts..")|"..knownexts.."|" or ""
|
||||
exts = exts.."All files (*)|*"
|
||||
|
||||
return exts
|
||||
end
|
||||
|
||||
function OpenFile(event)
|
||||
|
||||
local exts = getExtsString()
|
||||
|
||||
local fileDialog = wx.wxFileDialog(ide.frame, "Open file",
|
||||
"",
|
||||
"",
|
||||
exts,
|
||||
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
if not LoadFile(fileDialog:GetPath(), nil, true) then
|
||||
wx.wxMessageBox("Unable to load file '"..fileDialog:GetPath().."'.",
|
||||
"wxLua Error",
|
||||
wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
end
|
||||
end
|
||||
fileDialog:Destroy()
|
||||
end
|
||||
|
||||
-- save the file to filePath or if filePath is nil then call SaveFileAs
|
||||
function SaveFile(editor, filePath)
|
||||
if not filePath then
|
||||
return SaveFileAs(editor)
|
||||
else
|
||||
filePath = filePath:gsub("\\","/")
|
||||
|
||||
if (ide.config.savebak) then
|
||||
local backPath = filePath..".bak"
|
||||
os.remove(backPath)
|
||||
os.rename(filePath, backPath)
|
||||
end
|
||||
|
||||
local handle = io.open(filePath, "wb")
|
||||
if handle then
|
||||
local st = editor:GetText()
|
||||
|
||||
if GetConfigIOFilter("output") then
|
||||
st = GetConfigIOFilter("output")(filePath,st)
|
||||
end
|
||||
handle:write(st)
|
||||
handle:close()
|
||||
--editor:EmptyUndoBuffer()
|
||||
editor:SetSavePoint()
|
||||
local id = editor:GetId()
|
||||
openDocuments[id].filePath = filePath
|
||||
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
|
||||
openDocuments[id].modTime = GetFileModTime(filePath)
|
||||
SetDocumentModified(id, false)
|
||||
return true
|
||||
else
|
||||
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
|
||||
"wxLua Error Saving",
|
||||
wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SaveFileAs(editor)
|
||||
local id = editor:GetId()
|
||||
local saved = false
|
||||
local filePath = openDocuments[id].filePath
|
||||
if (not filePath) then
|
||||
filePath = GetFileTreeDir()
|
||||
filePath = (filePath or "").."untitled"
|
||||
end
|
||||
|
||||
local fn = wx.wxFileName(filePath)
|
||||
fn:Normalize() -- want absolute path for dialog
|
||||
|
||||
local exts = getExtsString()
|
||||
|
||||
local fileDialog = wx.wxFileDialog(ide.frame, "Save file as",
|
||||
fn:GetPath(wx.wxPATH_GET_VOLUME),
|
||||
fn:GetFullName(),
|
||||
exts,
|
||||
wx.wxSAVE)
|
||||
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
local filePath = fileDialog:GetPath()
|
||||
|
||||
if SaveFile(editor, filePath) then
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
IndicateFunctions(editor)
|
||||
saved = true
|
||||
end
|
||||
end
|
||||
|
||||
fileDialog:Destroy()
|
||||
return saved
|
||||
end
|
||||
|
||||
function SaveAll()
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
local filePath = document.filePath
|
||||
|
||||
if document.isModified then
|
||||
SaveFile(editor, filePath) -- will call SaveFileAs if necessary
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function RemovePage(index)
|
||||
local prevIndex = nil
|
||||
local nextIndex = nil
|
||||
--local newOpenDocuments = {}
|
||||
|
||||
local delid = nil
|
||||
for id, document in pairs(openDocuments) do
|
||||
if document.index < index then
|
||||
--newOpenDocuments[id] = document
|
||||
prevIndex = document.index
|
||||
elseif document.index == index then
|
||||
delid = id
|
||||
document.editor:Destroy()
|
||||
elseif document.index > index then
|
||||
document.index = document.index - 1
|
||||
if nextIndex == nil then
|
||||
nextIndex = document.index
|
||||
end
|
||||
--newOpenDocuments[id] = document
|
||||
end
|
||||
end
|
||||
|
||||
if (delid) then
|
||||
openDocuments[delid] = nil
|
||||
end
|
||||
|
||||
notebook:RemovePage(index)
|
||||
|
||||
if nextIndex then
|
||||
notebook:SetSelection(nextIndex)
|
||||
elseif prevIndex then
|
||||
notebook:SetSelection(prevIndex)
|
||||
end
|
||||
|
||||
SetEditorSelection(nil) -- will use notebook GetSelection to update
|
||||
end
|
||||
|
||||
-- Show a dialog to save a file before closing editor.
|
||||
-- returns wxID_YES, wxID_NO, or wxID_CANCEL if allow_cancel
|
||||
function SaveModifiedDialog(editor, allow_cancel)
|
||||
local result = wx.wxID_NO
|
||||
local id = editor:GetId()
|
||||
local document = openDocuments[id]
|
||||
local filePath = document.filePath
|
||||
local fileName = document.fileName
|
||||
if document.isModified then
|
||||
local message
|
||||
if fileName then
|
||||
message = "Save changes to '"..fileName.."' before exiting?"
|
||||
else
|
||||
message = "Save changes to 'untitled' before exiting?"
|
||||
end
|
||||
local dlg_styles = wx.wxYES_NO + wx.wxCENTRE + wx.wxICON_QUESTION
|
||||
if allow_cancel then dlg_styles = dlg_styles + wx.wxCANCEL end
|
||||
local dialog = wx.wxMessageDialog(ide.frame, message,
|
||||
"Save Changes?",
|
||||
dlg_styles)
|
||||
result = dialog:ShowModal()
|
||||
dialog:Destroy()
|
||||
if result == wx.wxID_YES then
|
||||
SaveFile(editor, filePath)
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function SaveOnExit(allow_cancel)
|
||||
for id, document in pairs(openDocuments) do
|
||||
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
|
||||
return false
|
||||
end
|
||||
|
||||
document.isModified = false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function FoldSome()
|
||||
local editor = GetEditor()
|
||||
editor:Colourise(0, -1) -- update doc's folding info
|
||||
local visible, baseFound, expanded, folded
|
||||
for ln = 2, editor.LineCount - 1 do
|
||||
local foldRaw = editor:GetFoldLevel(ln)
|
||||
local foldLvl = math.mod(foldRaw, 4096)
|
||||
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
|
||||
if not baseFound and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
|
||||
baseFound = true
|
||||
visible = editor:GetLineVisible(ln)
|
||||
end
|
||||
if foldHdr then
|
||||
if editor:GetFoldExpanded(ln) then
|
||||
expanded = true
|
||||
else
|
||||
folded = true
|
||||
end
|
||||
end
|
||||
if expanded and folded and baseFound then break end
|
||||
end
|
||||
local show = not visible or (not baseFound and expanded) or (expanded and folded)
|
||||
local hide = visible and folded
|
||||
|
||||
if show then
|
||||
editor:ShowLines(1, editor.LineCount-1)
|
||||
end
|
||||
|
||||
for ln = 1, editor.LineCount - 1 do
|
||||
local foldRaw = editor:GetFoldLevel(ln)
|
||||
local foldLvl = math.mod(foldRaw, 4096)
|
||||
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
|
||||
if show then
|
||||
if foldHdr then
|
||||
if not editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
|
||||
end
|
||||
elseif hide and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
|
||||
if not foldHdr then
|
||||
editor:HideLines(ln, ln)
|
||||
end
|
||||
elseif foldHdr then
|
||||
if editor:GetFoldExpanded(ln) then
|
||||
editor:ToggleFold(ln)
|
||||
end
|
||||
end
|
||||
end
|
||||
editor:EnsureCaretVisible()
|
||||
end
|
||||
|
||||
function EnsureRangeVisible(posStart, posEnd)
|
||||
local editor = GetEditor()
|
||||
if posStart > posEnd then
|
||||
posStart, posEnd = posEnd, posStart
|
||||
end
|
||||
|
||||
local lineStart = editor:LineFromPosition(posStart)
|
||||
local lineEnd = editor:LineFromPosition(posEnd)
|
||||
for line = lineStart, lineEnd do
|
||||
editor:EnsureVisibleEnforcePolicy(line)
|
||||
end
|
||||
end
|
||||
|
||||
function SetAllEditorsReadOnly(enable)
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:SetReadOnly(enable)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------
|
||||
-- Debug related
|
||||
|
||||
function ClearAllCurrentLineMarkers()
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
end
|
||||
end
|
||||
|
||||
function CompileProgram(editor)
|
||||
local editorText = editor:GetText()
|
||||
local id = editor:GetId()
|
||||
local filePath = MakeDebugFileName(editor, openDocuments[id].filePath)
|
||||
local ret, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
|
||||
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then
|
||||
ClearOutput()
|
||||
end
|
||||
|
||||
if line_num > -1 then
|
||||
DisplayOutput("Compilation error on line number :"..tostring(line_num).."\n"..errMsg.."\n")
|
||||
editor:GotoLine(line_num-1)
|
||||
else
|
||||
DisplayOutput("Compilation successful.\n")
|
||||
end
|
||||
|
||||
return line_num == -1 -- return true if it compiled ok
|
||||
end
|
||||
|
||||
------------------
|
||||
-- Save & Close
|
||||
|
||||
function SaveIfModified(editor)
|
||||
local id = editor:GetId()
|
||||
if openDocuments[id].isModified then
|
||||
local saved = false
|
||||
if not openDocuments[id].filePath then
|
||||
local ret = wx.wxMessageBox("You must save the program before running it.\nPress cancel to abort running.",
|
||||
"Save file?", wx.wxOK + wx.wxCANCEL + wx.wxCENTRE, ide.frame)
|
||||
if ret == wx.wxOK then
|
||||
saved = SaveFileAs(editor)
|
||||
end
|
||||
else
|
||||
saved = SaveFile(editor, openDocuments[id].filePath)
|
||||
end
|
||||
|
||||
if saved then
|
||||
openDocuments[id].isModified = false
|
||||
else
|
||||
return false -- not saved
|
||||
end
|
||||
end
|
||||
|
||||
return true -- saved
|
||||
end
|
||||
|
||||
function GetOpenFiles()
|
||||
local opendocs = {}
|
||||
for id, document in pairs(ide.openDocuments) do
|
||||
if (document.filePath) then
|
||||
local wxfname = wx.wxFileName(document.filePath)
|
||||
wxfname:Normalize()
|
||||
|
||||
table.insert(opendocs,{fname=wxfname:GetFullPath(),id=document.index,
|
||||
cursorpos = document.editor:GetCurrentPos()})
|
||||
end
|
||||
end
|
||||
|
||||
-- to keep tab order
|
||||
table.sort(opendocs,function(a,b) return (a.id < b.id) end)
|
||||
|
||||
local openfiles = {}
|
||||
for i,doc in ipairs(opendocs) do
|
||||
table.insert(openfiles,{filename = doc.fname, cursorpos = doc.cursorpos} )
|
||||
end
|
||||
|
||||
local id = GetEditor()
|
||||
id = id and id:GetId()
|
||||
|
||||
return openfiles, id and openDocuments[id].index or 0
|
||||
end
|
||||
|
||||
function SetOpenFiles(nametab,index)
|
||||
for i,doc in ipairs(nametab) do
|
||||
local editor = LoadFile(doc.filename,nil,true)
|
||||
if editor then
|
||||
editor:SetCurrentPos(doc.cursorpos or 0)
|
||||
editor:SetSelectionStart(doc.cursorpos or 0)
|
||||
editor:SetSelectionEnd(doc.cursorpos or 0)
|
||||
editor:EnsureCaretVisible()
|
||||
end
|
||||
end
|
||||
notebook:SetSelection(index or 0)
|
||||
end
|
||||
|
||||
function CloseWindow(event)
|
||||
exitingProgram = true -- don't handle focus events
|
||||
|
||||
if not SaveOnExit(event:CanVeto()) then
|
||||
event:Veto()
|
||||
exitingProgram = false
|
||||
return
|
||||
end
|
||||
|
||||
SettingsSaveProjectSession(GetProjects())
|
||||
SettingsSaveFileSession(GetOpenFiles())
|
||||
SettingsSaveView()
|
||||
SettingsSaveFramePosition(ide.frame, "MainFrame")
|
||||
SettingsSaveEditorSettings()
|
||||
CloseWatchWindow()
|
||||
ide.settings:delete() -- always delete the config
|
||||
event:Skip()
|
||||
end
|
||||
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
local frame = ide.frame
|
||||
local notebook = frame.notebook
|
||||
local openDocuments = ide.openDocuments
|
||||
local uimgr = frame.uimgr
|
||||
|
||||
function NewFile(event)
|
||||
local editor = CreateEditor("untitled.lua")
|
||||
SetupKeywords(editor, "lua")
|
||||
end
|
||||
|
||||
-- Find an editor page that hasn't been used at all, eg. an untouched NewFile()
|
||||
local function findDocumentToReuse()
|
||||
local editor = nil
|
||||
for id, document in pairs(openDocuments) do
|
||||
if (document.editor:GetLength() == 0) and
|
||||
(not document.isModified) and (not document.filePath) and
|
||||
not (document.editor:GetReadOnly() == true) then
|
||||
editor = document.editor
|
||||
break
|
||||
end
|
||||
end
|
||||
return editor
|
||||
end
|
||||
|
||||
function LoadFile(filePath, editor, file_must_exist)
|
||||
filePath = wx.wxFileName(filePath):GetFullPath()
|
||||
local cmpName = string.lower(string.gsub(filePath, "\\", "/"))
|
||||
|
||||
-- prevent files from being reopened again
|
||||
if (not editor) then
|
||||
for id, doc in pairs(openDocuments) do
|
||||
local docName = doc.filePath and string.lower(string.gsub(doc.filePath, "\\", "/"))
|
||||
if cmpName == docName then
|
||||
notebook:SetSelection(doc.index)
|
||||
return doc.editor
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if not opened yet, try open now
|
||||
local file_text = ""
|
||||
local handle = io.open(filePath, "rb")
|
||||
if handle then
|
||||
file_text = handle:read("*a")
|
||||
if GetConfigIOFilter("input") then
|
||||
file_text = GetConfigIOFilter("input")(filePath,file_text)
|
||||
end
|
||||
handle:close()
|
||||
elseif file_must_exist then
|
||||
return nil
|
||||
end
|
||||
|
||||
local current = editor and editor:GetCurrentPos()
|
||||
editor = editor
|
||||
or findDocumentToReuse()
|
||||
or CreateEditor(wx.wxFileName(filePath):GetFullName() or "untitled.lua")
|
||||
|
||||
editor:Clear()
|
||||
editor:ClearAll()
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
editor:MarkerDeleteAll(BREAKPOINT_MARKER)
|
||||
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
editor:AppendText(file_text)
|
||||
if current then editor:GotoPos(current) end
|
||||
if (ide.config.editor.autotabs) then
|
||||
local found = string.find(file_text,"\t") ~= nil
|
||||
editor:SetUseTabs(found)
|
||||
end
|
||||
|
||||
editor:EmptyUndoBuffer()
|
||||
local id = editor:GetId()
|
||||
openDocuments[id].filePath = filePath
|
||||
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
|
||||
openDocuments[id].modTime = GetFileModTime(filePath)
|
||||
SetDocumentModified(id, false)
|
||||
editor:Colourise(0, -1)
|
||||
|
||||
IndicateFunctions(editor)
|
||||
|
||||
SettingsAppendFileToHistory(filePath)
|
||||
|
||||
-- activate the editor; this is needed for those cases when the editor is
|
||||
-- created from some other element, for example, from a project tree.
|
||||
SetEditorSelection()
|
||||
|
||||
return editor
|
||||
end
|
||||
|
||||
local function getExtsString()
|
||||
local knownexts = ""
|
||||
for i,spec in pairs(ide.specs) do
|
||||
if (spec.exts) then
|
||||
for n,ext in ipairs(spec.exts) do
|
||||
knownexts = knownexts.."*."..ext..";"
|
||||
end
|
||||
end
|
||||
end
|
||||
knownexts = knownexts:len() > 0 and knownexts:sub(1,-2) or nil
|
||||
|
||||
local exts = knownexts and "Known Files ("..knownexts..")|"..knownexts.."|" or ""
|
||||
exts = exts.."All files (*)|*"
|
||||
|
||||
return exts
|
||||
end
|
||||
|
||||
function OpenFile(event)
|
||||
|
||||
local exts = getExtsString()
|
||||
|
||||
local fileDialog = wx.wxFileDialog(ide.frame, "Open file",
|
||||
"",
|
||||
"",
|
||||
exts,
|
||||
wx.wxOPEN + wx.wxFILE_MUST_EXIST)
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
if not LoadFile(fileDialog:GetPath(), nil, true) then
|
||||
wx.wxMessageBox("Unable to load file '"..fileDialog:GetPath().."'.",
|
||||
"Error",
|
||||
wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
end
|
||||
end
|
||||
fileDialog:Destroy()
|
||||
end
|
||||
|
||||
-- save the file to filePath or if filePath is nil then call SaveFileAs
|
||||
function SaveFile(editor, filePath)
|
||||
if not filePath then
|
||||
return SaveFileAs(editor)
|
||||
else
|
||||
if (ide.config.savebak) then
|
||||
local backPath = filePath..".bak"
|
||||
os.remove(backPath)
|
||||
os.rename(filePath, backPath)
|
||||
end
|
||||
|
||||
local handle = io.open(filePath, "wb")
|
||||
if handle then
|
||||
local st = editor:GetText()
|
||||
|
||||
if GetConfigIOFilter("output") then
|
||||
st = GetConfigIOFilter("output")(filePath,st)
|
||||
end
|
||||
handle:write(st)
|
||||
handle:close()
|
||||
--editor:EmptyUndoBuffer()
|
||||
editor:SetSavePoint()
|
||||
local id = editor:GetId()
|
||||
openDocuments[id].filePath = filePath
|
||||
openDocuments[id].fileName = wx.wxFileName(filePath):GetFullName()
|
||||
openDocuments[id].modTime = GetFileModTime(filePath)
|
||||
SetDocumentModified(id, false)
|
||||
return true
|
||||
else
|
||||
wx.wxMessageBox("Unable to save file '"..filePath.."'.",
|
||||
"Error",
|
||||
wx.wxOK + wx.wxCENTRE, ide.frame)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SaveFileAs(editor)
|
||||
local id = editor:GetId()
|
||||
local saved = false
|
||||
local filePath = openDocuments[id].filePath
|
||||
if (not filePath) then
|
||||
filePath = FileTreeGetDir()
|
||||
filePath = (filePath or "").."untitled"
|
||||
end
|
||||
|
||||
local fn = wx.wxFileName(filePath)
|
||||
fn:Normalize() -- want absolute path for dialog
|
||||
|
||||
local exts = getExtsString()
|
||||
|
||||
local fileDialog = wx.wxFileDialog(ide.frame, "Save file as",
|
||||
fn:GetPath(wx.wxPATH_GET_VOLUME),
|
||||
fn:GetFullName(),
|
||||
exts,
|
||||
wx.wxSAVE)
|
||||
|
||||
if fileDialog:ShowModal() == wx.wxID_OK then
|
||||
local filePath = fileDialog:GetPath()
|
||||
|
||||
if SaveFile(editor, filePath) then
|
||||
SetupKeywords(editor, GetFileExt(filePath))
|
||||
IndicateFunctions(editor)
|
||||
if MarkupStyle then MarkupStyle(editor) end
|
||||
saved = true
|
||||
end
|
||||
end
|
||||
|
||||
fileDialog:Destroy()
|
||||
return saved
|
||||
end
|
||||
|
||||
function SaveAll()
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
local filePath = document.filePath
|
||||
|
||||
if document.isModified then
|
||||
SaveFile(editor, filePath) -- will call SaveFileAs if necessary
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function removePage(index)
|
||||
local prevIndex = nil
|
||||
local nextIndex = nil
|
||||
|
||||
-- try to preserve old selection
|
||||
local selectIndex = notebook:GetSelection()
|
||||
selectIndex = selectIndex ~= index and selectIndex
|
||||
|
||||
local delid = nil
|
||||
for id, document in pairsSorted(openDocuments,
|
||||
function(a, b) -- sort by document index
|
||||
return openDocuments[a].index < openDocuments[b].index
|
||||
end) do
|
||||
local wasselected = document.index == selectIndex
|
||||
if document.index < index then
|
||||
prevIndex = document.index
|
||||
elseif document.index == index then
|
||||
delid = id
|
||||
document.editor:Destroy()
|
||||
elseif document.index > index then
|
||||
document.index = document.index - 1
|
||||
if nextIndex == nil then
|
||||
nextIndex = document.index
|
||||
end
|
||||
end
|
||||
if (wasselected) then
|
||||
selectIndex = document.index
|
||||
end
|
||||
end
|
||||
|
||||
if (delid) then
|
||||
openDocuments[delid] = nil
|
||||
end
|
||||
|
||||
notebook:RemovePage(index)
|
||||
|
||||
if selectIndex then
|
||||
notebook:SetSelection(selectIndex)
|
||||
elseif nextIndex then
|
||||
notebook:SetSelection(nextIndex)
|
||||
elseif prevIndex then
|
||||
notebook:SetSelection(prevIndex)
|
||||
end
|
||||
|
||||
SetEditorSelection() -- will use notebook GetSelection to update
|
||||
end
|
||||
|
||||
function ClosePage(selection)
|
||||
local editor = GetEditor(selection)
|
||||
local id = editor:GetId()
|
||||
if SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL then
|
||||
DynamicWordsRemoveAll(editor)
|
||||
local debugger = ide.debugger
|
||||
-- check if the window with the scratchpad running is being closed
|
||||
if debugger and debugger.scratchpad and debugger.scratchpad.editor == editor then
|
||||
DebuggerScratchpadOff()
|
||||
end
|
||||
-- check if the debugger is running and is using the current window
|
||||
-- abort the debugger if the current marker is in the window being closed
|
||||
-- also abort the debugger if it is running, as we don't know what
|
||||
-- window will need to be activated when the debugger is paused
|
||||
if debugger and debugger.pid and
|
||||
(debugger.running or editor:MarkerNext(0, CURRENT_LINE_MARKER_VALUE) >= 0) then
|
||||
debugger.terminate()
|
||||
end
|
||||
removePage(ide.openDocuments[id].index)
|
||||
end
|
||||
end
|
||||
|
||||
-- Show a dialog to save a file before closing editor.
|
||||
-- returns wxID_YES, wxID_NO, or wxID_CANCEL if allow_cancel
|
||||
function SaveModifiedDialog(editor, allow_cancel)
|
||||
local result = wx.wxID_NO
|
||||
local id = editor:GetId()
|
||||
local document = openDocuments[id]
|
||||
local filePath = document.filePath
|
||||
local fileName = document.fileName
|
||||
if document.isModified then
|
||||
local message = "Do you want to save the changes to '"..(fileName or 'untitled').."'?"
|
||||
local dlg_styles = wx.wxYES_NO + wx.wxCENTRE + wx.wxICON_QUESTION
|
||||
if allow_cancel then dlg_styles = dlg_styles + wx.wxCANCEL end
|
||||
local dialog = wx.wxMessageDialog(ide.frame, message,
|
||||
"Save Changes?",
|
||||
dlg_styles)
|
||||
result = dialog:ShowModal()
|
||||
dialog:Destroy()
|
||||
if result == wx.wxID_YES then
|
||||
if not SaveFile(editor, filePath) then
|
||||
return wx.wxID_CANCEL -- cancel if canceled save dialog
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function SaveOnExit(allow_cancel)
|
||||
for id, document in pairs(openDocuments) do
|
||||
if (SaveModifiedDialog(document.editor, allow_cancel) == wx.wxID_CANCEL) then
|
||||
return false
|
||||
end
|
||||
|
||||
document.isModified = false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function FoldSome()
|
||||
local editor = GetEditor()
|
||||
editor:Colourise(0, -1) -- update doc's folding info
|
||||
local visible, baseFound, expanded, folded
|
||||
for ln = 2, editor.LineCount - 1 do
|
||||
local foldRaw = editor:GetFoldLevel(ln)
|
||||
local foldLvl = math.mod(foldRaw, 4096)
|
||||
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
|
||||
if not baseFound and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
|
||||
baseFound = true
|
||||
visible = editor:GetLineVisible(ln)
|
||||
end
|
||||
if foldHdr then
|
||||
if editor:GetFoldExpanded(ln) then
|
||||
expanded = true
|
||||
else
|
||||
folded = true
|
||||
end
|
||||
end
|
||||
if expanded and folded and baseFound then break end
|
||||
end
|
||||
local show = not visible or (not baseFound and expanded) or (expanded and folded)
|
||||
local hide = visible and folded
|
||||
|
||||
if show then
|
||||
editor:ShowLines(1, editor.LineCount-1)
|
||||
end
|
||||
|
||||
for ln = 1, editor.LineCount - 1 do
|
||||
local foldRaw = editor:GetFoldLevel(ln)
|
||||
local foldLvl = math.mod(foldRaw, 4096)
|
||||
local foldHdr = math.mod(math.floor(foldRaw / 8192), 2) == 1
|
||||
if show then
|
||||
if foldHdr then
|
||||
if not editor:GetFoldExpanded(ln) then editor:ToggleFold(ln) end
|
||||
end
|
||||
elseif hide and (foldLvl == wxstc.wxSTC_FOLDLEVELBASE) then
|
||||
if not foldHdr then
|
||||
editor:HideLines(ln, ln)
|
||||
end
|
||||
elseif foldHdr then
|
||||
if editor:GetFoldExpanded(ln) then
|
||||
editor:ToggleFold(ln)
|
||||
end
|
||||
end
|
||||
end
|
||||
editor:EnsureCaretVisible()
|
||||
end
|
||||
|
||||
function EnsureRangeVisible(posStart, posEnd)
|
||||
local editor = GetEditor()
|
||||
if posStart > posEnd then
|
||||
posStart, posEnd = posEnd, posStart
|
||||
end
|
||||
|
||||
local lineStart = editor:LineFromPosition(posStart)
|
||||
local lineEnd = editor:LineFromPosition(posEnd)
|
||||
for line = lineStart, lineEnd do
|
||||
editor:EnsureVisibleEnforcePolicy(line)
|
||||
end
|
||||
end
|
||||
|
||||
function SetAllEditorsReadOnly(enable)
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:SetReadOnly(enable)
|
||||
end
|
||||
end
|
||||
|
||||
-----------------
|
||||
-- Debug related
|
||||
|
||||
function ClearAllCurrentLineMarkers()
|
||||
for id, document in pairs(openDocuments) do
|
||||
local editor = document.editor
|
||||
editor:MarkerDeleteAll(CURRENT_LINE_MARKER)
|
||||
end
|
||||
end
|
||||
|
||||
function CompileProgram(editor, quiet)
|
||||
local editorText = editor:GetText()
|
||||
local id = editor:GetId()
|
||||
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
|
||||
local _, errMsg, line_num = wxlua.CompileLuaScript(editorText, filePath)
|
||||
|
||||
if ide.frame.menuBar:IsChecked(ID_CLEAROUTPUT) then ClearOutput() end
|
||||
|
||||
if line_num > -1 then
|
||||
DisplayOutput("Compilation error on line "..tostring(line_num)..":\n"..
|
||||
errMsg:gsub("Lua:.-\n", "").."\n")
|
||||
if not quiet then editor:GotoLine(line_num-1) end
|
||||
else
|
||||
if not quiet then DisplayOutput("Compilation successful.\n") end
|
||||
end
|
||||
|
||||
return line_num == -1 -- return true if it compiled ok
|
||||
end
|
||||
|
||||
------------------
|
||||
-- Save & Close
|
||||
|
||||
function SaveIfModified(editor)
|
||||
local id = editor:GetId()
|
||||
if openDocuments[id].isModified then
|
||||
local saved = false
|
||||
if not openDocuments[id].filePath then
|
||||
local ret = wx.wxMessageBox("You must save the program before running it.\nPress cancel to abort running.",
|
||||
"Save file?", wx.wxOK + wx.wxCANCEL + wx.wxCENTRE, ide.frame)
|
||||
if ret == wx.wxOK then
|
||||
saved = SaveFileAs(editor)
|
||||
end
|
||||
else
|
||||
saved = SaveFile(editor, openDocuments[id].filePath)
|
||||
end
|
||||
|
||||
if saved then
|
||||
openDocuments[id].isModified = false
|
||||
else
|
||||
return false -- not saved
|
||||
end
|
||||
end
|
||||
|
||||
return true -- saved
|
||||
end
|
||||
|
||||
function GetOpenFiles()
|
||||
local opendocs = {}
|
||||
for id, document in pairs(ide.openDocuments) do
|
||||
if (document.filePath) then
|
||||
local wxfname = wx.wxFileName(document.filePath)
|
||||
wxfname:Normalize()
|
||||
|
||||
table.insert(opendocs,{fname=wxfname:GetFullPath(),id=document.index,
|
||||
cursorpos = document.editor:GetCurrentPos()})
|
||||
end
|
||||
end
|
||||
|
||||
-- to keep tab order
|
||||
table.sort(opendocs,function(a,b) return (a.id < b.id) end)
|
||||
|
||||
local openfiles = {}
|
||||
for i,doc in ipairs(opendocs) do
|
||||
table.insert(openfiles,{filename = doc.fname, cursorpos = doc.cursorpos} )
|
||||
end
|
||||
|
||||
local id = GetEditor()
|
||||
id = id and id:GetId()
|
||||
|
||||
return openfiles, id and openDocuments[id].index or 0
|
||||
end
|
||||
|
||||
function SetOpenFiles(nametab,index)
|
||||
for i,doc in ipairs(nametab) do
|
||||
local editor = LoadFile(doc.filename,nil,true)
|
||||
if editor then
|
||||
editor:SetCurrentPos(doc.cursorpos or 0)
|
||||
editor:SetSelectionStart(doc.cursorpos or 0)
|
||||
editor:SetSelectionEnd(doc.cursorpos or 0)
|
||||
editor:EnsureCaretVisible()
|
||||
end
|
||||
end
|
||||
notebook:SetSelection(index or 0)
|
||||
end
|
||||
|
||||
local beforeFullScreenPerspective
|
||||
function ShowFullScreen(setFullScreen)
|
||||
if setFullScreen then
|
||||
beforeFullScreenPerspective = uimgr:SavePerspective()
|
||||
uimgr:GetPane("bottomnotebook"):Show(false)
|
||||
uimgr:GetPane("projpanel"):Show(false)
|
||||
SetEditorSelection() -- make sure the focus is on the editor
|
||||
elseif beforeFullScreenPerspective then
|
||||
uimgr:LoadPerspective(beforeFullScreenPerspective)
|
||||
beforeFullScreenPerspective = nil
|
||||
end
|
||||
|
||||
uimgr:GetPane("toolBar"):Show(not setFullScreen)
|
||||
uimgr:Update()
|
||||
frame:ShowFullScreen(setFullScreen)
|
||||
end
|
||||
|
||||
function CloseWindow(event)
|
||||
ide.exitingProgram = true -- don't handle focus events
|
||||
|
||||
if not SaveOnExit(event:CanVeto()) then
|
||||
event:Veto()
|
||||
ide.exitingProgram = false
|
||||
return
|
||||
end
|
||||
|
||||
ShowFullScreen(false)
|
||||
SettingsSaveProjectSession(FileTreeGetProjects())
|
||||
SettingsSaveFileSession(GetOpenFiles())
|
||||
SettingsSaveView()
|
||||
SettingsSaveFramePosition(ide.frame, "MainFrame")
|
||||
SettingsSaveEditorSettings()
|
||||
DebuggerCloseWatchWindow()
|
||||
DebuggerCloseStackWindow()
|
||||
DebuggerShutdown()
|
||||
ide.settings:delete() -- always delete the config
|
||||
event:Skip()
|
||||
end
|
||||
frame:Connect(wx.wxEVT_CLOSE_WINDOW, CloseWindow)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,254 +1,323 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
--
|
||||
-- filetree, treectrl for drive & project
|
||||
--
|
||||
|
||||
ide.filetree = {
|
||||
dirdriveText = "",
|
||||
dirdriveTextArray = {},
|
||||
|
||||
projdirText = "",
|
||||
projdirTextArray = {},
|
||||
|
||||
showroot = true,
|
||||
|
||||
dirdata = {
|
||||
root_id = nil,
|
||||
rootdir = "",
|
||||
},
|
||||
|
||||
projdata = {
|
||||
root_id = nil,
|
||||
rootdir = "",
|
||||
},
|
||||
imglist,
|
||||
|
||||
newfiledir,
|
||||
}
|
||||
local filetree = ide.filetree
|
||||
local frame = ide.frame
|
||||
local sidenotebook = ide.frame.vsplitter.sidenotebook
|
||||
|
||||
|
||||
-- generic tree
|
||||
-- ------------
|
||||
|
||||
do
|
||||
filetree.imglist = wx.wxImageList(16,16)
|
||||
-- 0 = directory
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_FOLDER,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
|
||||
-- 1 = file known spec
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_HELP_PAGE ,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
|
||||
-- 2 = file rest
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetIcon(wx.wxART_NORMAL_FILE,wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function treeAddDir(tree,parent_id,rootdir)
|
||||
tree:DeleteChildren(parent_id)
|
||||
local search = rootdir..string_Pathsep.."*.*"
|
||||
local dirs = FileSysGet(search,wx.wxDIR)
|
||||
-- append directories
|
||||
for i,dir in ipairs(dirs) do
|
||||
local dir_id = tree:AppendItem(parent_id, dir:match("(%"..string_Pathsep..stringset_File.."+)$"),0)
|
||||
|
||||
tree:SetItemHasChildren(dir_id,FileSysHasContent(dir))
|
||||
end
|
||||
-- then append files
|
||||
local files = FileSysGet(search,wx.wxFILE)
|
||||
for i,file in ipairs(files) do
|
||||
local fname = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
|
||||
local known = GetSpec(GetFileExt(fname))
|
||||
tree:AppendItem(parent_id, fname,known and 1 or 2)
|
||||
end
|
||||
end
|
||||
|
||||
local function treeGetItemFullName(tree,treedata,item_id,isfile)
|
||||
local str = isfile and string_Pathsep or ""
|
||||
str = str..tree:GetItemText(item_id)
|
||||
local cur = str
|
||||
|
||||
local stop = 4
|
||||
while (#cur > 0) do
|
||||
item_id = tree:GetItemParent(item_id)
|
||||
cur = tree:GetItemText(item_id)
|
||||
str = cur..str
|
||||
end
|
||||
return ((not filetree.showroot) and filetree.projdata.rootdir or "").. str
|
||||
end
|
||||
|
||||
local function treeSetRoot(tree,treedata,rootdir)
|
||||
tree:DeleteAllItems()
|
||||
|
||||
if (not wx.wxDirExists(rootdir)) then
|
||||
treedata.root_id = nil
|
||||
tree:AddRoot("Invalid")
|
||||
return
|
||||
end
|
||||
|
||||
local root_id = tree:AddRoot(rootdir,0)
|
||||
treedata.root_id = root_id
|
||||
treedata.rootdir = rootdir
|
||||
|
||||
treeAddDir(tree,root_id,rootdir)
|
||||
|
||||
filetree.newfiledir = rootdir..string_Pathsep
|
||||
|
||||
tree:Expand(root_id)
|
||||
end
|
||||
|
||||
local function treeSetConnectorsAndIcons(tree,treedata)
|
||||
tree:SetImageList(filetree.imglist)
|
||||
|
||||
-- connect to some events from the wxTreeCtrl
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
local dir = treeGetItemFullName(tree,treedata,item_id)
|
||||
DisplayOutput(dir.."\n")
|
||||
treeAddDir(tree,item_id,dir)
|
||||
|
||||
return true
|
||||
end )
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
tree:DeleteChildren(item_id)
|
||||
|
||||
-- directories must stay expandable if they have content
|
||||
local dir = treeGetItemFullName(tree,treedata,item_id)
|
||||
tree:SetItemHasChildren(item_id,FileSysHasContent(dir))
|
||||
|
||||
return true
|
||||
end )
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
|
||||
if (tree:GetItemImage(item_id) == 0) then return end
|
||||
-- openfile
|
||||
local name = treeGetItemFullName(tree,treedata,item_id,true)
|
||||
LoadFile(name,nil,true)
|
||||
|
||||
end )
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
|
||||
-- set "newfile-path"
|
||||
local isfile = tree:GetItemImage(item_id) ~= 0
|
||||
filetree.newfiledir = treeGetItemFullName(tree,treedata,item_id,isfile)
|
||||
|
||||
if (isfile) then
|
||||
-- remove file
|
||||
filetree.newfiledir = wx.wxFileName(filetree.newfiledir):GetPath(wx.wxPATH_GET_VOLUME)
|
||||
end
|
||||
|
||||
filetree.newfiledir = filetree.newfiledir..string_Pathsep
|
||||
end )
|
||||
end
|
||||
|
||||
-- project
|
||||
-- panel
|
||||
-- ( combobox, button)
|
||||
-- ( treectrl)
|
||||
|
||||
local projpanel = wx.wxPanel(sidenotebook,wx.wxID_ANY)
|
||||
local projcombobox = wx.wxComboBox(projpanel, ID "filetree.proj.drivecb",
|
||||
filetree.projdirText,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
filetree.projdirTextArray, wx.wxTE_PROCESS_ENTER)
|
||||
|
||||
|
||||
local projbutton = wx.wxButton(projpanel, ID "debug.projectdir.choose", "...",wx.wxDefaultPosition, wx.wxSize(26,20))
|
||||
|
||||
|
||||
|
||||
local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
filetree.showroot
|
||||
and (wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE)
|
||||
or (wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT))
|
||||
|
||||
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
|
||||
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
projTopSizer:Add(projbutton, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE, 0)
|
||||
|
||||
local projSizer = wx.wxBoxSizer( wx.wxVERTICAL );
|
||||
projSizer:Add(projTopSizer, 0, wx.wxALL + wx.wxALIGN_CENTER_HORIZONTAL + wx.wxGROW, 0)
|
||||
projSizer:Add(projtree, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
|
||||
projpanel:SetSizer(projSizer)
|
||||
|
||||
-- proj connectors
|
||||
-- ---------------
|
||||
|
||||
local function projcomboboxUpdate(event)
|
||||
local cur = projcombobox:GetValue()
|
||||
local fn = wx.wxFileName(cur)
|
||||
fn:Normalize()
|
||||
|
||||
filetree:UpdateProjectDir(fn:GetFullPath(), event:GetEventType() == wx.wxEVT_COMMAND_COMBOBOX_SELECTED)
|
||||
end
|
||||
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_COMBOBOX_SELECTED, projcomboboxUpdate)
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_TEXT_ENTER, projcomboboxUpdate)
|
||||
|
||||
|
||||
treeSetConnectorsAndIcons(projtree,filetree.projdata)
|
||||
|
||||
-- proj functions
|
||||
-- ---------------
|
||||
|
||||
|
||||
|
||||
function filetree:UpdateProjectDir(newdir, cboxsel)
|
||||
if (newdir and newdir:sub(-3,-2) == string_Pathsep) then
|
||||
newdir = newdir:sub(0,-2)
|
||||
end
|
||||
|
||||
if ((not newdir) or filetree.projdirText == newdir or not wx.wxDirExists(newdir)) then return end
|
||||
filetree.projdirText = newdir
|
||||
|
||||
--if (not cboxsel) then
|
||||
PrependStringToArray(filetree.projdirTextArray,newdir,ide.config.projecthistorylength)
|
||||
projcombobox:Clear()
|
||||
projcombobox:Append(filetree.projdirTextArray)
|
||||
if (not cboxsel) then
|
||||
projcombobox:SetValue(newdir)
|
||||
--projcombobox:SetValue(newdir)
|
||||
else
|
||||
projcombobox:Select(0)
|
||||
end
|
||||
--end
|
||||
UpdateProjectDir(newdir,true)
|
||||
treeSetRoot(projtree,filetree.projdata,newdir)
|
||||
end
|
||||
|
||||
|
||||
projpanel.projbutton = projbutton
|
||||
projpanel.projcombobox = projcombobox
|
||||
projpanel.projtree = projtree
|
||||
sidenotebook.projpanel = projpanel
|
||||
|
||||
sidenotebook:AddPage(projpanel, "Project",true)
|
||||
|
||||
function GetFileTreeDir()
|
||||
-- atm only projtree
|
||||
--print(ide.frame.vsplitter:IsSplit(),filetree.newfiledir)
|
||||
return ide.frame.vsplitter:IsSplit() and filetree.newfiledir
|
||||
end
|
||||
|
||||
function SetProjects(tab)
|
||||
filetree.projdirTextArray = tab
|
||||
if (tab and tab[1]) then
|
||||
filetree:UpdateProjectDir(tab[1])
|
||||
end
|
||||
end
|
||||
|
||||
function GetProjects()
|
||||
return filetree.projdirTextArray
|
||||
end
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
--
|
||||
-- filetree, treectrl for drive & project
|
||||
--
|
||||
|
||||
ide.filetree = {
|
||||
dirdriveText = "",
|
||||
dirdriveTextArray = {},
|
||||
|
||||
projdirText = "",
|
||||
projdirTextArray = {},
|
||||
|
||||
showroot = true,
|
||||
|
||||
dirdata = {
|
||||
root_id = nil,
|
||||
rootdir = "",
|
||||
},
|
||||
|
||||
projdata = {
|
||||
root_id = nil,
|
||||
rootdir = "",
|
||||
},
|
||||
}
|
||||
local filetree = ide.filetree
|
||||
|
||||
-- generic tree
|
||||
-- ------------
|
||||
|
||||
do
|
||||
local size = wx.wxSize(16, 16)
|
||||
filetree.imglist = wx.wxImageList(16,16)
|
||||
-- 0 = directory
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_FOLDER, wx.wxART_OTHER, size))
|
||||
-- 1 = file known spec
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_HELP_PAGE, wx.wxART_OTHER, size))
|
||||
-- 2 = file rest
|
||||
filetree.imglist:Add(wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_OTHER, size))
|
||||
end
|
||||
|
||||
local function treeAddDir(tree,parent_id,rootdir)
|
||||
local item, cookie = tree:GetFirstChild(parent_id)
|
||||
local items = {}
|
||||
while true do
|
||||
if not item:IsOk() then break end
|
||||
items[tree:GetItemText(item) .. tree:GetItemImage(item)] = item
|
||||
item, cookie = tree:GetNextChild(item, cookie)
|
||||
end
|
||||
|
||||
local curr
|
||||
local search = rootdir..string_Pathsep.."*.*"
|
||||
local dirs = FileSysGet(search,wx.wxDIR)
|
||||
|
||||
-- append directories
|
||||
for _,dir in ipairs(dirs) do
|
||||
local name = dir:match("%"..string_Pathsep.."("..stringset_File.."+)$")
|
||||
local icon = 0
|
||||
local item = items[name .. icon]
|
||||
if item then -- existing item
|
||||
-- keep deleting items until we find item
|
||||
while true do
|
||||
local next = curr and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id)
|
||||
if not next:IsOk() or name == tree:GetItemText(next) then
|
||||
curr = next
|
||||
break
|
||||
end
|
||||
tree:Delete(next)
|
||||
end
|
||||
else -- new item
|
||||
local dir_id = curr and tree:InsertItem(parent_id, curr, name, icon)
|
||||
or tree:PrependItem(parent_id, name, icon)
|
||||
tree:SetItemHasChildren(dir_id,FileSysHasContent(dir))
|
||||
curr = dir_id
|
||||
end
|
||||
end
|
||||
|
||||
-- then append files
|
||||
local files = FileSysGet(search,wx.wxFILE)
|
||||
for _,file in ipairs(files) do
|
||||
local name = file:match("%"..string_Pathsep.."("..stringset_File.."+)$")
|
||||
local known = GetSpec(GetFileExt(name))
|
||||
local icon = known and 1 or 2
|
||||
local item = items[name .. icon]
|
||||
if item then -- existing item
|
||||
-- keep deleting items until we find item
|
||||
while true do
|
||||
local next = curr and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id)
|
||||
if not next:IsOk() or name == tree:GetItemText(next) then
|
||||
curr = next
|
||||
break
|
||||
end
|
||||
tree:Delete(next)
|
||||
end
|
||||
else -- new item
|
||||
curr = curr and tree:InsertItem(parent_id, curr, name, icon)
|
||||
or tree:PrependItem(parent_id, name, icon)
|
||||
end
|
||||
end
|
||||
|
||||
-- delete any leftovers (something that exists in the tree, but not on disk)
|
||||
while true do
|
||||
local next = curr and tree:GetNextSibling(curr)
|
||||
or tree:GetFirstChild(parent_id)
|
||||
if not next:IsOk() then break end
|
||||
tree:Delete(next)
|
||||
end
|
||||
|
||||
tree:SetItemHasChildren(parent_id,
|
||||
tree:GetChildrenCount(parent_id, false) > 0)
|
||||
end
|
||||
|
||||
local function treeGetItemFullName(tree,treedata,item_id)
|
||||
local str = tree:GetItemText(item_id)
|
||||
local cur = str
|
||||
|
||||
while (#cur > 0) do
|
||||
item_id = tree:GetItemParent(item_id)
|
||||
cur = tree:GetItemText(item_id)
|
||||
if cur and string.len(cur) > 0 then str = cur..string_Pathsep..str end
|
||||
end
|
||||
return ((not filetree.showroot) and filetree.projdata.rootdir or "")..str
|
||||
end
|
||||
|
||||
local function treeSetRoot(tree,treedata,rootdir)
|
||||
tree:DeleteAllItems()
|
||||
|
||||
if (not wx.wxDirExists(rootdir)) then
|
||||
treedata.root_id = nil
|
||||
tree:AddRoot("Invalid")
|
||||
return
|
||||
end
|
||||
|
||||
local root_id = tree:AddRoot(rootdir,0)
|
||||
treedata.root_id = root_id
|
||||
treedata.rootdir = rootdir
|
||||
|
||||
treeAddDir(tree,root_id,rootdir)
|
||||
filetree.newfiledir = rootdir
|
||||
|
||||
tree:Expand(root_id)
|
||||
end
|
||||
|
||||
local function treeSetConnectorsAndIcons(tree,treedata)
|
||||
tree:SetImageList(filetree.imglist)
|
||||
|
||||
-- connect to some events from the wxTreeCtrl
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
local dir = treeGetItemFullName(tree,treedata,item_id)
|
||||
treeAddDir(tree,item_id,dir)
|
||||
return true
|
||||
end )
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED,
|
||||
function() return true end )
|
||||
tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
|
||||
function( event )
|
||||
local item_id = event:GetItem()
|
||||
|
||||
local name = treeGetItemFullName(tree,treedata,item_id)
|
||||
-- refresh the folder
|
||||
if (tree:GetItemImage(item_id) == 0) then
|
||||
if wx.wxFileName(name):DirExists() then
|
||||
treeAddDir(tree,item_id,name) -- refresh the content
|
||||
else -- stale filetree information; rescan
|
||||
treeAddDir(tree,tree:GetItemParent(item_id),name)
|
||||
end
|
||||
else -- open file
|
||||
if wx.wxFileName(name):FileExists() then
|
||||
LoadFile(name,nil,true)
|
||||
FileTreeMarkSelected(name)
|
||||
else -- stale filetree information; rescan
|
||||
treeAddDir(tree,tree:GetItemParent(item_id),name)
|
||||
end
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
-- project
|
||||
-- panel
|
||||
-- (combobox, button)
|
||||
-- (treectrl)
|
||||
local projpanel = ide.frame.projpanel
|
||||
local projcombobox = wx.wxComboBox(projpanel, ID "filetree.proj.drivecb",
|
||||
filetree.projdirText,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
filetree.projdirTextArray, wx.wxTE_PROCESS_ENTER)
|
||||
|
||||
local projbutton = wx.wxButton(projpanel, ID "debug.projectdir.choose", "...",wx.wxDefaultPosition, wx.wxSize(26,20))
|
||||
|
||||
local projtree = wx.wxTreeCtrl(projpanel, ID "filetree.projtree",
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
filetree.showroot
|
||||
and (wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE)
|
||||
or (wx.wxTR_HAS_BUTTONS + wx.wxTR_SINGLE + wx.wxTR_HIDE_ROOT))
|
||||
|
||||
-- use the same font in the combobox as is used in the filetree
|
||||
projcombobox:SetFont(projtree:GetFont())
|
||||
|
||||
local projTopSizer = wx.wxBoxSizer( wx.wxHORIZONTAL );
|
||||
projTopSizer:Add(projcombobox, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
projTopSizer:Add(projbutton, 0, wx.wxALL + wx.wxALIGN_RIGHT + wx.wxADJUST_MINSIZE + wx.wxALIGN_CENTER_VERTICAL, 0)
|
||||
|
||||
local projSizer = wx.wxBoxSizer( wx.wxVERTICAL );
|
||||
projSizer:Add(projTopSizer, 0, wx.wxALL + wx.wxALIGN_CENTER_HORIZONTAL + wx.wxGROW, 0)
|
||||
projSizer:Add(projtree, 1, wx.wxALL + wx.wxALIGN_LEFT + wx.wxGROW, 0)
|
||||
|
||||
projpanel:SetSizer(projSizer)
|
||||
|
||||
-- proj connectors
|
||||
-- ---------------
|
||||
|
||||
local function projcomboboxUpdate(event)
|
||||
local cur = projcombobox:GetValue()
|
||||
local fn = wx.wxFileName(cur)
|
||||
fn:Normalize()
|
||||
|
||||
filetree:updateProjectDir(fn:GetFullPath(), event:GetEventType() == wx.wxEVT_COMMAND_COMBOBOX_SELECTED)
|
||||
end
|
||||
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_COMBOBOX_SELECTED, projcomboboxUpdate)
|
||||
projpanel:Connect(ID "filetree.proj.drivecb", wx.wxEVT_COMMAND_TEXT_ENTER, projcomboboxUpdate)
|
||||
|
||||
treeSetConnectorsAndIcons(projtree,filetree.projdata)
|
||||
|
||||
-- proj functions
|
||||
-- ---------------
|
||||
|
||||
function filetree:updateProjectDir(newdir, cboxsel)
|
||||
if (newdir and newdir:sub(-3,-2) == string_Pathsep) then
|
||||
newdir = newdir:sub(0,-2)
|
||||
end
|
||||
|
||||
if ((not newdir) or filetree.projdirText == newdir or not wx.wxDirExists(newdir)) then return end
|
||||
filetree.projdirText = newdir
|
||||
|
||||
PrependStringToArray(filetree.projdirTextArray,newdir,ide.config.projecthistorylength)
|
||||
projcombobox:Clear()
|
||||
projcombobox:Append(filetree.projdirTextArray)
|
||||
if (not cboxsel) then
|
||||
projcombobox:SetValue(newdir)
|
||||
else
|
||||
projcombobox:Select(0)
|
||||
end
|
||||
|
||||
ProjectUpdateProjectDir(newdir,true)
|
||||
treeSetRoot(projtree,filetree.projdata,newdir)
|
||||
|
||||
-- sync with the current editor window and activate selected file
|
||||
local editor = GetEditor()
|
||||
if (editor) then
|
||||
local id = GetEditor():GetId()
|
||||
if ide.openDocuments[id] then
|
||||
FileTreeMarkSelected(ide.openDocuments[id].filePath)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
projpanel.projbutton = projbutton
|
||||
projpanel.projcombobox = projcombobox
|
||||
projpanel.projtree = projtree
|
||||
|
||||
function FileTreeGetDir()
|
||||
return projpanel:IsShown() and filetree.newfiledir
|
||||
and wx.wxFileName.DirName(filetree.newfiledir):GetFullPath()
|
||||
end
|
||||
|
||||
function FileTreeSetProjects(tab)
|
||||
filetree.projdirTextArray = tab
|
||||
if (tab and tab[1]) then
|
||||
filetree:updateProjectDir(tab[1])
|
||||
end
|
||||
end
|
||||
|
||||
function FileTreeGetProjects()
|
||||
return filetree.projdirTextArray
|
||||
end
|
||||
|
||||
local function findItem(tree, match)
|
||||
local node = projtree:GetRootItem()
|
||||
local label = tree:GetItemText(node)
|
||||
|
||||
local s, e = string.find(match, label)
|
||||
if not s or s ~= 1 then return end
|
||||
|
||||
for token in string.gmatch(string.sub(match,e+1), "[^%"..string_Pathsep.."]+") do
|
||||
local dir = treeGetItemFullName(tree,filetree.projdata,node)
|
||||
treeAddDir(tree,node,dir)
|
||||
|
||||
local item, cookie = tree:GetFirstChild(node)
|
||||
while true do
|
||||
if not item:IsOk() then return end -- not found
|
||||
if tree:GetItemText(item) == token then
|
||||
node = item
|
||||
break
|
||||
end
|
||||
item, cookie = tree:GetNextChild(item, cookie)
|
||||
end
|
||||
end
|
||||
|
||||
-- this loop exits only when a match is found
|
||||
return node
|
||||
end
|
||||
|
||||
local curr_id
|
||||
function FileTreeMarkSelected(file)
|
||||
if not file then return end
|
||||
local item_id = findItem(projtree, file)
|
||||
if curr_id ~= item_id then
|
||||
if curr_id and projtree:IsBold(curr_id) then
|
||||
projtree:SetItemBold(curr_id, false)
|
||||
end
|
||||
if item_id then
|
||||
projtree:EnsureVisible(item_id)
|
||||
projtree:SetItemBold(item_id, true)
|
||||
curr_id = item_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,213 +1,226 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
-- Lomtik Software (J. Winwood & John Labenski)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
-- Global variables
|
||||
-- Markers for editor marker margin
|
||||
BREAKPOINT_MARKER = 1
|
||||
BREAKPOINT_MARKER_VALUE = 2 -- = 2^BREAKPOINT_MARKER
|
||||
CURRENT_LINE_MARKER = 2
|
||||
CURRENT_LINE_MARKER_VALUE = 4 -- = 2^CURRENT_LINE_MARKER
|
||||
|
||||
-- Globals
|
||||
local font = nil -- fonts to use for the editor
|
||||
local fontItalic = nil
|
||||
local ofont = nil -- fonts to use for the outputshell
|
||||
local ofontItalic = nil
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Pick some reasonable fixed width fonts to use for the editor
|
||||
if wx.__WXMSW__ then
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New")
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New")
|
||||
else
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "")
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "")
|
||||
end
|
||||
|
||||
if wx.__WXMSW__ then
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New")
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New")
|
||||
else
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "")
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC, wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "")
|
||||
end
|
||||
|
||||
ide.font = font
|
||||
ide.fontItalic = fontItalic
|
||||
ide.ofont = ofont
|
||||
ide.ofontItalic = ofontItalic
|
||||
|
||||
-- wxWindow variables
|
||||
local frame = nil -- wxFrame the main top level window
|
||||
local toolBar = nil
|
||||
local funclist = nil
|
||||
local statusBar = nil
|
||||
local menuBar = nil
|
||||
|
||||
local vsplitter = nil
|
||||
local sidenotebook = nil
|
||||
|
||||
local splitter = nil -- wxSplitterWindow for the notebook and errorlog
|
||||
local notebook = nil -- wxNotebook of editors
|
||||
local bottomnotebook = nil -- notebook for the GUIs in the bottom line
|
||||
local errorlog = nil -- wxStyledTextCtrl log window for messages
|
||||
local shellbox = nil -- 2 wxStyledTextCtrl for lua shell
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Create the wxFrame
|
||||
-- ----------------------------------------------------------------------------
|
||||
frame = wx.wxFrame(wx.NULL, wx.wxID_ANY, GetIDEString("editor"))
|
||||
|
||||
menuBar = wx.wxMenuBar()
|
||||
statusBar = frame:CreateStatusBar( 5 )
|
||||
local status_txt_width = statusBar:GetTextExtent("OVRW")
|
||||
statusBar:SetStatusWidths({-1, status_txt_width*6, status_txt_width, status_txt_width, status_txt_width*5})
|
||||
statusBar:SetStatusText(GetIDEString("statuswelcome"))
|
||||
|
||||
frame:DragAcceptFiles(true)
|
||||
frame:Connect(wx.wxEVT_DROP_FILES,function(evt)
|
||||
local files = evt:GetFiles()
|
||||
if not files or #files == 0 then return end
|
||||
for i,f in ipairs(files) do
|
||||
LoadFile(f,nil,true)
|
||||
end
|
||||
end)
|
||||
|
||||
toolBar = frame:CreateToolBar(wx.wxNO_BORDER + wx.wxTB_FLAT + wx.wxTB_DOCKABLE)
|
||||
funclist = wx.wxChoice.new(toolBar,ID "toolBar.funclist",wx.wxDefaultPosition, wx.wxSize.new(300,16))
|
||||
|
||||
-- note: Ususally the bmp size isn't necessary, but the HELP icon is not the right size in MSW
|
||||
local toolBmpSize = toolBar:GetToolBitmapSize()
|
||||
toolBar:AddTool(ID_NEW, "New", wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_MENU, toolBmpSize), "Create an empty document")
|
||||
toolBar:AddTool(ID_OPEN, "Open", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_OPEN, wx.wxART_MENU, toolBmpSize), "Open an existing document")
|
||||
toolBar:AddTool(ID_SAVE, "Save", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_SAVE, wx.wxART_MENU, toolBmpSize), "Save the current document")
|
||||
toolBar:AddTool(ID_SAVEALL, "Save All", wx.wxArtProvider.GetBitmap(wx.wxART_NEW_DIR, wx.wxART_MENU, toolBmpSize), "Save all documents")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_CUT, "Cut", wx.wxArtProvider.GetBitmap(wx.wxART_CUT, wx.wxART_MENU, toolBmpSize), "Cut the selection")
|
||||
toolBar:AddTool(ID_COPY, "Copy", wx.wxArtProvider.GetBitmap(wx.wxART_COPY, wx.wxART_MENU, toolBmpSize), "Copy the selection")
|
||||
toolBar:AddTool(ID_PASTE, "Paste", wx.wxArtProvider.GetBitmap(wx.wxART_PASTE, wx.wxART_MENU, toolBmpSize), "Paste text from the clipboard")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_UNDO, "Undo", wx.wxArtProvider.GetBitmap(wx.wxART_UNDO, wx.wxART_MENU, toolBmpSize), "Undo last edit")
|
||||
toolBar:AddTool(ID_REDO, "Redo", wx.wxArtProvider.GetBitmap(wx.wxART_REDO, wx.wxART_MENU, toolBmpSize), "Redo last undo")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_FIND, "Find", wx.wxArtProvider.GetBitmap(wx.wxART_FIND, wx.wxART_MENU, toolBmpSize), "Find text")
|
||||
toolBar:AddTool(ID_REPLACE, "Replace", wx.wxArtProvider.GetBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_MENU, toolBmpSize), "Find and replace text")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", wx.wxArtProvider.GetBitmap(wx.wxART_GO_DIR_UP , wx.wxART_MENU, toolBmpSize), "Sets projectdir from file")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddControl(funclist)
|
||||
toolBar:Realize()
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Add the child windows to the frame
|
||||
|
||||
-- vertical splitter (splitter / sidenotebook)
|
||||
vsplitter = wx.wxSplitterWindow(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxSP_3DSASH)
|
||||
|
||||
|
||||
-- horizontal splitter (notebook,bottomnotebook)
|
||||
splitter = wx.wxSplitterWindow(vsplitter, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxSP_3DSASH)
|
||||
local ph
|
||||
splitter:Connect(wx.wxEVT_SIZE, function (evt)
|
||||
local h = evt:GetSize():GetHeight()
|
||||
ph = ph or h
|
||||
local h2 = ph
|
||||
ph = h
|
||||
local dh = splitter:GetSashPosition()
|
||||
splitter:SetSashPosition(dh-h2+h)
|
||||
splitter:UpdateSize()
|
||||
evt:Skip()
|
||||
end)
|
||||
|
||||
-- notebook for editors
|
||||
notebook = wx.wxNotebook(splitter, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxCLIP_CHILDREN)
|
||||
|
||||
local current -- the currently active editor, needed by the focus selection
|
||||
notebook:Connect(wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
|
||||
function (event)
|
||||
current = event:GetSelection() -- update the active editor reference
|
||||
SetEditorSelection(event:GetSelection())
|
||||
event:Skip() -- skip to let page change
|
||||
end)
|
||||
|
||||
notebook:Connect(wx.wxEVT_SET_FOCUS, -- Notepad tabs shouldn't be selectable,
|
||||
function (event) -- select the editor then instead
|
||||
SetEditorSelection(current) -- select the currently active one.
|
||||
end)
|
||||
|
||||
-- bottomnotebook (errorlog,shellbox)
|
||||
bottomnotebook = wx.wxNotebook(splitter, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxCLIP_CHILDREN)
|
||||
errorlog = wxstc.wxStyledTextCtrl(bottomnotebook, wx.wxID_ANY,wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxBORDER_STATIC)
|
||||
bottomnotebook:AddPage(errorlog, "Output", true)
|
||||
|
||||
shellbox = wx.wxPanel(bottomnotebook,wx.wxID_ANY)
|
||||
shellbox.output = wxstc.wxStyledTextCtrl(shellbox, ID "shellbox.output")
|
||||
shellbox.input = wxstc.wxStyledTextCtrl(shellbox, ID "shellbox.input")
|
||||
shellbox.run = wx.wxButton(shellbox, ID "shellbox.run", "Run")
|
||||
shellbox.remote = wx.wxCheckBox(shellbox, ID "shellbox.remote", "Remote")
|
||||
shellbox.remote:Disable()
|
||||
|
||||
local hsizer = wx.wxFlexGridSizer(0, 1, 0, 0)
|
||||
hsizer:AddGrowableCol(0)
|
||||
hsizer:AddGrowableRow(0)
|
||||
hsizer:Add(shellbox.run, 0, wx.wxGROW+wx.wxALIGN_CENTER_VERTICAL, 0 )
|
||||
hsizer:Add(shellbox.remote, 0, wx.wxGROW+wx.wxALIGN_CENTER_VERTICAL, 0 )
|
||||
|
||||
local vsizer = wx.wxFlexGridSizer(1, 0, 0, 0)
|
||||
vsizer:AddGrowableCol(0)
|
||||
vsizer:AddGrowableRow(0)
|
||||
vsizer:Add(shellbox.input, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
|
||||
vsizer:Add(hsizer, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
|
||||
|
||||
local gridsizer = wx.wxFlexGridSizer(0, 1, 0, 0)
|
||||
gridsizer:AddGrowableCol(0)
|
||||
gridsizer:AddGrowableRow(0)
|
||||
gridsizer:Add(shellbox.output, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
|
||||
gridsizer:Add(vsizer, 0, wx.wxGROW+wx.wxALIGN_CENTER_HORIZONTAL, 0 )
|
||||
shellbox:SetSizer(gridsizer)
|
||||
|
||||
bottomnotebook:AddPage(shellbox, "Lua shell",false)
|
||||
|
||||
|
||||
-- sidenotebook
|
||||
sidenotebook = wx.wxNotebook(vsplitter, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wx.wxCLIP_CHILDREN)
|
||||
|
||||
|
||||
-- init splitters
|
||||
splitter:Initialize(notebook)
|
||||
vsplitter:Initialize(splitter)
|
||||
|
||||
|
||||
-------
|
||||
-- hierarchy
|
||||
bottomnotebook.shellbox = shellbox
|
||||
bottomnotebook.errorlog = errorlog
|
||||
|
||||
splitter.bottomnotebook = bottomnotebook
|
||||
splitter.notebook = notebook
|
||||
|
||||
vsplitter.splitter = splitter
|
||||
vsplitter.sidenotebook = sidenotebook
|
||||
|
||||
toolBar.funclist = funclist
|
||||
|
||||
frame.vsplitter = vsplitter
|
||||
frame.toolBar = toolBar
|
||||
frame.statusBar = statusBar
|
||||
frame.menuBar = menuBar
|
||||
|
||||
ide.frame = frame
|
||||
|
||||
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
-- Lomtik Software (J. Winwood & John Labenski)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
-- Global variables
|
||||
-- Markers for editor marker margin
|
||||
BREAKPOINT_MARKER = 1
|
||||
BREAKPOINT_MARKER_VALUE = 2 -- = 2^BREAKPOINT_MARKER
|
||||
CURRENT_LINE_MARKER = 2
|
||||
CURRENT_LINE_MARKER_VALUE = 4 -- = 2^CURRENT_LINE_MARKER
|
||||
|
||||
-- Globals
|
||||
local font = nil -- fonts to use for the editor
|
||||
local fontItalic = nil
|
||||
local ofont = nil -- fonts to use for the outputshell
|
||||
local ofontItalic = nil
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Pick some reasonable fixed width fonts to use for the editor
|
||||
if wx.__WXMSW__ then
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "Courier New", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
else
|
||||
font = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
fontItalic = wx.wxFont(ide.config.editor.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.editor.fontname or "", ide.config.editor.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
end
|
||||
|
||||
if wx.__WXMSW__ then
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "Courier New", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
else
|
||||
ofont = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_NORMAL,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
ofontItalic = wx.wxFont(ide.config.outputshell.fontsize or 10, wx.wxFONTFAMILY_MODERN, wx.wxFONTSTYLE_ITALIC,
|
||||
wx.wxFONTWEIGHT_NORMAL, false, ide.config.outputshell.fontname or "", ide.config.outputshell.fontencoding or wx.wxFONTENCODING_DEFAULT)
|
||||
end
|
||||
|
||||
ide.font = font
|
||||
ide.fontItalic = fontItalic
|
||||
ide.ofont = ofont
|
||||
ide.ofontItalic = ofontItalic
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Create the wxFrame
|
||||
-- ----------------------------------------------------------------------------
|
||||
local function createFrame()
|
||||
frame = wx.wxFrame(wx.NULL, wx.wxID_ANY, GetIDEString("editor"),
|
||||
wx.wxDefaultPosition, wx.wxSize(1000, 700))
|
||||
-- wrap into protected call as DragAcceptFiles fails on MacOS with
|
||||
-- wxwidgets 2.8.12 even though it should work according to change notes
|
||||
-- for 2.8.10: "Implemented wxWindow::DragAcceptFiles() on all platforms."
|
||||
pcall(function() frame:DragAcceptFiles(true) end)
|
||||
frame:Connect(wx.wxEVT_DROP_FILES,function(evt)
|
||||
local files = evt:GetFiles()
|
||||
if not files or #files == 0 then return end
|
||||
for i,f in ipairs(files) do
|
||||
LoadFile(f,nil,true)
|
||||
end
|
||||
end)
|
||||
|
||||
local menuBar = wx.wxMenuBar()
|
||||
frame.menuBar = menuBar
|
||||
|
||||
local statusBar = frame:CreateStatusBar( 5 )
|
||||
frame.statusBar = statusBar
|
||||
local status_txt_width = statusBar:GetTextExtent("OVRW")
|
||||
statusBar:SetStatusWidths({-1, status_txt_width*6, status_txt_width, status_txt_width, status_txt_width*5})
|
||||
statusBar:SetStatusText(GetIDEString("statuswelcome"))
|
||||
|
||||
local mgr = wxaui.wxAuiManager()
|
||||
frame.uimgr = mgr
|
||||
mgr:SetManagedWindow(frame)
|
||||
|
||||
return frame
|
||||
end
|
||||
|
||||
local function createToolBar(frame)
|
||||
local toolBar = wx.wxToolBar(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxTB_FLAT + wx.wxTB_NODIVIDER)
|
||||
local funclist = wx.wxChoice.new(toolBar,ID "toolBar.funclist",wx.wxDefaultPosition, wx.wxSize.new(240,16))
|
||||
|
||||
-- note: Ususally the bmp size isn't necessary, but the HELP icon is not the right size in MSW
|
||||
local toolBmpSize = toolBar:GetToolBitmapSize()
|
||||
toolBar:AddTool(ID_NEW, "New", wx.wxArtProvider.GetBitmap(wx.wxART_NORMAL_FILE, wx.wxART_TOOLBAR, toolBmpSize), "Create an empty document")
|
||||
toolBar:AddTool(ID_OPEN, "Open", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_OPEN, wx.wxART_TOOLBAR, toolBmpSize), "Open an existing document")
|
||||
toolBar:AddTool(ID_SAVE, "Save", wx.wxArtProvider.GetBitmap(wx.wxART_FILE_SAVE, wx.wxART_TOOLBAR, toolBmpSize), "Save the current document")
|
||||
toolBar:AddTool(ID_SAVEALL, "Save All", wx.wxArtProvider.GetBitmap(wx.wxART_NEW_DIR, wx.wxART_TOOLBAR, toolBmpSize), "Save all documents")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_CUT, "Cut", wx.wxArtProvider.GetBitmap(wx.wxART_CUT, wx.wxART_TOOLBAR, toolBmpSize), "Cut the selection")
|
||||
toolBar:AddTool(ID_COPY, "Copy", wx.wxArtProvider.GetBitmap(wx.wxART_COPY, wx.wxART_TOOLBAR, toolBmpSize), "Copy the selection")
|
||||
toolBar:AddTool(ID_PASTE, "Paste", wx.wxArtProvider.GetBitmap(wx.wxART_PASTE, wx.wxART_TOOLBAR, toolBmpSize), "Paste text from the clipboard")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_UNDO, "Undo", wx.wxArtProvider.GetBitmap(wx.wxART_UNDO, wx.wxART_TOOLBAR, toolBmpSize), "Undo last edit")
|
||||
toolBar:AddTool(ID_REDO, "Redo", wx.wxArtProvider.GetBitmap(wx.wxART_REDO, wx.wxART_TOOLBAR, toolBmpSize), "Redo last undo")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID_FIND, "Find", wx.wxArtProvider.GetBitmap(wx.wxART_FIND, wx.wxART_TOOLBAR, toolBmpSize), "Find text")
|
||||
toolBar:AddTool(ID_REPLACE, "Replace", wx.wxArtProvider.GetBitmap(wx.wxART_FIND_AND_REPLACE, wx.wxART_TOOLBAR, toolBmpSize), "Find and replace text")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddTool(ID "debug.projectdir.fromfile", "Update", wx.wxArtProvider.GetBitmap(wx.wxART_GO_DIR_UP , wx.wxART_TOOLBAR, toolBmpSize), "Sets projectdir from file")
|
||||
toolBar:AddSeparator()
|
||||
toolBar:AddControl(funclist)
|
||||
toolBar:Realize()
|
||||
|
||||
toolBar.funclist = funclist
|
||||
frame.toolBar = toolBar
|
||||
return toolBar
|
||||
end
|
||||
|
||||
|
||||
local function createNotebook(frame)
|
||||
-- notebook for editors
|
||||
local notebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
|
||||
+ wx.wxNO_BORDER)
|
||||
|
||||
-- the following group of event handlers allows the active editor
|
||||
-- to get/keep focus after execution of Run and other commands
|
||||
local current -- the currently active editor, needed by the focus selection
|
||||
local function onPageChange(event)
|
||||
current = event:GetSelection() -- update the active editor reference
|
||||
SetEditorSelection(current)
|
||||
event:Skip() -- skip to let page change
|
||||
end
|
||||
notebook:Connect(wx.wxEVT_SET_FOCUS, -- Notepad tabs shouldn't be selectable,
|
||||
function (event)
|
||||
SetEditorSelection(current) -- select the currently active editor
|
||||
end)
|
||||
notebook:Connect(wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, onPageChange)
|
||||
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, onPageChange)
|
||||
|
||||
notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
|
||||
function (event)
|
||||
ClosePage(event:GetSelection())
|
||||
event:Veto() -- don't propagate the event as the page is already closed
|
||||
end)
|
||||
|
||||
frame.notebook = notebook
|
||||
return notebook
|
||||
end
|
||||
|
||||
local function createBottomNotebook(frame)
|
||||
-- bottomnotebook (errorlog,shellbox)
|
||||
local bottomnotebook = wxaui.wxAuiNotebook(frame, wx.wxID_ANY,
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize,
|
||||
wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE
|
||||
- wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER)
|
||||
|
||||
local errorlog = wxstc.wxStyledTextCtrl(bottomnotebook, ID "output",
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
|
||||
|
||||
local shellbox = wxstc.wxStyledTextCtrl(bottomnotebook, ID "shell",
|
||||
wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_STATIC)
|
||||
|
||||
bottomnotebook:AddPage(errorlog, "Output", true)
|
||||
bottomnotebook:AddPage(shellbox, "Local console", false)
|
||||
bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE,
|
||||
function (event)
|
||||
event:Veto() -- don't allow closing pages in this notebook
|
||||
end)
|
||||
|
||||
frame.bottomnotebook = bottomnotebook
|
||||
bottomnotebook.errorlog = errorlog
|
||||
bottomnotebook.shellbox = shellbox
|
||||
|
||||
return bottomnotebook
|
||||
end
|
||||
|
||||
local function createProjpanel(frame)
|
||||
local projpanel = wx.wxPanel(frame,wx.wxID_ANY)
|
||||
frame.projpanel = projpanel
|
||||
return projpanel
|
||||
end
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- Add the child windows to the frame
|
||||
|
||||
local frame = createFrame()
|
||||
ide.frame = frame
|
||||
createToolBar(frame)
|
||||
createNotebook(frame)
|
||||
createProjpanel(frame)
|
||||
createBottomNotebook(frame)
|
||||
|
||||
do
|
||||
local frame = ide.frame
|
||||
local mgr = frame.uimgr
|
||||
|
||||
mgr:AddPane(frame.toolBar, wxaui.wxAuiPaneInfo():
|
||||
Name("toolBar"):Caption("Main Toolbar"):
|
||||
MinSize(300,16):
|
||||
ToolbarPane():Top():CloseButton(false):
|
||||
LeftDockable(false):RightDockable(false):Hide())
|
||||
|
||||
mgr:AddPane(frame.notebook, wxaui.wxAuiPaneInfo():
|
||||
Name("notebook"):
|
||||
CenterPane():PaneBorder(false):Hide())
|
||||
|
||||
mgr:AddPane(frame.projpanel, wxaui.wxAuiPaneInfo():
|
||||
Name("projpanel"):Caption("Project"):
|
||||
MinSize(200,200):FloatingSize(200,400):
|
||||
Left():Layer(1):Position(1):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true):Hide())
|
||||
|
||||
mgr:AddPane(frame.bottomnotebook, wxaui.wxAuiPaneInfo():
|
||||
Name("bottomnotebook"):
|
||||
MinSize(200,200):FloatingSize(400,250):
|
||||
Bottom():Layer(1):Position(1):
|
||||
CloseButton(true):MaximizeButton(false):PinButton(true):Hide())
|
||||
|
||||
mgr:GetPane("toolBar"):Show(true)
|
||||
mgr:GetPane("bottomnotebook"):Show(true)
|
||||
mgr:GetPane("projpanel"):Show(true)
|
||||
mgr:GetPane("notebook"):Show(true)
|
||||
|
||||
local pp = mgr:SavePerspective()
|
||||
mgr.defaultPerspective = pp
|
||||
|
||||
mgr:Update()
|
||||
end
|
||||
|
||||
@@ -1,77 +1,76 @@
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
-- Generate a unique new wxWindowID
|
||||
local ID_IDCOUNTER = wx.wxID_HIGHEST + 1
|
||||
function NewID()
|
||||
ID_IDCOUNTER = ID_IDCOUNTER + 1
|
||||
return ID_IDCOUNTER
|
||||
end
|
||||
|
||||
-- File menu
|
||||
ID_NEW = wx.wxID_NEW
|
||||
ID_OPEN = wx.wxID_OPEN
|
||||
ID_CLOSE = NewID()
|
||||
ID_SAVE = wx.wxID_SAVE
|
||||
ID_SAVEAS = wx.wxID_SAVEAS
|
||||
ID_SAVEALL = NewID()
|
||||
ID_EXIT = wx.wxID_EXIT
|
||||
-- Edit menu
|
||||
ID_CUT = wx.wxID_CUT
|
||||
ID_COPY = wx.wxID_COPY
|
||||
ID_PASTE = wx.wxID_PASTE
|
||||
ID_SELECTALL = wx.wxID_SELECTALL
|
||||
ID_UNDO = wx.wxID_UNDO
|
||||
ID_REDO = wx.wxID_REDO
|
||||
ID_AUTOCOMPLETE = NewID()
|
||||
ID_AUTOCOMPLETE_ENABLE = NewID()
|
||||
ID_COMMENT = NewID()
|
||||
ID_FOLD = NewID()
|
||||
-- Find menu
|
||||
ID_FIND = wx.wxID_FIND
|
||||
ID_FINDNEXT = NewID()
|
||||
ID_FINDPREV = NewID()
|
||||
ID_REPLACE = NewID()
|
||||
ID_FIND_IN_FILES = NewID()
|
||||
ID_REPLACE_IN_FILES = NewID()
|
||||
ID_GOTOLINE = NewID()
|
||||
ID_SORT = NewID()
|
||||
-- Debug menu
|
||||
ID_TOGGLEBREAKPOINT = NewID()
|
||||
ID_COMPILE = NewID()
|
||||
ID_RUN = NewID()
|
||||
ID_ATTACH_DEBUG = NewID()
|
||||
ID_START_DEBUG = NewID()
|
||||
--ID_USECONSOLE = NewID()
|
||||
|
||||
ID_STOP_DEBUG = NewID()
|
||||
ID_STEP = NewID()
|
||||
ID_STEP_OVER = NewID()
|
||||
ID_STEP_OUT = NewID()
|
||||
ID_CONTINUE = NewID()
|
||||
ID_BREAK = NewID()
|
||||
--ID_VIEWCALLSTACK = NewID()
|
||||
--ID_VIEWWATCHWINDOW = NewID()
|
||||
ID_CLEAROUTPUT = NewID()
|
||||
ID_DEBUGGER_PORT = NewID()
|
||||
-- Help menu
|
||||
ID_ABOUT = wx.wxID_ABOUT
|
||||
-- Watch window menu items
|
||||
ID_WATCH_LISTCTRL = NewID()
|
||||
ID_ADDWATCH = NewID()
|
||||
ID_EDITWATCH = NewID()
|
||||
ID_REMOVEWATCH = NewID()
|
||||
ID_EVALUATEWATCH = NewID()
|
||||
|
||||
ID_WORKDIR_CHOSE = NewID()
|
||||
|
||||
local ids = {}
|
||||
function ID (name)
|
||||
ids[name] = ids[name] or NewID()
|
||||
return ids[name]
|
||||
end
|
||||
|
||||
function IDget (name)
|
||||
return ids[name]
|
||||
end
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
|
||||
-- Generate a unique new wxWindowID
|
||||
local ID_IDCOUNTER = wx.wxID_HIGHEST + 1
|
||||
function NewID()
|
||||
ID_IDCOUNTER = ID_IDCOUNTER + 1
|
||||
return ID_IDCOUNTER
|
||||
end
|
||||
|
||||
-- File menu
|
||||
ID_NEW = wx.wxID_NEW
|
||||
ID_OPEN = wx.wxID_OPEN
|
||||
ID_CLOSE = NewID()
|
||||
ID_SAVE = wx.wxID_SAVE
|
||||
ID_SAVEAS = wx.wxID_SAVEAS
|
||||
ID_SAVEALL = NewID()
|
||||
ID_EXIT = wx.wxID_EXIT
|
||||
-- Edit menu
|
||||
ID_CUT = wx.wxID_CUT
|
||||
ID_COPY = wx.wxID_COPY
|
||||
ID_PASTE = wx.wxID_PASTE
|
||||
ID_SELECTALL = wx.wxID_SELECTALL
|
||||
ID_UNDO = wx.wxID_UNDO
|
||||
ID_REDO = wx.wxID_REDO
|
||||
ID_AUTOCOMPLETE = NewID()
|
||||
ID_AUTOCOMPLETE_ENABLE = NewID()
|
||||
ID_COMMENT = NewID()
|
||||
ID_FOLD = NewID()
|
||||
-- Find menu
|
||||
ID_FIND = wx.wxID_FIND
|
||||
ID_FINDNEXT = NewID()
|
||||
ID_FINDPREV = NewID()
|
||||
ID_REPLACE = NewID()
|
||||
ID_FIND_IN_FILES = NewID()
|
||||
ID_REPLACE_IN_FILES = NewID()
|
||||
ID_GOTOLINE = NewID()
|
||||
ID_SORT = NewID()
|
||||
-- Project/Debug menu
|
||||
ID_TOGGLEBREAKPOINT = NewID()
|
||||
ID_COMPILE = NewID()
|
||||
ID_RUN = NewID()
|
||||
ID_RUNNOW = NewID()
|
||||
ID_ATTACH_DEBUG = NewID()
|
||||
ID_START_DEBUG = NewID()
|
||||
ID_STOP_DEBUG = NewID()
|
||||
ID_STEP = NewID()
|
||||
ID_STEP_OVER = NewID()
|
||||
ID_STEP_OUT = NewID()
|
||||
ID_CONTINUE = NewID()
|
||||
ID_BREAK = NewID()
|
||||
ID_TRACE = NewID()
|
||||
ID_VIEWCALLSTACK = NewID()
|
||||
ID_VIEWWATCHWINDOW = NewID()
|
||||
ID_CLEAROUTPUT = NewID()
|
||||
ID_PROJECTDIR = NewID()
|
||||
ID_INTERPRETER = NewID()
|
||||
-- Help menu
|
||||
ID_ABOUT = wx.wxID_ABOUT
|
||||
-- Watch window menu items
|
||||
ID_WATCH_LISTCTRL = NewID()
|
||||
ID_ADDWATCH = NewID()
|
||||
ID_EDITWATCH = NewID()
|
||||
ID_REMOVEWATCH = NewID()
|
||||
ID_EVALUATEWATCH = NewID()
|
||||
|
||||
local ids = {}
|
||||
function ID (name)
|
||||
ids[name] = ids[name] or NewID()
|
||||
return ids[name]
|
||||
end
|
||||
|
||||
function IDget (name)
|
||||
return ids[name]
|
||||
end
|
||||
|
||||
180
src/editor/inspect.lua
Normal file
180
src/editor/inspect.lua
Normal file
@@ -0,0 +1,180 @@
|
||||
-- Integration with LuaInspect
|
||||
-- (C) 2012 Paul Kulchenko
|
||||
|
||||
local M, LA, LI, T = {}
|
||||
local FAST = true
|
||||
|
||||
local function init()
|
||||
if LA then return end
|
||||
|
||||
require "metalua"
|
||||
LA = require "luainspect.ast"
|
||||
LI = require "luainspect.init"
|
||||
T = require "luainspect.types"
|
||||
|
||||
if FAST then
|
||||
LI.eval_comments = function () end
|
||||
LI.infer_values = function () end
|
||||
end
|
||||
end
|
||||
|
||||
function M.warnings_from_string(src, file)
|
||||
init()
|
||||
|
||||
local ast, err, linenum, colnum = LA.ast_from_string(src, file)
|
||||
if err then return nil, err, linenum, colnum end
|
||||
|
||||
if FAST then
|
||||
LI.inspect(ast, nil, src)
|
||||
LA.ensure_parents_marked(ast)
|
||||
else
|
||||
local tokenlist = LA.ast_to_tokenlist(ast, src)
|
||||
LI.inspect(ast, tokenlist, src)
|
||||
LI.mark_related_keywords(ast, tokenlist, src)
|
||||
end
|
||||
|
||||
return M.show_warnings(ast)
|
||||
end
|
||||
|
||||
function M.show_warnings(top_ast)
|
||||
local warnings = {}
|
||||
local function warn(msg, linenum, path)
|
||||
warnings[#warnings+1] = (path or "?") .. "(" .. (linenum or 0) .. "): " .. msg
|
||||
end
|
||||
local function known(o) return not T.istype[o] end
|
||||
local isseen, globseen = {}, {}
|
||||
LA.walk(top_ast, function(ast)
|
||||
local line = ast.lineinfo and ast.lineinfo.first[1] or 0
|
||||
local path = ast.lineinfo and ast.lineinfo.first[4] or '?'
|
||||
local name = ast[1]
|
||||
-- check if we're masking a variable in the same scope
|
||||
if ast.localmasking and name ~= '_' and
|
||||
ast.level == ast.localmasking.level then
|
||||
local linenum = ast.localmasking.lineinfo.first[1]
|
||||
local parent = ast.parent and ast.parent.parent
|
||||
local func = parent and parent.tag == 'Localrec'
|
||||
warn("local " .. (func and 'function' or 'variable') .. " '" ..
|
||||
name .. "' masks earlier declaration " ..
|
||||
(linenum and "on line " .. linenum or "in the same scope"),
|
||||
line, path)
|
||||
end
|
||||
if ast.localdefinition == ast and not ast.isused and
|
||||
not ast.isignore then
|
||||
local parent = ast.parent and ast.parent.parent
|
||||
local isparam = parent and parent.tag == 'Function'
|
||||
if isparam then
|
||||
if name ~= 'self' then
|
||||
local func = parent.parent and parent.parent.parent
|
||||
local assignment = not func.tag or func.tag == 'Set' or func.tag == 'Localrec'
|
||||
local fname = assignment and type(func[1][1][1]) == 'string' and func[1][1][1]
|
||||
-- "function foo(bar)" => func.tag == 'Set'
|
||||
-- "local function foo(bar)" => func.tag == 'Localrec'
|
||||
-- "local _, foo = 1, function(bar)" => func.tag == 'Local'
|
||||
-- "print(function(bar) end)" => func.tag == nil
|
||||
warn("unused parameter '" .. name .. "'" ..
|
||||
(func and assignment
|
||||
and (fname and func.tag
|
||||
and (" in function '" .. fname .. "'")
|
||||
or " in anonymous function")
|
||||
or ""),
|
||||
line, path)
|
||||
end
|
||||
else
|
||||
if parent.tag == 'Localrec' then -- local function foo...
|
||||
warn("unused local function '" .. name .. "'", line, path)
|
||||
else
|
||||
warn("unused local variable '" .. name .. "'; "..
|
||||
"consider removing or replacing with '_'", line, path)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- added check for FAST as ast.seevalue relies on value evaluation,
|
||||
-- which is very slow even on simple and short scripts
|
||||
if not FAST and ast.isfield and not(known(ast.seevalue.value) and ast.seevalue.value ~= nil) then
|
||||
warn("unknown field " .. name, ast.lineinfo.first[1], path)
|
||||
elseif ast.tag == 'Id' and not ast.localdefinition and not ast.definedglobal then
|
||||
if not globseen[name] then
|
||||
globseen[name] = true
|
||||
local parent = ast.parent
|
||||
-- if being called and not one of the parameters
|
||||
if parent and parent.tag == 'Call' and parent[1] == ast then
|
||||
warn("first use of unknown global function '" .. name .. "'", line, path)
|
||||
else
|
||||
warn("first use of unknown global variable '" .. name .. "'", line, path)
|
||||
end
|
||||
end
|
||||
elseif ast.tag == 'Id' and not ast.localdefinition and ast.definedglobal then
|
||||
local parent = ast.parent and ast.parent.parent
|
||||
if parent and parent.tag == 'Set' and not globseen[name] -- report assignments to global
|
||||
-- only report if it is on the left side of the assignment
|
||||
-- this is a bit tricky as it can be assigned as part of a, b = c, d
|
||||
-- `Set{ {lhs+} {expr+} } -- lhs1, lhs2... = e1, e2...
|
||||
and parent[1] == ast.parent
|
||||
and parent[2][1].tag ~= "Function" then -- but ignore global functions
|
||||
warn("first assignment to global variable '" .. name .. "'", line, path)
|
||||
globseen[name] = true
|
||||
end
|
||||
elseif (ast.tag == 'Set' or ast.tag == 'Local') and #(ast[2]) > #(ast[1]) then
|
||||
warn(("value discarded in multiple assignment: %d values assigned to %d variable%s")
|
||||
:format(#(ast[2]), #(ast[1]), #(ast[1]) > 1 and 's' or ''), line, path)
|
||||
end
|
||||
local vast = ast.seevalue or ast
|
||||
local note = vast.parent
|
||||
and (vast.parent.tag == 'Call' or vast.parent.tag == 'Invoke')
|
||||
and vast.parent.note
|
||||
if note and not isseen[vast.parent] then
|
||||
isseen[vast.parent] = true
|
||||
warn("function '" .. name .. "': " .. note, line, path)
|
||||
end
|
||||
end)
|
||||
return warnings
|
||||
end
|
||||
|
||||
local frame = ide.frame
|
||||
local menu = frame.menuBar:GetMenu(frame.menuBar:FindMenu("&Project"))
|
||||
local ID_ANALYZE = ID "debug.analyze"
|
||||
|
||||
-- insert after "Compile" item
|
||||
for item = 0, menu:GetMenuItemCount()-1 do
|
||||
if menu:FindItemByPosition(item):GetId() == ID_COMPILE then
|
||||
menu:Insert(item+1, ID_ANALYZE, "Analyze\tShift-F7", "Analyze the source code")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local debugger = ide.debugger
|
||||
local openDocuments = ide.openDocuments
|
||||
|
||||
local function analyzeProgram(editor)
|
||||
local editorText = editor:GetText()
|
||||
local id = editor:GetId()
|
||||
local filePath = DebuggerMakeFileName(editor, openDocuments[id].filePath)
|
||||
|
||||
if frame.menuBar:IsChecked(ID_CLEAROUTPUT) then ClearOutput() end
|
||||
DisplayOutput("Analizing the source code")
|
||||
frame:Update()
|
||||
|
||||
local warn, err = M.warnings_from_string(editorText, filePath)
|
||||
if err then -- report compilation error
|
||||
DisplayOutput(": not completed\n")
|
||||
return false
|
||||
end
|
||||
|
||||
DisplayOutput((": %s warning%s.\n")
|
||||
:format(#warn > 0 and #warn or 'no', #warn == 1 and '' or 's'))
|
||||
DisplayOutputNoMarker(table.concat(warn, "\n") .. "\n")
|
||||
|
||||
return true -- analyzed ok
|
||||
end
|
||||
|
||||
frame:Connect(ID_ANALYZE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function ()
|
||||
ActivateOutput()
|
||||
local editor = GetEditor()
|
||||
if not analyzeProgram(editor) then CompileProgram(editor) end
|
||||
end)
|
||||
frame:Connect(ID_ANALYZE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable((debugger.server == nil and debugger.pid == nil) and (editor ~= nil))
|
||||
end)
|
||||
@@ -1,61 +1,59 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
ide.iofilters["GermanUtf8Ascii"] = {
|
||||
|
||||
-- this function converts some utf8 character output. It's a hack.
|
||||
-- Since luxinia is not utf8 prepared, this is still necessary.
|
||||
-- if you wish to turn this off, edit user.lua and set this filefunction to nil
|
||||
output = function (fpath, content)
|
||||
local utf8escape = ("string").char(195)
|
||||
-- only simple cases are handled (umlauts)
|
||||
local chr = ("string").char
|
||||
local charconv = {
|
||||
[chr(164)] = chr(228), -- ä
|
||||
[chr(182)] = chr(246), -- ö
|
||||
[chr(188)] = chr(252), -- ü
|
||||
[chr(132)] = chr(196), -- Ä
|
||||
[chr(150)] = chr(214), -- Ö
|
||||
[chr(156)] = chr(220), -- Ü
|
||||
[chr(159)] = chr(223), -- ß
|
||||
}
|
||||
return content : gsub (utf8escape.."(.)",charconv)
|
||||
end,
|
||||
|
||||
|
||||
-- this function is another hack to read an ANSI encoded
|
||||
-- file and converts the umlauts to utf8 chars
|
||||
input = function (fpath, content)
|
||||
local utf8escape = ("string").char(195)
|
||||
local chr = ("string").char
|
||||
local charconv = {
|
||||
[chr(228)] = utf8escape..chr(164), -- ä
|
||||
[chr(246)] = utf8escape..chr(182), -- ö
|
||||
[chr(252)] = utf8escape..chr(188), -- ü
|
||||
[chr(196)] = utf8escape..chr(132), -- Ä
|
||||
[chr(214)] = utf8escape..chr(150), -- Ö
|
||||
[chr(220)] = utf8escape..chr(156), -- Ü
|
||||
[chr(223)] = utf8escape..chr(159), -- ß
|
||||
}
|
||||
local lst = "["
|
||||
for k in pairs(charconv) do lst = lst .. k end
|
||||
lst = "]"
|
||||
|
||||
return content:gsub(lst,charconv)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
--üäß
|
||||
|
||||
for i,filter in pairs(ide.iofilters) do
|
||||
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„â€ÂäöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
|
||||
end
|
||||
|
||||
-- which: "input" or "output"
|
||||
function GetConfigIOFilter(which)
|
||||
local filtername = ide.config.editor.iofilter
|
||||
return (filtername and ide.iofilters[filtername] and ide.iofilters[filtername][which])
|
||||
end
|
||||
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
ide.iofilters["GermanUtf8Ascii"] = {
|
||||
|
||||
-- this function converts some utf8 character output. It's a hack.
|
||||
-- Since luxinia is not utf8 prepared, this is still necessary.
|
||||
-- if you wish to turn this off, edit user.lua and set this filefunction to nil
|
||||
output = function (fpath, content)
|
||||
local utf8escape = ("string").char(195)
|
||||
-- only simple cases are handled (umlauts)
|
||||
local chr = ("string").char
|
||||
local charconv = {
|
||||
[chr(164)] = chr(228), -- ä
|
||||
[chr(182)] = chr(246), -- ö
|
||||
[chr(188)] = chr(252), -- ü
|
||||
[chr(132)] = chr(196), -- Ä
|
||||
[chr(150)] = chr(214), -- Ö
|
||||
[chr(156)] = chr(220), -- Ü
|
||||
[chr(159)] = chr(223), -- ß
|
||||
}
|
||||
return content : gsub (utf8escape.."(.)",charconv)
|
||||
end,
|
||||
|
||||
-- this function is another hack to read an ANSI encoded
|
||||
-- file and converts the umlauts to utf8 chars
|
||||
input = function (fpath, content)
|
||||
local utf8escape = ("string").char(195)
|
||||
local chr = ("string").char
|
||||
local charconv = {
|
||||
[chr(228)] = utf8escape..chr(164), -- ä
|
||||
[chr(246)] = utf8escape..chr(182), -- ö
|
||||
[chr(252)] = utf8escape..chr(188), -- ü
|
||||
[chr(196)] = utf8escape..chr(132), -- Ä
|
||||
[chr(214)] = utf8escape..chr(150), -- Ö
|
||||
[chr(220)] = utf8escape..chr(156), -- Ü
|
||||
[chr(223)] = utf8escape..chr(159), -- ß
|
||||
}
|
||||
local lst = "["
|
||||
for k in pairs(charconv) do lst = lst .. k end
|
||||
lst = lst.."]"
|
||||
|
||||
return content:gsub(lst,charconv)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
--üäß
|
||||
|
||||
for i,filter in pairs(ide.iofilters) do
|
||||
assert(filter.output("",filter.input("","äöüÄÖÜß")),"„â€ÂäöüÄÖÜß","UTF8-ANSI conversion failed: "..(i))
|
||||
end
|
||||
|
||||
-- which: "input" or "output"
|
||||
function GetConfigIOFilter(which)
|
||||
local filtername = ide.config.editor.iofilter
|
||||
return (filtername and ide.iofilters[filtername] and ide.iofilters[filtername][which])
|
||||
end
|
||||
|
||||
197
src/editor/markup.lua
Normal file
197
src/editor/markup.lua
Normal file
@@ -0,0 +1,197 @@
|
||||
-- Copyright (C) Paul Kulchenko 2011-2012
|
||||
-- styles for comment markup
|
||||
|
||||
local styles = ide.config.styles
|
||||
local comment = styles.comment
|
||||
local MD_MARK_ITAL = '_' -- italic
|
||||
local MD_MARK_BOLD = '**' -- bold
|
||||
local MD_MARK_LINK = '[' -- link
|
||||
local MD_MARK_LINT = ')' -- link terminator
|
||||
local MD_MARK_HEAD = '#' -- header
|
||||
local MD_MARK_CODE = '`' -- code
|
||||
local MD_MARK_BOXD = '|' -- highlight
|
||||
local MD_MARK_LSEP = '](' -- link separator (between text and link)
|
||||
local MD_MARK_MARK = ' ' -- separator
|
||||
local MD_LINK_NEWWINDOW = '+' -- indicator to open a new window for links
|
||||
local markup = {
|
||||
[MD_MARK_BOXD] = {st=25, fg={127,0,127}, bg=comment.bg, b=true},
|
||||
[MD_MARK_CODE] = {st=26, fg={127,127,127}, bg=comment.bg, fs=9},
|
||||
[MD_MARK_HEAD] = {st=27, fg=comment.fg, bg=comment.bg, fn="Lucida Console", b=true},
|
||||
[MD_MARK_LINK] = {st=28, fg=comment.fg, bg=comment.bg, u=true, hs={0, 0, 127}},
|
||||
[MD_MARK_BOLD] = {st=29, fg=comment.fg, bg=comment.bg, b=true, fs=11},
|
||||
[MD_MARK_ITAL] = {st=30, fg=comment.fg, bg=comment.bg, i=true},
|
||||
[MD_MARK_MARK] = {st=31, fg=comment.fg, bg=comment.bg, v=false},
|
||||
}
|
||||
|
||||
-- allow other editor features to recognize this special markup
|
||||
function MarkupIsSpecial(style) return style == 31 end
|
||||
|
||||
local function q(s) return s:gsub('(.)','%%%1') end
|
||||
|
||||
local MD_MARK_PTRN = '' -- combination of all markup marks that can start styling
|
||||
for key,value in pairs(markup) do
|
||||
styles[key] = value
|
||||
if key ~= MD_MARK_MARK then MD_MARK_PTRN = MD_MARK_PTRN .. q(key) end
|
||||
end
|
||||
|
||||
function MarkupHotspotClick(pos, editor)
|
||||
-- check if this is "our" hotspot event
|
||||
if bit.band(editor:GetStyleAt(pos),31) ~= markup[MD_MARK_LINK].st then
|
||||
-- not "our" style, so nothing to do for us here
|
||||
return
|
||||
end
|
||||
local line = editor:LineFromPosition(pos)
|
||||
local tx = editor:GetLine(line)
|
||||
pos = pos + #MD_MARK_LINK - editor:PositionFromLine(line) -- turn into relative position
|
||||
|
||||
-- extract the URL/command on the right side of the separator
|
||||
local _,_,text = string.find(tx, q(MD_MARK_LSEP).."([^%s]+)"..q(MD_MARK_LINT), pos)
|
||||
if text then
|
||||
local filepath = ide.openDocuments[editor:GetId()].filePath
|
||||
local _,_,shell = string.find(text, [[^macro:shell%((.*%S)%)$]])
|
||||
local _,_,http = string.find(text, [[^(http:%S+)$]])
|
||||
local _,_,command = string.find(text, [[^macro:(%w+)$]])
|
||||
if shell then
|
||||
ShellExecuteCode(shell)
|
||||
elseif command == 'run' then -- run the current file
|
||||
ProjectRun()
|
||||
elseif command == 'debug' then -- debug the current file
|
||||
ProjectDebug()
|
||||
elseif http then -- open the URL in a new browser window
|
||||
wx.wxLaunchDefaultBrowser(http, 0)
|
||||
else
|
||||
-- check if requested to open in a new window
|
||||
local newwindow = string.find(text, MD_LINK_NEWWINDOW, 1, true) -- plain search
|
||||
if newwindow then text = string.gsub(text, "^%" .. MD_LINK_NEWWINDOW, "") end
|
||||
local name = wx.wxFileName(filepath):GetPath(wx.wxPATH_GET_VOLUME
|
||||
+ wx.wxPATH_GET_SEPARATOR) .. text
|
||||
-- load/activate file
|
||||
local filename = wx.wxFileName(name)
|
||||
filename:Normalize() -- remove .., ., and other similar elements
|
||||
if filename:FileExists() and
|
||||
(newwindow or SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL) then
|
||||
LoadFile(filename,not newwindow and editor or nil,true)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function ismarkup (tx)
|
||||
local start = 1
|
||||
while true do
|
||||
-- find a separator first
|
||||
local st,_,sep,more = string.find(tx, "(["..MD_MARK_PTRN.."])(.)", start)
|
||||
if not st then return end
|
||||
|
||||
-- check if this is a first character of a multi-character separator
|
||||
if not markup[sep] then sep = sep .. (more or '') end
|
||||
|
||||
local s,e,cap
|
||||
local qsep = q(sep)
|
||||
local nonsep = ("[^%s]"):format(qsep)
|
||||
local nonspace = ("[^%s]"):format(qsep.."%s")
|
||||
if sep == MD_MARK_HEAD then
|
||||
-- always search from the start of the line
|
||||
-- [%w%p] set is needed to avoid continuing this markup to the next line
|
||||
s,e,cap = string.find(tx,"^("..q(MD_MARK_HEAD)..".+[%w%p])")
|
||||
elseif sep == MD_MARK_LINK then
|
||||
-- allow everything except spaces in the second part
|
||||
s,e,cap = string.find(tx,"^("..q(MD_MARK_LINK)..nonspace..".-"..nonspace
|
||||
..q(MD_MARK_LSEP).."[^%s]+"
|
||||
..q(MD_MARK_LINT)..")", st)
|
||||
elseif markup[sep] then
|
||||
-- try 2+ characters between separators first
|
||||
-- if not found, try a single character
|
||||
s,e,cap = string.find(tx,"^("..qsep..nonspace..nonsep.."-"..nonspace..qsep..")", st)
|
||||
if not s then s,e,cap = string.find(tx,"^("..qsep..nonspace..qsep..")", st) end
|
||||
end
|
||||
if s and -- selected markup is surrounded by spaces or punctuation
|
||||
(s == start or tx:sub(s-1, s-1):match("[%s%p]")) and
|
||||
(e-s == #tx-1 or tx:sub(e+1, e+1):match("[%s%p]"))
|
||||
then return s,e,cap,sep end
|
||||
start = st+1
|
||||
end
|
||||
end
|
||||
|
||||
function MarkupStyle(editor, lines, linee)
|
||||
local lines = lines or 0
|
||||
if (lines < 0) then return end
|
||||
|
||||
-- always style to the end as there may be comments that need re-styling
|
||||
-- technically, this should be GetLineCount()-1, but we want to style
|
||||
-- beyond the last line to make sure it is styled correctly
|
||||
local linee = linee or editor:GetLineCount()
|
||||
|
||||
local iscomment = {}
|
||||
for i,v in pairs(editor.spec.iscomment) do
|
||||
iscomment[i] = v
|
||||
end
|
||||
|
||||
for line=lines,linee do
|
||||
local tx = editor:GetLine(line)
|
||||
local ls = editor:PositionFromLine(line)
|
||||
|
||||
editor:StartStyling(ls, 0)
|
||||
|
||||
local from = 1
|
||||
local off = -1
|
||||
|
||||
while from do
|
||||
tx = string.sub(tx,from)
|
||||
local f,t,w,mark = ismarkup(tx)
|
||||
|
||||
if (f) then
|
||||
local p = ls+f+off
|
||||
local s = bit.band(editor:GetStyleAt(p), 31)
|
||||
if iscomment[s] then
|
||||
local smark = #mark
|
||||
local emark = #mark -- assumes end mark is the same length as start mark
|
||||
if mark == MD_MARK_HEAD then
|
||||
-- grab multiple MD_MARK_HEAD if present
|
||||
local _,_,full = string.find(w,"^("..q(MD_MARK_HEAD).."+)")
|
||||
smark,emark = #full,0
|
||||
elseif mark == MD_MARK_LINK then
|
||||
local lsep = w:find(q(MD_MARK_LSEP))
|
||||
if lsep then emark = #w-lsep+#MD_MARK_LINT end
|
||||
end
|
||||
editor:StartStyling(p, 31)
|
||||
editor:SetStyling(smark, markup[MD_MARK_MARK].st)
|
||||
editor:SetStyling(t-f+1-smark-emark, markup[mark].st or markup[MD_MARK_MARK].st)
|
||||
editor:SetStyling(emark, markup[MD_MARK_MARK].st)
|
||||
end
|
||||
|
||||
off = off + t
|
||||
end
|
||||
from = t and (t+1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- this could work by calling MarkupStyle directly from EVT_UPDATEUI,
|
||||
-- but the styling didn't work correctly as the style on block comments
|
||||
-- (which is used to identify where the markup should be applied)
|
||||
-- was not always correct during UPDATEUI event.
|
||||
-- to rectify this, we style immediately (by calling MarkupStyle
|
||||
-- from UPDATEUI), but also store the starting point and re-style during
|
||||
-- the next UPDATEUI/IDLE event when the block comment style is correct.
|
||||
local needStyle = {}
|
||||
local frame
|
||||
function MarkupStyleRefresh(editor, ev)
|
||||
if not frame then
|
||||
frame = ide.frame
|
||||
frame:Connect(wx.wxEVT_IDLE,
|
||||
function(event) MarkupStyleRefresh(); event:Skip() end)
|
||||
end
|
||||
|
||||
if not ev or #ev == 0 then -- no new records, refresh deferred ones
|
||||
for ed,line in pairs(needStyle) do
|
||||
MarkupStyle(ed, line)
|
||||
needStyle[ed] = nil
|
||||
end
|
||||
else -- store records from the event table to defer refresh
|
||||
for _,pos in ipairs(ev) do
|
||||
needStyle[editor] = editor:LineFromPosition(pos[1])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,12 +1,10 @@
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
dofile "src/editor/menu_file.lua"
|
||||
dofile "src/editor/menu_edit.lua"
|
||||
dofile "src/editor/menu_search.lua"
|
||||
dofile "src/editor/menu_view.lua"
|
||||
dofile "src/editor/menu_project.lua"
|
||||
dofile "src/editor/menu_tools.lua"
|
||||
|
||||
ide.frame:SetMenuBar(ide.frame.menuBar )
|
||||
-- authors: Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
|
||||
dofile "src/editor/menu_file.lua"
|
||||
dofile "src/editor/menu_edit.lua"
|
||||
dofile "src/editor/menu_search.lua"
|
||||
dofile "src/editor/menu_view.lua"
|
||||
dofile "src/editor/menu_project.lua"
|
||||
dofile "src/editor/menu_tools.lua"
|
||||
|
||||
@@ -1,199 +1,177 @@
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Create the Edit menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
|
||||
|
||||
|
||||
local editMenu = wx.wxMenu{
|
||||
{ ID_CUT, "Cu&t\tCtrl-X", "Cut selected text to clipboard" },
|
||||
{ ID_COPY, "&Copy\tCtrl-C", "Copy selected text to the clipboard" },
|
||||
{ ID_PASTE, "&Paste\tCtrl-V", "Insert clipboard text at cursor" },
|
||||
{ ID_SELECTALL, "Select A&ll\tCtrl-A", "Select all text in the editor" },
|
||||
{ },
|
||||
{ ID_UNDO, "&Undo\tCtrl-Z", "Undo the last action" },
|
||||
{ ID_REDO, "&Redo\tCtrl-Y", "Redo the last action undone" },
|
||||
{ },
|
||||
{ ID "edit.showtooltip", "Show &Tooltip\tCtrl+T", "Show tooltip for current position. Place cursor after opening bracket of function."},
|
||||
{ ID_AUTOCOMPLETE, "Complete &Identifier\tCtrl+K", "Complete the current identifier" },
|
||||
{ ID_AUTOCOMPLETE_ENABLE, "Auto complete Identifiers", "Auto complete while typing", wx.wxITEM_CHECK },
|
||||
{ },
|
||||
{ ID_COMMENT, "C&omment/Uncomment\tCtrl-Q", "Comment or uncomment current or selected lines"},
|
||||
{ },
|
||||
{ ID_FOLD, "&Fold/Unfold all\tF12", "Fold or unfold all code folds"} }
|
||||
menuBar:Append(editMenu, "&Edit")
|
||||
|
||||
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
|
||||
|
||||
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor ~= nil)
|
||||
end
|
||||
|
||||
local shellboxeditor = ide.frame.vsplitter.splitter.bottomnotebook.shellbox.input
|
||||
function OnEditMenu(event)
|
||||
|
||||
local menu_id = event:GetId()
|
||||
local editor = GetEditor()
|
||||
if shellboxeditor:FindFocus():GetId() == shellboxeditor:GetId() then
|
||||
editor = shellboxeditor
|
||||
end
|
||||
if editor == nil then return end
|
||||
|
||||
if menu_id == ID_CUT then editor:Cut()
|
||||
elseif menu_id == ID_COPY then editor:Copy()
|
||||
elseif menu_id == ID_PASTE then editor:Paste()
|
||||
elseif menu_id == ID_SELECTALL then editor:SelectAll()
|
||||
elseif menu_id == ID_UNDO then editor:Undo()
|
||||
elseif menu_id == ID_REDO then editor:Redo()
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_CUT, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_CUT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_COPY, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_COPY, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
-- buggy GTK clipboard runs eventloop and can generate asserts
|
||||
event:Enable(editor and (wx.__WXGTK__ or editor:CanPaste()))
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanUndo())
|
||||
end)
|
||||
|
||||
frame:Connect(ID_REDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_REDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanRedo())
|
||||
end)
|
||||
|
||||
frame:Connect(ID "edit.showtooltip", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
linetxtopos = linetx:sub(1,localpos)
|
||||
linetxtopos = linetxtopos..")"
|
||||
linetxtopos = linetxtopos:match("([a-zA-Z_0-9%.%:]+)%b()$")
|
||||
|
||||
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
|
||||
if tip then
|
||||
if(editor:CallTipActive()) then
|
||||
editor:CallTipCancel()
|
||||
end
|
||||
editor:CallTipShow(pos,tip)
|
||||
end
|
||||
end)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
if (editor == nil or not editor.spec) then return end
|
||||
|
||||
-- retrieve the current line and get a string to the current cursor position in the line
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
|
||||
local lt = linetx:sub(1,localpos)
|
||||
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
|
||||
lt = lt:gsub("%s*%b[]%s*","")
|
||||
lt = lt:gsub("%s*%b()%s*","")
|
||||
lt = lt:gsub("%s*%b{}%s*","")
|
||||
lt = lt:match("[^%[%(%s]*$")
|
||||
lt = lt:gsub("%s","")
|
||||
|
||||
|
||||
--[[
|
||||
local acstart = 1
|
||||
local state = ""
|
||||
for i=localpos,1,-1 do -- find out what should be completed
|
||||
local c = linetx:sub(i,i)
|
||||
if c : match "[%s]" and state~="begin" then
|
||||
state = "space"
|
||||
elseif c : match "[_0-9a-zA-Z]" then
|
||||
if state == "space" then
|
||||
acstart = i+1
|
||||
break
|
||||
end
|
||||
state = "word"
|
||||
elseif c : match(editor.spec.sep) then
|
||||
state = "begin"
|
||||
elseif c : match "[^%s]" then -- unknown char
|
||||
acstart = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
local lt = linetx:sub(acstart,localpos) : gsub("%s","")
|
||||
]]
|
||||
|
||||
-- know now which string is to be completed
|
||||
|
||||
local userList = CreateAutoCompList(editor,lt)
|
||||
if userList and string.len(userList) > 0 then
|
||||
editor:UserListShow(1, userList)
|
||||
--ShowList(userList)
|
||||
elseif (editor:AutoCompActive()) then
|
||||
editor:AutoCompCancel()
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE_ENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ide.config.autocomplete = event:IsChecked()
|
||||
end)
|
||||
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local buf = {}
|
||||
if editor:GetSelectionStart() == editor:GetSelectionEnd() then
|
||||
local lineNumber = editor:GetCurrentLine()
|
||||
editor:SetSelection(editor:PositionFromLine(lineNumber), editor:GetLineEndPosition(lineNumber))
|
||||
end
|
||||
local lc = editor.spec.linecomment
|
||||
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
|
||||
if string.sub(line,1,2) == lc then
|
||||
line = string.sub(line,3)
|
||||
else
|
||||
line = lc..line
|
||||
end
|
||||
table.insert(buf, line)
|
||||
end
|
||||
editor:ReplaceSelection(table.concat(buf,"\n"))
|
||||
end)
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
|
||||
frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
FoldSome()
|
||||
end)
|
||||
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Create the Edit menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
|
||||
local editMenu = wx.wxMenu{
|
||||
{ ID_CUT, "Cu&t\tCtrl-X", "Cut selected text to clipboard" },
|
||||
{ ID_COPY, "&Copy\tCtrl-C", "Copy selected text to the clipboard" },
|
||||
{ ID_PASTE, "&Paste\tCtrl-V", "Insert clipboard text at cursor" },
|
||||
{ ID_SELECTALL, "Select A&ll\tCtrl-A", "Select all text in the editor" },
|
||||
{ },
|
||||
{ ID_UNDO, "&Undo\tCtrl-Z", "Undo the last action" },
|
||||
{ ID_REDO, "&Redo\tCtrl-Y", "Redo the last action undone" },
|
||||
{ },
|
||||
{ ID "edit.showtooltip", "Show &Tooltip\tCtrl-T", "Show tooltip for current position. Place cursor after opening bracket of function."},
|
||||
{ ID_AUTOCOMPLETE, "Complete &Identifier\tCtrl-K", "Complete the current identifier" },
|
||||
{ ID_AUTOCOMPLETE_ENABLE, "Auto complete Identifiers", "Auto complete while typing", wx.wxITEM_CHECK },
|
||||
{ },
|
||||
{ ID_COMMENT, "C&omment/Uncomment\tCtrl-U", "Comment or uncomment current or selected lines"},
|
||||
{ },
|
||||
{ ID_FOLD, "&Fold/Unfold all\tF12", "Fold or unfold all code folds"},
|
||||
{ ID "edit.cleardynamics", "Clear &Dynamic Words", "Resets the dynamic word list for autcompletion."},
|
||||
}
|
||||
menuBar:Append(editMenu, "&Edit")
|
||||
|
||||
editMenu:Check(ID_AUTOCOMPLETE_ENABLE, ide.config.autocomplete)
|
||||
|
||||
function OnUpdateUIEditMenu(event) -- enable if there is a valid focused editor
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor ~= nil)
|
||||
end
|
||||
|
||||
local othereditors = { frame.bottomnotebook.shellbox, frame.bottomnotebook.errorlog }
|
||||
|
||||
function OnEditMenu(event)
|
||||
local menu_id = event:GetId()
|
||||
local editor = GetEditor()
|
||||
for _,e in pairs(othereditors) do
|
||||
if e:FindFocus():GetId() == e:GetId() then editor = e end
|
||||
end
|
||||
if editor == nil then return end
|
||||
|
||||
if menu_id == ID_CUT then editor:Cut()
|
||||
elseif menu_id == ID_COPY then editor:Copy()
|
||||
elseif menu_id == ID_PASTE then editor:Paste()
|
||||
elseif menu_id == ID_SELECTALL then editor:SelectAll()
|
||||
elseif menu_id == ID_UNDO then editor:Undo()
|
||||
elseif menu_id == ID_REDO then editor:Redo()
|
||||
end
|
||||
end
|
||||
|
||||
frame:Connect(ID_CUT, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_CUT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_COPY, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_COPY, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_PASTE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
-- buggy GTK clipboard runs eventloop and can generate asserts
|
||||
event:Enable(editor and (wx.__WXGTK__ or editor:CanPaste()))
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_SELECTALL, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_UNDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanUndo())
|
||||
end)
|
||||
|
||||
frame:Connect(ID_REDO, wx.wxEVT_COMMAND_MENU_SELECTED, OnEditMenu)
|
||||
frame:Connect(ID_REDO, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor and editor:CanRedo())
|
||||
end)
|
||||
|
||||
frame:Connect(ID "edit.cleardynamics", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
DynamicWordsReset()
|
||||
end)
|
||||
|
||||
frame:Connect(ID "edit.showtooltip", wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local linetxtopos = linetx:sub(1,localpos)
|
||||
linetxtopos = linetxtopos..")"
|
||||
linetxtopos = linetxtopos:match("([a-zA-Z_0-9%.%:]+)%b()$")
|
||||
|
||||
local tip = linetxtopos and GetTipInfo(editor,linetxtopos.."(",false)
|
||||
if tip then
|
||||
if(editor:CallTipActive()) then
|
||||
editor:CallTipCancel()
|
||||
end
|
||||
editor:CallTipShow(pos,tip)
|
||||
end
|
||||
end)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
if (editor == nil or not editor.spec) then return end
|
||||
|
||||
-- retrieve the current line and get a string to the current cursor position in the line
|
||||
local pos = editor:GetCurrentPos()
|
||||
local line = editor:GetCurrentLine()
|
||||
local linetx = editor:GetLine(line)
|
||||
local linestart = editor:PositionFromLine(line)
|
||||
local localpos = pos-linestart
|
||||
|
||||
local lt = linetx:sub(1,localpos)
|
||||
lt = lt:gsub("%s*("..editor.spec.sep..")%s*",function(a) return a end)
|
||||
lt = lt:gsub("%s*%b[]%s*","")
|
||||
lt = lt:gsub("%s*%b()%s*","")
|
||||
lt = lt:gsub("%s*%b{}%s*","")
|
||||
lt = lt:match("[^%[%(%s]*$")
|
||||
lt = lt:gsub("%s","")
|
||||
|
||||
-- know now which string is to be completed
|
||||
|
||||
local userList = CreateAutoCompList(editor,lt)
|
||||
if userList and string.len(userList) > 0 then
|
||||
editor:UserListShow(1, userList)
|
||||
--ShowList(userList)
|
||||
elseif (editor:AutoCompActive()) then
|
||||
editor:AutoCompCancel()
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_AUTOCOMPLETE, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_AUTOCOMPLETE_ENABLE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ide.config.autocomplete = event:IsChecked()
|
||||
end)
|
||||
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local buf = {}
|
||||
if editor:GetSelectionStart() == editor:GetSelectionEnd() then
|
||||
local lineNumber = editor:GetCurrentLine()
|
||||
editor:SetSelection(editor:PositionFromLine(lineNumber), editor:GetLineEndPosition(lineNumber))
|
||||
end
|
||||
local lc = editor.spec.linecomment
|
||||
for line in string.gmatch(editor:GetSelectedText()..'\n', "(.-)\r?\n") do
|
||||
if string.sub(line,1,2) == lc then
|
||||
line = string.sub(line,3)
|
||||
else
|
||||
line = lc..line
|
||||
end
|
||||
table.insert(buf, line)
|
||||
end
|
||||
editor:ReplaceSelection(table.concat(buf,"\n"))
|
||||
end)
|
||||
frame:Connect(ID_COMMENT, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
frame:Connect(ID_FOLD, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
FoldSome()
|
||||
end)
|
||||
frame:Connect(ID_FOLD, wx.wxEVT_UPDATE_UI, OnUpdateUIEditMenu)
|
||||
|
||||
@@ -1,125 +1,115 @@
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- Create the File menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
local openDocuments = ide.openDocuments
|
||||
local debugger = ide.debugger
|
||||
|
||||
local fileMenu = wx.wxMenu({
|
||||
{ ID_NEW, "&New\tCtrl-N", "Create an empty document" },
|
||||
{ ID_OPEN, "&Open...\tCtrl-O", "Open an existing document" },
|
||||
{ ID_CLOSE, "&Close page\tCtrl+W", "Close the current editor window" },
|
||||
{ },
|
||||
{ ID_SAVE, "&Save\tCtrl-S", "Save the current document" },
|
||||
{ ID_SAVEAS, "Save &As...\tAlt-Shift-S", "Save the current document to a file with a new name" },
|
||||
{ ID_SAVEALL, "Save A&ll...\tCtrl-Shift-S", "Save all open documents" },
|
||||
{ },
|
||||
--{ ID "file.recentfiles", "Recent files",},
|
||||
{ },
|
||||
{ ID_EXIT, "E&xit\tAlt-X", "Exit Program" }})
|
||||
menuBar:Append(fileMenu, "&File")
|
||||
|
||||
local filehistorymenu = wx.wxMenu({})
|
||||
local filehistory = wx.wxMenuItem(fileMenu,ID"file.recentfiles","Recent files", "File history", wx.wxITEM_NORMAL,filehistorymenu)
|
||||
fileMenu:Insert(8,filehistory)
|
||||
function UpdateFileHistoryUI(list)
|
||||
-- remove all at first
|
||||
for i=1,filehistorymenu:GetMenuItemCount() do
|
||||
filehistorymenu:Delete( ID("file.recentfiles."..i))
|
||||
end
|
||||
for i=1,#list do
|
||||
local file = list[i].filename
|
||||
local item = wx.wxMenuItem(filehistorymenu, ID("file.recentfiles."..i),file,"")
|
||||
filehistorymenu:Append(item)
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,ide.config.filehistorylength do
|
||||
frame:Connect(ID("file.recentfiles."..i), wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local item = filehistorymenu:FindItemByPosition(i-1)
|
||||
local filename = item:GetLabel()
|
||||
LoadFile(filename)
|
||||
--DisplayOutput("selected "..tostring(filename).."\n")
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, NewFile)
|
||||
frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile)
|
||||
frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local id = editor:GetId()
|
||||
local filePath = openDocuments[id].filePath
|
||||
if (filePath) then
|
||||
SaveFile(editor, filePath)
|
||||
else
|
||||
SaveFileAs(editor)
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
if editor then
|
||||
local id = editor:GetId()
|
||||
if openDocuments[id] then
|
||||
event:Enable(openDocuments[id].isModified or not openDocuments[id].filePath)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
SaveFileAs(editor)
|
||||
end)
|
||||
frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor ~= nil)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
SaveAll()
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local atLeastOneModifiedDocument = false
|
||||
for id, document in pairs(openDocuments) do
|
||||
if document.isModified then
|
||||
atLeastOneModifiedDocument = true
|
||||
break
|
||||
end
|
||||
end
|
||||
event:Enable(atLeastOneModifiedDocument)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local id = editor:GetId()
|
||||
if SaveModifiedDialog(editor, true) ~= wx.wxID_CANCEL then
|
||||
RemovePage(openDocuments[id].index)
|
||||
end
|
||||
end)
|
||||
|
||||
frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
event:Enable((GetEditor() ~= nil) and (debugger.server == nil))
|
||||
end)
|
||||
|
||||
|
||||
frame:Connect( ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
if not SaveOnExit(true) then return end
|
||||
frame:Close() -- will handle wxEVT_CLOSE_WINDOW
|
||||
CloseWatchWindow()
|
||||
end)
|
||||
|
||||
-- authors: Lomtik Software (J. Winwood & John Labenski)
|
||||
-- Luxinia Dev (Eike Decker & Christoph Kubisch)
|
||||
---------------------------------------------------------
|
||||
local ide = ide
|
||||
-- Create the File menu and attach the callback functions
|
||||
|
||||
local frame = ide.frame
|
||||
local menuBar = frame.menuBar
|
||||
local openDocuments = ide.openDocuments
|
||||
local debugger = ide.debugger
|
||||
|
||||
local fileMenu = wx.wxMenu({
|
||||
{ ID_NEW, "&New\tCtrl-N", "Create an empty document" },
|
||||
{ ID_OPEN, "&Open...\tCtrl-O", "Open an existing document" },
|
||||
{ ID_CLOSE, "&Close page\tCtrl-W", "Close the current editor window" },
|
||||
{ },
|
||||
{ ID_SAVE, "&Save\tCtrl-S", "Save the current document" },
|
||||
{ ID_SAVEAS, "Save &As...\tAlt-Shift-S", "Save the current document to a file with a new name" },
|
||||
{ ID_SAVEALL, "Save A&ll...", "Save all open documents" },
|
||||
{ },
|
||||
--{ ID "file.recentfiles", "Recent files",},
|
||||
{ },
|
||||
{ ID_EXIT, "E&xit", "Exit Program" }})
|
||||
menuBar:Append(fileMenu, "&File")
|
||||
|
||||
local filehistorymenu = wx.wxMenu({})
|
||||
local filehistory = wx.wxMenuItem(fileMenu,ID"file.recentfiles","Recent files", "File history", wx.wxITEM_NORMAL,filehistorymenu)
|
||||
fileMenu:Insert(8,filehistory)
|
||||
function UpdateFileHistoryUI(list)
|
||||
-- remove all at first
|
||||
for i=1,filehistorymenu:GetMenuItemCount() do
|
||||
filehistorymenu:Delete( ID("file.recentfiles."..i))
|
||||
end
|
||||
for i=1,#list do
|
||||
local file = list[i].filename
|
||||
local item = wx.wxMenuItem(filehistorymenu, ID("file.recentfiles."..i),file,"")
|
||||
filehistorymenu:Append(item)
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,ide.config.filehistorylength do
|
||||
frame:Connect(ID("file.recentfiles."..i), wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local item = filehistorymenu:FindItemByPosition(i-1)
|
||||
local filename = item:GetLabel()
|
||||
LoadFile(filename)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, NewFile)
|
||||
frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile)
|
||||
frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
local id = editor:GetId()
|
||||
local filePath = openDocuments[id].filePath
|
||||
if (filePath) then
|
||||
SaveFile(editor, filePath)
|
||||
else
|
||||
SaveFileAs(editor)
|
||||
end
|
||||
end)
|
||||
frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
if editor then
|
||||
local id = editor:GetId()
|
||||
if openDocuments[id] then
|
||||
event:Enable(openDocuments[id].isModified or not openDocuments[id].filePath)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
SaveFileAs(editor)
|
||||
end)
|
||||
frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local editor = GetEditor()
|
||||
event:Enable(editor ~= nil)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
SaveAll()
|
||||
end)
|
||||
frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
local atLeastOneModifiedDocument = false
|
||||
for id, document in pairs(openDocuments) do
|
||||
if document.isModified then
|
||||
atLeastOneModifiedDocument = true
|
||||
break
|
||||
end
|
||||
end
|
||||
event:Enable(atLeastOneModifiedDocument)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
ClosePage() -- this will find the current editor
|
||||
end)
|
||||
frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI,
|
||||
function (event)
|
||||
event:Enable(GetEditor() ~= nil)
|
||||
end)
|
||||
|
||||
frame:Connect(ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED,
|
||||
function (event)
|
||||
if not SaveOnExit(true) then return end
|
||||
frame:Close() -- this will trigger wxEVT_CLOSE_WINDOW
|
||||
end)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user