001: /*
002: * @(#)Generator.java 1.5 05/04/29
003: *
004: * Copyright (c) 2004,2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution of
007: * this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.lang;
010:
011: import org.pnuts.util.Stack;
012: import org.pnuts.lang.GeneratorHelper;
013: import java.util.*;
014:
015: public class Generator {
016: private final static String THIS = "this".intern();
017: private final static String SUPER = "super".intern();
018:
019: Context context;
020:
021: private PnutsFunction gfunc;
022:
023: protected Generator() {
024: }
025:
026: public Generator(PnutsFunction gfunc) {
027: this .gfunc = gfunc;
028: }
029:
030: public Object apply(PnutsFunction closure, Context context) {
031: return gfunc.exec(new Object[] { closure }, context);
032: }
033:
034: public Object[] toArray() {
035: final List elements = new ArrayList();
036: apply(new PnutsFunction() {
037: protected Object exec(Object[] args, Context context) {
038: elements.add(args[0]);
039: return null;
040: }
041: }, context);
042: return elements.toArray();
043: }
044:
045: public String toString() {
046: return "<generator>";
047: }
048:
049: /*
050: * Generator function in AST interpreter
051: */
052: static class GeneratorFunction extends Function {
053:
054: private SimpleNode gnode;
055: private static long ID = 0L;
056:
057: private Context ctx;
058: private String closureSymbol;
059:
060: protected GeneratorFunction(String name, String[] locals,
061: int nargs, SimpleNode node, Package pkg, Context context) {
062: super (name, locals, nargs, false, node, pkg, context);
063: String identity = Long.toHexString(ID++);
064: this .closureSymbol = ("!<closure" + identity + ">")
065: .intern();
066: this .gnode = convertYield(GeneratorHelper.renameLocals(
067: node, identity), closureSymbol);
068: this .ctx = (Context) context.clone(false, false);
069:
070: String[] newLocals = new String[locals.length];
071: for (int i = 0; i < locals.length; i++) {
072: String local = locals[i];
073: if (THIS == local || SUPER == local) {
074: newLocals[i] = local;
075: } else {
076: newLocals[i] = (local + "!" + identity).intern();
077: }
078: }
079: this .locals = newLocals;
080:
081: }
082:
083: protected Object exec(final Object[] args, Context _context) {
084: Generator gen = new Generator();
085: gen.context = _context;
086:
087: final Context context = this .ctx;
088:
089: gen.gfunc = new PnutsFunction() {
090: protected Object exec(Object[] a, Context ctx) {
091: try {
092: PnutsFunction closure = (PnutsFunction) a[0];
093:
094: String[] lc = new String[locals.length + 1];
095: for (int i = 0; i < locals.length; i++) {
096: lc[i] = locals[i];
097: }
098: lc[locals.length] = closureSymbol;
099:
100: context.openLocal(lc);
101: context.bind(closureSymbol, closure);
102: for (int i = 0; i < locals.length; i++) {
103: context.bind(locals[i], args[i]);
104: }
105: return gnode.accept(PnutsInterpreter.instance,
106: context);
107:
108: } catch (Jump j) {
109: return j.getValue();
110: } finally {
111: context.closeLocal();
112: }
113: }
114: };
115: return gen;
116: }
117: }
118:
119: /*
120: * yield <expression>=> CLOSURE( <expression>)
121: */
122: public static SimpleNode convertYield(SimpleNode node,
123: String closureSymbol) {
124: Stack stack = new Stack();
125: return convertYield(node, stack, closureSymbol);
126: }
127:
128: static SimpleNode convertYield(SimpleNode node, Stack stack,
129: String closureSymbol) {
130: if (node.id == PnutsParserTreeConstants.JJTYIELD) {
131: SimpleNode applicationNode = new SimpleNode(
132: PnutsParserTreeConstants.JJTAPPLICATIONNODE);
133: SimpleNode idNode = new SimpleNode(
134: PnutsParserTreeConstants.JJTIDNODE);
135: idNode.str = closureSymbol;
136: applicationNode.jjtAddChild(idNode, 0);
137: idNode.jjtSetParent(applicationNode);
138: SimpleNode argNode = new SimpleNode(
139: PnutsParserTreeConstants.JJTLISTELEMENTS);
140: SimpleNode tmp = convertYield(node.jjtGetChild(0),
141: closureSymbol);
142: argNode.jjtAddChild(tmp, 0);
143: tmp.jjtSetParent(argNode);
144: applicationNode.jjtAddChild(argNode, 1);
145: argNode.jjtSetParent(applicationNode);
146: return applicationNode;
147: } else {
148: stack.push(node);
149: }
150: int n = node.jjtGetNumChildren();
151: for (int i = 0; i < n; i++) {
152: SimpleNode ni = node.jjtGetChild(i);
153: SimpleNode c = convertYield(ni, stack, closureSymbol);
154: node.jjtAddChild(c, i);
155: c.jjtSetParent(node);
156: }
157: return (SimpleNode) stack.pop();
158: }
159:
160: public static class Break extends Escape {
161: public Break(Object value) {
162: super(value);
163: }
164: }
165: }
|