Compare commits

...

293 Commits
0.20 ... 0.30

Author SHA1 Message Date
Paul Kulchenko
ce8f120e48 Improved logic in love2d integration to distinguish Debug and Run commands
(closes #13)
2012-06-28 10:24:13 -07:00
Paul Kulchenko
048fd2349a Updated menus to avoid conflicts with MacOS shortcuts 2012-06-26 22:13:52 -07:00
Paul Kulchenko
2627957e5a Updated logic creating menubar to make it work correctly on MacOS with special Help/About items 2012-06-26 21:32:06 -07:00
Paul Kulchenko
16b0ca0fc7 Updated path handling to better detect how the app is started and to avoid loading dlls on non-windows platforms 2012-06-26 19:29:00 -07:00
Paul Kulchenko
e3189ba38a Updated logic for detecting hostname (used in the debugger) to make sure it is resolvable 2012-06-26 19:11:39 -07:00
Paul Kulchenko
ad48622f68 Fixed aborting running/debugged programs on MacOS by adding MAKE_GROUP_LEADER option to wxExecute 2012-06-26 19:06:14 -07:00
Paul Kulchenko
0a9439ad22 Added display of hierarchical data in Stack window 2012-06-25 18:23:26 -07:00
Paul Kulchenko
a7577d5054 Updated Analyze output 2012-06-25 18:22:20 -07:00
Paul Kulchenko
668cdcb4db Added auto complete for love2d API 2012-06-25 14:47:21 -07:00
Paul Kulchenko
4ec3e87473 Added support for debugging processes running under LuaJIT (requires MobDebug v0.467+) 2012-06-24 22:01:02 -07:00
Paul Kulchenko
90b4f38223 Added love2d support 2012-06-24 17:52:59 -07:00
Paul Kulchenko
c1918e5c38 Removed extensions from launch commands and updated display logic in the Output window 2012-06-24 16:40:10 -07:00
Paul Kulchenko
34baaa9447 Fixed an issue in the logic for setting breakpoints, which ignored breakpoints in luxinia2 debug sessions 2012-06-24 16:00:25 -07:00
Paul Kulchenko
817938593a Fixed logic in the local/remote console that returned incorrect error message on executing code like '%s':format(1); expressions are evaluated first now and the order of evaluation is consistent between local and remote consoles 2012-06-23 23:55:59 -07:00
Paul Kulchenko
b944f9d01d Fixed IDs for Project menu items to allow them to be removed from the menu if needed 2012-06-23 23:53:34 -07:00
Paul Kulchenko
5d4b2395b5 Added execution time and updated messages in the Output window to be more consistent 2012-06-23 13:33:29 -07:00
Paul Kulchenko
f9ab1546ff Added displaying 'nil' values in local console when no result is returned by an expression 2012-06-20 21:36:04 -07:00
Paul Kulchenko
971e7c8316 Disabled Stack and Watch updates when scratchpad is active as they interfere with application execution 2012-06-20 21:30:42 -07:00
Paul Kulchenko
60a89b8f32 Fixed an app running without debugger when 'stack' command is sent immediately after an external application connects to the debugger 2012-06-20 19:21:25 -07:00
Paul Kulchenko
7275f0d11a Fixed an issue with remote application not terminating when IDE is closed while debugging is in progress 2012-06-20 18:19:40 -07:00
Paul Kulchenko
35213d7d3b Added a check to refuse starting a new debugging session if there is one in progress already 2012-06-20 17:02:05 -07:00
Paul Kulchenko
cde26253e3 Fixed sending breakpoints set before establishing a debugging session started from another process that connects to the IDE debugger 2012-06-20 16:54:50 -07:00
Paul Kulchenko
b45c0600c7 Added handling of tail calls in the Stack window 2012-06-20 16:33:24 -07:00
Paul Kulchenko
5784dea99a Fixed refreshing a modified file when the editor is set to read-only mode 2012-06-19 12:24:06 -07:00
Paul Kulchenko
e880fdde60 Added pretty printing in Watch and Console (local and remote) windows and handling of multiple results in Console 2012-06-19 09:34:32 -07:00
Paul Kulchenko
b7d8512b7b Added Stack window to display stack information and local/upvalue values for each stack frame 2012-06-18 14:53:10 -07:00
Paul Kulchenko
a7a8f32c91 Fixed saving/restoring configuration of 'Output'/'Console' tabs when IDE is closed while debugging is in progress 2012-06-16 17:31:21 -07:00
Paul Kulchenko
9fc4ab5e9b Fixed removing variable name in Watch window after escaping editing 2012-06-15 16:39:51 -07:00
Paul Kulchenko
37434534cc Fixed #9 as it had incorrect logic in one of UTF filters 2012-06-11 08:24:27 -07:00
Paul Kulchenko
fc03c2843b Fixed ability to set font encoding for 'Output' and 'Console' windows in the config 2012-06-10 16:01:24 -07:00
Paul Kulchenko
2abbad04ac Added ability to set font encoding in the config 2012-06-10 15:40:14 -07:00
Paul Kulchenko
dbb392e009 Moved processing of user.lua to a later phase after tools and specs are
already loaded to allow modification of IDE configuration from `user.lua`.
Closes #5.

Added example to user-sample.lua on how the configuration can be modified.
2012-06-09 18:57:11 -07:00
Paul Kulchenko
65947ff924 Added checks to prevent text modification in 'Output' and 'Console'
windows. Fixes #8.

Text modifications are checked against (1) direct input, (2) actions using
context menu, and (3) move/copy using selection and mouse drag and drop.
Added input marker to the 'Output' window to indicate where input is
expected.
2012-06-09 17:17:24 -07:00
Paul Kulchenko
d8324b269d Fixed edit menu shortcuts to work in the 'Output' window (when allowed) 2012-06-08 16:44:17 -07:00
Paul Kulchenko
ac9c2e9a84 Added ability to interact with scripts by allowing text to be entered in the 'Output' window.
This is controlled by ide.config.allowinteractivescript variable".
 The window is only activated and switched into read-write mode after
 there is some output to it.
2012-06-08 13:07:48 -07:00
Paul Kulchenko
3b2fcfd1f9 Added restoring cursor position when a modified file is reloaded in the editor; removed unnecessary isFileAlteredOnDisk check 2012-06-08 13:01:44 -07:00
Paul Kulchenko
14fe7af771 Fixed reporting of processes that failed to start after 'Run' or 'Debug' commands 2012-06-07 14:13:17 -07:00
Paul Kulchenko
7b0405bc79 Fixed executable path matching to work on systems that don't have file extensions 2012-06-07 13:52:50 -07:00
Paul Kulchenko
fc6b0c176d Cleaned up ShellSupportRemote interface to remove a parameter not being used 2012-06-07 13:51:20 -07:00
Paul Kulchenko
5c50a2645b Improved reporting in static analysis for functions and global variables.
Added "unknown global function...".
Added "unused local function...".
Added "local function ... masks...".
Updated reporting of unused global to "first use of unknown global" to
minimise the number of instances reported until globals assigned through
"required" modules are recognized.
2012-06-05 16:15:02 -07:00
Paul Kulchenko
11cfbfa68d Fixed localization of variables in several places 2012-06-05 15:37:30 -07:00
Paul Kulchenko
e6b318c643 Fixed #3 'unused parameter...' check not to fail on anonymous functions that are part of an expression 2012-06-05 14:06:40 -07:00
Paul Kulchenko
1351db6114 Several fixes to the static code analyzer.
"Unknown global" is only reported once per line.
"First assignment to global..." is fixed to only report when the variable
is on the left side of the assignment.
"Value discarded" warning is added when multiple assignment has more values than
variables.
2012-06-05 11:06:46 -07:00
Paul Kulchenko
b58e931409 Changed static analyzer to only load metalua when Analyze function is
used, rather than on startup.
2012-06-04 12:21:47 -07:00
Paul Kulchenko
e0eb05b122 Disabled 'Run as Scratchpad' if there is no debugger registered capable of running it 2012-06-04 12:15:14 -07:00
Paul Kulchenko
8ecd8dfa6b Changed order of lualibs/ and bin/ directories in package.path and
package.cpath to load included modules first.

This should minimize conflicts with other versions of same modules that
may exist somewhere else in the path.
2012-06-04 12:01:10 -07:00
Paul Kulchenko
c1961e5c4b Added Ctrl(-Shift)-TAB navigation between tabs in the editor 2012-05-31 14:20:48 -07:00
Paul Kulchenko
3ead2966d8 Fixed localization of variables based on static analysis 2012-05-30 13:15:58 -07:00
Paul Kulchenko
0bcf590f45 Added reporting of assignment to global variables in the code analyzer 2012-05-30 11:27:17 -07:00
Paul Kulchenko
e8f308ca08 Added ability to turn external processes that connect to debugger into a scratchpad; fixed 'exit' to make it work for remote applications; upgraded to MobDebug 0.449 2012-05-26 23:02:20 -07:00
Paul Kulchenko
ecb59ceb9e Updated comment styling to follow markdown syntax 2012-05-15 23:05:26 -07:00
Paul Kulchenko
a317f986e1 Fixed styling in markup module that wasn't always working when a block comment was uncommented 2012-05-14 19:01:40 -07:00
Paul Kulchenko
623905c81c Added navigation between editor tabs using Ctrl-PgUp and Ctrl-PgDn 2012-05-13 23:10:25 -07:00
Paul Kulchenko
11b702ac6e Added exit from full screen mode using ESC key 2012-05-13 22:38:17 -07:00
Paul Kulchenko
f926aef2f8 Updated MANIFEST with luainspect module files and luasocket module reorg 2012-05-13 22:36:12 -07:00
Paul Kulchenko
3754406e85 Merge branch 'scratchpad' 2012-05-11 16:39:21 -07:00
Paul Kulchenko
981bccbe27 Added menu shortcut for Run As Scratchpad 2012-05-11 14:56:35 -07:00
Paul Kulchenko
047a9e8ac5 Upgraded to Mobdebug 0.448 to fix handling of scripts with comments in the remote shell 2012-05-11 14:30:58 -07:00
Paul Kulchenko
d1f2e8450a Fixed an issue with Analyze process when the analyzed script has compilation errors 2012-05-07 23:01:31 -07:00
Paul Kulchenko
21cfba9cb6 Added reporting of compilation errors during debugging sessions (when external client connects to the debugger and the current script has compilation errors) 2012-05-07 22:56:30 -07:00
Paul Kulchenko
3f711373ed Added handling of more error in the shell to allow calculations like '(1+2)' to be executed correctly (both locally and remotely) 2012-05-07 22:25:22 -07:00
Paul Kulchenko
00fe05e89f Fixed an earlier introduced bug with Run/Debug proceeding after failed compilation; removed references to internal code in compilation errors (in scratchpad) 2012-05-06 18:27:15 -07:00
Paul Kulchenko
3bcd54bd46 Added moving focus back to the notebook after unhiding/activating a wx window 2012-05-06 15:28:16 -07:00
Paul Kulchenko
8de9e41fd6 Updated README 2012-05-06 14:34:45 -07:00
Paul Kulchenko
29b6755a9b Fixed cursor to change to a default one (instead of an arrow) after number sliding 2012-05-06 14:29:49 -07:00
Paul Kulchenko
7d6be282f1 Updated clearing 'output' window to minimize showing duplicate output when running as scratchpad 2012-05-06 14:20:59 -07:00
Paul Kulchenko
f89fd4d752 Added handling of negative numbers for number sliders in scratchpad; added logic to ignore malformed numbers (they are still styled though) 2012-05-05 23:11:22 -07:00
Paul Kulchenko
03adda1cef Added stopping debugger and scratchpad when a window with debugging/scratchpad action is closed 2012-05-05 18:42:12 -07:00
Paul Kulchenko
2992424e87 Fixed an issue with scratchpad being on after Save dialog is canceled 2012-05-05 17:16:24 -07:00
Paul Kulchenko
e302a97682 Added support for using different debugger calls and moved scratchpad to a different debugger for performance reasons; upgraded to Mobdebug 0.446 2012-05-05 14:20:55 -07:00
Paul Kulchenko
7b5d37d595 Added mouse capture for slider operations in scratchpad to increase the range of available values 2012-05-03 16:40:47 -07:00
Paul Kulchenko
01ae85dc5a Reorganized the scratchpad code and added scratchpad teardown code to run when the debugged application is closed 2012-05-03 16:27:54 -07:00
Paul Kulchenko
f650d8f64f Added clearing output window when requested and formatting for compile/execution error messages 2012-05-03 12:58:39 -07:00
Paul Kulchenko
602f8ef223 Fixed debugging menu items to be hidden when running as scratchpad 2012-05-03 12:22:03 -07:00
Paul Kulchenko
6afc999b75 Added number slider processing with dynamic reloading of scratchpad scripts; upgraded to MobDebug 0.445 for better stability 2012-05-03 10:25:25 -07:00
Paul Kulchenko
2ccd214a1f Added stopping criteria to allow execution of any scripts (even empty ones) under 'Run as Scratchpad'; removed stack trace from remote error messages in the scratchpad 2012-05-02 10:45:59 -07:00
Paul Kulchenko
8efde0ec1f Added a check to turn 'Run as Scratchpad' on even when the initial compilation fails 2012-05-02 10:16:30 -07:00
Paul Kulchenko
1c5b14870c Updated event logic in the scratchpad to make sure editor change events do not get lost while an earlier change is being worked on 2012-05-02 00:09:48 -07:00
Paul Kulchenko
2c87909920 Disabled 'Run as Scratchpad' option when the script is already running 2012-05-01 22:00:46 -07:00
Paul Kulchenko
2a2a3bed96 Added reporting of run-time errors when running as scratchpad; upgraded to MobDebug 0.444 2012-05-01 21:49:45 -07:00
Paul Kulchenko
e2f65bced5 Fixed an issue with frequent modifications in a scratchpad; added safety check to avoid reloads from loaded modules (like wx) 2012-04-30 13:49:33 -07:00
Paul Kulchenko
c979d60d28 Moved the logic to disable checkbox for scratchpad menu to IDLE event as EVT_UPDATE_UI is only executed when the user opens up the menu (menu is updated) 2012-04-29 23:08:29 -07:00
Paul Kulchenko
7954ff1f64 Fixed about screen 2012-04-29 21:57:47 -07:00
Paul Kulchenko
a3a5c75694 Reorganized scratchpad code to have all its logic in one place 2012-04-29 18:41:23 -07:00
Paul Kulchenko
d6f3b4052b Reimplemented scratchpad functionality using internal processes (similar to how the debugger is done) as IDE was too unstable when running in the same process 2012-04-29 17:26:22 -07:00
Paul Kulchenko
7bc64d90c7 Removed 'error during pre-compilation' message from compile errors 2012-04-28 15:11:42 -07:00
Paul Kulchenko
56d262b753 Added stopping the debugger when a debugged program exits 2012-04-27 16:33:56 -07:00
Paul Kulchenko
a368f0acf9 Merge branch 'master' of github.com:pkulchenko/ZeroBraneStudio 2012-04-23 09:32:45 -07:00
Paul Kulchenko
d4a53733e7 Added to static analysis reporting of unused parameters in functions (the function name is also reported when possible) 2012-04-23 09:16:13 -07:00
Paul Kulchenko
1117e9df9a Disabled warning in static analysis about unused 'self' in methods 2012-04-22 23:31:58 -07:00
Paul Kulchenko
230de3450f Cleaned up warnings based on results of static analysis 2012-04-22 23:29:32 -07:00
Paul Kulchenko
0ae48ce6de Cleaned up warnings based on results of static analysis 2012-04-22 22:04:23 -07:00
Paul Kulchenko
6a90c5e850 Turned 'unhiding' wx window while running or debugging off by default as it was causing performance problems with some applications 2012-04-22 15:39:03 -07:00
Paul Kulchenko
f1ac72b265 Added scratchpad (running live) functionality 2012-04-21 22:29:21 -07:00
Paul Kulchenko
79fd90c986 Removed logic to update project directory based on file selection in the filetree 2012-04-21 22:26:15 -07:00
Paul Kulchenko
4dcf470c09 Fixed an issue with menu search to insert a new item 2012-04-20 22:25:14 -07:00
Paul Kulchenko
fcdbd456de Added code analyzer based on lua-inspect 2012-04-20 14:47:31 -07:00
Paul Kulchenko
e92127d6c8 Added luainspect library (https://github.com/davidm/lua-inspect) 2012-04-20 14:36:38 -07:00
Paul Kulchenko
0d8e6b0581 Added LuaSec (including binary Windows package from http://www.inf.puc-rio.br/~brunoos/luasec/) to provide SSL/HTTPS support for the socket library (needed for gist/github integration) 2012-04-19 18:17:48 -07:00
Paul Kulchenko
16d72396b1 Added missing mime/code.dll and reorganized socket module files (socket.*) to load correctly with require 2012-04-07 22:40:55 -07:00
Paul Kulchenko
6c7e289f71 Merge pull request #1 from dkulchenko/master
Format README with Markdown
2012-04-07 22:26:03 -07:00
Daniil Kulchenko
deb99ec084 Formatting improvements. 2012-03-27 14:08:36 -07:00
Daniil Kulchenko
12f84d3509 Switch README to Markdown. 2012-03-27 13:58:19 -07:00
Paul Kulchenko
3a18136076 Fixed 'Trace' command to continue working when a debugged file is not activated 2012-03-21 10:16:17 -07:00
Paul Kulchenko
1b057988bc Updated to work with mobdebug v0.44 2012-03-21 10:14:30 -07:00
Paul Kulchenko
92001a4a78 Added option to activate output/console when Run/Debug/Compile commands are executed 2012-03-20 21:25:38 -07:00
Paul Kulchenko
906c70248b Added full screen mode 2012-03-17 21:20:32 -07:00
Paul Kulchenko
4554c67c3e Added killing running process on IDE exit. Allowed killing a running process with Shift-F12. Disabled compilation and debugging when some process is running. 2012-03-10 22:21:36 -08:00
Paul Kulchenko
cb7ee575c7 Fixed an issue with saving a file when no project directory is set 2012-03-10 21:55:31 -08:00
Paul Kulchenko
c758d4c62a Updated MANIFEST with metalua lib 2012-03-09 22:06:18 -08:00
Paul Kulchenko
8c1c06bb16 Fixed missing semicolon in lualibs path; added path for debugger to search under lualibs 2012-03-09 22:01:20 -08:00
Paul Kulchenko
99ca5fe952 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-03-08 11:49:22 -08:00
Paul Kulchenko
1f064655cc Added metalua library 2012-03-08 11:48:57 -08:00
Paul Kulchenko
9a05cc3678 Fixed missing slash on SaveAs by enforcing trailing slash for the project path 2012-03-08 10:50:47 -08:00
Paul Kulchenko
6da3cb2c32 Disabled buffering of the output for scripts run from IDE 2012-02-27 22:49:00 -08:00
Paul Kulchenko
d2cb7cb1c2 Fixed an issue with a missing path separator, which prevented debugging from executing step commands in some cases 2012-02-22 21:54:36 -08:00
crazybutcher
0ac769ffba bugfix in luxinia1 interpreter 2012-02-16 21:52:35 +01:00
Paul Kulchenko
ef60786e48 Removed debug output when coroutines are edited 2012-02-14 23:35:56 -08:00
Paul Kulchenko
f9c15faab8 Fixed activation of a correct tab when one of the editor tabs is closed 2012-02-13 18:30:45 -08:00
Paul Kulchenko
59b28ef35c Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-12 22:42:12 -08:00
Paul Kulchenko
9db7d4ec8a Fixed an issue with file activation from a debugger (files that are 'required' now actiate correctly) 2012-02-12 22:41:41 -08:00
Paul Kulchenko
40eaace714 Disabled dynamic words in the config (zbstudio) 2012-02-10 09:47:05 -08:00
Paul Kulchenko
fe000bb59e Wrapped DragAcceptFiles into a protected call to make it not fail on MacOS (compiled with wxwidgets 2.8.12) 2012-02-09 12:23:47 -08:00
crazybutcher
9aa220df41 Merge branch 'master' of ssh://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-08 20:05:33 +01:00
Paul Kulchenko
97c52f15f3 Added highlight style to markup 2012-02-07 23:41:29 -08:00
Paul Kulchenko
54f578790b Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-02-01 22:29:54 -08:00
Paul Kulchenko
a51a08c1b8 Removed slash conversion in filename on Save; added markup styling on SaveAs 2012-02-01 22:29:28 -08:00
Paul Kulchenko
7620e758a0 Updated error messages to more generic ones 2012-02-01 19:52:55 -08:00
Paul Kulchenko
80da9253dd Normalized the filename path to remove '.' and such 2012-02-01 19:33:08 -08:00
Paul Kulchenko
a133fa900e Fixed the issue of ClosePage method being called with two different parameters 2012-01-31 23:00:55 -08:00
Paul Kulchenko
0fa62e544a Updated markup processing with run and debug commands, http link processing, and opening local files in a new window. Switched from hotspot click event to mouse button processing to avoid the issue with selection being active in a newly loaded page 2012-01-31 22:56:18 -08:00
Paul Kulchenko
601dbef6e5 Added Debug and Run methods to simulate menu commands 2012-01-31 22:49:09 -08:00
unknown
01b3a4fd09 Merge branch 'master' of ssh://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-31 12:08:36 +01:00
crazybutcher
ed0df13acb dx backwards compat mode and replace / in filenames 2012-01-31 12:06:55 +01:00
Paul Kulchenko
642fd63724 Added setting a project folder on initial start (zbstudio) 2012-01-30 18:21:51 -08:00
Paul Kulchenko
a1586cd530 Replaced hardcoded path separater with a method call 2012-01-30 18:19:18 -08:00
Paul Kulchenko
291cba2d79 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-30 15:58:40 -08:00
Paul Kulchenko
96bffc1322 Added markup formatting in the comments 2012-01-30 15:58:28 -08:00
Paul Kulchenko
e88710fbbc Updated debugger to use project dir as basedir if it is specified (rather than the path to the currently edited file) 2012-01-30 15:03:22 -08:00
Paul Kulchenko
99da8be0f8 Fixed the issue of the project dir being returned with two trailing slashes 2012-01-30 15:03:05 -08:00
crazybutcher
c8c654cb2b removed ptx r,g,b,a keywords 2012-01-30 22:05:47 +01:00
crazybutcher
cf68a42547 added nvidia ptx spec 2012-01-30 22:01:57 +01:00
Paul Kulchenko
5c0d4cccdd Added setting the current project directory for the shell to allow 'require' commands to work with local modules 2012-01-29 17:10:55 -08:00
Paul Kulchenko
b979b41688 Fixed an issue with activating the currenly edited file in the file tree 2012-01-29 13:55:59 -08:00
Paul Kulchenko
b807fa9a99 Enforced visibility for shell prompt 2012-01-28 11:59:18 -08:00
Paul Kulchenko
ef5b1b0e09 Removed hardcoded references to the console page/tab 2012-01-28 11:53:56 -08:00
Paul Kulchenko
04a038da45 Moved wrap flags to the line end to make them less noticeable 2012-01-28 11:52:17 -08:00
Paul Kulchenko
bc0e3190d4 Added style processing for font name, font size, visibility and hotspot attributes 2012-01-28 11:20:52 -08:00
Paul Kulchenko
16dcd084e1 Renamed ShellExecuteCode to ...File; added ShellExecuteCode to execute a fragment of code 2012-01-28 10:52:35 -08:00
crazybutcher
15f8c15039 bugfix on close-file 2012-01-25 22:00:28 +01:00
crazybutcher
bff0da36dc minor updates to license (2012) and readme (front-ends explained) 2012-01-21 14:27:03 +01:00
crazybutcher
1e933a6b75 Merge remote-tracking branch 'zbstudio/master' 2012-01-21 14:15:06 +01:00
crazybutcher
c9bb3e01ca added glfw 2.7.2 api and changed luxinia2 to use it instead of glfw3 2012-01-21 14:13:54 +01:00
Paul Kulchenko
e4e5e82660 Disabled attaching debugger by default as this triggers warning to open firewall on the first start, which is inconvenient 2012-01-18 14:00:48 -08:00
Paul Kulchenko
c5f2d3cf18 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-18 10:44:46 -08:00
crazybutcher
017049f473 updated lua.exe to 5.1.4 as well 2012-01-18 19:41:33 +01:00
Paul Kulchenko
75ce8116ca Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2012-01-18 10:19:20 -08:00
crazybutcher
73dc7ca2ed Merge remote-tracking branch 'zbstudio/master' 2012-01-18 18:54:52 +01:00
crazybutcher
8c6e111e13 updated lua to 5.1.4 2012-01-18 18:54:22 +01:00
Paul Kulchenko
305cafbfcf Added About page for zbstudio 2012-01-17 20:38:02 -08:00
Paul Kulchenko
8c3d927820 Fixed typos in the About page 2012-01-17 19:45:13 -08:00
Paul Kulchenko
b83138c127 Added version file 2012-01-17 19:44:11 -08:00
Paul Kulchenko
e7a789e466 Moved 'Watch Window' to 'View' menu for consistency and changed to always enable; disabled 'Compile' menu while debugging 2012-01-17 12:51:35 -08:00
Paul Kulchenko
d5f448c952 Updated settings to allow each window to set its default size avoid one-size-fits-all default 2012-01-17 12:35:58 -08:00
Paul Kulchenko
f43babc491 Disabled autotabs/usetabs by default in zbstudio 2012-01-16 22:34:30 -08:00
Paul Kulchenko
6a78042869 Removed duplicate call 2012-01-16 22:33:50 -08:00
Paul Kulchenko
4984cf7a4b Added ability to attach to a debugger from an arbitrary process running MobDebug; upgraded to MobDebug v0.43 2012-01-16 15:28:53 -08:00
Paul Kulchenko
6693a6cd96 Added 'pid' text 2012-01-16 14:13:57 -08:00
Paul Kulchenko
2909eeb0c3 Fixed reference to projpanel to use a local variable as the global is not guaranteed to be correct in the calling context 2012-01-16 14:13:13 -08:00
Paul Kulchenko
61260f6e48 Added reporting of the folder in which the external program is run 2012-01-16 13:08:27 -08:00
Paul Kulchenko
c741d35c67 Updated local/remote shell to handle expressions ('1+2'), accept '=' to show values, and remove 'return ' from error messages where needed 2012-01-16 11:13:45 -08:00
Paul Kulchenko
18e06631bf Fixed an issue with saving a new file when project filetree is open 2012-01-15 19:18:24 -08:00
Paul Kulchenko
efd78f57b9 Fixed issue with autocomplete that caused an error when a substring of an earlier word is typed 2012-01-15 19:09:36 -08:00
Paul Kulchenko
e366377d64 Added display of nil values for variables in the shell (local and remote) 2012-01-15 15:26:43 -08:00
Paul Kulchenko
4b334a0d40 Updated spec list for zbstudio to limit specs to lua 2012-01-15 13:32:11 -08:00
Paul Kulchenko
c3471d0077 Added logic to unhide wx window while debugging or running wxwidget application 2012-01-15 10:47:58 -08:00
Paul Kulchenko
7c7a45d99d Fix to make display of errors with and without stack trace consistent in the shellbox/console 2012-01-14 23:53:00 -08:00
Paul Kulchenko
c57215aeeb Fixed a bug in shell that prevented some of the errors from being displayed 2012-01-14 23:27:09 -08:00
Paul Kulchenko
66e0e04f45 Fixed filetree selection when 'untitled' window is active 2012-01-14 23:21:02 -08:00
Paul Kulchenko
9d1d3256c8 Fixed project browse dialog when no editor window is open 2012-01-14 23:10:42 -08:00
Paul Kulchenko
d61a0d64fc Added manifest for zbstudio 2012-01-12 23:16:02 -08:00
Paul Kulchenko
796e793902 Fixed fields left from the replaced shellbox panel 2012-01-12 23:15:32 -08:00
Paul Kulchenko
adfc4d98a7 Made default windows larger for the first run 2012-01-11 21:54:27 -08:00
Paul Kulchenko
cb28bb1b97 Fixed hiding 'load style' menu for zbstudio 2012-01-10 23:44:28 -08:00
Paul Kulchenko
77ae45ef8b Disabled maximized buttons for output/console and project windows as those are not useful and don't work correctly in all cases 2012-01-10 23:43:31 -08:00
Paul Kulchenko
d64b44943b Renamed 'View' menu items 2012-01-10 23:42:26 -08:00
Paul Kulchenko
8fb808d75f Added winapi module to be able to (optionally) show wx windows under running/debugging 2012-01-10 23:25:49 -08:00
crazybutcher
81e92eec88 changed defaults a bit, disabled autocomplete dynword engine by default 2012-01-08 14:47:21 +01:00
crazybutcher
7d763054b7 improved dynamic word ac engine (counts words active and handles delete/insert ops) 2012-01-08 14:45:38 +01:00
crazybutcher
6b39babf34 bugfix nblayout loader: assure openDocuments[id].index is correct 2012-01-08 14:44:45 +01:00
crazybutcher
214c598a85 added rudimentary notebook layout saving (cannot cope with complex splits yet) 2012-01-07 23:06:35 +01:00
crazybutcher
a297104017 bugfix in filetree for "save path" due to ui restructure 2012-01-07 23:05:36 +01:00
crazybutcher
f6e72fc9ce shell execute: prefer direct string over "return" version 2012-01-06 23:40:24 +01:00
crazybutcher
631ca23a97 main frame now managed through wxAUI, more customizeable layout 2012-01-06 23:25:00 +01:00
crazybutcher
c2d9a0dbac Merge remote branch 'zbstudio/master'
Conflicts:
	src/editor/shellbox.lua
2012-01-06 19:49:13 +01:00
Paul Kulchenko
cec4eb869d Merge branch 'simplified-shellbox' 2012-01-06 09:36:49 -08:00
crazybutcher
7602facb7a Merge remote branch 'zbstudio/master' 2012-01-06 18:32:49 +01:00
crazybutcher
d5827e233c bugfix for luxinia interpreters (do not prepend directory for exe)
bugfix when creating an error in the shell
2012-01-06 14:26:33 +01:00
crazybutcher
d59a92e0bf bugfix in filetree and loadfile when starting from empty sessions 2012-01-06 13:51:55 +01:00
crazybutcher
65d460452b luxinia interpreters should only load when found on system 2012-01-06 09:37:43 +01:00
Paul Kulchenko
867de8f3e4 Fixed localization of 'next' variable, which was causing debugger failure 2012-01-05 23:11:49 -08:00
crazybutcher
ec756721c2 bring back stack traceback on shell execute but filter traces 2012-01-06 00:04:15 +01:00
crazybutcher
3b554526c6 bugfix with file execution in shell 2012-01-05 19:03:16 +01:00
Paul Kulchenko
4246d7683a Updated resources for zbstudio with a new logo 2012-01-04 22:32:20 -08:00
Paul Kulchenko
b7c922e253 Updated prompt symbol in the shell; redirected local shell output back to the shell window 2012-01-04 19:08:09 -08:00
Paul Kulchenko
beaeb9a65d Updated icon license to MIT license and added permission reference 2012-01-04 14:55:34 -08:00
Paul Kulchenko
b3d0f40519 Redirected all shell output (print and such) to the output window 2012-01-04 14:07:24 -08:00
Paul Kulchenko
c64906d09a Added 'clear' command to the shell to clear shell window 2012-01-04 13:34:05 -08:00
Paul Kulchenko
2d993203f8 Added ability for the shell to handle async output; the output is inserted before the prompt. Fixed a bug in the debugger that wasn't redirecting the shell output to the shell 2012-01-04 13:25:50 -08:00
crazybutcher
3fdc605d36 Merge remote branch 'zbstudio/master' 2012-01-04 22:05:15 +01:00
Paul Kulchenko
393c0703a6 Added re-scanning of folders in the filetree to keep the data up-to-date. The re-scanning is done on expanding a node or on activation of a file/folder 2012-01-04 00:31:40 -08:00
Paul Kulchenko
2c396b775e Fixed loading icons when no ico file is present 2012-01-03 22:21:33 -08:00
Paul Kulchenko
d14c4b544a Updated marker for the current line in the console 2012-01-03 22:19:40 -08:00
crazybutcher
730835a04d bugfix when deleting editor tab via middlemouse, the third try ;) this time should delete proper tab and preserve current selected tab 2012-01-03 19:12:04 +01:00
crazybutcher
db315532ed Merge remote branch 'zbstudio/master'
Conflicts:
	src/editor/commands.lua
2012-01-03 18:57:09 +01:00
crazybutcher
cc9128ad73 bugfix, filename loaded multiple times, also fixes bug with selection not updated on new file loads 2012-01-03 18:52:12 +01:00
Paul Kulchenko
99763ce992 Simplified the interactive shell to use a single one-page control for everything; included history of commands and dynamic switching between local/remote shell 2012-01-03 00:21:43 -08:00
Paul Kulchenko
c735b7476d Added configuration and support for word wrap in the editor 2012-01-02 12:02:59 -08:00
Paul Kulchenko
932274fbbe Re-applied and simplified handling of editor tab close event 2012-01-01 20:16:31 -08:00
Paul Kulchenko
7fed63512d Removed Estrela references 2012-01-01 18:09:11 -08:00
Paul Kulchenko
14cf94f3bb Enabled 'Clear Output' menu by default for zbstudio 2012-01-01 18:04:32 -08:00
Paul Kulchenko
14665f57dd Added ability to break applications under debugging; upgraded to mobdebug v0.42 2011-12-30 12:17:52 -08:00
Paul Kulchenko
414f44b6f5 Merge branch 'master' of git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor 2011-12-29 14:22:32 -08:00
Paul Kulchenko
0c1a335aa0 Moved wx.dll file to allow execution and debugging of wx applications 2011-12-29 14:22:07 -08:00
Paul Kulchenko
ae04d6e1aa Fixed logic of loading application .ico files to allow icons of different sizes to be correctly used 2011-12-29 13:16:53 -08:00
CrazyButcher
6fb6c73495 Merge remote-tracking branch 'zbstudio/master'
Conflicts:
	src/editor/gui.lua
2011-12-29 16:51:48 +01:00
CrazyButcher
5083d561d2 bugfix with middle mouse close file tab 2011-12-29 16:00:45 +01:00
CrazyButcher
2a2bfa69a2 autcomplete bugfix for non-lua specs 2011-12-29 13:39:48 +01:00
CrazyButcher
56f05aa5fe luxinia1 api loading bugfix 2011-12-29 13:02:15 +01:00
Paul Kulchenko
4607721020 Moved wx.dll file to allow debugging of wx applications 2011-12-27 18:28:40 -08:00
Paul Kulchenko
329baf4b82 Added killing a debugger client on exit from IDE 2011-12-27 18:26:31 -08:00
Paul Kulchenko
ed30c2399d Fixed an issue with the filetree when a new file is saved 2011-12-27 08:32:09 -08:00
Paul Kulchenko
7663cbbf0c Removed slash conversion in debugger as it is no longer needed with mobdebug v0.41. Normalized use of slashes in file names 2011-12-24 18:58:06 -08:00
Paul Kulchenko
c48182b902 Added logic to populate and expand nodes in the project filetree to correctly mark active files in subfolders.
Removed code to delete and repopulate tree nodes as this logic was recreating all tree objects (which made them lost their content, marks, open/close state and everything else). This change makes the list (potentially) stale if the directory content changes, but this issue will be addressed later.
2011-12-23 19:01:12 -08:00
Paul Kulchenko
9297a18b8d Added handling of editor tab close event to fix the issue with closing notebook tab with middle mouse button.
Added close button on an active notebook tab.
2011-12-23 18:58:51 -08:00
Paul Kulchenko
4fdeccdbc1 Removed commented out code 2011-12-23 18:46:46 -08:00
Paul Kulchenko
5c76dbabd6 Upgraded mobdebug module to v0.41 to include changes with handling path conversion 2011-12-23 13:55:08 -08:00
Paul Kulchenko
b6176efd07 Improved project filetree display
Fixed expanding empty folder; now removes expand item on it.
Fixed marking an item in subfolders; now markes those files that are open
in the editor (but only if the subfolder has been expanded).
Removed slash from folder names; simplified file/folder handling logic.
2011-12-22 21:51:34 -08:00
Paul Kulchenko
5327916817 Modified logic for 'jump to function' list to recognize 'local foo = function' and 'foo.bar = function' syntax; added default message to the function list 2011-12-22 19:32:06 -08:00
CrazyButcher
78e52ac04a bugfix for default interpreter setup 2011-12-22 18:17:21 +01:00
CrazyButcher
a9b1729057 do not put user.lua under source control 2011-12-22 18:05:46 +01:00
Paul Kulchenko
a226c6e432 Documentation clean-up: added README, updated LICENSE, moved doc/ files 2011-12-19 22:37:13 -08:00
Paul Kulchenko
79af98d75b Added marking of current file in the project file tree; disabled slash conversion in file load 2011-12-18 16:21:47 -08:00
Paul Kulchenko
ab26ded71a Tweaks to the filetree control to set the font and to better align the browse button 2011-12-18 10:43:41 -08:00
Paul Kulchenko
defba4f767 Added a new set of icons and handling of custom icons in zbstudio 2011-12-18 10:23:20 -08:00
Paul Kulchenko
585c5c0f9c Updated GetBitmap calls to reference correct client (TOOLBAR/OTHER); moved filetree.lua call to be after gui.lua to make ArtProvider.GetBitmap call to work 2011-12-18 10:18:22 -08:00
crazybutcher
047165b6aa bugfix on debugger.pid boolean behavior, clear all markers prior actions 2011-12-17 15:50:13 +01:00
Paul Kulchenko
3d0e52bdbe Added killing the debugee process for real when debugging is stopped by the user 2011-12-13 23:03:46 -08:00
Paul Kulchenko
2e1a512f00 Another end-of-line conversion to fix CRLF endings that were added by the beautification process 2011-12-12 17:01:37 -08:00
crazybutcher
09dbdc1cb1 rename Start Debugging to Continue if debugger.server is present 2011-12-12 23:40:29 +01:00
Paul Kulchenko
a9835c25cb Added Trace command to show execution path in debugger.
Added reporting of error in Watch window and fixed a bug in the Watch
window that made Trace to stop on errors in Watch expressions.
2011-12-12 13:18:17 -08:00
Paul Kulchenko
dab674be91 Split Run and Continue commands 2011-12-12 11:53:59 -08:00
Paul Kulchenko
8e5a6bc284 Returned back wx*.dll as wxLua dll don't draw folds correctly and have tendency to crash in autocomplete 2011-12-12 11:37:56 -08:00
Paul Kulchenko
fe53414868 Ran tools/ and spec/ files through a beautifier 2011-12-12 09:33:35 -08:00
Paul Kulchenko
6f675b60cb Ran files with preferences through a beautifier 2011-12-11 22:03:54 -08:00
Paul Kulchenko
85be275590 Ran most of the lua files (except tools, specs, apis, and lualibs) through a beautifier 2011-12-11 21:14:18 -08:00
crazybutcher
378fe2818e minor refactoring and speedup to modebug and debugging for luxinia2 :) 2011-12-11 15:26:15 +01:00
Paul Kulchenko
20ed88665a Fixed incorrect method name for debugging termination 2011-12-10 18:29:33 -08:00
Paul Kulchenko
31759939f2 Fixed issue with displaying errors in local shell;
Added markers to multi-line expressions
2011-12-10 18:27:58 -08:00
Paul Kulchenko
03b63b491e Updated icon in the executable 2011-12-10 16:55:07 -08:00
Paul Kulchenko
409f1f4214 Enabled singleinstance for zbstudio to check that only one instance is running 2011-12-10 16:54:43 -08:00
Paul Kulchenko
caf9db40b1 Fixed method name in the debugger 2011-12-10 15:12:41 -08:00
Paul Kulchenko
fc7e075a01 Added back all zbstudio files that got removed in the merge 2011-12-10 15:11:44 -08:00
crazybutcher
c956350dc2 minor changes to allow interpreter controlled debugging 2011-12-10 15:36:40 +01:00
crazybutcher
8273b622e9 added missing doc info about app.preinit 2011-12-10 15:04:56 +01:00
crazybutcher
85b016457b sync with zbstudio issue 2011-12-10 14:55:22 +01:00
crazybutcher
15154050f9 Merge remote branch 'zbstudio/master'
Conflicts:
	cfg/config.lua
	doc/defs.lua
	estrela/config.lua
	src/editor/commands.lua
	src/editor/debugger.lua
	src/editor/filetree.lua
	src/editor/gui.lua
	src/editor/menu_file.lua
	src/editor/menu_project.lua
	src/editor/menu_tools.lua
	src/editor/menu_view.lua
	src/editor/output.lua
	src/editor/shellbox.lua
	src/editor/style.lua
	src/main.lua
2011-12-10 14:53:08 +01:00
Paul Kulchenko
d6472a2fd5 Switched from wxNotebook to wxAuiNotebook as it has better looking UI 2011-12-09 23:08:00 -08:00
Paul Kulchenko
3d452e3092 Updated wx dlls to use ones from http://code.google.com/p/luaforwindows/, which have smaller size 2011-12-09 22:59:40 -08:00
Paul Kulchenko
bc2a15915c Added missing config for one of the applications 2011-12-09 21:45:07 -08:00
crazybutcher
6cdecea47c moving default config to application path, and changed config load order:
1) internal defaults
2) app/config.lua
3) cfg/user.lua
4) commandline -cfg

