001    package nl.cwi.sen1.tide.adapters;
002    
003    import java.lang.reflect.InvocationTargetException;
004    import java.lang.reflect.Method;
005    import java.util.ArrayList;
006    import java.util.List;
007    
008    import aterm.ATerm;
009    import aterm.ATermAppl;
010    import aterm.ATermFactory;
011    import aterm.ATermInt;
012    import aterm.ATermList;
013    import aterm.ParseError;
014    
015    abstract public class DebugAdapterProcess {
016            private static final int MAXIMUM_METHOD_ARITY = 8;
017            public final static int STATE_STOPPED = 0;
018            public final static int STATE_RUNNING = 1;
019    
020            private Class<?>[][] protos = new Class[MAXIMUM_METHOD_ARITY][];
021            final static int MAX_RULES = 256;
022            public DebugAdapter adapter;
023    
024            static private int processId = 0;
025            private String processName;
026    
027            private boolean debug = true;
028    
029            public DebugAdapterRule[] rules = new DebugAdapterRule[MAX_RULES];
030            public List<DebugAdapterRule>[] rulesPerPort = (List<DebugAdapterRule>[]) new List[DebugAdapterRule.NR_PORT_TYPES];
031            public DebugAdapterRule current_rule = null;
032    
033            int exec_state = STATE_STOPPED;
034            int start_level = 0;
035    
036            private ATermFactory factory;
037    
038            ATerm termTrue;
039            ATerm termFalse;
040            ATerm termRunning;
041            ATerm termStopped;
042            ATerm termUnknown;
043    
044            public String getProcessName() {
045                    return processName;
046            }
047            public DebugAdapterProcess(DebugAdapter adapter, String name) {
048                    this.adapter = adapter;
049                    this.processName = name;
050                    this.factory = adapter.getFactory();
051    
052                    for (int i = 0; i < DebugAdapterRule.NR_PORT_TYPES; i++) {
053                            rulesPerPort[i] = new ArrayList<DebugAdapterRule>();
054                    }
055    
056                    initializeATermClassObjects();
057    
058                    try {
059                            termTrue = factory.parse("true");
060                            termFalse = factory.parse("false");
061                            termRunning = factory.parse("running");
062                            termStopped = factory.parse("stopped");
063                            termUnknown = factory.parse("unknown");
064                    } catch (ParseError e) {
065                            throw new RuntimeException(
066                                    "internal error, malformed term: " + e.getMessage());
067                    }
068            }
069    
070            private void initializeATermClassObjects() {
071                    try {
072                            Class<?> aterm = Class.forName("aterm.ATerm");
073                            for (int i = 0; i < MAXIMUM_METHOD_ARITY; i++) {
074                                    protos[i] = new Class[i];
075                                    for (int j = 0; j < i; j++)
076                                            protos[i][j] = aterm;
077                            }
078                    } catch (ClassNotFoundException e) {
079                            throw new RuntimeException("could not find class: aterm.ATerm");
080                    }
081            }
082            public int getPid() {
083                    return processId;
084            }
085    
086            public int getExecState() {
087                    return exec_state;
088            }
089    
090            public void changeExecState(int newstate) {
091                    if (exec_state != newstate) {
092                            exec_state = newstate;
093                            switch (exec_state) {
094                                    case STATE_STOPPED :
095                                            fireRules(DebugAdapterRule.PORT_STOPPED);
096                                            break;
097                                    case STATE_RUNNING :
098                                            fireRules(DebugAdapterRule.PORT_STARTED);
099                                            break;
100                            }
101                    }
102            }
103    
104            public boolean isRunning() {
105                    return exec_state == STATE_RUNNING;
106            }
107    
108            public void fireLocationRules(String filename, int sl, int sc, int el,int ec) {}
109    
110            public void fireRules(int porttype) {
111                    Object[] elems = rulesPerPort[porttype].toArray();
112                    for (int i = 0; i < elems.length; i++) {
113                            DebugAdapterRule rule = (DebugAdapterRule) elems[i];
114                            fireRule(rule);
115                    }
116            }
117    
118            private void debugMsg(String msg) {
119                    if (debug) {
120                            System.err.println(msg);
121                    }
122            }
123    
124            public void fireRule(DebugAdapterRule rule) {
125                    DebugAdapterRule old_rule = current_rule;
126                    current_rule = rule;
127    
128                    ATerm cond = rule.getCondition();
129                    ATerm result = evaluate(cond);
130                    if (result.isEqual(termTrue)) {
131                            result = evaluate(rule.getAction());
132                            adapter.event(getPid(), current_rule, result);
133                    }
134    
135                    current_rule = old_rule;
136            }
137    
138            public DebugAdapterRule createRule(int pid, ATerm port, ATerm cond, ATerm act, ATerm tag, boolean enabled) {
139                    int rid;
140    
141                    /* Find a free rule */
142                    for (rid = 0; rid < MAX_RULES; rid++) {
143                            if (rules[rid] == null) {
144                                    break;
145                            }
146                    }
147    
148                    if (rid >= MAX_RULES) {
149                            throw new RuntimeException("too many rules: " + rid);
150                    }
151    
152                    DebugAdapterRule rule =
153                            new DebugAdapterRule(rid, port, cond, act, tag, enabled);
154    
155                    rules[rule.getId()] = rule;
156    
157                    if (enabled) {
158                            enableRule(rid);
159                    }
160    
161                    handleRuleCreation(rule);
162    
163                    return rule;
164            }
165    
166            public void enableRule(int rid) {
167                    DebugAdapterRule rule = rules[rid];
168                    int porttype = rule.getPortType();
169    
170                    rule.setEnabled(true);
171                    synchronized(rulesPerPort[porttype]){
172                            rulesPerPort[porttype].add(rule);
173                    }
174                    handleRuleEnabling(rule);
175            }
176    
177            public void disableRule(int rid) {
178                    DebugAdapterRule rule = rules[rid];
179                    int porttype = rule.getPortType();
180    
181                    rule.setEnabled(false);
182                    synchronized (rulesPerPort[porttype]) {
183                            rulesPerPort[rule.getPortType()].remove(rule);
184                    }
185                    handleRuleDisabling(rule);
186            }
187    
188            public void modifyRule(
189                    int rid,
190                    ATerm port,
191                    ATerm cond,
192                    ATerm act,
193                    boolean enabled) {
194                    int oldtype, newtype;
195                    boolean wasEnabled;
196    
197                    DebugAdapterRule rule = rules[rid];
198    
199                    debugMsg("oldrule" + rule);
200    
201                    oldtype = rule.getPortType();
202                    wasEnabled = rule.isEnabled();
203    
204                    rule.modify(port, cond, act, enabled);
205                    newtype = rule.getPortType();
206    
207                    debugMsg("newrule" + rule);
208    
209                    if (wasEnabled && newtype != oldtype) {
210                            synchronized (rulesPerPort[oldtype]) {
211                                    synchronized (rulesPerPort[newtype]) {
212                                            rulesPerPort[oldtype].remove(rule);
213                                            rulesPerPort[newtype].add(rule);
214                                    }
215                            }
216                    }
217                    if (enabled) {
218                            enableRule(rid);
219                    }
220            }
221    
222            public void deleteRule(int rid) {
223                    DebugAdapterRule rule = rules[rid];
224                    int porttype = rule.getPortType();
225                    synchronized (rulesPerPort[porttype]) {
226                            rulesPerPort[porttype].remove(rule);
227                    }
228                    rules[rid] = null;
229                    handleRuleDestruction(rule);
230            }
231    
232            public ATerm evaluate(ATerm act) {
233                    int i;
234    
235                    switch (act.getType()) {
236                            case ATerm.LIST :
237                                    //{ Evaluate all elements in a list
238    
239                                    ATermList list = (ATermList) act;
240                                    List<ATerm> result = new ArrayList<ATerm>();
241                                    while (!list.isEmpty()) {
242                                            ATerm elem = list.getFirst();
243                                            ATerm val = evaluate(elem);
244                                            list = list.getNext();
245                                            if (!val.equals(termTrue))
246                                                    result.add(elem);
247                                    }
248                                    if (result.isEmpty())
249                                            return termTrue;
250                                    list = factory.makeList();
251                                    for (int idx = result.size() - 1; idx >= 0; idx--)
252                                            list = factory.makeList(result.get(idx), list);
253                                    return list;
254    
255                                    //}
256    
257                            case ATerm.APPL :
258                                    //{ Evaluate a function
259    
260                                    ATermAppl appl = (ATermAppl) act;
261                                    if (appl.isQuoted()) {
262                                            return act;
263                                    } 
264                                    String action = appl.getName();
265                                    Class<?> myclass = getClass();
266                                    String name = "action" + capitalize(action, true);
267                                    int arity = appl.getArity();
268    
269                                    boolean found = false;
270    
271                                    do {
272                                            try {
273                                                    Method method =
274                                                            myclass.getDeclaredMethod(name, protos[arity]);
275                                                    found = true;
276                                                    Object[] args = new Object[arity];
277                                                    for (i = 0; i < arity; i++) {
278                                                            args[i] = evaluate(appl.getArgument(i));
279                                                    }
280                                                    debugMsg("invoking method: " + name);
281                                                    return (ATerm) method.invoke(this, args);
282                                            } catch (NoSuchMethodException e) {
283                                                    found = false;
284                                            } catch (InvocationTargetException e) {
285                                                    return factory.make("error(\"the function " + name + " has thrown an exception\")");
286                                            } catch (IllegalAccessException e) {
287                                                    e.printStackTrace();
288                                                    found = false;
289                                            }
290                                            myclass = myclass.getSuperclass();
291                                    } while (!found && myclass.getSuperclass() != null);
292    
293                                    if (!found) {
294                                            return factory.make(
295                                                    "error(\"unknown function: "
296                                                            + action + " (" + name + ")"
297                                                            + " with arity "
298                                                            + arity
299                                                            + "\")");
300                                    }
301                            default :
302                                    return act;
303                    }
304            }
305    
306            static private String capitalize(String str, boolean firstCap) {
307                    StringBuffer name = new StringBuffer();
308                    for (int i = 0; i < str.length(); i++) {
309                            if (str.charAt(i) == '-')
310                                    firstCap = true;
311                            else {
312                                    if (firstCap) {
313                                            name.append(Character.toUpperCase(str.charAt(i)));
314                                            firstCap = false;
315                                    } else
316                                            name.append(str.charAt(i));
317                            }
318                    }
319                    return name.toString();
320            }
321    
322            public void handleRuleCreation(DebugAdapterRule rule){}
323    
324            public void handleRuleDestruction(DebugAdapterRule rule){}
325    
326            public void handleRuleEnabling(DebugAdapterRule rule){}
327    
328            public void handleRuleDisabling(DebugAdapterRule rule){}
329    
330            public void doBreak() {
331                    changeExecState(STATE_STOPPED);
332            }
333    
334            public void doResume() {
335                    exec_state = STATE_RUNNING;
336                    start_level = getStackLevel();
337            }
338    
339            public void doDisable(DebugAdapterRule rule) {
340                    disableRule(rule.getId());
341                    List<Object> args = new ArrayList<Object>();
342                    args.add(new Integer(getPid()));
343                    args.add(new Integer(rule.getId()));
344                    adapter.postEvent(
345                            factory.make("rule-disabled(proc(<str>),<int>)", args));
346            }
347    
348            public ATerm actionTrue() {
349                    return termTrue;
350            }
351    
352            public ATerm actionFalse() {
353                    return termFalse;
354            }
355    
356            public ATerm actionBreak() {
357                    doBreak();
358                    return termTrue;
359            }
360    
361            public ATerm actionResume() {
362                    doResume();
363                    return termTrue;
364            }
365    
366            public ATerm actionState() {
367                    switch (exec_state) {
368                            case STATE_RUNNING :
369                                    return termRunning;
370                            case STATE_STOPPED :
371                                    return termStopped;
372                            default :
373                                    return termUnknown;
374                    }
375            }
376    
377            public ATerm actionDisable() {
378                    doDisable(current_rule);
379                    return termTrue;
380            }
381    
382            public ATerm actionHigherEqual(ATerm t1, ATerm t2) {
383                    if (t1.getType() == ATerm.INT && t2.getType() == ATerm.INT) {
384                            ATermInt i1 = (ATermInt) t1;
385                            ATermInt i2 = (ATermInt) t2;
386                            if (i1.getInt() >= i2.getInt())
387                                    return termTrue;
388                    }
389                    return termFalse;
390            }
391    
392            public ATerm actionEqual(ATerm t1, ATerm t2) {
393                    return t1.isEqual(t2) ? termTrue : termFalse;
394            }
395    
396            public ATerm actionStartLevel() {
397                    return factory.parse("" + start_level);
398            }
399    
400            public ATerm actionStackLevel() {
401                    return factory.parse("" + getStackLevel());
402            }
403    
404            public abstract ATerm actionCpe();
405            public abstract ATerm actionSourceVar(ATerm var, ATerm offset, ATerm line, ATerm col, ATerm dontknow);
406            
407            public abstract int getStackLevel();
408    }