This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
skwerlman's profile picture

CLua - Conditional Lua Compilation

Started by skwerlman, 01 June 2014 - 05:33 AM
skwerlman #1
Posted 01 June 2014 - 07:33 AM
CLua
A Conditional Lua compiler!

Currently on version: 2.0.0

Now available through MPT! (currently on version 2.0.0-p42; usually updated within 15 minutes of main version)

What does it do?
SpoilerCLua allows you to create modular CC Programs and release them as a single file, without needing to copy-paste them into a release file.

Why'd you make it?
SpoilerI felt inspired after seeing http://www.computerc...essor-includes/, so I decided to make a conditional compiler.

How do I use it?
SpoilerIt works just like the preprocessor in C++. It scans for preprocessor directives (PPDs), and performs commands based on them.

The current PPDs are:
#INCLUDE file FROM dir -- Copies the contents of the specified file to that point in the file. Use '~' as a shortcut to the library folder. Use '?here' as a shortcut to the current directory. Use '?there' as a shortcut to the output directory.
#DEFINE flag -- Sets flag at a given point. CLua keeps track of these flags to prevent infinite loops, so I recommend using something like #DEFINE <filename> at the start of each file.
#IFDEF flag ... #ENDIFDEF -- Only copies the code between #IFDEF and ENDIFDEF if flag has been set.
#IFNDEF flag ... #ENDIFNDEF -- Only copies the code between #IFNDEF and #ENDIFNDEF if flag has not been set.
#IFVAR variable ... #ENDIFVAR -- Only copies the code between #IFVAR and #ENDIFVAR if variable is defined.
#IFNVAR variable ... #ENDIFNVAR -- Only copies the code between #IFNVAR and #ENDIFNVAR if variable is not defined.
#SNIPPET -- Ignores all directives until the end of the file. Use at the start of a file if you want to be able to #INCLUDE it several times.
#EXEC code -- Executes arbitrary Lua code. Should not be used to set variables.
#LICENSE license [vars] -- Adds the specified license to the .licensing file for the current file.
#SETDYNAMICVAR variable:value ... -- adds a value the the list VAR.
#DYNAMIC-INCLUDE delim1 delim2 [text] ... -- Inserts a line into the current file, replacing text between delim1 and delim2 with its value in VAR.