Conflicts:

	src/main.lua
2011-12-09 21:41:05 -08:00
crazybutcher
4967a0a68b removed dead meat 2011-12-09 21:35:05 -08:00
Paul Kulchenko
2428b66add Refactored and normalized interfaces to use Debugger*, Project*, FileTree* convention for public methods; updated local methods in debugger 2011-12-09 21:33:10 -08:00
Paul Kulchenko
0a550c1d25 Convert CRLF that were inherited with original clone to LF 2011-12-07 20:20:22 -08:00
crazybutcher
43e0566cb6 DebuggerFileAction should return true on success 2011-12-07 21:41:07 +01:00
crazybutcher
8739e37faa improve async debugger behavior 2011-12-07 21:31:12 +01:00
crazybutcher
fcc11f7dff moving default config to application path, and changed config load order:
1) internal defaults
2) app/config.lua
3) cfg/user.lua
4) commandline -cfg
2011-12-07 21:10:21 +01:00
crazybutcher
705b5f939c removed dead meat 2011-12-07 19:17:34 +01:00
Paul Kulchenko
af27ef7682 Refactored debugger commands to match debugserver interface in defs.lua 2011-12-07 09:38:26 -08:00
Paul Kulchenko
863f2780b3 Refactored interpreter/debugger interface to move the logic into the interpreter 2011-12-06 22:46:14 -08:00
Paul Kulchenko
790191a681 Added handling of .hasdebugger attribute 2011-12-06 22:38:25 -08:00
Paul Kulchenko
ca0fda0bee Fixed using projectdir from interpreter with debugger 2011-12-06 19:20:22 -08:00
Paul Kulchenko
81e4048754 Added 'Start debugger server' menu; updated starting debugger server automatically to be application-based 2011-12-06 17:53:45 -08:00
Paul Kulchenko
353336796d Fixed an issue with LoadStyle dialog and style processing 2011-12-06 15:30:55 -08:00
Paul Kulchenko
c39ee8fb2f Fixed issue with closing an editor window and then canceling Save dialog 2011-12-06 15:16:07 -08:00
Paul Kulchenko
fbcc555f4e Fixed issue with running/debugging an 'untitled' file 2011-12-06 15:15:37 -08:00
Paul Kulchenko
43237b1b1d Added logic to remove menu items not used in zbstudio 2011-12-06 09:15:53 -08:00
Paul Kulchenko
5f8ee5ce63 Added 'Lua with debugger' interpreter and reverted changes to 'Lua' interpreter back;
Registered 'Lua with debugger' with zbstudio by default;
Added logic to load custom icons
2011-12-05 12:16:32 -08:00
crazybutcher
edd82b8a4a Fix CRLF 2011-12-05 20:21:43 +01:00
Paul Kulchenko
d710fdb4a9 Added preinit callback; moved postinit before frame:Show 2011-12-04 23:43:59 -08:00
Paul Kulchenko
b7124a26ba Fixed shortcuts in Project menu 2011-12-04 23:28:40 -08:00
Paul Kulchenko
fba27ba1b0 Added logic to only enable Tools menu if it is not empty 2011-12-04 16:47:28 -08:00
crazybutcher
1a2a3ac721 abstract debugger interface (untested) 2011-12-04 20:54:30 +01:00
153 changed files with 36276 additions and 18047 deletions

