lua-users home
lua-l archive

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


Thomas Lauer <thomas.lauer@virgin.net> wrote:

> This package, which is loosely based on steve d.'s LuaMacro code[1,2],
> implements textual macros for Lua. WRT steve's module I changed the
> lexer and the way macros are defined and expanded and also streamlined
> most functions.

I've uploaded a new version which supports searching a sequence of paths
when textually including files. Download source and examples:
http://thomaslauer.com/download/LuMaX.zip

> Time permitting I will scrape together some documentation

Here goes, see the attached text file. This is not yet a full
description of the functions in module macro but at least it gives some
explanations as to how the predefined macros are called (which, I
assume, is what most people will use anyway).

-- 
cheers  thomasl

web: http://thomaslauer.com/start
Module macro
============
Module macro adds textual macros and preprocessing facilities, similar to the C preprocessor, to Lua. It supports definition and replacement of macros, with or without parameters, and supports textually including source files (by contrast, require() and dofile() introduce separate compilation units with, among other things, a separate scope).

This module provides around a dozen functions to define and manipulate macros. However, using the predefined macros (see below) to define macros is much easier and more straightforward than calling these functions. Furthermore, some of the macro functions are still experimental and their usage may well change in future versions while the predefined macro calls should be rather stable. Because of this, the functions in module macro are currently not documented, although it is quite possible to use these functions for special cases or in circumstances where the predefined macros are not feasible; the enclosed example scripts do show some ways of doing so.

An important consideration to keep in mind while using this module is the fact that all macros are expanded at *compile time* and not at run-time (these are textual macros, after all). If Lua code has to be executed during compile time, the predefined macro __INLINE() can be used (see predefined macro __INCLUDE() for an example).

Note: this module is based on lhf's token filtering facility. In order for module macro to work Lua has to be patched accordingly. You also have to call lua with the appropriate switch to load the module:

  lua -l macro test.lua

Predefined Macros
=================
The following macros are predefined by module macro. As all macros, both predefined and user-defined, have global scope, the names of predefined macros start with two underscores in order to minimise the risk of contaminating existing programs. It is trivial to define additional macros with less obtuse names:

__DEFINE(DEFINE,__DEFINE)
DEFINE(INCLUDE,__INCLUDE)
-- and so on

__DEFINE(mdef,repl)
-------------------
Defines a macro. mdef is the macro name, optionally followed by a list of comma-separated argument names in parentheses. repl is the replacement code which is expanded each time the macro is used; the arguments, if any, are replaced with the actual parameters. Example:

__DEFINE(ATTRIBUTE_VALUE,0x0003)
__DEFINE(INC(n),n=n+1)
__DEFINE(IF2(cond,x,t,f),if cond then x=t else x=f end)
s=2
INC(s)
IF2(s==ATTRIBUTE_VALUE,s,'three','rubbish')
print(s)  --> prints 'three'

__FILE__
--------
Returns the current source file name.

__IF(m,v,t,f)
-------------
Allows conditional compilation. If argument m has value v, then t is compiled else f is compiled. If v is the empty string then __IF() checks whether m is defined as a macro: if yes, then t is compiled else f is compiled. Example:

__DEFINE(IFDEF(name,tru,fals),__IF(name,'',tru,fals))
-- DEBUG is not defined, uncomment next line to define
--__DEFINE(DEBUG,'')
IFDEF(DEBUG,
  __DEFINE(ASSERT(cond,msg),assert(cond,msg))
, -- ELSE
  __DEFINE(ASSERT(cond,msg),'')
)
print('Testing a few assertions:')
ASSERT(type(macro)=='table','macro ain\'t a table.')
print('Survived 1st')
ASSERT(1==1,'one is not one in this universe.')
print('Survived 2nd')
ASSERT(1==2,'one is not two in this universe.')
print('Survived 3rd')

__INCLUDE(fname)
----------------
Textually includes file fname. __INCLUDE() searches files along the path given in package.ipath. The macro module initialises this with the content of environment variable path but package.ipath can be set to any semicolon-separated sequence of pathnames. However, the following naive attempt will not work as expected...:

package.ipath='.;..;c:\\Lua\\inc'
__INCLUDE('test.inc')

... as the __INCLUDE() macro is executed at compile time and the package.ipath assignment is performed at runtime, ie much later. The following works as it inlines the assignment to package.ipath:

__INLINE("package.ipath='.;..;c:\\Lua\\inc'")
__INCLUDE('test.inc')  -- searches test.inc in current, parent and c:\Lua\inc

__INLINE(str)
-------------
Executes the Lua source code in string str during compile time. See __INCLUDE() for an example.

__LINE__
--------
Returns the current line number.

__REQUIRE(fname)
----------------
Temporarily disables macro processing and calls require() to load file fname during compile time. This can be used to load modules with macro definitions.

__STR(arg)
----------
Stringises its argument. Example:

__DEFINE(PRINT(n),print(__STR(n)..'='..n)
PRINT(math.sin(math.pi/4))  --> prints "math.sin(math.pi/4)=0.70710678118655"