lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



The work on luaSuper is approaching release, and I would like to share some of it here, although "code complete" stage is still a few days away, hopefully no more.

The concept is making 'luas' command a syntax modifiable version of the 'lua' interpreter. This is how it goes:

luas -s select demo.lua # loads demo.lua with syntax mods from 'luas_select.so'

or, one can make demo.lua load the syntax mods automatically, by having the following shebang line:

	#!/.../luas -s select

Some differentiation of luaSuper to regular token filtering, and MetaLua:

	- made in C++ (about 2500 lines, 4 .cpp files)
- parsing speed should be similar to regular Lua parser, _even_ when the syntax is modified
	- multiple syntax mods are usable
	- different source files can use each their own set of syntax mods

Performance and ease of making syntax modifications have been the design goals. As a sample, below is what it takes to make a "select" syntax mod, build by:

	g++ -bundle luas_select.cpp -o luas_select.so

I will hopefully get the code ready during next week. It'd be motivating to get some feedback, ideas, questions already now.

-asko


/*
* SELECT token filter                   Copyright 2006-07 Asko Kauppi
*
* Simplifies the 'select' usage a bit, making it look less like a function
*
*      #...        -> select('#',...)  = number of values in ...
*      ...[n]      -> (select(n,...))  = value #n of ...
*
* 'select(n,...)' is still used explicitly when wanting all values from 'n' onwards.
*
* License: MIT/Lua5 (see LICENSE)
*/

#include "plugin.hpp"

/*
* Called by luaSuper parser, for "#..."
*/
static bool CATCH1( PluginParser& p )
{
    p.replace( 0,2, "select", "(", "\"#\"", ",", "...", ")" );
    return true;
}

/*
* Called by luaSuper parser, for "...[exp]"
*/
static bool CATCH2( PluginParser& p )
{
    p.replace( 0,2, "(", "select", "(" );
    p.replace( -1,1, ",", "...", ")", ")" );
    return true;
}

/*
* Override normal syntax:
*
*    ["exp"]= { opt(unop),
* alt{ "nil", "false", "true", "<number>", "<string>", "...",
*                    { "{", opt(fieldlist), "}" },
*                    { "function", funcbody },
*                    prefixexp },
*               opt( binop, exp ) }
*      -->
*    ["exp"]= { opt( ent( opt(unop),
*					alt{ { "#", "..." },
* { "...", opt{ "[", exp, "]" } },
*                         		opt(binop,exp) ),
*			original }
*
* Note: Not repeating the original syntax makes us play nice with potential * other plugins. We would otherwise let the original path be considered * first, but "..." within it would make a match, avoiding "... [exp]"
*       extension to work. Alas, we need to be first.
*
*       Other plugins may further extend the 'exp' syntax, appending
*       or prepending their modifications, without troubling us or the
* original syntax (unless, of course, the syntaxes themselves do clash).
*/
void syntax_select( PluginSyntax& syntax ) {

// Note: use 'syntax["exp"]' to get the _current_ syntax, using 'ref()' // would make a loop! However, for "...[exp]" we can use 'ref()' // since it's within an 'alt' case. Ref allows our syntax to be // recursively applied, and further changes to 'exp' to apply also
    //       within our syntax.

    const EntBase *unop= ref("unop");
    const EntBase *binop= ref("binop");
    const EntBase *exp= ref("exp");

    syntax["exp"]= opt( ent( opt(unop),
                             alt( "#", ent( "...", CATCH1 ),
"...", ent( "[", exp, "]", CATCH2 ) ),
                             opt(binop,exp)
                            ),
syntax["exp"] // earlier exp ('ref' would make a loop!)
                        );
}