View File

@@ -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
View 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.

View 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

View File

@@ -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
View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

Binary file not shown.

BIN
bin/clibs/ssl.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/winapi.dll Normal file

Binary file not shown.

View File

@@ -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},
}

View File

@@ -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},
}

View File

@@ -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},
}

View File

@@ -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
View 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
--]]--

View File

@@ -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},},
}
]]

View File

@@ -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},},
}
]]

View File

@@ -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,
}

View File

@@ -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
View 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},
}

View File

@@ -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 &copy; 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 &copy; 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 &copy; 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 &copy; 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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -1 +0,0 @@
git://estrelaeditor.git.sourceforge.net/gitroot/estrelaeditor/estrelaeditor

View File

@@ -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,
}

View File

@@ -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
View 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,
}

View File

@@ -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
View 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,
}

View File

@@ -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,
}

View File

@@ -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,
}

View File

@@ -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
View 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

View 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
--]]

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

756
lualibs/metalua/gg.lua Normal file
View 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

File diff suppressed because it is too large Load Diff

441
lualibs/metalua/ldump.lua Normal file
View 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
View 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

View 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
}

View 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()
]]

View 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

View File

@@ -0,0 +1,3 @@
require 'metalua.base'
require 'metalua.table2'
require 'metalua.string2'

View 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

View 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

View 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 } } }

View 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"})

View 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

View 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

View 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 }

View 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

View 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) }

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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
View 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
View 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

View File

@@ -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
]],
},
}

View File

@@ -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 ]],
},
}

View File

@@ -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
""
},
}

View File

@@ -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]],
},
}

View File

@@ -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 ]],
},
}

View File

@@ -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 ]],
},
}

View File

@@ -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
View 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
]],
},
}

View File

@@ -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]]
},
}
]==]

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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)

View File

@@ -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
View 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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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