001: package kawa.lang;
002:
003: import gnu.mapping.*;
004: import gnu.expr.*;
005: import gnu.lists.*;
006: import gnu.bytecode.Type;
007: import gnu.kawa.functions.Convert;
008:
009: /**
010: * The Syntax transformer that re-writes the lambda builtin.
011: * @author Per Bothner
012: */
013:
014: public class Lambda extends Syntax {
015: public Object optionalKeyword;
016: public Object restKeyword;
017: public Object keyKeyword;
018:
019: public static final Keyword nameKeyword = Keyword.make("name");
020:
021: public Expression defaultDefault = QuoteExp.falseExp;
022:
023: public void setKeywords(Object optional, Object rest, Object key) {
024: optionalKeyword = optional;
025: restKeyword = rest;
026: keyKeyword = key;
027: }
028:
029: public Expression rewriteForm(Pair form, Translator tr) {
030: Expression exp = rewrite(form.cdr, tr);
031: Translator.setLine(exp, form);
032: return exp;
033: }
034:
035: public Expression rewrite(Object obj, Translator tr) {
036: if (!(obj instanceof Pair))
037: return tr.syntaxError("missing formals in lambda");
038: int old_errors = tr.getMessages().getErrorCount();
039: LambdaExp lexp = new LambdaExp();
040: Pair pair = (Pair) obj;
041: Translator.setLine(lexp, pair);
042: rewrite(lexp, pair.car, pair.cdr, tr, null);
043: if (tr.getMessages().getErrorCount() > old_errors)
044: return new ErrorExp("bad lambda expression");
045: return lexp;
046: }
047:
048: /**
049: * Higher-level constructor, that does the re-writing.
050: * @param formals the formal parameter list (or symbol)
051: * @param body the body of the procedure
052: * @param tr the (Scheme) Translator
053: */
054: public void rewrite(LambdaExp lexp, Object formals, Object body,
055: Translator tr, TemplateScope templateScopeRest) {
056: rewriteFormals(lexp, formals, tr, templateScopeRest);
057: if (body instanceof PairWithPosition)
058: lexp.setFile(((PairWithPosition) body).getFileName());
059: body = rewriteAttrs(lexp, body, tr);
060: rewriteBody(lexp, body, tr);
061: }
062:
063: public void rewriteFormals(LambdaExp lexp, Object formals,
064: Translator tr, TemplateScope templateScopeRest) {
065: if (lexp.getSymbol() == null) {
066: String filename = lexp.getFileName();
067: int line = lexp.getLineNumber();
068: if (filename != null && line > 0)
069: lexp.setSourceLocation(filename, line);
070: }
071: /* Count formals, while checking that the syntax is OK. */
072: Object bindings = formals;
073: int opt_args = -1;
074: int rest_args = -1;
075: int key_args = -1;
076: Pair pair;
077: for (;; bindings = pair.cdr) {
078: if (bindings instanceof SyntaxForm) {
079: SyntaxForm sf = (SyntaxForm) bindings;
080: // FIXME
081: bindings = sf.form;
082: }
083: if (!(bindings instanceof Pair))
084: break;
085: pair = (Pair) bindings;
086: // An initial pass to count the parameters.
087: Object pair_car = pair.car;
088: if (pair_car instanceof SyntaxForm)
089: pair_car = ((SyntaxForm) pair_car).form;
090: if (pair_car == optionalKeyword) {
091: if (opt_args >= 0) {
092: tr.syntaxError("multiple " + optionalKeyword
093: + " in parameter list");
094: return;
095: } else if (rest_args >= 0 || key_args >= 0) {
096: tr.syntaxError(optionalKeyword.toString()
097: + " after " + restKeyword + " or "
098: + keyKeyword);
099: return;
100: }
101: opt_args = 0;
102: } else if (pair_car == restKeyword) {
103: if (rest_args >= 0) {
104: tr.syntaxError("multiple " + restKeyword
105: + " in parameter list");
106: return;
107: } else if (key_args >= 0) {
108: tr.syntaxError(restKeyword.toString() + " after "
109: + keyKeyword);
110: return;
111: }
112: rest_args = 0;
113: } else if (pair_car == keyKeyword) {
114: if (key_args >= 0) {
115: tr.syntaxError("multiple " + keyKeyword
116: + " in parameter list");
117: return;
118: }
119: key_args = 0;
120: } else if (tr.matches(pair.car, "::")
121: && pair.cdr instanceof Pair)
122: pair = (Pair) pair.cdr;
123: else if (key_args >= 0)
124: key_args++;
125: else if (rest_args >= 0)
126: rest_args++;
127: else if (opt_args >= 0)
128: opt_args++;
129: else
130: lexp.min_args++;
131: bindings = pair.cdr;
132: }
133: if (bindings instanceof String || bindings instanceof Symbol) {
134: if (opt_args >= 0 || key_args >= 0 || rest_args >= 0) {
135: tr.syntaxError("dotted rest-arg after "
136: + optionalKeyword + ", " + restKeyword
137: + ", or " + keyKeyword);
138: return;
139: }
140: rest_args = 1;
141: } else if (bindings != LList.Empty) {
142: tr.syntaxError("misformed formals in lambda");
143: return;
144: }
145: if (rest_args > 1) {
146: tr.syntaxError("multiple " + restKeyword + " parameters");
147: return;
148: }
149: if (opt_args < 0)
150: opt_args = 0;
151: if (rest_args < 0)
152: rest_args = 0;
153: if (key_args < 0)
154: key_args = 0;
155: if (rest_args > 0)
156: lexp.max_args = -1;
157: else
158: // Is this useful?
159: lexp.max_args = lexp.min_args + opt_args + 2 * key_args;
160: if (opt_args + key_args > 0)
161: lexp.defaultArgs = new Expression[opt_args + key_args];
162: if (key_args > 0)
163: lexp.keywords = new Keyword[key_args];
164:
165: bindings = formals;
166: opt_args = 0;
167: key_args = 0;
168: Object mode = null;
169: for (;; bindings = pair.cdr) {
170: if (bindings instanceof SyntaxForm) {
171: SyntaxForm sf = (SyntaxForm) bindings;
172: bindings = sf.form;
173: // The SyntaxForm "surrounds" both the current binding (the car),
174: // as well as the cdr - i.e. the remaining bindings.
175: templateScopeRest = sf.scope;
176: }
177: TemplateScope templateScope = templateScopeRest;
178: if (!(bindings instanceof Pair))
179: break;
180: pair = (Pair) bindings;
181: Object pair_car = pair.car;
182: if (pair_car instanceof SyntaxForm) {
183: SyntaxForm sf = (SyntaxForm) pair_car;
184: pair_car = sf.form;
185: templateScope = sf.scope;
186: }
187: if (pair_car == optionalKeyword || pair_car == restKeyword
188: || pair_car == keyKeyword) {
189: mode = pair_car;
190: continue;
191: }
192: Object savePos = tr.pushPositionOf(pair);
193: Object name = null;
194: Object defaultValue = defaultDefault;
195: Pair typeSpecPair = null;
196: Pair p;
197: if (tr.matches(pair_car, "::")) {
198: tr.syntaxError("'::' must follow parameter name");
199: return;
200: }
201: if (pair_car instanceof String
202: || pair_car instanceof Symbol) {
203: name = pair_car;
204: if (pair.cdr instanceof Pair
205: && tr.matches((p = (Pair) pair.cdr).car, "::")) {
206: if (!(pair.cdr instanceof Pair)) {
207: tr
208: .syntaxError("'::' not followed by a type specifier"
209: + " (for parameter '"
210: + name
211: + "')");
212: return;
213: }
214: p = (Pair) p.cdr;
215: typeSpecPair = p;
216: pair = p;
217: }
218: } else if (pair_car instanceof Pair) {
219: p = (Pair) pair_car;
220: pair_car = p.car;
221: if (pair_car instanceof SyntaxForm) {
222: SyntaxForm sf = (SyntaxForm) pair_car;
223: pair_car = sf.form;
224: templateScope = sf.scope;
225: }
226: if ((pair_car instanceof String || pair_car instanceof Symbol)
227: && p.cdr instanceof Pair) {
228: name = pair_car;
229: p = (Pair) p.cdr;
230: if (tr.matches(p.car, "::")) {
231: if (!(p.cdr instanceof Pair)) {
232: tr
233: .syntaxError("'::' not followed by a type specifier"
234: + " (for parameter '"
235: + name + "')");
236: return;
237: }
238: p = (Pair) p.cdr;
239: typeSpecPair = p;
240: if (p.cdr instanceof Pair)
241: p = (Pair) p.cdr;
242: else if (p.cdr == LList.Empty)
243: p = null;
244: else {
245: tr
246: .syntaxError("improper list in specifier for parameter '"
247: + name + "')");
248: return;
249: }
250: }
251: if (p != null && mode != null) {
252: defaultValue = p.car;
253: if (p.cdr instanceof Pair)
254: p = (Pair) p.cdr;
255: else if (p.cdr == LList.Empty)
256: p = null;
257: else {
258: tr
259: .syntaxError("improper list in specifier for parameter '"
260: + name + "')");
261: return;
262: }
263: }
264: if (p != null) {
265: if (typeSpecPair != null) {
266: tr
267: .syntaxError("duplicate type specifier for parameter '"
268: + name + '\'');
269: return;
270: }
271: typeSpecPair = p;
272: if (p.cdr != LList.Empty) {
273: tr
274: .syntaxError("junk at end of specifier for parameter '"
275: + name
276: + '\''
277: + " after type " + p.car);
278: return;
279: }
280: }
281: }
282: }
283: if (name == null) {
284: tr
285: .syntaxError("parameter is neither name nor (name :: type) nor (name default)"
286: + ": " + pair);
287: return;
288: }
289: if (mode == optionalKeyword || mode == keyKeyword)
290: lexp.defaultArgs[opt_args++] = new LangExp(defaultValue);
291: if (mode == keyKeyword)
292: lexp.keywords[key_args++] = Keyword
293: .make(name instanceof Symbol ? ((Symbol) name)
294: .getName() : name.toString());
295: Declaration decl = new Declaration(name);
296: Translator.setLine(decl, bindings);
297: if (typeSpecPair != null) {
298: decl.setType(tr.exp2Type(typeSpecPair));
299: decl.setFlag(Declaration.TYPE_SPECIFIED);
300: } else if (mode == restKeyword)
301: decl.setType(Compilation.scmListType);
302: decl.noteValue(null); // Does not have a known value.
303: addParam(decl, templateScope, lexp, tr);
304: tr.popPositionOf(savePos);
305: }
306: if (bindings instanceof SyntaxForm) {
307: SyntaxForm sf = (SyntaxForm) bindings;
308: bindings = sf.form;
309: templateScopeRest = sf.scope;
310: }
311: if (bindings instanceof String || bindings instanceof Symbol) {
312: Declaration decl = new Declaration(bindings);
313: decl.setType(Compilation.scmListType);
314: decl.noteValue(null); // Does not have a known value.
315: addParam(decl, templateScopeRest, lexp, tr);
316: }
317: }
318:
319: private static void addParam(Declaration decl,
320: ScopeExp templateScope, LambdaExp lexp, Translator tr) {
321: if (templateScope != null)
322: decl = tr.makeRenamedAlias(decl, templateScope);
323: lexp.addDeclaration(decl);
324: if (templateScope != null)
325: decl.context = templateScope;
326: }
327:
328: public Object rewriteAttrs(LambdaExp lexp, Object body,
329: Translator tr) {
330: String accessFlagName = null;
331: String allocationFlagName = null;
332: int accessFlag = 0;
333: int allocationFlag = 0;
334: SyntaxForm syntax = null;
335: for (;;) {
336: while (body instanceof SyntaxForm) {
337: syntax = (SyntaxForm) body;
338: body = syntax.form;
339: }
340: if (!(body instanceof Pair))
341: break;
342: Pair pair1 = (Pair) body;
343: Object attrName = Translator.stripSyntax(pair1.car);
344: Object pair1_cdr = pair1.cdr;
345: while (pair1_cdr instanceof SyntaxForm) {
346: syntax = (SyntaxForm) pair1_cdr;
347: pair1_cdr = syntax.form;
348: }
349: if (!(pair1_cdr instanceof Pair))
350: break;
351: Pair pair2 = (Pair) pair1_cdr;
352:
353: Object attrValue;
354: if (tr.matches(attrName, "::"))
355: attrName = null;
356: else if (!(attrName instanceof Keyword))
357: break;
358: if (attrName == null) {
359: Expression attrExpr = tr.rewrite_car(pair2, syntax);
360: if (lexp.isClassMethod()
361: && "*init*".equals(lexp.getName()))
362: tr.error('e',
363: "explicit return type for '*init*' method");
364: else {
365: gnu.bytecode.Type rtype = tr.getLanguage()
366: .getTypeFor(attrExpr);
367: if (rtype != null)
368: lexp.setReturnType(rtype);
369: }
370: } else if (attrName == kawa.standard.object.accessKeyword) {
371: Expression attrExpr = tr.rewrite_car(pair2, syntax);
372: if (!(attrExpr instanceof QuoteExp)
373: || !((attrValue = ((QuoteExp) attrExpr)
374: .getValue()) instanceof String || attrValue instanceof FString))
375: tr
376: .error('e',
377: "access: value not a constant symbol or string");
378: else if (lexp.nameDecl == null)
379: tr
380: .error('e',
381: "access: not allowed for anonymous function");
382: else {
383: String value = attrValue.toString();
384: if ("private".equals(value))
385: accessFlag = Declaration.PRIVATE_ACCESS;
386: else if ("protected".equals(value))
387: accessFlag = Declaration.PROTECTED_ACCESS;
388: else if ("public".equals(value))
389: accessFlag = Declaration.PUBLIC_ACCESS;
390: else if ("package".equals(value))
391: accessFlag = Declaration.PACKAGE_ACCESS;
392: else
393: tr.error('e', "unknown access specifier");
394: if (accessFlagName != null && value != null) {
395: tr.error('e', "duplicate access specifiers - "
396: + accessFlagName + " and " + value);
397: }
398: accessFlagName = value;
399: }
400: } else if (attrName == kawa.standard.object.allocationKeyword) {
401: Expression attrExpr = tr.rewrite_car(pair2, syntax);
402: if (!(attrExpr instanceof QuoteExp)
403: || !((attrValue = ((QuoteExp) attrExpr)
404: .getValue()) instanceof String || attrValue instanceof FString))
405: tr
406: .error('e',
407: "allocation: value not a constant symbol or string");
408: else if (lexp.nameDecl == null)
409: tr
410: .error('e',
411: "allocation: not allowed for anonymous function");
412: else {
413: String value = attrValue.toString();
414: if ("class".equals(value) || "static".equals(value))
415: allocationFlag = Declaration.STATIC_SPECIFIED;
416: else if ("instance".equals(value))
417: allocationFlag = Declaration.NONSTATIC_SPECIFIED;
418: else
419: tr.error('e', "unknown allocation specifier");
420: if (allocationFlagName != null && value != null) {
421: tr.error('e',
422: "duplicate allocation specifiers - "
423: + allocationFlagName + " and "
424: + value);
425: }
426: allocationFlagName = value;
427: }
428: } else if (attrName == kawa.standard.object.throwsKeyword) {
429: attrValue = pair2.car;
430: int count = Translator.listLength(attrValue);
431: if (count < 0)
432: tr.error('e', "throws: not followed by a list");
433: else {
434: ReferenceExp[] exps = new ReferenceExp[count];
435: SyntaxForm syntaxLocal = syntax;
436: for (int i = 0; i < count; i++) {
437: while (attrValue instanceof SyntaxForm) {
438: syntaxLocal = (SyntaxForm) attrValue;
439: attrValue = syntaxLocal.form;
440: }
441: Pair pair3 = (Pair) attrValue;
442: Expression throwsExpr = tr.rewrite_car(pair3,
443: syntaxLocal);
444: if (throwsExpr instanceof ReferenceExp) {
445: exps[i] = (ReferenceExp) throwsExpr;
446: } else {
447: Object savePos = tr.pushPositionOf(pair3);
448: tr
449: .error('e',
450: "throws not followed by a classname");
451: tr.popPositionOf(savePos);
452: }
453: attrValue = pair3.cdr;
454: }
455: lexp.setExceptions(exps);
456: }
457: } else if (attrName == nameKeyword) {
458: Expression attrExpr = tr.rewrite_car(pair2, syntax);
459: if (attrExpr instanceof QuoteExp)
460: lexp.setName(((QuoteExp) attrExpr).getValue()
461: .toString());
462: } else {
463: tr.error('w', "unknown procedure property " + attrName);
464: }
465: body = pair2.cdr;
466: }
467: accessFlag |= allocationFlag;
468: if (accessFlag != 0)
469: lexp.nameDecl.setFlag(accessFlag);
470: if (syntax != null)
471: body = syntax.fromDatumIfNeeded(body);
472: return body;
473: }
474:
475: public Object skipAttrs(LambdaExp lexp, Object body, Translator tr) {
476: while (body instanceof Pair) {
477: Pair pair = (Pair) body;
478: if (!(pair.cdr instanceof Pair))
479: break;
480: Object attrName = pair.car;
481: if (tr.matches(attrName, "::"))
482: attrName = null;
483: else if (!(attrName instanceof Keyword))
484: break;
485: body = ((Pair) pair.cdr).cdr;
486: }
487: return body;
488: }
489:
490: public void rewriteBody(LambdaExp lexp, Object body, Translator tr) {
491: int numRenamedAlias = 0;
492: // We view a top-level named function as a method, in the sense that the
493: // form (this) is allowed, if the supertype is explicitly specified.
494: if (tr.curMethodLambda == null
495: && lexp.nameDecl != null
496: && tr.getModule()
497: .getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
498: tr.curMethodLambda = lexp;
499: tr.pushScope(lexp);
500: Declaration prev = null;
501: int key_args = lexp.keywords == null ? 0 : lexp.keywords.length;
502: int opt_args = lexp.defaultArgs == null ? 0
503: : lexp.defaultArgs.length - key_args;
504: int arg_i = 0;
505: int opt_i = 0;
506: for (Declaration cur = lexp.firstDecl(); cur != null; cur = cur
507: .nextDecl()) {
508: if (cur.isAlias()) {
509: Declaration param = Translator.getOriginalRef(cur)
510: .getBinding();
511: lexp.replaceFollowing(prev, param);
512: param.context = lexp;
513: tr.pushRenamedAlias(cur);
514: numRenamedAlias++;
515: cur = param;
516: }
517: prev = cur;
518:
519: if (arg_i >= lexp.min_args
520: && (arg_i < lexp.min_args + opt_args
521: || lexp.max_args >= 0 || arg_i != lexp.min_args
522: + opt_args)) {
523: lexp.defaultArgs[opt_i] = tr
524: .rewrite(lexp.defaultArgs[opt_i]);
525: opt_i++;
526: }
527: arg_i++;
528:
529: tr.lexical.push(cur);
530: }
531:
532: if (lexp.isClassMethod()
533: && !lexp.nameDecl.getFlag(Declaration.STATIC_SPECIFIED)) {
534: // We set the type of this in ClassExp.walkChildren.
535: lexp.add(null, new Declaration(ThisExp.THIS_NAME));
536: }
537:
538: LambdaExp saveLambda = tr.curLambda;
539: tr.curLambda = lexp;
540: lexp.body = tr.rewrite_body(body);
541: tr.curLambda = saveLambda;
542: Expression[] exps;
543: int len;
544: if (lexp.body instanceof BeginExp
545: && (len = (exps = ((BeginExp) lexp.body)
546: .getExpressions()).length) > 1
547: && exps[0] instanceof ReferenceExp) {
548: // Handle '<TYPENAME> BODY':
549: Expression rexp = exps[0];
550: len--;
551: if (len == 1)
552: lexp.body = exps[1];
553: else {
554: Expression[] new_body = new Expression[len];
555: System.arraycopy(exps, 1, new_body, 0, len);
556: lexp.body = new BeginExp(new_body);
557: }
558: Convert.setCoercedReturnValue(lexp, rexp, tr.getLanguage());
559: } else if (lexp.returnType != null
560: && lexp.returnType != Type.pointer_type
561: && lexp.returnType != Type.void_type) {
562: Expression value = lexp.body;
563: lexp.body = Convert.makeCoercion(value, lexp.returnType);
564: lexp.body.setLine(value);
565: }
566: tr.pop(lexp);
567: lexp.countDecls();
568: tr.popRenamedAlias(numRenamedAlias);
569: lexp.countDecls();
570: if (tr.curMethodLambda == lexp)
571: tr.curMethodLambda = null;
572: }
573:
574: public void print(Consumer out) {
575: out.write("#<builtin lambda>");
576: }
577: }
|