001: /* -*- mode: Java; c-basic-offset: 2; -*- */
002:
003: /***
004: * A linked list of TranslationContexts stores information that is used
005: * for break, continue, and return. The TranslationContext is threaded
006: * through calls to the statement visitors, as the context argument.
007: *
008: * There are two views of the context list: the abstract view, which
009: * the abrupt completion code uses, and the concrete view, which is
010: * what's constructed and what's threaded through the statement
011: * visitors. In the abstract view, each item in the list represents an
012: * iteration context (a context for an iteration construct such as for
013: * or do statement), except for the outermost context which either
014: * represents a program or a function; and each context is labelled
015: * with a list of labels. In the concrete view, each context has a
016: * single, optional, label, and there are contexts representing labeled
017: * statements as well. In order to produce the first view from the
018: * second, the accessor methods consider a context to have as labels
019: * all the labels of it labeled statement ancestors as well, up to the
020: * closest ancestor that's not a labeled statement; and a context's
021: * parent is considered to be the closest ancestor that's not a labeled
022: * statement.
023: */package org.openlaszlo.sc;
024:
025: import java.util.*;
026: import org.openlaszlo.sc.parser.*;
027:
028: public class TranslationContext extends HashMap {
029: public static String FLASM = "flasm";
030: public static String VARIABLES = "variables";
031: public static String LOWERVARIABLES = "lowerVariables";
032: public static String REGISTERS = "registers";
033: public static String LOWERREGISTERS = "lowerRegisters";
034:
035: public Object type; // Class or String
036: public TranslationContext parent;
037: public String label;
038: public boolean isEnumeration;
039: public HashMap targets;
040:
041: // properties are stored in this
042:
043: public TranslationContext(Object type, TranslationContext parent) {
044: this (type, parent, null);
045: }
046:
047: public TranslationContext(Object type, TranslationContext parent,
048: String label) {
049: super ();
050: if (ASTFunctionDeclaration.class.equals(type)) {
051: type = ASTFunctionExpression.class;
052: }
053: this .type = type;
054: this .parent = parent;
055: this .label = label;
056: // if isEnumeration is true, this context represents a
057: // "for...in", and unused values need to be popped from the
058: // stack during an abrupt completion
059: this .isEnumeration = false;
060: this .targets = new HashMap();
061: }
062:
063: public Object clone() {
064: TranslationContext copy = (TranslationContext) super .clone();
065: copy.targets = (HashMap) targets.clone();
066: return copy;
067: }
068:
069: public Object get(Object key) {
070: if (containsKey(key)) {
071: return super .get(key);
072: } else if (parent != null) {
073: return parent.get(key);
074: } else {
075: return null;
076: }
077: }
078:
079: // jython compatibility
080: public Object getProperty(Object key) {
081: return get(key);
082: }
083:
084: // jython compatibility
085: public Object setProperty(Object key, Object value) {
086: return put(key, value);
087: }
088:
089: public boolean isFunctionBoundary() {
090: return ASTFunctionExpression.class.equals(type);
091: }
092:
093: public boolean inLabelSet(String label) {
094: for (TranslationContext context = this ; context != null
095: && ASTLabeledStatement.class.equals(context.type); context = context.parent) {
096: if (label == context.label) {
097: return true;
098: }
099: }
100: return false;
101: }
102:
103: public TranslationContext getParentStatement() {
104: TranslationContext context;
105: for (context = parent; context != null
106: && ASTLabeledStatement.class.equals(context.type); context = context.parent) {
107: ;
108: }
109: return context;
110: }
111:
112: // Returns the innermost context labelled with the specified label,
113: // or null.
114: public TranslationContext findLabeledContext(String label) {
115: if (label == null) {
116: return this ;
117: }
118: if (inLabelSet(label)) {
119: return this ;
120: }
121: TranslationContext parent = getParentStatement();
122: if (parent == null || parent.isFunctionBoundary()) {
123: return null;
124: }
125: return parent.findLabeledContext(label);
126: }
127:
128: // Returns the next enclosing function context
129: public TranslationContext findFunctionContext() {
130: if (isFunctionBoundary()) {
131: return this ;
132: }
133: if (parent == null) {
134: return null;
135: }
136: return parent.findFunctionContext();
137: }
138:
139: public void setTarget(Object type, Object instrs) {
140: assert "break".equals(type) || "continue".equals(type);
141: targets.put(type, instrs);
142: }
143:
144: public Object getTarget(Object type) {
145: assert "break".equals(type) || "continue".equals(type);
146: return targets.get(type);
147: }
148:
149: // Emit the code necessary to abruptly leave a context (not
150: // including the jump statement itself).
151: // TODO: [2005-12-13 ptw] CodeGenerator translator -> Translator translator
152: public void emitBreakPreamble(SimpleNode node,
153: CodeGenerator translator) {
154: if (isEnumeration) {
155: translator.unwindEnumeration(node);
156: }
157: }
158: }
|