001: /*
002: * $Id: FunctionStatement.java,v 1.18 2002/09/16 08:05:06 jkl Exp $
003: *
004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
005: *
006: * Use is subject to license terms, as defined in
007: * Anvil Sofware License, Version 1.1. See LICENSE
008: * file, or http://njet.org/license-1.1.txt
009: */
010: package anvil.script.statements;
011:
012: import anvil.core.Any;
013: import anvil.core.AnyClass;
014: import anvil.core.AnyTuple;
015: import anvil.codec.ExceptionHandler;
016: import anvil.codec.ClassRoom;
017: import anvil.codec.Field;
018: import anvil.codec.Method;
019: import anvil.codec.Code;
020: import anvil.codec.CodecConstants;
021: import anvil.codec.ConstantPool;
022: import anvil.codec.Target;
023: import anvil.codec.Source;
024: import anvil.codec.Switch;
025: import anvil.Location;
026: import anvil.doc.DocParser;
027: import anvil.doc.Doc;
028: import anvil.parser.Tag;
029: import anvil.ErrorListener;
030: import anvil.script.CompilableFunction;
031: import anvil.script.compiler.ByteCompiler;
032: import anvil.script.Context;
033: import anvil.script.Type;
034: import anvil.script.FunctionDispatcher;
035: import anvil.script.expression.Node;
036: import anvil.script.expression.Expression;
037: import anvil.script.expression.VariableNode;
038: import anvil.script.expression.ConstantNode;
039: import anvil.script.ParameterListDeclaration;
040: import anvil.script.parser.ExpressionParser;
041: import anvil.script.parser.TemplateParser;
042: import anvil.script.Module;
043: import anvil.script.StackFrame;
044: import anvil.script.Grammar;
045: import anvil.java.util.Hashlist;
046: import java.io.IOException;
047: import java.util.Enumeration;
048:
049: /**
050: * class FunctionStatement
051: *
052: * @author: Jani Lehtimäki
053: */
054: public class FunctionStatement extends DefinitionStatement implements
055: CompilableFunction, CodecConstants {
056:
057: protected FunctionStatement _context;
058: protected boolean _synchronized = false;
059: protected ParameterListDeclaration _parameters = null;
060: protected BlockStatement _block;
061: protected ExceptionHandler _handler;
062: protected Switch _switch;
063: protected boolean _escaped = false;
064: protected int _localcount = 0;
065: protected int _yieldcount = 0;
066: protected String _signature;
067: protected int _local_frame;
068: protected VariableNode _return_var = null;
069:
070: public FunctionStatement(DefinitionStatement parent,
071: Location location) {
072: super (parent, location);
073: _block = new ImplicitBlockStatement(this , location);
074: }
075:
076: public FunctionStatement(Location location,
077: DefinitionStatement parent, FunctionStatement context,
078: boolean sync, String name, String document,
079: ParameterListDeclaration parameters) {
080: super (parent, location, (context != null) ? context.getName()
081: + '$' + name : name, DocParser.parseFunction(name,
082: document));
083: _context = context;
084: _synchronized = sync;
085: _parameters = parameters;
086: _parameters.declareTo(this );
087: _parameters.importDocuments(_document);
088: _block = new ImplicitBlockStatement(this , location);
089: }
090:
091: public String toString() {
092: StringBuffer buffer = new StringBuffer(40);
093: buffer.append(super .toString());
094: buffer.append('(');
095: if (_parameters != null) {
096: _parameters.toString(buffer);
097: } else {
098: buffer.append("<unparsed>");
099: }
100: buffer.append(')');
101: return buffer.toString();
102: }
103:
104: public int typeOf() {
105: return Statement.ST_FUNCTION;
106: }
107:
108: public int getNextLocalSlot() {
109: return _localcount++;
110: }
111:
112: public Type lookupDeclaration(String name) {
113: Type type = (Type) _types.get(name);
114: if (type == null) {
115: if (_context != null) {
116: type = _context.lookupDeclaration(name);
117: }
118: if (type == null) {
119: return super .lookupDeclaration(name);
120: }
121: }
122: return type;
123: }
124:
125: public LocalVariableStatement declare(String name) {
126: LocalVariableStatement var = new LocalVariableStatement(
127: getLocation(), this , name);
128: declare(var);
129: return var;
130: }
131:
132: public ParameterStatement declareParameter(String name) {
133: ParameterStatement param = new ParameterStatement(
134: getLocation(), this , name);
135: declare(param);
136: return param;
137: }
138:
139: public boolean isStaticRegion() {
140: return true;
141: }
142:
143: public boolean isInnerFunction() {
144: return _context != null;
145: }
146:
147: public void parse(TemplateParser parser, Tag tag) {
148: super .parse(parser, tag);
149: String name = tag.getValue("name");
150: if (name != null) {
151: name = name.trim();
152: if (!Grammar.isValidIdentifier(name)) {
153: parser.error(getLocation(), "invalid function name: '"
154: + name + "'");
155: } else {
156: _name = name;
157: }
158: _document = DocParser.parseFunction(_name, parser
159: .getDocument());
160: } else {
161: parser.error(getLocation(),
162: "function attribute 'name' not given");
163: }
164: _synchronized = tag.contains("synchronized");
165: _parameters = parseParameters(parser, tag);
166: _parameters.declareTo(this );
167: }
168:
169: public boolean onTag(TemplateParser parser, int type, Tag tag) {
170: switch (type) {
171: case ST_ENDFUNCTION:
172: parser.pop();
173: return true;
174:
175: default:
176: return super .onTag(parser, type, tag);
177: }
178:
179: }
180:
181: public ParameterListDeclaration parseParameters(
182: TemplateParser parser, Tag tag) {
183: ParameterListDeclaration parameters = new ParameterListDeclaration();
184: String params = tag.getValue("params");
185: if (params != null) {
186: ExpressionParser p = new ExpressionParser(parser, parser
187: .getLocation(), params);
188: p.parseParameterListDeclaration(parameters);
189:
190: } else {
191: parameters.open();
192: int n = tag.getLength();
193: for (int i = 0; i < n; i++) {
194: String name = tag.getName(i);
195: if (name.equalsIgnoreCase("param")) {
196:
197: String param = tag.getValue(i);
198: Expression defaultexpr = null;
199:
200: if ((i < n - 1)
201: && tag.getName(i + 1).equalsIgnoreCase(
202: "default")) {
203: String def = tag.getValue(i + 1);
204: defaultexpr = Grammar.parseExpression(def,
205: getLocation(), parser);
206: i++;
207: } else {
208: if (parameters.hasDefaultValues()) {
209: parser
210: .error(getLocation(),
211: "Parameters with default values must appear last");
212: defaultexpr = null;
213: }
214: }
215:
216: if (Grammar.isValidIdentifier(param)) {
217: if (parameters.isDeclared(param)) {
218: parser.error(getLocation(), "Entity '"
219: + param + "' is already declared");
220: } else {
221: parameters.add(param, defaultexpr);
222: }
223: } else {
224: parser.error(getLocation(), "Parameter name '"
225: + param + "' is invalid");
226: }
227:
228: }
229: }
230:
231: String rest = tag.getValue("rest");
232: if (rest != null) {
233: rest = rest.trim();
234: if (!Grammar.isValidIdentifier(rest)) {
235: parser.error(getLocation(), "Parameter '" + rest
236: + "' is invalid");
237: } else {
238: if (parameters.isDeclared(rest)) {
239: parser.error(getLocation(), "Entity '" + rest
240: + "' is already declared");
241: } else {
242: parameters.add(PARAMETER_REST, rest,
243: Any.EMPTY_TUPLE, null);
244: }
245: }
246: }
247: parameters.close();
248: }
249:
250: return parameters;
251: }
252:
253: public void check(ErrorListener context) {
254: _parameters.check(context);
255: _block.check(context);
256: _block.eliminate(context);
257: }
258:
259: public void markEscaped() {
260: _escaped = true;
261: }
262:
263: public boolean isEscaped() {
264: return _escaped;
265: }
266:
267: public int addYieldState() {
268: return ++_yieldcount;
269: }
270:
271: public boolean isGenerator() {
272: return _yieldcount > 0;
273: }
274:
275: public String name() {
276: return "function";
277: }
278:
279: public String getName() {
280: return _name;
281: }
282:
283: public String getDescriptor() {
284: return "f_" + _name;
285: }
286:
287: public int getType() {
288: return FUNCTION;
289: }
290:
291: public FunctionStatement getContext() {
292: return _context;
293: }
294:
295: public Doc getDocument() {
296: return _document;
297: }
298:
299: public Statement getChildStatement() {
300: return _block;
301: }
302:
303: public int getMinimumParameterCount() {
304: return _parameters.minSize();
305: }
306:
307: public int getParameterCount() {
308: return _parameters.size();
309: }
310:
311: public String getParameterName(int index) {
312: return _parameters.getName(index);
313: }
314:
315: public int getParameterType(int index) {
316: return _parameters.getType(index);
317: }
318:
319: public Any getParameterDefault(int index) {
320: return _parameters.getDefault(index);
321: }
322:
323: public Doc getParameterDoc(int index) {
324: return _parameters.getDoc(index);
325: }
326:
327: public Any getAttribute(String name) {
328: return null;
329: }
330:
331: public FunctionDispatcher getDispatcher(Context context) {
332: return null;
333: }
334:
335: public Any execute(Context context, Any[] parameters) {
336: return execute(context, null, parameters);
337: }
338:
339: public Any execute(Context context, Any self, Any[] parameters) {
340: return null;
341: }
342:
343: public Any execute(Context context, Any self) {
344: return null;
345: }
346:
347: public Any execute(Context context, Any self, Any param1) {
348: return null;
349: }
350:
351: public Any execute(Context context, Any self, Any param1, Any param2) {
352: return null;
353: }
354:
355: public Any execute(Context context, Any self, Any param1,
356: Any param2, Any param3) {
357: return null;
358: }
359:
360: public Any execute(Context context, Any self, Any param1,
361: Any param2, Any param3, Any param4) {
362: return null;
363: }
364:
365: public int getFrameIndex() {
366: return _local_frame;
367: }
368:
369: public String getSignature() {
370: if (_signature == null) {
371: StringBuffer buffer = new StringBuffer();
372: buffer.append('(');
373: buffer.append("Lanvil/script/Context;");
374: int n = _parameters.size();
375: for (int i = 1; i < n; i++) {
376: buffer.append("Lanvil/core/Any;");
377: }
378: buffer.append(")Lanvil/core/Any;");
379: _signature = buffer.toString();
380: }
381: return _signature;
382: }
383:
384: public void compileDescriptor(ByteCompiler context) {
385: _parameters.compileDescriptor(context);
386: }
387:
388: public void compile(ByteCompiler context) {
389: ClassRoom clazz = context.getClassRoom();
390: Field typefield = clazz.createField("f_" + _name,
391: "Lanvil/script/Function;", ACC_PUBLIC | ACC_STATIC);
392: clazz.createField("F_" + _name, "Lanvil/core/Any;", ACC_PUBLIC
393: | ACC_STATIC);
394: Method method = clazz.createMethod("f_" + _name,
395: getSignature(), ACC_PUBLIC | ACC_FINAL | ACC_STATIC
396: | (_synchronized ? ACC_SYNCHRONIZED : 0));
397: compileBody(context, method, typefield);
398: }
399:
400: public void compileBody(ByteCompiler context, Method method, Field typefield)
401: {
402: ClassRoom clazz = context.getClassRoom();
403: ConstantPool pool = clazz.getPool();
404: Code code = method.getCode();
405: boolean is_method = (getType() != FUNCTION);
406: boolean is_generator = (_yieldcount > 0);
407:
408: context.pushCode(code);
409: int l_context = code.addLocal();
410:
411: Enumeration enum = _types.elements();
412: while(enum.hasMoreElements()) {
413: Object obj = enum.nextElement();
414: if (obj instanceof ParameterStatement) {
415: ((ParameterStatement)obj).compileInit(context);
416: }
417: }
418:
419: if (is_generator) {
420: enum = _types.elements();
421: while(enum.hasMoreElements()) {
422: Object obj = enum.nextElement();
423: if (obj instanceof LocalVariableStatement) {
424: ((LocalVariableStatement)obj).markEscaped();
425: }
426: }
427:
428: int generatorclazz = pool.addClass("anvil/script/Generator");
429: _local_frame = code.addLocal();
430: code.anew(generatorclazz);
431: code.dup();
432: code.aload_first();
433: code.getstatic(pool.addFieldRef(context.TYPE_MODULE, "_module", "Lanvil/script/compiler/CompiledModule;"));
434: if (is_method) {
435: code.self();
436: } else {
437: code.aconst_null();
438: }
439: code.getstatic(typefield);
440: code.iconst(_localcount);
441: code.iconst(getLocation().getLine());
442: code.invokespecial(pool.addMethodRef(generatorclazz, "<init>",
443: "(Lanvil/script/Context;Lanvil/script/Module;Lanvil/core/AnyClass;Lanvil/script/Function;II)V"));
444: code.astore(_local_frame);
445: enum = _types.elements();
446:
447: enum = _types.elements();
448: while(enum.hasMoreElements()) {
449: Object obj = enum.nextElement();
450: if (obj instanceof LocalVariableStatement) {
451: ((LocalVariableStatement)obj).compile(context);
452: }
453: }
454:
455: code.aload(_local_frame);
456: code.invokevirtual(pool.addMethodRef(generatorclazz, "getWrapper", "()Lanvil/core/Any;"));
457: code.areturn();
458: context.popCode();
459:
460: Method method2;
461: if (is_method) {
462: method2 = clazz.createMethod("h_"+_name, "(Lanvil/script/Context;Lanvil/script/Generator;)Lanvil/core/Any;", ACC_PUBLIC|(_synchronized?ACC_SYNCHRONIZED:0));
463: } else {
464: method2 = clazz.createMethod("h_"+_name, "(Lanvil/script/Context;Lanvil/script/Generator;)Lanvil/core/Any;", ACC_PUBLIC|ACC_FINAL|ACC_STATIC|(_synchronized?ACC_SYNCHRONIZED:0));
465: }
466: code = method2.getCode();
467: code.addLocal();
468: _local_frame = code.addLocal();
469: code.addLocals(2);
470: context.pushCode(code);
471:
472: code.aload(_local_frame);
473: code.invokevirtual(pool.addMethodRef("anvil/script/Generator", "getState", "()I"));
474: _switch = code.select();
475: for(int i=0; i<=_yieldcount; i++) {
476: _switch.addCase(i);
477: }
478: _switch.end();
479: _switch.bindCase(0);
480: _block.compile(context);
481: _switch.bindDefault();
482: code.aload(_local_frame);
483: code.invokevirtual(pool.addMethodRef("anvil/script/Generator", "setClosedState", "()V"));
484: code.getstatic(pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;"));
485: code.areturn();
486:
487: } else {
488:
489: _local_frame = code.addLocal();
490:
491: _return_var = new VariableNode(declare("return$"+hashCode()));
492: //_return_var.compile(context, ConstantNode.UNDEFINED);
493: //code.pop();
494:
495: code.aload(l_context);
496: code.getstatic(pool.addFieldRef(context.TYPE_MODULE, "_module", "Lanvil/script/compiler/CompiledModule;"));
497: if (is_method) {
498: code.self();
499: }
500: code.getstatic(typefield);
501: code.iconst(_escaped ? _localcount : 0);
502: code.iconst(getLocation().getLine());
503: code.iconst(_escaped);
504: code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "push",
505: is_method ?
506: "(Lanvil/script/Module;Lanvil/core/AnyClass;Lanvil/script/Function;IIZ)Lanvil/script/StackFrame;" :
507: "(Lanvil/script/Module;Lanvil/script/Function;IIZ)Lanvil/script/StackFrame;"
508: ));
509: code.astore(_local_frame);
510:
511: ExceptionHandler handler = code.startExceptionHandler(true);
512: _handler = handler;
513: {
514: enum = _types.elements();
515: while(enum.hasMoreElements()) {
516: Object obj = enum.nextElement();
517: if (obj instanceof LocalVariableStatement) {
518: ((LocalVariableStatement)obj).compile(context);
519: }
520: }
521:
522: _block.compile(context);
523: handler.callFinally();
524: if (getType() == CONSTRUCTOR) {
525: code.self();
526: } else {
527: _return_var.compile(context, Node.GET);
528: //code.aload(_return_var);
529: //code.getstatic(pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;"));
530: }
531: code.areturn();
532: }
533: handler.endTry();
534: handler.endProtectedRegion();
535:
536: handler.startCatch(0);
537: {
538: int l_thrown = code.addLocal();
539: code.astore(l_thrown);
540: handler.callFinally();
541: code.aload(l_thrown);
542: code.athrow();
543: }
544: handler.endCatches();
545:
546: handler.startFinally();
547: {
548: int l_ret = code.addLocal();
549: code.astore(l_ret);
550: code.aload(l_context);
551: code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "pop", "()V"));
552: code.ret(l_ret);
553: }
554: handler.endFinally();
555: handler.end();
556: }
557:
558: context.popCode();
559: }
560:
561: public int getTypeRef(ConstantPool pool) {
562: return pool.addMethodRef(_parent.getTypeRef(pool),
563: getDescriptor(), getSignature());
564: }
565:
566: public void bindYieldState(int state) {
567: if (_switch != null) {
568: _switch.bindCase(state);
569: }
570: }
571:
572: public boolean callFinalizer() {
573: if (_handler != null) {
574: _handler.callFinally();
575: }
576: return false;
577: }
578:
579: public VariableNode getReturnVariable() {
580: return _return_var;
581: }
582:
583: }
|