To compile a program, use the following syntax:
clua <input> <output> [--help] [-?] [--log] [--version] [--dry-run] [--exec:<code> ...] [--dyn:<var>=<val>[;<var>=<val>...] ...] [--define:<flag>[;<flag>...] ...] [--quiet] [--silent] [--verbose] [--devel] [--no-debug] [--no-trim] [--self-update] [--to-path:<path>] [--from-path:<path>]
--help, -? - Display this help message and exit.
--log - Enables logging.
--version - Print version info and exit.
--dry-run - Runs through the compilation, but doesn't modify the output file.
--exec:<code> - Executes arbitrary code before compilation. Use ++ instead of spaces, or include the entire option in double quotes (").
--dyn:<var>=<val>[;<var>=<val>...] - Equivelent to #DYNAMIC-INCLUDE
--define:<flag>[;<flag>...] - Equivelent to #DEFINE.
--quiet - Do not print most messages.
--silent - Only print errors.
--verbose - Prints ALL messages.
--devel - Allows logging of DEVEL level messages. Useful only for debugging. Much slower than normal, especially for large programs. Not recommended.
--no-debug - Don't log DEBUG level messages.
--self-update - Downloads and runs the latest CLua installer, then reboots.
--no-trim - Prevents the trimming of empty lines when writing the output.
--to-path:/path/ - Specifies where to output the compiled program and license.
--from-path:/path/ - Specifies where to look for the main source file.
Don't worry about including clua's path when you call it; the installer takes care of that for you.

When should I use it?
SpoilerCLua really shines in large projects where managing code becomes a hassle, because multiple independent phases of a program get forced into a single massive file.
It's also really useful when you use the same code in multiple projects; just write that code in a separate file, and #INCLUDE it.

When shouldn't I use it?
SpoilerCLua is NOT a replacement for os.loadAPI(). Use PPI for that. (Don't worry, we're compatible!)
CLua does not support more than one level of recursion. Loop detection would need way too much work to fix this, so it'll probably never change.

How do I install it?
Spoiler
Using pastebinSimply type:
pastebin run zPMasvZ2
to install it.
If that doesn't work, type:
pastebin get zPMasvZ2 clua-inst
clua-inst
The installer will ask you where you'd like it installed; I recommend using /clua, but it's really a matter of preference.
To update, just run:
clua --self-update
Using MPTSimply run
mpt ppa add skwerlman
mpt install clua

How do I uninstall it?
SpoilerStep one: let me know why (assuming its an issue with the program itself). I'm always looking for feedback about the quality of programs, and knowing what people like or dislike is essential to creating a good program.
Step two: Depends on how it was installed.
If you installed using MPTSimply run:
mpt remove clua
mpt install clua-uninstall
mpt remove clua-uninstall
If you installed using PastebinFirst, delete the folder where clua was installed.
Next, run 'edit /startup'
Look through startup for the line "– BEGIN CLUA GLOBALS". It should be near the top.
Delete all of the lines from that one until the line "– END CLUA GLOBALS".

What's next?
SpoilerI'm going to start working on a collection of libraries which will be included with CLua, and will be easily available.

My current To-Do list (in no particular order):
  • Add #ELSE directive
  • Add #ELSEIF directive
  • Add #ELSEIFN directive
  • Fix everything in the 'Known Bugs' section
My top three priorities ATM (most to least important):
  1. Add #ELSE, #ELSEIF, and #ELSEIFN
  2. ???
  3. ???

What if there's an issue?
SpoilerIf you encounter a bug, typo, or other problem with the code, create a new issue here.
If you'd like to make a suggestion, put it in the comments below.

I coded this in CC 1.63, but with the intention of it being backwards compatible with CC 1.5. If it isn't, let me know here!

Can you add…?
SpoilerLet me know in the comments.
If it's a good idea (and I can figure out how to implement it) I'll add it.
One thing will never happen, though: a GUI.

Known bugs
SpoilerNone, at the moment. Help me find some!

I'd like to submit a library…
SpoilerIf you'd like to submit a library for inclusion in the CLua library, send me a PM with a link to the code. If it's good enough, I'll include it.

Important notes!
SpoilerThe CLua installer will inject code into the existing startup file. If there is no startup file, it will create one.
The code inserted includes several global variable definitions, and one shell.setAlias command.
This code is inserted at the top of the startup file, and should have no effect on the function of rest of the startup file.
As of version 1.3.0, the injected code will look something like this:
-- BEGIN CLUA GLOBALS
-- FILE MODIFIED BY CLUA-INSTALL
-- CLua Copyright 2014 Skwerlman
CLUA_VERSION = '1.3.0'
CLUA_HOME = '/clua/'
CLUA = CLUA_HOME..'clua.lua'
CLUA_LIB = CLUA_HOME..'lib'
CLUA_LIB_LIST = {}
CLUA_LOG = CLUA_HOME..'clua.log'
CLUA_LUAMAN = false
shell.setAlias('clua', CLUA)
-- END CLUA GLOBALS
When rerunning the installer (such as when upgrading to a new version), all code between
-- BEGIN CLUA GLOBALS
and
-- END CLUA GLOBALS
will be removed from the file, and replaced with the newer info.
If you'd like to override any of these values, I recommend doing so after
-- END CLUA GLOBALS
so that the changes aren't overwritten.

CLua is semantically versioned.

CLua is released under GPLv2. A copy of the license is available here.

Examples!
SpoilerSome very basic examples detailing how to use CLua.

Except where otherwise specified, the command used to compile these applications is:
clua test1 test --log

NOTE: These examples are somewhat old, and while they will compile, the output will look somewhat different than it appears here.
I'm working on updating these examples, and adding new ones for the newer features.

Insert a file into another filetest1

--test1 line 1
print('1')
#INCLUDE test2 FROM /
print('3')
--test1 line 5
test2

--test2 line 1
print('2')
--test2 line 3
output file

--test1 line 1
print('1')
--test2 line 1
print('2')
--test2 line 3
print('3')
--test1 line 5
clua log

[16.978][DEBUG] Enable logging: true
[16.978][OKAY] Begin parsing test1...
[16.978][DEBUG] Building source table from test1...
[16.978][DEBUG] Attempting to handle "#INCLUDE test2 FROM /"
[16.978][OKAY] Begin parsing test2...
[16.978][DEBUG] Building source table from test2...
[16.978][OKAY] End parsing test2
[16.978][OKAY] End parsing test1
[16.978][OKAY] Writing source table to test...
[16.978][OKAY] Removing blank lines from test...
[16.979][DEBUG] Building source table from test...
[16.979][OKAY] Writing source table to test...
[16.979][DEBUG] Trimmed 0 lines from test
[16.979][DONE] Compilation complete
Conditionally insert a file into anothertest1

--test1 line 1
print('1; test1')
#DEFINE test1
print('2; test1')

#IFNDEF test2
#INCLUDE test2 FROM /
#ENDIFNDEF

#IFNDEF test2
print('3; test1')
#ENDIFNDEF

#IFDEF test2
print('4; test1')
#ENDIFDEF

--test1 line 18
test2

--test2 line 1
#DEFINE test2
#IFNDEF test1
print('2; test2')
#ENDIFNDEF

#IFDEF test1
print('3; test2')
#ENDIFDEF

--test2 line 11
output file

--test1 line 1
print('1; test1')
print('2; test1')
--test2 line 1
print('3; test2')
--test2 line 11
print('4; test1')
--test1 line 18
clua log

[16.933][DEBUG] Enable logging: true
[16.933][OKAY] Begin parsing test1...
[16.933][DEBUG] Building source table from test1...
[16.933][DEBUG] Attempting to handle "#DEFINE test1" on line 3
[16.933][DEBUG] Defined "test1"
[16.933][DEBUG] Attempting to handle "#IFNDEF test2" on line 6
[16.933][DEBUG] No definition found for test2
[16.933][DEBUG] Attempting to handle "#INCLUDE test2 FROM /" on line 8
[16.933][OKAY] Begin parsing test2...
[16.933][DEBUG] Building source table from test2...
[16.933][DEBUG] Attempting to handle "#DEFINE test2" on line 2
[16.933][DEBUG] Defined "test2"
[16.933][DEBUG] Attempting to handle "#IFNDEF test1" on line 3
[16.933][DEBUG] Definition found for test1
[16.933][DEBUG] Attempting to handle "#IFDEF test1" on line 7
[16.933][DEBUG] Definition found for test1
[16.933][OKAY] End parsing test2
[16.933][DEBUG] Attempting to handle "#IFNDEF test2" on line 10
[16.933][DEBUG] Definition found for test2
[16.933][DEBUG] Attempting to handle "#IFDEF test2" on line 14
[16.933][DEBUG] Definition found for test2
[16.933][OKAY] End parsing test1
[16.933][OKAY] Writing source table to test...
[16.933][DEBUG] Ignoring line 4 because it's empty
[16.934][DEBUG] Ignoring line 6 because it's empty
[16.934][DEBUG] Ignoring line 8 because it's empty
[16.934][DEBUG] Ignoring line 10 because it's empty
[16.934][DEBUG] Ignoring line 11 because it's empty
[16.934][DEBUG] Ignoring line 13 because it's empty
[16.934][DEBUG] Trimmed 6 lines from test
[16.934][DONE] Compilation complete
[16.934][DONE] Time: 0.001
Single recursiontest1

--test1 line 1
#DEFINE test1

print('test1')

#IFNDEF test2
#INCLUDE test2 FROM /
#ENDIFNDEF

#IFNDEF test2
print('this line is always ignored')
#ENDIFNDEF

print('finished')
--test1 line 15
test2

--test2 line 1
#DEFINE test2

print('test2')

#INCLUDE test1 FROM /
--test2 line 7
output file

--test1 line 1
print('test1')
--test2 line 1
print('test2')
--test1 line 1
print('test1')
print('finished')
--test1 line 15
--test2 line 7
print('finished')
--test1 line 15
clua log

[13.626][DEBUG] Enable logging: true
[13.626][OKAY] Begin parsing test1...
[13.626][DEBUG] Building source table from test1...
[13.626][DEBUG] Attempting to handle "#DEFINE test1" on line 2
[13.626][DEBUG] Defined "test1"
[13.626][DEBUG] Attempting to handle "#IFNDEF test2" on line 6
[13.626][DEBUG] No definition found for test2
[13.626][DEBUG] Attempting to handle "#INCLUDE test2 FROM /" on line 8
[13.626][OKAY] Begin parsing test2...
[13.626][DEBUG] Building source table from test2...
[13.626][DEBUG] Attempting to handle "#DEFINE test2" on line 2
[13.626][DEBUG] Defined "test2"
[13.626][DEBUG] Attempting to handle "#INCLUDE test1 FROM /" on line 6
[13.626][OKAY] Begin parsing test1...
[13.626][DEBUG] Building source table from test1...
[13.626][DEBUG] Attempting to handle "#DEFINE test1" on line 2
[13.626][WARNING] Potential infinite loop detected!
[13.626][WARNING] Setting warning flag
[13.626][WARNING] #DEFINE directive ignored
[13.626][DEBUG] Attempting to handle "#IFNDEF test2" on line 6
[13.626][DEBUG] Definition found for test2
[13.626][DEBUG] Attempting to handle "#IFNDEF test2" on line 10
[13.626][DEBUG] Definition found for test2
[13.626][OKAY] End parsing test1
[13.627][OKAY] End parsing test2
[13.627][DEBUG] Attempting to handle "#IFNDEF test2" on line 10
[13.627][DEBUG] Definition found for test2
[13.628][OKAY] End parsing test1
[13.628][OKAY] Writing source table to test...
[13.628][DEBUG] Ignoring line 2 because it's empty
[13.628][DEBUG] Ignoring line 4 because it's empty
[13.628][DEBUG] Ignoring line 6 because it's empty
[13.628][DEBUG] Ignoring line 8 because it's empty
[13.628][DEBUG] Ignoring line 10 because it's empty
[13.628][DEBUG] Ignoring line 12 because it's empty
[13.628][DEBUG] Ignoring line 13 because it's empty
[13.628][DEBUG] Ignoring line 14 because it's empty
[13.628][DEBUG] Ignoring line 18 because it's empty
[13.628][DEBUG] Ignoring line 19 because it's empty
[13.628][DEBUG] Trimmed 10 lines fro[list]
[*]
[/list]

[list]
[*]Add full support for nested directives
m test
[13.628][DONE] Compilation complete
[13.628][DONE] Time: 0.002
Multiple recursionThis example will always produce a compiler error, because it will see a specific #DEFINE (test1, line 2) three times, and assume its an infinite loop.
test1

--test1 line 1
#DEFINE test1

print('test1')

#IFNDEF test2
#INCLUDE test2 FROM /
#ENDIFNDEF

#IFNDEF test2
print('this line is always ignored')
#ENDIFNDEF

print('finished')
--test1 line 15
test2

--test2 line 1
#DEFINE test2

print('test2')

#INCLUDE test1 FROM /
#INCLUDE test1 FROM /
--test2 line 7
output file

clua log

[14.832][DEBUG] Enable logging: true
[14.832][OKAY] Begin parsing test1...
[14.832][DEBUG] Building source table from test1...
[14.832][DEBUG] Attempting to handle "#DEFINE test1"
[14.832][DEBUG] Defined "test1"
[14.832][DEBUG] Attempting to handle "#IFNDEF test2"
[14.832][DEBUG] No definition found for test2
[14.832][DEBUG] Attempting to handle "#INCLUDE test2 FROM /"
[14.832][OKAY] Begin parsing test2...
[14.832][DEBUG] Building source table from test2...
[14.832][DEBUG] Attempting to handle "#DEFINE test2"
[14.832][DEBUG] Defined "test2"
[14.832][DEBUG] Attempting to handle "#INCLUDE test1 FROM /"
[14.832][OKAY] Begin parsing test1...
[14.832][DEBUG] Building source table from test1...
[14.832][DEBUG] Attempting to handle "#DEFINE test1"
[14.832][WARNING] Potential infinite loop detected!
[14.832][WARNING] Setting warning flag
[14.832][WARNING] #DEFINE directive ignored
[14.832][DEBUG] Attempting to handle "#IFNDEF test2"
[14.832][DEBUG] Definition found for test2
[14.832][OKAY] End parsing test1
[14.832][DEBUG] Attempting to handle "#INCLUDE test1 FROM /"
[14.832][OKAY] Begin parsing test1...
[14.832][DEBUG] Building source table from test1...
[14.832][DEBUG] Attempting to handle "#DEFINE test1"
[14.832][ERROR] Infite loop detected!
[14.832][ERROR] Terminating job!
Set a flag from the command linetest1

--test1 line 1
print('1')
#IFNDEF test2
#INCLUDE test2 FROM /
#ENDIFNDEF
print('3')
--test1 line 7
test2

--test2 line 1
#DEFINE test2
print('2')
--test2 line 4
CLua command
clua test1 test --log --define:test2
output file

--test1 line 1
print('1')
print('3')
--test1 line 7
clua log

[16.998][DEBUG] Enable logging: true
[16.998][OKAY] Begin parsing test1...
[16.998][DEBUG] Building source table from test1...
[16.998][DEBUG] Attempting to handle "#IFNDEF test2" on line 3
[16.998][DEBUG] Definition found for test2
[16.998][OKAY] End parsing test1
[16.998][OKAY] Writing source table to test...
[16.998][DEBUG] Trimmed 0 lines from test
[16.998][DONE] Compilation complete
[16.998][DONE] Time: 0

Changelog
Spoiler
2.0.0BUGFIX: Nested block-type directives now behave as expected

BUGFIX: Line numbers are no longer distorted by block-type directives
BUGFIX: EXEC no longer crashes when reporting certain crashes
BUGFIX: Handles failure to open log more gracefully (more improvements to come)

CHANGE: –silent now prevents ALL output except errors
CHANGE: GPLv2 now lists author in MODULE line
CHANGE: –define now supports multiple flags per option, separated by semicolons
CHANGE: because of a change in the versioning system, we've moved to version 2.0.0
CHANGE: LICENSE no longer errors when a file is given more than one license; it throws a warning instead
CHANGE: DEVEL logging is slightly less verbose

NEW: self testing suite added (not automatically downloaded; available on the github)
NEW: –no-trim option
NEW: –dyn option
NEW: –from-path option
NEW: –to-path option
1.5.0BUGFIX: EXEC, IFVAR, IFNVAR, and –exec now have read-only access to certain internal functions and vars
BUGFIX: EXEC, IFVAR, IFNVAR, and –exec now have read-only access to _G
BUGFIX: Various typos fixed
BUGFIX: CLua now reports faulty environments rather than simply crashing

CHANGE: all code now wrapped in pcall to allow for prettier errors
CHANGE: libraries now call EXEC log() instead of EXEC print()
CHANGE: added correct licensing info to LUABIT
CHANGE: all libraries are now formatted the same way
CHANGE: logging output is now cleaner

NEW: 3 new directives
  • #SETDYNAMICVAR
  • #DYNAMIC-INCLUDE
  • #LICENSE
NEW: 1 new library
  • RANDOM
NEW: 3 new licenses
  • GPLv3
  • MIT
  • UNKNOWN – used when I don't know which license to use
NEW: CLua now generates a .licensing file during compilation
1.4.0BUGFIX: IFVAR and IFNVAR now actually receive the correct input
BUGFIX: IFDEF, IFNDEF, IFVAR, and IFNVAR now always find the end of their block
BUGFIX: CLua now handles invalid source files gracefully
BUGFIX: more efficient option parsing
BUGFIX: updater now skips asking where to install if it detects a current install

CHANGE: timer now measures in ticks and seconds instead of delta gametime
CHANGE: better timer formatting
CHANGE: better overall formatting
CHANGE: all libraries now have credit headers
CHANGE: usage info is now displayed using textutils.pagedPrint()

NEW: adjustable logging
NEW: 10 new command line options
  • –help
  • -?
  • –version
  • –dry-run
  • –quiet
  • –silent
  • –verbose
  • –devel
  • –no-debug
  • –self-update
NEW: 2 new libraries
  • JSON
  • SPLASH
1.3.0BUGFIX: Fixed a crash caused by the –exec option
BUGFIX: When a crash occurs during option parsing but after logging is enabled, it now creates a new log file

CHANGE: Logging now supports multiline strings
CHANGE: Various minor logging changes

NEW: Add #EXEC directive
NEW: Add #IFVAR directive
NEW: Add #IFNVAR directive
NEW: Add #ENDIFVAR directive
NEW: Add #ENDIFNVAR directive
NEW: Errors in the –exec option now reference the specific option that caused the issue
1.2.0NEW: Add command line args
  • –log - Enables logging
  • –exec:<code> - Executes arbitrary code before compilation
  • –define:<flag> - Equivalent to #DEFINE
NEW: Add two libraries to pastebin version (they were already in MPT version):
  • CRC32 - A high-speed hashing API
  • LUABIT - A bitwise API capable of handling 32-bit integers
NEW: Add compilation timing
1.1.1BUGFIX: Line numbers in logs (should) now reference the line in the source instead of their source table key.
BUGFIX: #SNIPPET no longer claims to ignore itself

CHANGE: fixed a typo ('beacause' ==> 'because')
CHANGE: significantly less console spam (no effect on logging verbosity)
CHANGE: #ELSE, #ELSEIF, and #ELSEIFN now have their own error messages, since the main loop should never encounter them

NEW: enabled FROM shortcut. Use as:
#INCLUDE library FROM ~
to load a standa
    rd library. Standard libraries are currently only available through MPT.

    MPT Version Only:
    BUGFIX: no longer crashes under X System (we're now injecting into the kernel instead of startup; I'm working on re-enabling the alias)
    NEW: now includes two libraries
    1.1.0BUGFIX: #IFDEF and #IFNDEF no longer destroy the line after their closing directive

    CHANGE: minor directive recognition optimization
    CHANGE: minor #IFDEF and #IFNDEF optimization
    CHANGE: file trimming is now ~2x faster (I merged two loops)
    CHANGE: better logging

    NEW: Set CLUA_LIB global and create /<clua-root>/lib folder (prep for library support)
    NEW: add #SNIPPET directive
    NEW: don't error on #ELSE, #ELSEIF, #ELSEIFN (Planned directives)
    NEW: strip trailing whitespace (may prevent issues with newer directive recognition)
    1.0.0Initial public release
    Edited on 26 July 2014 - 04:29 AM
    SquidDev #2
    Posted 01 June 2014 - 03:49 PM
    I like it. I use C# a lot and it also has conditional compilation symbols. My one question is why conditional? Because we are not compiling for multiple platforms (Ok, we have coloured or not, pocket, turtle or computer) when would we choose to use it. I could actually find this useful for coloured/not compilation. I though about implementing it in PPI but looks like you have done a better job. Two suggestions though:
    1. #ELSE statement. For instance you could have:
    2. 
      		#IFDEF
      		print("Hello")
      		#ELSE
      		print("Hi")
      		#ENDIFDEF
      		
      I know you could have an #IFDEF … #ENDIFDEF, #IFNDEF … #ENDIFNDEF but I think this would be easier.
    3. Be able to define variables in the command line: clua –var=thing This would make it more convenient than editing the files. How do you choose the output file though?
    You can also do pastebin run zPMasvZ2 instead, but this is just a matter of preference (and doesn't work pre 1.6).

    I'm so happy that someone has developed the idea of PPI further.
    Edited on 01 June 2014 - 01:50 PM
    skwerlman #3
    Posted 01 June 2014 - 04:24 PM
    I like it. I use C# a lot and it also has conditional compilation symbols. My one question is why conditional? Because we are not compiling for multiple platforms (Ok, we have coloured or not, pocket, turtle or computer) when would we choose to use it. I could actually find this useful for coloured/not compilation. I though about implementing it in PPI but looks like you have done a better job.
    Well, while we don't have multiple platforms, we do have multiple environments. Certain programs expose APIs, such as in OneOS. Conditional compiling lets you write something like Environment.lua that contains a bunch of #DEFINEs to specify what you expect to your environment to look like. (or after I add those command line args you suggested, it could be compiled dynamically)

    Two suggestions though:
    1. #ELSE statement. For instance you could have:
    2. 
      					#IFDEF
      					print("Hello")
      					#ELSE
      					print("Hi")
      					#ENDIFDEF
      					
      I know you could have an #IFDEF … #ENDIFDEF, #IFNDEF … #ENDIFNDEF but I think this would be easier.
    3. Be able to define variables in the command line: clua –var=thing This would make it more convenient than editing the files. How do you choose the output file though?
    1. First, IFDEF needs a flag… Second, yes ELSE is a very good idea. Thats going right onto my TODO list.
    2. That's a really good idea. I'll definitely add command line arguments. It'll make logging make more sense (a third arg of ANYTHING (even false) will enable logging).

    The output file is the second argument passed to clua. As it stands now, usage is clua <input> <output> <logging>
    I thought I put that in the post…
    EDIT: Wow that was a massive derp… Fixed


    You can also do pastebin run zPMasvZ2 instead, but this is just a matter of preference (and doesn't work pre 1.6).

    I included the instructions the way I did because in future versions the installer will double as an updater

    I'm so happy that someone has developed the idea of PPI further.
    It wouldn't have happened without PPI :)/>
    skwerlman #4
    Posted 04 June 2014 - 10:51 PM
    I'm considering adding a directive, #DEFONCE, which will define a flag and also set it in the warning table, so the compiler will error if anything tries to #DEFINE it later. Thoughts?
    SquidDev #5
    Posted 05 June 2014 - 08:00 AM
    I'm considering adding a directive, #DEFONCE, which will define a flag and also set it in the warning table, so the compiler will error if anything tries to #DEFINE it later. Thoughts?

    When you you use that? I just can't see any practical applications of it, would defining it twice break your code or something?
    skwerlman #6
    Posted 05 June 2014 - 06:45 PM
    I'm considering adding a directive, #DEFONCE, which will define a flag and also set it in the warning table, so the compiler will error if anything tries to #DEFINE it later. Thoughts?

    When you you use that? I just can't see any practical applications of it, would defining it twice break your code or something?
    It can be used in libraries that define functions to indicate that loading it more than once is not allowed.
    Basically, it helps enforce good library writing/loading standards.
    It also completely exempts a file from any loop detection (which may be more complex later) potentially making compilation faster.
    Edited on 09 June 2014 - 06:31 PM
    skwerlman #7
    Posted 10 June 2014 - 08:35 AM
    CLua version 1.1.1 is now available! This update fixes issues with logging and the SNIPPET directive, and includes some more prep for libraries (and actual, working libraries if you installed using MPT).
    I also fixed an issue which made the MPT version incompatible with X System (the OS MPT was written for).
    Finally, and perhaps most importantly, I cut the console output down from pages to lines.
    See the changelog for full info.

    Fixing IFDEF and IFNDEF is next on my list, but I can't seem to find the code that was giving me issues… I'll put it on hold for now, and work on command line arguments instead.

    EDIT:
    Clua version 1.2.0 is now available! This version adds support for command line arguments! I added three args: log, exec, and define. log enables logging (wow, so informative!), exec runs whatever code is passed to it, and define sets the flag passed to it. All of these args can be supplied multiple times (though I don't think you'll need to pass log more than once…). I also added the two MPT-only libraries to the pastebin version.
    As always, see the changelog for full info.

    I'm still trying reproduce that IFDEF bug, but I haven't succeeded… Maybe I dreamt it? Since I can't reproduce it yet, I'll work on adding some more libraries for now. Mikk809h's LogAPI is next.

    Oh, and I added a compilation timer. It's mostly for me benchmarking my code, but I bet someone out there will find it useful.
    Edited on 11 June 2014 - 02:57 AM
    skwerlman #8
    Posted 13 June 2014 - 07:26 AM
    CLua version 1.3.0 is now available! This version adds 5 new PPDs, (slightly) better logging, and fixes a serious bug in the exec option.
    Oh, and a TON of error checking (mostly in the new PPDs + exec)
    The new PPDs:
    #EXEC <code> - Basically the same as the –exec option, but a PPD
    #IFVAR <variable> - Checks whether a variable is defined. Syntax is similar to #IFDEF.
    #ENDIFVAR - Ends an #IFVAR block
    #IFNVAR <variable> - Checks whether a variable is undefined. Syntax is similar to #IFNDEF.
    #ENDIFNVAR - Ends an #IFNVAR block

    I've given up on that IFDEF bug, but if anyone can manage to reproduce it, I'll see if I can fix it.
    skwerlman #9
    Posted 23 June 2014 - 07:19 AM
    Forgot to mention that 1.4.0 is out!

    I fixed that one IFDEF bug. It would happen when an #END… directive was either the last line or the second to last line followed by a blank line. The corresponding #IF… would never reach it since it would think it ran out of file before it reached the actual last line.

    I added ten new command line options, and imporved the usage formatting. Also, the usage got kinda long, so I'm now using pagedprint.

    I also added two new libraries, SPLASH and JSON.
    JSON allows you to convert JSON files into Lua tables and vice versa.
    SPLASH allows you to read and write to a JSON formatted list of splash texts, as well as grab a random, persistent splash text.

    I fixed a couple other minor bugs, and made some minor changes.

    And, as seems to be the case with every update, I improved logging. Actually, it changed a lot this time.

    See the CL for more info.
    skwerlman #10
    Posted 25 June 2014 - 03:38 AM
    Version 1.5.0 is out!

    This version adds a bunch of features to make licensing requirements easy. With a single line of code, you can pick a license for your program, and you never need to worry about fulfilling the requirements of the modules you're using, since CLua takes care of it for you.

    This version also adds the ability to have lines of code generated at compile time.

    As always, there's some more improvements to logging. (I'm beginning to think I have an issue… :P/>)
    The CL has more info.
    Edited on 25 June 2014 - 01:39 AM
    skwerlman #11
    Posted 26 July 2014 - 06:07 AM
    Version 2.0.0 is out!

    This version fixes all known bugs, adds a couple nifty new options, expands the syntax of –define and makes a couple other tweaks and improvements.
    As always, the changelog has a much more descriptive list of changes/fixes/additions.

    I'll be updating the MPT repo soon, though I'm considering dropping it, as MPT's development seems to have stalled.

    I'm looking for library submissions now. If you'd like your library to be included with CLua, send me a PM with the license and a link to the source and I'll see about adding it.

    Oh, yeah, I also wrote an optional test suite for CLua. It's available on the Github. Drop those files into /clua/test/ and run selftest.lua to make sure your copy is working right. It's useful if you're messing with the source code, since it tests every directive CLua provides, plus all of its libraries.
    0099 #12
    Posted 13 August 2014 - 05:21 PM
    It reminds me of one of my first Lua projects - it was a custom preprocessor for C, so instead of writing large amount of C code, I could leave a Lua script at that point, which will automatically generate it. It turned out to be useful, especially commands "rememer this struct" and "write remembered struct into a file field-by-field".