123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668 |
- package kawa.lang;
- import gnu.mapping.*;
- import gnu.expr.*;
- import gnu.lists.*;
- import gnu.bytecode.Type;
- import gnu.kawa.lispexpr.LangObjType;
- import gnu.kawa.lispexpr.LispLanguage;
- import java.util.ArrayList;
- import kawa.standard.object;
- /**
- * The Syntax transformer that re-writes the lambda builtin.
- * @author Per Bothner
- */
- public class Lambda extends Syntax
- {
- public Object optionalKeyword;
- public Object restKeyword;
- public Object keyKeyword;
- static BindDecls defaultBindParser = new LambdaBindDecls();
- public BindDecls bindParser = defaultBindParser;
- static {
- defaultBindParser.allowShadowing = true;
- defaultBindParser.makeConstant = false;
- }
- public static final Keyword nameKeyword = Keyword.make("name");
- // This should technically have the type of Scheme.booleanType.
- public Expression defaultDefault = QuoteExp.falseExp;
- public void setKeywords(Object optional, Object rest, Object key)
- {
- optionalKeyword = optional;
- restKeyword = rest;
- keyKeyword = key;
- }
- @Override
- public Expression rewrite (Object obj, Translator tr)
- {
- if (! (obj instanceof Pair))
- return tr.syntaxError ("missing formals in lambda");
- int old_errors = tr.getMessages().getErrorCount();
- LambdaExp lexp = new LambdaExp();
- Pair pair = (Pair) obj;
- rewrite(lexp, pair.getCar(), pair.getCdr(), tr, null);
- if (tr.getMessages().getErrorCount() > old_errors)
- return new ErrorExp("bad lambda expression");
- return lexp;
- }
- /**
- * Higher-level constructor, that does the re-writing.
- * @param formals the formal parameter list (or symbol)
- * @param body the body of the procedure
- * @param tr the (Scheme) Translator
- */
- public void rewrite(LambdaExp lexp, Object formals, Object body,
- Translator tr, TemplateScope templateScopeRest)
- {
- lexp.setCallConvention(tr);
- rewriteFormals(lexp, formals, tr, templateScopeRest);
- if (body instanceof PairWithPosition)
- lexp.setFile(((PairWithPosition) body).getFileName());
- body = rewriteAttrs(lexp, body, tr);
- rewriteBody(lexp, body, tr);
- }
- public void rewriteFormals(LambdaExp lexp, Object formals,
- Translator tr, TemplateScope templateScopeRest)
- {
- tr.pushScope(lexp);
- if (lexp.getSymbol() == null)
- {
- String filename = lexp.getFileName();
- int line = lexp.getLineNumber();
- if (filename != null && line > 0)
- lexp.setSourceLocation(filename, line);
- }
- Object bindings = formals;
- int opt_args = -1;
- int rest_args = -1;
- int key_args = -1;
- Pair pair;
- bindings = formals;
- opt_args = -1;
- key_args = -1;
- ArrayList<Expression> defaultArgs = null;
- ArrayList<Keyword> keywords = null;
- Object mode = null;
- Object next = null;
- for (; ; bindings = next)
- {
- if (bindings instanceof SyntaxForm)
- {
- SyntaxForm sf = (SyntaxForm) bindings;
- bindings = sf.getDatum();
- // The SyntaxForm "surrounds" both the current binding (the car),
- // as well as the cdr - i.e. the remaining bindings.
- templateScopeRest = sf.getScope();
- }
- if (! (bindings instanceof Pair))
- break;
- TemplateScope templateScope = templateScopeRest;
- pair = (Pair) bindings;
- Object pair_car = pair.getCar();
- next = pair.getCdr();
- if (pair_car instanceof SyntaxForm)
- {
- SyntaxForm sf = (SyntaxForm) pair_car;
- pair_car = sf.getDatum();
- templateScope = sf.getScope();
- }
- Object pccar;
- if (pair_car == optionalKeyword)
- {
- if (opt_args >= 0)
- tr.syntaxError ("multiple "+optionalKeyword+" keywords in parameter list");
- else if (rest_args >= 0 || key_args >= 0)
- tr.syntaxError (optionalKeyword.toString()+" after " + restKeyword + " or " + keyKeyword);
- opt_args = 0;
- }
- else if (pair_car instanceof Pair
- && ((pccar = ((Pair) pair_car).getCar()) == LispLanguage.splice_sym
- || pccar == LispLanguage.splice_colon_sym))
- {
- if (rest_args >= 0)
- tr.syntaxError ("multiple " + restKeyword
- + " keywords in parameter list");
- mode = null;
- rest_args = 0;
- }
- else if (pair_car == restKeyword)
- {
- if (rest_args >= 0)
- tr.syntaxError ("multiple " + restKeyword
- + " keywords in parameter list");
- rest_args = 0;
- }
- else if (pair_car == keyKeyword)
- {
- if (key_args >= 0)
- tr.syntaxError ("multiple " + keyKeyword
- + " keywords in parameter list");
- key_args = 0;
- }
- else if (mode == keyKeyword)
- key_args++;
- else if (mode == restKeyword) {
- if (pair_car != Special.ifk)
- rest_args++;
- } else if (opt_args >= 0)
- opt_args++;
- else if (pair_car != Special.ifk) {
- lexp.min_args++;
- }
- if (pair_car == optionalKeyword
- || pair_car == restKeyword || pair_car == keyKeyword)
- {
- mode = pair_car;
- continue;
- }
- Object savePos = tr.pushPositionOf(pair);
- Object name = null;
- Object defaultValue = defaultDefault;
- Pair suppliedPair = null;
- Pair typeSpecPair = null;
- Pair p;
- if (tr.matches(pair_car, "::"))
- {
- tr.syntaxError("'::' must follow parameter name");
- break;
- }
- pair_car = tr.namespaceResolve(pair_car);
- Declaration decl = null;
- if (pair_car instanceof Symbol
- || pair_car == Special.ifk
- || bindParser.literalPattern(pair_car, tr) != null
- || (pair_car instanceof Pair
- && (mode == null
- || (pccar = ((Pair) pair_car).getCar()) == LispLanguage.splice_sym
- || pccar == LispLanguage.splice_colon_sym)
- && (Translator.listLength(pair_car) != 3
- || ! tr.matches(((Pair) ((Pair) pair_car).getCdr()).getCar(), "::"))))
- {
- Object[] r = parsePatternCar(pair, templateScope, lexp, tr);
- next = r[0];
- decl = (Declaration) r[1];
- if (decl == null)
- decl = new Declaration("<error>");
- if (decl.getFlag(Declaration.IS_REST_PARAMETER)) {
- if (rest_args > 0)
- tr.syntaxError("multiple rest arguments in parameter list");
- rest_args = 1;
- }
- name = decl == null ? null : decl.getSymbol();
- }
- else if (pair_car instanceof Pair)
- {
- Object[] r = parsePatternCar((Pair) pair_car, templateScope, lexp, tr);
- Object xrest = r[0];
- if (xrest instanceof Pair && mode != null) {
- p = (Pair) xrest;
- defaultValue = p.getCar();
- xrest = p.getCdr();
- }
- if (xrest instanceof Pair && mode != null) {
- p = (Pair) xrest;
- if (p.getCar() instanceof Symbol) {
- suppliedPair = p;
- }
- else
- tr.syntaxError("expected a supplied-parameter name");
- xrest = p.getCdr();
- }
- if (xrest != LList.Empty) {
- Object savePos1 = tr.pushPositionOf(r[0]);
- tr.syntaxError("junk at end of specifier for parameter");
- tr.popPositionOf(savePos1);
- }
- decl = (Declaration) r[1];
- if (decl == null)
- decl = new Declaration("<error>");
- name = decl == null ? null : decl.getSymbol();
- next = pair.getCdr();
- }
- if (decl == null) {
- if (name == null) {
- tr.syntaxError ("parameter is neither name nor (name :: type) nor (name default)"+": "+pair);
- break;
- }
- decl = new Declaration(name);
- }
- decl.setFlag(Declaration.IS_PARAMETER);
- if (mode == optionalKeyword || mode == keyKeyword)
- {
- decl.setInitValue(new LangExp(defaultValue));
- if (mode == keyKeyword)
- {
- if (keywords == null)
- keywords = new ArrayList<Keyword>();
- keywords.add(Keyword.make(name instanceof Symbol ? ((Symbol) name).getName() : name.toString()));
- }
- }
- Translator.setLine(decl, bindings);
- if (typeSpecPair != null)
- {
- decl.setType(new LangExp(typeSpecPair), null);
- decl.setFlag(Declaration.TYPE_SPECIFIED);
- }
- if (mode == restKeyword && pair_car != Special.ifk)
- {
- decl.setFlag(Declaration.IS_REST_PARAMETER);
- if (! decl.getFlag(Declaration.TYPE_SPECIFIED)) {
- decl.setType(LangObjType.listType);
- if (key_args < 0) {
- decl.setFlag(Declaration.KEYWORDS_OK);
- lexp.setFlag(LambdaExp.ALLOW_OTHER_KEYWORDS);
- }
- }
- }
- decl.setFlag(Declaration.IS_SINGLE_VALUE);
- if (suppliedPair != null) {
- Declaration suppliedDecl = addParam((Symbol) suppliedPair.getCar(),
- templateScope/*FIXME*/,
- lexp, tr);
- decl.setFlag(Declaration.IS_SUPPLIED_PARAMETER);
- suppliedDecl.setFlag(Declaration.IS_SUPPLIED_PARAMETER);
- suppliedDecl.setType(Type.booleanType);
- Translator.setLine(suppliedDecl, suppliedPair);
- }
- tr.popPositionOf(savePos);
- }
- if (bindings instanceof SyntaxForm)
- {
- SyntaxForm sf = (SyntaxForm) bindings;
- bindings = sf.getDatum();
- templateScopeRest = sf.getScope();
- }
- if (bindings instanceof Symbol)
- {
- if (opt_args >= 0 || key_args >= 0 || rest_args >= 0)
- {
- tr.syntaxError ("dotted rest-arg after " + optionalKeyword
- +", " + restKeyword + ", or " + keyKeyword);
- }
- else
- {
- rest_args = 1;
- Declaration decl = addParam((Symbol) bindings,
- templateScopeRest, lexp, tr);
- decl.setType(LangObjType.listType);
- decl.setFlag(Declaration.IS_SINGLE_VALUE
- |Declaration.IS_PARAMETER
- |Declaration.IS_REST_PARAMETER);
- // For compatibility
- decl.setFlag(Declaration.KEYWORDS_OK);
- lexp.setFlag(LambdaExp.ALLOW_OTHER_KEYWORDS);
- }
- }
- else if (bindings != LList.Empty)
- {
- tr.syntaxError ("misformed formals in lambda");
- }
- if (rest_args > 1)
- {
- tr.syntaxError ("multiple " + restKeyword + " parameters");
- rest_args = 1;
- }
- if (opt_args < 0)
- opt_args = 0;
- if (rest_args < 0)
- rest_args = 0;
- if (key_args < 0)
- key_args = 0;
- if (rest_args > 0)
- lexp.max_args = -1;
- else // Is this useful?
- lexp.max_args = lexp.min_args + opt_args;
- lexp.opt_args = opt_args;
- if (keywords != null)
- lexp.keywords = keywords.toArray(new Keyword[keywords.size()]);
- }
- protected Declaration addParam(Symbol name, TemplateScope templateScope,
- LambdaExp lexp, Translator tr) {
- return bindParser.define(name, templateScope, lexp, tr);
- }
- public Object rewriteAttrs(LambdaExp lexp, Object body, Translator tr)
- {
- String allocationFlagName = null;
- long accessFlag = 0;
- int allocationFlag = 0;
- SyntaxForm syntax0 = null;
- for (;;)
- {
- while (body instanceof SyntaxForm)
- {
- syntax0 = (SyntaxForm) body;
- body = syntax0.getDatum();
- }
- if (! (body instanceof Pair))
- break;
- Pair pair1 = (Pair) body;
- Object attrName = Translator.stripSyntax(pair1.getCar());
- if (tr.matches(attrName, "::"))
- attrName = null;
- else if (attrName instanceof Pair
- && isAnnotationSymbol(((Pair)attrName).getCar()))
- {
- if (lexp.nameDecl == null)
- tr.error('e', "annotation for anonymous function");
- else
- lexp.nameDecl.addAnnotation(new LangExp(pair1));
- body = pair1.getCdr();
- continue;
- }
- else if (! (attrName instanceof Keyword))
- break;
- SyntaxForm syntax1 = syntax0;
- Object pair1_cdr = pair1.getCdr();
- while (pair1_cdr instanceof SyntaxForm)
- {
- syntax1 = (SyntaxForm) pair1_cdr;
- pair1_cdr = syntax1.getDatum();
- }
- if (! (pair1_cdr instanceof Pair))
- break;
- Pair pair2 = (Pair) pair1_cdr;
- Object attrValue;
- if (attrName == null)
- {
- if (lexp.isClassMethod() && "*init*".equals(lexp.getName()))
- tr.error('e', "explicit return type for '*init*' method");
- else
- // Defer rewrite until rewriteBody.
- lexp.body = new LangExp(new Object[] { pair2, syntax1 });
- }
- else if (attrName == kawa.standard.object.accessKeyword)
- {
- accessFlag = object.addAccessFlags(pair2.getCar(),
- accessFlag,
- Declaration.METHOD_ACCESS_FLAGS,
- "method", tr);
- }
- else if (attrName == kawa.standard.object.allocationKeyword)
- {
- Expression attrExpr = tr.rewrite_car(pair2, syntax1);
- if (! (attrExpr instanceof QuoteExp)
- || ! ((attrValue = ((QuoteExp) attrExpr).getValue()) instanceof SimpleSymbol
- /* #ifdef use:java.lang.CharSequence */
- || attrValue instanceof CharSequence
- /* #else */
- // || attrValue instanceof String
- // || attrValue instanceof CharSeq
- /* #endif */
- ))
- tr.error('e', "allocation: value not a constant symbol or string");
- else if (lexp.nameDecl == null)
- tr.error('e', "allocation: not allowed for anonymous function");
- else
- {
- String value = attrValue.toString();
- if ("class".equals(value) || "static".equals(value))
- allocationFlag = Declaration.STATIC_SPECIFIED;
- else if ("instance".equals(value))
- allocationFlag = Declaration.NONSTATIC_SPECIFIED;
- else
- tr.error('e', "unknown allocation specifier");
- if (allocationFlagName != null && value != null)
- {
- tr.error('e', "duplicate allocation specifiers - "
- + allocationFlagName + " and "
- + value);
- }
- allocationFlagName = value;
- }
- }
- else if (attrName == kawa.standard.object.throwsKeyword)
- {
- attrValue = pair2.getCar();
- int count = Translator.listLength(attrValue);
- if (count < 0)
- tr.error('e', "throws: not followed by a list");
- else
- {
- Expression[] exps = new Expression[count];
- SyntaxForm syntax2 = syntax1;
- for (int i = 0; i < count; i++)
- {
- while (attrValue instanceof SyntaxForm)
- {
- syntax2 = (SyntaxForm) attrValue;
- attrValue = syntax2.getDatum();
- }
- Pair pair3 = (Pair) attrValue;
- exps[i] = tr.rewrite_car(pair3, syntax2);
- // Error-checking is done later.
- Translator.setLine(exps[i], pair3);
- attrValue = pair3.getCdr();
- }
- lexp.setExceptions(exps);
- }
- }
- else if (attrName == nameKeyword)
- {
- Expression attrExpr = tr.rewrite_car(pair2, syntax1);
- if (attrExpr instanceof QuoteExp)
- lexp.setName(((QuoteExp) attrExpr).getValue().toString());
- }
- else
- {
- Expression attrExpr = tr.rewrite_car(pair2, syntax1);
- attrName = ((Keyword) attrName).asSymbol();
- lexp.setProperty(attrName, attrExpr);
- }
- body = pair2.getCdr();
- }
- accessFlag |= allocationFlag;
- if (accessFlag != 0)
- lexp.nameDecl.setFlag(accessFlag);
- if (syntax0 != null)
- body = SyntaxForms.fromDatumIfNeeded(body, syntax0);
- return body;
- }
- public Object skipAttrs(LambdaExp lexp, Object body, Translator tr)
- {
- while (body instanceof Pair)
- {
- Pair pair = (Pair) body;
- if (! (pair.getCdr() instanceof Pair))
- break;
- Object attrName = pair.getCar();
- if (tr.matches(attrName, "::"))
- attrName = null;
- else if (! (attrName instanceof Keyword))
- break;
- body = ((Pair) pair.getCdr()).getCdr();
- }
- return body;
- }
- public void rewriteBody(LambdaExp lexp, Object body, Translator tr)
- {
- int numRenamedAlias = 0;
- // We view a top-level named function as a method, in the sense that the
- // form (this) is allowed, if the supertype is explicitly specified.
- if (tr.curMethodLambda == null
- && lexp.nameDecl != null
- && tr.getModule().getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
- tr.curMethodLambda = lexp;
- if (lexp.nameDecl != null)
- rewriteAnnotations(lexp.nameDecl, tr);
- Declaration prev = null;
- int key_args = lexp.keywords == null ? 0 : lexp.keywords.length;
- int opt_args = lexp.opt_args;
- int arg_i = 0;
- tr.lexical.pop(lexp);
- for (Declaration cur = lexp.firstDecl(); cur != null; cur = cur.nextDecl())
- {
- if (cur.isAlias())
- {
- Declaration param = Translator.getOriginalRef(cur).getBinding();
- lexp.replaceFollowing(prev, param);
- param.context = lexp;
- tr.pushRenamedAlias(cur);
- numRenamedAlias++;
- cur = param;
- }
- Expression texp = cur.getTypeExpRaw();
- if (texp instanceof LangExp)
- {
- Pair typeSpecPair = (Pair) ((LangExp) texp).getLangValue();
- Type t = tr.exp2Type(typeSpecPair, cur, null/*FIXME*/);
- if (t != null)
- cur.setType(t);
- }
- prev = cur;
- if (cur.getFlag(Declaration.IS_PARAMETER)) {
- Expression initValue = cur.getInitValue();
- if (initValue != null)
- cur.setInitValue(tr.rewrite(initValue));
- if (cur.getFlag(Declaration.IS_REST_PARAMETER)
- && cur.getFlag(Declaration.TYPE_SPECIFIED)) {
- Type rstType = cur.getType();
- if (rstType == LangObjType.argListType
- || rstType == LangObjType.argVectorType) {
- cur.setFlag(Declaration.KEYWORDS_OK);
- lexp.setFlag(LambdaExp.ALLOW_OTHER_KEYWORDS);
- }
- }
- arg_i++;
- }
- tr.lexical.push(cur);
- }
- if (lexp.isClassMethod()
- && ! lexp.nameDecl.getFlag(Declaration.STATIC_SPECIFIED))
- {
- // We set the type of this in ClassExp.walkChildren.
- lexp.add(null, new Declaration(ThisExp.THIS_NAME));
- }
- LambdaExp saveLambda = tr.curLambda;
- tr.curLambda = lexp;
- Type rtype = lexp.returnType;
- Object[] tform = lexp.body instanceof LangExp
- ? (Object[]) ((LangExp) lexp.body).getLangValue()
- : null;
- lexp.body = auxillaryRewrite(body, tr);
- tr.curLambda = saveLambda;
- Expression[] exps;
- int len;
- Object val;
- try {
- if (tform != null) {
- Expression texp = tr.rewrite_car((Pair) tform[0],
- (SyntaxForm) tform[1]);
- lexp.setCoercedReturnValue(texp, tr.getLanguage());
- } else if (lexp.body instanceof BeginExp
- && body instanceof Pair
- && ((Pair) body).getCar() instanceof Symbol
- && (len = (exps = ((BeginExp) lexp.body).getExpressions()).length) > 1
- && (exps[0] instanceof ReferenceExp
- || ((val = exps[0].valueIfConstant()) instanceof Type
- || val instanceof Class))) {
- // Handle '<TYPENAME> BODY':
- tr.error('w', "deprecated return-type specifier - use '::TYPE'");
- Expression rexp = exps[0];
- len--;
- if (len == 1)
- lexp.body = exps[1];
- else {
- Expression[] new_body = new Expression[len];
- System.arraycopy(exps, 1, new_body, 0, len);
- lexp.body = BeginExp.canonicalize(new_body);
- }
- lexp.setCoercedReturnValue(rexp, tr.getLanguage());
- } else
- lexp.setCoercedReturnType(rtype);
- } finally {
- tr.pop(lexp);
- lexp.countDecls();
- tr.popRenamedAlias(numRenamedAlias);
- lexp.countDecls();
- }
- if (tr.curMethodLambda == lexp)
- tr.curMethodLambda = null;
- }
-
- public Expression auxillaryRewrite(Object body, Translator tr)
- {
- return tr.rewrite_body(body);
- }
- @Override
- public void print (Consumer out)
- {
- out.write("#<builtin lambda>");
- }
- public static boolean isAnnotationSymbol (Object key)
- {
- if (key instanceof Pair)
- {
- Pair keyp = (Pair) key;
- if (keyp.getCar() == LispLanguage.splice_sym)
- return true;
- }
- if (key instanceof SimpleSymbol) // Deprecated: Symbol starting with '@'
- {
- String name = ((SimpleSymbol) key).getName();
- if (name.length() > 1 && name.charAt(0) == '@')
- return true;
- }
- return false;
- }
- public static void rewriteAnnotations (Declaration decl, Translator tr)
- {
- int n = decl.numAnnotations();
- for (int i = 0; i < n; i++)
- {
- Expression ann = decl.getAnnotation(i);
- if (ann instanceof LangExp)
- {
- ann = tr.rewrite_car((Pair) ((LangExp) ann).getLangValue(), false);
- decl.setAnnotation(i, ann);
- }
- }
- }
- public Object[] parsePatternCar(Pair patList, TemplateScope templateScope,
- LambdaExp lexp, Translator comp) {
- return bindParser.parsePatternCar(patList, null, templateScope, 0,
- lexp, comp);
- }
- static class LambdaBindDecls extends BindDecls {
- @Override
- public Declaration define(Symbol name,
- TemplateScope templateScope,
- ScopeExp lexp, Translator tr) {
- Declaration decl0 = new Declaration(name);
- Declaration decl = decl0;
- if (templateScope != null)
- decl = tr.makeRenamedAlias(decl, templateScope);
- lexp.addDeclaration(decl);
- if (templateScope != null)
- decl.context = templateScope;
- Declaration old = tr.lexical.lookup(name, -1);
- if (old != null && old.context == decl.context)
- ScopeExp.duplicateDeclarationError((Declaration) old,
- decl, tr);
- tr.push(decl);
- return decl0;
- }
- }
- }
|