001: package kawa.standard;
002:
003: import gnu.expr.*;
004: import kawa.lang.*;
005: import gnu.lists.*;
006: import java.util.Vector;
007: import gnu.mapping.Symbol;
008: import gnu.bytecode.Type;
009: import gnu.kawa.functions.Convert;
010:
011: public class object extends Syntax {
012: public static final object objectSyntax = new kawa.standard.object(
013: Scheme.lambda);
014: static {
015: objectSyntax.setName("object");
016: }
017:
018: Lambda lambda;
019: public static final Keyword accessKeyword = Keyword.make("access");
020: public static final Keyword throwsKeyword = Keyword.make("throws");
021: static final Keyword typeKeyword = Keyword.make("type");
022: public static final Keyword allocationKeyword = Keyword
023: .make("allocation");
024: static final Keyword initKeyword = Keyword.make("init");
025: static final Keyword initformKeyword = Keyword.make("initform");
026: static final Keyword init_formKeyword = Keyword.make("init-form");
027: static final Keyword init_valueKeyword = Keyword.make("init-value");
028: static final Keyword init_keywordKeyword = Keyword
029: .make("init-keyword");
030:
031: public object(Lambda lambda) {
032: this .lambda = lambda;
033: }
034:
035: public Expression rewriteForm(Pair form, Translator tr) {
036: if (!(form.cdr instanceof Pair))
037: return tr
038: .syntaxError("missing superclass specification in object");
039: Pair pair = (Pair) form.cdr;
040: ObjectExp oexp = new ObjectExp();
041: if (pair.car instanceof FString) {
042: // oexp.setName(pair.car.toString());
043: if (!(pair.cdr instanceof Pair))
044: return tr
045: .syntaxError("missing superclass specification after object class name");
046: pair = (Pair) pair.cdr;
047: }
048: Object[] saved = scanClassDef(pair, oexp, tr);
049: if (saved != null)
050: rewriteClassDef(saved, tr);
051: return oexp;
052: }
053:
054: /** Does the first "scan-time" processing of the class/object definition.
055: * Returns an array of values to be used at "rewrite-time".
056: */
057: public Object[] scanClassDef(Pair pair, ClassExp oexp, Translator tr) {
058: tr.mustCompileHere();
059: Object super list = pair.car;
060: Object components = pair.cdr;
061: LambdaExp method_list = null;
062: LambdaExp last_method = null;
063: // First pass (get Declarations).
064: Vector inits = new Vector(20);
065: for (Object obj = components; obj != LList.Empty;) {
066: // The SyntaxForm scopes aren't used in scanClassDef, but they are
067: // used in rewriteClassDef, and might as well make the code the same.
068: while (obj instanceof SyntaxForm)
069: obj = ((SyntaxForm) obj).form;
070: if (!(obj instanceof Pair)) {
071: tr.error('e', "object member not a list");
072: return null;
073: }
074: pair = (Pair) obj;
075: Object pair_car = pair.car;
076: while (pair_car instanceof SyntaxForm)
077: pair_car = ((SyntaxForm) pair_car).form;
078: if (!(pair_car instanceof Pair)) {
079: tr.error('e', "object member not a list");
080: return null;
081: }
082: obj = pair.cdr; // Next member.
083: Object savedPos1 = tr.pushPositionOf(pair);
084: pair = (Pair) pair_car;
085: pair_car = pair.car;
086: while (pair_car instanceof SyntaxForm)
087: pair_car = ((SyntaxForm) pair_car).form;
088: if (pair_car instanceof String
089: || pair_car instanceof Symbol
090: || pair_car instanceof Keyword) { // Field declaration.
091: Pair typePair = null;
092: Object sname = pair_car;
093: Object args;
094: Declaration decl;
095: int allocationFlag = 0;
096: String accessFlagName = null;
097: int accessFlag = 0;
098: if (sname instanceof Keyword) {
099: decl = null;
100: args = pair;
101: } else {
102: decl = oexp.addDeclaration(sname);
103: decl.setSimple(false);
104: decl.setFlag(Declaration.FIELD_OR_METHOD);
105: Translator.setLine(decl, pair);
106: args = pair.cdr;
107: }
108: int nKeywords = 0;
109: boolean seenInit = false;
110: Pair initPair = null;
111: while (args != LList.Empty) {
112: while (args instanceof SyntaxForm)
113: args = ((SyntaxForm) args).form;
114: pair = (Pair) args;
115: Pair keyPair = pair;
116: Object key = pair.car;
117: while (key instanceof SyntaxForm)
118: key = ((SyntaxForm) key).form;
119: Object savedPos2 = tr.pushPositionOf(pair);
120: args = pair.cdr;
121: if ((key == "::" || key instanceof Keyword)
122: && args instanceof Pair) {
123: nKeywords++;
124: pair = (Pair) args;
125: Object value = pair.car;
126: args = pair.cdr;
127: if (key == "::" || key == typeKeyword)
128: typePair = pair;
129: else if (key == allocationKeyword) {
130: if (allocationFlag != 0)
131: tr
132: .error('e',
133: "duplicate allocation: specification");
134: if (matches(value, "class", tr)
135: || matches(value, "static", tr))
136: allocationFlag = Declaration.STATIC_SPECIFIED;
137: else if (matches(value, "instance", tr))
138: allocationFlag = Declaration.NONSTATIC_SPECIFIED;
139: else
140: tr.error('e',
141: "unknown allocation kind '"
142: + value + "'");
143: } else if (key == initKeyword
144: || key == initformKeyword
145: || key == init_formKeyword
146: || key == init_valueKeyword) {
147: if (seenInit)
148: tr.error('e',
149: "duplicate initialization");
150: seenInit = true;
151: // In the case of 'init-form: EXPR' the scope of EXPR
152: // doesn't include this class;
153: // in the case of 'init: EXPR' it does.
154: if (key != initKeyword)
155: initPair = pair;
156: } else if (key == init_keywordKeyword) {
157: if (!(value instanceof Keyword))
158: tr
159: .error('e',
160: "invalid 'init-keyword' - not a keyword");
161: else if (((Keyword) value).getName() != sname
162: .toString())
163: tr.error('w',
164: "init-keyword option ignored");
165: } else if (key == accessKeyword) {
166: String newAccessFlag = null;
167: if (matches(value, "private", tr)) {
168: newAccessFlag = "private";
169: accessFlag = Declaration.PRIVATE_ACCESS;
170: } else if (matches(value, "protected", tr)) {
171: newAccessFlag = "protected";
172: accessFlag = Declaration.PROTECTED_ACCESS;
173: } else if (matches(value, "public", tr)) {
174: newAccessFlag = "public";
175: accessFlag = Declaration.PUBLIC_ACCESS;
176: } else if (matches(value, "package", tr)) {
177: newAccessFlag = "package";
178: accessFlag = Declaration.PACKAGE_ACCESS;
179: } else {
180: tr.error('e',
181: "unknown access specifier");
182: }
183: if (accessFlagName != null
184: && newAccessFlag != null) {
185: tr.error('e',
186: "duplicate access specifiers - "
187: + accessFlagName
188: + " and "
189: + newAccessFlag);
190: }
191: accessFlagName = newAccessFlag;
192: } else {
193: tr.error('w', "unknown slot keyword '"
194: + key + "'");
195: }
196: } else if (args == LList.Empty && !seenInit) {
197: // CLtL:2 explicitly prohibits this as an extension.
198: initPair = keyPair;
199: seenInit = true;
200: } else if (args instanceof Pair && nKeywords == 0
201: && !seenInit && typePair == null
202: && (pair = (Pair) args).cdr == LList.Empty) {
203: // Backward compatibility.
204: typePair = keyPair;
205: initPair = pair;
206: args = pair.cdr;
207: seenInit = true;
208: } else {
209: args = null; // Trigger error message
210: break;
211: }
212: tr.popPositionOf(savedPos2);
213: }
214: if (args != LList.Empty) {
215: tr.error('e', "invalid argument list for slot '"
216: + sname
217: + '\''
218: + " args:"
219: + (args == null ? "null" : args.getClass()
220: .getName()));
221: return null;
222: }
223: if (seenInit) {
224: boolean isStatic = allocationFlag == Declaration.STATIC_SPECIFIED;
225: inits.addElement(decl != null ? (Object) decl
226: : isStatic ? Boolean.TRUE : Boolean.FALSE);
227: inits.addElement(initPair);
228: }
229: if (decl == null) {
230: if (!seenInit) {
231: tr.error('e', "missing field name");
232: return null;
233: }
234: } else {
235: if (typePair != null)
236: decl.setType(tr.exp2Type(typePair));
237: if (allocationFlag != 0)
238: decl.setFlag(allocationFlag);
239: if (accessFlag != 0)
240: decl.setFlag(accessFlag);
241: decl.setCanRead(true);
242: decl.setCanWrite(true);
243: }
244: } else if (pair_car instanceof Pair) { // Method declaration.
245: Pair mpair = (Pair) pair_car;
246: Object mname = mpair.car;
247: if (!(mname instanceof String)
248: && !(mname instanceof Symbol)) {
249: tr.error('e', "missing method name");
250: return null;
251: }
252: Declaration decl = oexp.addDeclaration(mname,
253: Compilation.typeProcedure);
254: Translator.setLine(decl, mpair);
255: LambdaExp lexp = new LambdaExp();
256: lexp.outer = oexp;
257: lexp.setClassMethod(true);
258: decl.noteValue(lexp);
259: decl.setFlag(Declaration.FIELD_OR_METHOD);
260: decl.setProcedureDecl(true);
261: lexp.setSymbol(mname);
262: if (last_method == null)
263: method_list = lexp;
264: else
265: last_method.nextSibling = lexp;
266: last_method = lexp;
267: } else
268: tr.error('e', "invalid field/method definition");
269: tr.popPositionOf(savedPos1);
270: }
271: Object[] result = { oexp, components, inits, method_list,
272: super list };
273: return result;
274: }
275:
276: public void rewriteClassDef(Object[] saved, Translator tr) {
277: ClassExp oexp = (ClassExp) saved[0];
278: Object components = saved[1];
279: Vector inits = (Vector) saved[2];
280: LambdaExp method_list = (LambdaExp) saved[3];
281: Object super list = saved[4];
282: oexp.firstChild = method_list;
283:
284: int num_super s = Translator.listLength(super list);
285: if (num_super s < 0) {
286: tr.error('e', "object superclass specification not a list");
287: num_super s = 0;
288: }
289: Expression[] super s = new Expression[num_super s];
290: for (int i = 0; i < num_super s; i++) {
291: while (super list instanceof SyntaxForm) {
292: // FIXME - need to pass syntax.
293: super list = ((SyntaxForm) super list).form;
294: }
295: Pair super pair = (Pair) super list;
296: super s[i] = tr.rewrite_car(super pair, false);
297: super list = super pair.cdr;
298: }
299: oexp.super s = super s;
300:
301: oexp.setClassName(tr);
302: oexp.setTypes(tr);
303:
304: // First a pass over init-form: specifiers, since these are evaluated
305: // in a scope outside the current class.
306: int len = inits.size();
307: for (int i = 0; i < len; i += 2) {
308: Object init = inits.elementAt(i + 1);
309: if (init != null)
310: rewriteInit(inits.elementAt(i), oexp, (Pair) init, tr,
311: null);
312: }
313:
314: tr.push(oexp);
315:
316: // Pass to rewrite method/initializer bodies.
317: LambdaExp meth = method_list;
318: int init_index = 0; // Input index in inits Vector.
319: SyntaxForm componentsSyntax = null;
320: for (Object obj = components; obj != LList.Empty;) {
321: while (obj instanceof SyntaxForm) {
322: componentsSyntax = (SyntaxForm) obj;
323: obj = componentsSyntax.form;
324: }
325: Pair pair = (Pair) obj;
326: Object savedPos1 = tr.pushPositionOf(pair);
327: Object pair_car = pair.car;
328: SyntaxForm memberSyntax = componentsSyntax;
329: while (pair_car instanceof SyntaxForm) {
330: memberSyntax = (SyntaxForm) pair_car;
331: pair_car = memberSyntax.form;
332: }
333: try {
334: obj = pair.cdr; // Next member.
335: pair = (Pair) pair_car;
336: pair_car = pair.car;
337: SyntaxForm memberCarSyntax = memberSyntax;
338: while (pair_car instanceof SyntaxForm) {
339: memberCarSyntax = (SyntaxForm) pair_car;
340: pair_car = memberCarSyntax.form;
341: }
342: if (pair_car instanceof String
343: || pair_car instanceof Symbol
344: || pair_car instanceof Keyword) { // Field declaration.
345: Object type = null;
346: int nKeywords = 0;
347: Object args = pair_car instanceof Keyword ? pair
348: : pair.cdr;
349: Pair initPair = null;
350: SyntaxForm initSyntax = null;
351: while (args != LList.Empty) {
352: while (args instanceof SyntaxForm) {
353: memberSyntax = (SyntaxForm) args;
354: args = memberSyntax.form;
355: }
356: pair = (Pair) args;
357: Object key = pair.car;
358: while (key instanceof SyntaxForm)
359: key = ((SyntaxForm) key).form;
360: Object savedPos2 = tr.pushPositionOf(pair);
361: args = pair.cdr;
362: if ((key == "::" || key instanceof Keyword)
363: && args instanceof Pair) {
364: nKeywords++;
365: pair = (Pair) args;
366: Object value = pair.car;
367: args = pair.cdr;
368: if (key == "::" || key == typeKeyword)
369: type = value;
370: else if (key == initKeyword
371: || key == initformKeyword
372: || key == init_formKeyword
373: || key == init_valueKeyword) {
374: initPair = pair;
375: initSyntax = memberSyntax;
376: } else {
377: // handled in first pass.
378: }
379: } else if (args == LList.Empty
380: && initPair == null) {
381: // CLtL:2 explicitly prohibits this as an extension.
382: initPair = pair;
383: initSyntax = memberSyntax;
384: } else if (args instanceof Pair
385: && nKeywords == 0
386: && initPair == null
387: && type == null
388: && (pair = (Pair) args).cdr == LList.Empty) {
389: // Backward compatibility.
390: type = key;
391: initPair = pair;
392: initSyntax = memberSyntax;
393: args = pair.cdr;
394: } else {
395: args = null; // Trigger error message
396: break;
397: }
398: tr.popPositionOf(savedPos2);
399: }
400: if (initPair != null) {
401: Object d = inits.elementAt(init_index++);
402: boolean isStatic = d instanceof Declaration ? ((Declaration) d)
403: .getFlag(Declaration.STATIC_SPECIFIED)
404: : d == Boolean.TRUE;
405: if (inits.elementAt(init_index++) == null)
406: rewriteInit(d, oexp, initPair, tr,
407: initSyntax);
408: }
409: } else if (pair_car instanceof Pair) { // Method declaration.
410: ScopeExp save_scope = tr.currentScope();
411: // If we saw a TemplateScope (in a SyntaxForm) specific to the
412: // formal parameters, pass it to rewrite so it can create a
413: // renamed alias. A TemplateScope that covers the formals
414: // *and* the body we handle using setCurrentScope.
415: if (memberSyntax != null)
416: tr.setCurrentScope(memberSyntax.scope);
417: if ("*init*".equals(meth.getName())) {
418: meth.setReturnType(Type.void_type);
419: if (!oexp.isSimple())
420: tr
421: .error('e',
422: "'*init*' methods only supported for simple classes");
423: }
424: Translator.setLine(meth, pair);
425: LambdaExp saveLambda = tr.curMethodLambda;
426: tr.curMethodLambda = meth;
427: lambda
428: .rewrite(
429: meth,
430: ((Pair) pair_car).cdr,
431: pair.cdr,
432: tr,
433: memberCarSyntax != null
434: && (memberSyntax == null || memberCarSyntax.scope != memberSyntax.scope) ? memberCarSyntax.scope
435: : null);
436: tr.curMethodLambda = saveLambda;
437: if (memberSyntax != null)
438: tr.setCurrentScope(save_scope);
439: meth = meth.nextSibling;
440: } else
441: tr.syntaxError("invalid field/method definition");
442: } finally {
443: tr.popPositionOf(savedPos1);
444: }
445:
446: }
447: // If initMethod/clinitMethod were created by the "outer" (first) call
448: // to rewriteInit, then we may need to fix up their outer chain.
449: if (oexp.initMethod != null)
450: oexp.initMethod.outer = oexp;
451: if (oexp.clinitMethod != null)
452: oexp.clinitMethod.outer = oexp;
453: tr.pop(oexp);
454: oexp.declareParts(tr);
455: }
456:
457: private static void rewriteInit(Object d, ClassExp oexp,
458: Pair initPair, Translator tr, SyntaxForm initSyntax) {
459: boolean isStatic = d instanceof Declaration ? ((Declaration) d)
460: .getFlag(Declaration.STATIC_SPECIFIED)
461: : d == Boolean.TRUE;
462: LambdaExp initMethod = isStatic ? oexp.clinitMethod
463: : oexp.initMethod;
464: if (initMethod == null) {
465: initMethod = new LambdaExp(new BeginExp());
466: initMethod.setClassMethod(true);
467: if (isStatic) {
468: initMethod.setName("$clinit$");
469: oexp.clinitMethod = initMethod;
470: } else {
471: initMethod.setName("$finit$");
472: oexp.initMethod = initMethod;
473: // pseudo-this?? $finit$ is a static method - but (this) is valid.
474: // Is type getting set? FIXME
475: initMethod
476: .add(null, new Declaration(ThisExp.THIS_NAME));
477: }
478: initMethod.nextSibling = oexp.firstChild;
479: oexp.firstChild = initMethod;
480: }
481: tr.push(initMethod);
482: LambdaExp saveLambda = tr.curMethodLambda;
483: tr.curMethodLambda = initMethod;
484: Expression initValue = tr.rewrite_car(initPair, initSyntax);
485: if (d instanceof Declaration) {
486: Declaration decl = (Declaration) d;
487: SetExp sexp = new SetExp(decl, initValue);
488: sexp.setLocation(decl);
489: decl.noteValue(null);
490: initValue = sexp;
491: } else
492: initValue = Convert.makeCoercion(initValue, new QuoteExp(
493: Type.void_type));
494: ((BeginExp) initMethod.body).add(initValue);
495: tr.curMethodLambda = saveLambda;
496: tr.pop(initMethod);
497: }
498:
499: /** True if <code>exp</code> matches <code>tag:</code>, <code>"tag"</code>,
500: * or <code>'tag</code>. The latter is recommended as a matter of style.
501: */
502: static boolean matches(Object exp, String tag, Translator tr) {
503: String value;
504: Pair pair;
505: if (exp instanceof Keyword)
506: value = ((Keyword) exp).getName();
507: else if (exp instanceof FString)
508: value = ((FString) exp).toString();
509: else if (exp instanceof Pair
510: && tr
511: .matches((pair = (Pair) exp).car,
512: Scheme.quote_sym)
513: && pair.cdr instanceof Pair
514: && (pair = (Pair) pair.cdr).cdr == LList.Empty
515: && pair.car instanceof String)
516: value = (String) pair.car;
517: else
518: return false;
519: return tag == null || tag.equals(value);
520: }
521: }
|