MacroApplication

Overview

Macros are created by use of the Defmacro keyword followed by the Name, Lambda List of parameters, and the Body of the macro. The Body of the macro may consist of numerous expressions that require evaluating. When Defmacro is used, the compiler calls the Macro Expansion code which parses out the Lambda List from the expression and sends it to the Macro Parser. In the Macro Parser the list is separated into "bindings" that contain the pertinent information for each variable/expression in the Lambda List. All of the "bindings" are grouped into a larger list which is then passed to the Macro Letification code where the individual variables are bound to a symbol which links their place/keyword to the init-form in the Lambda List.

Once completed, the bound Lambda List is then put into the overall Lambda expression that is used when the macro is called. This is where the Body of the macro gets connected with the bound variable symbols that were used in the Defmacro statement. The bound Lambda List and the bound Body are put together into a Let* statement. This entire Let* is then used by the compiler, whenever someone initiates the macro, to build the code that will be used during run-time.

Implementation

Details of implementation

All code for these functions was written in Lisp and placed into the Compiler section of Core Functions. The first part written was the Macro Parser which was based on the rewritten Function Parser and reuses many of the existing Function Parser functions to limit duplication of code. The functions for required, optional, rest, and keyword parameters had to be rewritten to account for the extra parameters whole, environment, and body. Since environment can appear at any point in the argument list after whole, whole and each of the original functions had to be modified to check for environment when it completed all the arguments in its section. Whole, if used, could only appear at the beginning - before required - and body is the same as rest so these changes were easy.

The Defmacro form is passed into the outer wrapper create-macro-expansion where the Lambda List is removed and handed to parse-macro-lambda-list. Each argument type is checked in order - whole, environment, required, environment, optional, environment, body/rest, environment, and keywords. Each argument type has a binding created that includes the variable name, scope, usage, type, init-form, and allocation. Of these - only the variable name, usage, and init-form are currently of interest to the letification code. Each binding is added to the list of bindings until there are no more parameters to be bound.

When the Macro Parser returns the list of bindings, they are passed to letify-macro-lambda-list where two things occur: 1) each succesive parameter is converted to a symbol and bound to its init-form and 2) the unbound symbols are added to a list that is then bound to the macro name and body in the Let* application. Each successive function only handles parameters of its type and when done, or if there are no parameters of that type, passes the remaining list of bindings to the next function. The final return is an anonymous Lambda that the compiler uses to create the form when a user calls the macro. Because the macro parameters are part of a symbolized list, a counter is used to iterate through them on each succesive call up to body/rest. Body/rest makes a list of all remaining parameters and if keywords are included the list will be verified as a property list before the first keyword is processed at run-time.

Discussions

Links to Blog issues

Current Status of MacroApplication

Status:

Release Level:

Open bug count:

Test Suites

Links to JUnit results

-- JerryBoetje - 12 Jul 2003

Topic revision: r3 - 2009-02-11 - 01:23:06 - MeganLusher
 
Home
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback