Changeset 14131


Ignore:
Timestamp:
08/21/12 14:00:13 (9 years ago)
Author:
ehuelsmann
Message:

Close #219: lambda list keyword checking too lenient for ANSI.

Note: This introduces a new argument to the FUNCTION special form

(LAMBDA and NAMED-LAMBDA were already supported)
(FUNCTION (MACRO-FUNCTION ...))

Location:
trunk/abcl/src/org/armedbear/lisp
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/abcl/src/org/armedbear/lisp/ArgumentListProcessor.java

    r14022 r14131  
    3939import static org.armedbear.lisp.Lisp.*;
    4040
    41 /** A class to parse a lambda list and match function call arguments with it
     41/** A class to parse a lambda list and match function call arguments with it.
     42 *
     43 * The lambda list may either be of type ORDINARY or MACRO lambda list.
     44 * All other lambda lists are parsed elsewhere in our code base.
    4245 */
    4346public class ArgumentListProcessor {
     47   
     48  public enum LambdaListType {
     49      ORDINARY,
     50      MACRO
     51  }
    4452
    4553  // States.
     
    163171   *    bind as specials during initform evaluation
    164172   */
    165   public ArgumentListProcessor(Operator fun, LispObject lambdaList, LispObject specials) {
     173  public ArgumentListProcessor(Operator fun, LispObject lambdaList,
     174          LispObject specials, LambdaListType type) {
    166175    function = fun;
    167176   
     
    177186        int state = STATE_REQUIRED;
    178187        LispObject remaining = lambdaList;
     188       
     189        if (remaining.car() == Symbol.AND_WHOLE) {
     190            if (type == LambdaListType.ORDINARY) {
     191                error(new ProgramError("&WHOLE not allowed in ordinary lambda lists."));
     192            } else {
     193                // skip the &WHOLE <var> part of the lambda list
     194                remaining = remaining.cdr().cdr();
     195            }
     196        }
     197           
     198         
    179199        while (remaining != NIL)
    180200          {
     
    182202            if (obj instanceof Symbol)
    183203              {
     204                if (obj == Symbol.AND_WHOLE) {
     205                    if (type == LambdaListType.ORDINARY)
     206                      error(new ProgramError("&WHOLE not allowed in ordinary lambda lists."));
     207                    else
     208                      error(new ProgramError("&WHOLE must appear first in macro lambda list."));
     209                }
    184210                if (state == STATE_AUX)
    185211                  {
     
    201227                          "&REST/&BODY must precede &KEY."));
    202228                      }
     229                    if (type == LambdaListType.ORDINARY && obj == Symbol.AND_BODY)
     230                      error(new ProgramError("&BODY not allowed in ordinary lambda lists."));
    203231                    state = STATE_REST;
    204232                    arity = -1;
     
    229257                else if (obj == Symbol.AND_ENVIRONMENT)
    230258                  {
     259                    if (type == LambdaListType.ORDINARY)
     260                      error(new ProgramError("&ENVIRONMENT not allowed in ordinary lambda lists."));
    231261                    remaining = remaining.cdr();
    232262                    envVar = (Symbol) remaining.car();
  • trunk/abcl/src/org/armedbear/lisp/Closure.java

    r14130 r14131  
    9696    this.environment = env;
    9797
    98     arglist = new ArgumentListProcessor(this, lambdaList, specials);
     98    /* In the bootstrapping process, functions with MACRO LAMBDA LIST
     99     * lambda list types are being generated using the MACRO_FUNCTION instead
     100     * of the LAMBDA or NAMED_LAMBDA keys.
     101     *
     102     * Use that to perform argument list lambda list keyword checking.
     103     */
     104    arglist = new ArgumentListProcessor(this, lambdaList, specials,
     105            (lambdaExpression.car() == Symbol.MACRO_FUNCTION) ?
     106            ArgumentListProcessor.LambdaListType.MACRO
     107            : ArgumentListProcessor.LambdaListType.ORDINARY);
    99108    freeSpecials = arglist.freeSpecials(specials);
    100109  }
  • trunk/abcl/src/org/armedbear/lisp/Primitives.java

    r14023 r14131  
    18801880
    18811881        {
     1882            /* Create an expansion function
     1883             * `(lambda (,formArg ,envArg)
     1884             *     (apply (function (macro-function ,lambdaList
     1885             *                         (block ,symbol ,@body)))
     1886             *            (cdr ,formArg)))
     1887             */
    18821888            Symbol symbol = checkSymbol(args.car());
    18831889            LispObject lambdaList = checkList(args.cadr());
     
    18851891            LispObject block = new Cons(Symbol.BLOCK, new Cons(symbol, body));
    18861892            LispObject toBeApplied =
    1887                 list(Symbol.FUNCTION, list(Symbol.LAMBDA, lambdaList, block));
     1893                list(Symbol.FUNCTION, list(Symbol.MACRO_FUNCTION, lambdaList, block));
    18881894            final LispThread thread = LispThread.currentThread();
    18891895            LispObject formArg = gensym("FORM-", thread);
     
    19001906            else
    19011907                symbol.setSymbolFunction(macroObject);
    1902             macroObject.setLambdaList(lambdaList);
    1903             thread._values = null;
     1908            macroObject.setLambdaList(args.cadr());
     1909            LispThread.currentThread()._values = null;
    19041910            return symbol;
    19051911        }
     
    36573663
    36583664        {
     3665            /* Create an expansion function
     3666             * `(lambda (,formArg ,envArg)
     3667             *     (apply (function (macro-function ,lambdaList
     3668             *                         (block ,symbol ,@body)))
     3669             *            (cdr ,formArg)))
     3670             */
    36593671            Symbol symbol = checkSymbol(definition.car());
    36603672            LispObject lambdaList = definition.cadr();
     
    36633675                new Cons(Symbol.BLOCK, new Cons(symbol, body));
    36643676            LispObject toBeApplied =
    3665                 list(Symbol.LAMBDA, lambdaList, block);
     3677                list(Symbol.FUNCTION, list(Symbol.MACRO_FUNCTION, lambdaList, block));
    36663678            final LispThread thread = LispThread.currentThread();
    36673679            LispObject formArg = gensym("WHOLE-", thread);
  • trunk/abcl/src/org/armedbear/lisp/SpecialOperators.java

    r13695 r14131  
    499499                    return type_error(name, FUNCTION_NAME);
    500500                }
     501                if (car == Symbol.MACRO_FUNCTION)
     502                    return new Closure(arg, env);
    501503            }
    502504            return error(new UndefinedFunction(list(Keyword.NAME, arg)));
Note: See TracChangeset for help on using the changeset viewer.