001    package nl.cwi.sen1.tide.tool.support;
002    
003    //{{{ imports
004    
005    import java.util.Iterator;
006    import java.util.List;
007    
008    import aterm.ATerm;
009    import aterm.ATermAppl;
010    import aterm.ATermFactory;
011    import aterm.ATermList;
012    
013    
014    //}}}
015    
016    public class Expr
017    {
018      //{{{ Patterns
019    
020      private static final String PATTERN_LOC_LC =
021        "location(lc(<str>,<int>,<int>))";
022      private static final String PATTERN_LOC_LINE =
023        "location(line(<str>,<int>))";
024      private static final String PATTERN_LOC_AREA =
025        "location(area-in-file(<str>,area(<int>,<int>,<int>,<int>,<int>,<int>)))";
026      private static final String PAT_SOURCE_VAR =
027        "source-var(<str>,<int>,<int>,<int>,<str>)";
028      private static final String PAT_VARIABLE =
029        "variable(<str>,<term>)";
030      private static final String PAT_VAR =
031        "var(<str>,<term>,<int>,<int>,<int>,<int>)";
032      private static final String PAT_VAR_UNKNOWN =
033        "var-unknown(<str>)";
034      private static final String PAT_ERROR =
035        "error(<str>,<term>)";
036      private static final String PAT_SOURCE_PATH =
037        "source-path(<str>)";
038      private static final String PAT_SOURCE_LIST =
039        "source-list([<list>])";
040      private static final String PAT_STACK_TRACE =
041        "stack([<list>])";
042      private static final String PAT_STACK_FRAME =
043        "frame(<int>,<str>,<term>,<term>)";
044    
045      //}}}
046    
047      public static ATermFactory factory;
048    
049      private ATerm term;
050    
051      //{{{ public static void initialize(ATermFactory factory)
052    
053      public static void initialize(ATermFactory factory)
054      {
055        Expr.factory = factory;
056      }
057    
058      //}}}
059    
060      //{{{ public static Expr parse(String spec)
061    
062      public static Expr parse(String spec)
063      {
064        try {
065          return fromTerm(factory.parse(spec));
066        } catch (Exception e) {
067          return null;
068        }
069      }
070    
071      //}}}
072    
073      //{{{ public static Expr makeTrue()
074    
075      public static Expr makeTrue()
076      {
077        return make("true");
078      }
079    
080      //}}}
081      //{{{ public static Expr makeFalse()
082    
083      public static Expr makeFalse()
084      {
085        return make("false");
086      }
087    
088      //}}}
089      //{{{ public static Expr makeCpe()
090    
091      public static Expr makeCpe()
092      {
093        return make("cpe");
094      }
095    
096      //}}}
097      //{{{ public static Expr makeBreak()
098    
099      public static Expr makeBreak()
100      {
101        return make("break");
102      }
103    
104      //}}}
105      //{{{ public static Expr makeResume()
106    
107      public static Expr makeResume()
108      {
109        return make("resume");
110      }
111    
112      //}}}
113      //{{{ public static Expr makeLocation(String file, int line, int col)
114    
115      public static Expr makeLocation(String file, int line, int column)
116      {
117        return make(factory.make(PATTERN_LOC_LC, file, new Integer(line),
118                                 new Integer(column)));
119      }
120    
121      //}}}
122      //{{{ public static Expr makeListSources()
123    
124      public static Expr makeListSources()
125      {
126        return make("list-sources");
127      }
128    
129      //}}}
130      //{{{ public static Expr makeStackTrace()
131    
132      public static Expr makeStackTrace()
133      {
134        return make("stack-trace");
135      }
136    
137      //}}}
138      //{{{ public static Expr make(String expr)
139    
140      public static Expr make(String expr)
141      {
142        return make(factory.parse(expr));
143      }
144    
145      //}}}
146      //{{{ public static Expr make(ATerm expr)
147    
148      public static Expr make(ATerm expr)
149      {
150        return new Expr(expr);
151      }
152    
153      //}}}
154      //{{{ public static Expr fromTerm(ATerm expr)
155    
156      public static Expr fromTerm(ATerm expr)
157      {
158        return make(expr);
159      }
160    
161      //}}}
162    
163      //{{{ public static Expr makeSourceVar(file, pos, linenr, col, line)
164    
165      public static Expr makeSourceVar(String file, int pos,
166                                       int linenr, int col, String line)
167      {
168        return Expr.make(Expr.factory.make(PAT_SOURCE_VAR,
169                                           file,
170                                           new Integer(pos),
171                                           new Integer(linenr),
172                                           new Integer(col), line));
173      }
174    
175      //}}}
176    
177      //{{{ Expr(ATerm term)
178    
179      Expr(ATerm term)
180      {
181        this.term = term;
182      }
183    
184      //}}}
185    
186      //{{{ public boolean isError()
187    
188      public boolean isError()
189      {
190        return term.match(PAT_ERROR) != null;
191      }
192    
193      //}}}
194      //{{{ public String getErrorMessage()
195    
196      public String getErrorMessage()
197      {
198        List<?> result = term.match(PAT_ERROR);
199    
200        if (result != null) {
201          return (String)result.get(0);
202        }
203        
204        throw new RuntimeException("not an error: " + term);
205      }
206    
207      //}}}
208      //{{{ public Expr getErrorData()
209    
210      public Expr getErrorData()
211      {
212        List<?> result = term.match(PAT_ERROR);
213    
214        if (result != null) {
215          return Expr.make((ATerm)result.get(1));
216        }
217        
218        throw new RuntimeException("not an error: " + term);
219      }
220    
221      public boolean isLocation()
222      {
223        return term.match("location(<list>)") != null;
224      }
225    
226      public boolean isLocationUnknown()
227      {
228        return term.match("location(unknown)") != null;
229      }
230    
231      //{{{ public String getLocationFileName()
232    
233      public String getLocationFileName()
234      {
235        List<?> args = term.match(PATTERN_LOC_LINE);
236        if (args != null) {
237          return (String)args.get(0);
238        }
239    
240        args = term.match(PATTERN_LOC_LC);
241        if (args != null) {
242          return (String)args.get(0);
243        }
244    
245        args = term.match(PATTERN_LOC_AREA);
246        if (args != null) {
247          return (String)args.get(0);
248        }
249    
250        throw new RuntimeException("illegal location: " + term);
251      }
252    
253      //}}}
254      //{{{ public String getLocationShortFile()
255    
256      public String getLocationShortFile()
257      {
258        String file = getLocationFileName();
259        int index = file.lastIndexOf('/');
260        return file.substring(index+1);
261      }
262    
263      //}}}
264      //{{{ public int getLocationStartLine()
265    
266      public int getLocationStartLine()
267      {
268        List<?> args = term.match(PATTERN_LOC_LINE);
269        if (args != null) {
270          return ((Integer)args.get(1)).intValue();
271        }
272    
273        args = term.match(PATTERN_LOC_LC);
274        if (args != null) {
275          return ((Integer)args.get(1)).intValue();
276        }
277    
278        args = term.match(PATTERN_LOC_AREA);
279        if (args != null) {
280          return ((Integer)args.get(1)).intValue();
281        }
282    
283        throw new RuntimeException("illegal location: " + term);
284      }
285    
286      //}}}
287      //{{{ public int getLocationStartColumn()
288    
289      public int getLocationStartColumn()
290      {
291        List<?> args = term.match(PATTERN_LOC_LINE);
292        if (args != null) {
293          return 0;
294        }
295    
296        args = term.match(PATTERN_LOC_LC);
297        if (args != null) {
298          return ((Integer)args.get(2)).intValue();
299        }
300    
301        args = term.match(PATTERN_LOC_AREA);
302        if (args != null) {
303          return ((Integer)args.get(2)).intValue();
304        }
305    
306        throw new RuntimeException("illegal location: " + term);
307      }
308    
309      //}}}
310      //{{{ public int getLocationEndLine()
311    
312      public int getLocationEndLine()
313      {
314        List<?> args = term.match(PATTERN_LOC_LINE);
315        if (args != null) {
316          return ((Integer)args.get(1)).intValue();
317        }
318    
319        args = term.match(PATTERN_LOC_LC);
320        if (args != null) {
321          return ((Integer)args.get(1)).intValue();
322        }
323    
324        args = term.match(PATTERN_LOC_AREA);
325        if (args != null) {
326          return ((Integer)args.get(3)).intValue();
327        }
328    
329        throw new RuntimeException("illegal location: " + term);
330      }
331    
332      //}}}
333      //{{{ public int getLocationEndColumn()
334    
335      public int getLocationEndColumn()
336      {
337        List<?> args = term.match(PATTERN_LOC_LINE);
338        if (args != null) {
339          return -1;
340        }
341    
342        args = term.match(PATTERN_LOC_LC);
343        if (args != null) {
344          return ((Integer)args.get(2)).intValue();
345        }
346    
347        args = term.match(PATTERN_LOC_AREA);
348        if (args != null) {
349          return ((Integer)args.get(4)).intValue();
350        }
351    
352        throw new RuntimeException("illegal location: " + term);
353      }
354    
355      //}}}
356    
357      //{{{ public boolean isVariable()
358    
359      public boolean isVariable()
360      {
361        List<?> result = term.match(PAT_VARIABLE);
362        return result != null;
363      }
364    
365      //}}}
366      //{{{ public String getVariableName()
367    
368      public String getVariableName()
369      {
370        List<?> result = term.match(PAT_VARIABLE);
371        if (result != null) {
372          return (String)result.get(0);
373        }
374    
375        throw new RuntimeException("not a variable: " + term);
376      }
377    
378      //}}}
379      //{{{ public Expr getVariableValue()
380    
381      public Expr getVariableValue()
382      {
383        List<?> result = term.match(PAT_VARIABLE);
384        if (result != null) {
385          return Expr.make((ATerm)result.get(1));
386        }
387    
388        throw new RuntimeException("not a variable: " + term);
389      }
390    
391      //}}}
392    
393      //{{{ public boolean isVar()
394    
395      public boolean isVar()
396      {
397        List<?> result = term.match(PAT_VAR);
398        return result != null;
399      }
400    
401      //}}}
402      //{{{ public String getVarName()
403    
404      public String getVarName()
405      {
406        List<?> result = term.match(PAT_VAR);
407        if (result != null) {
408          return (String)result.get(0);
409        }
410    
411        throw new RuntimeException("not a variable spec: " + term);
412      }
413    
414      //}}}
415      //{{{ public Expr getVarValue()
416    
417      public Expr getVarValue()
418      {
419        List<?> result = term.match(PAT_VAR);
420        if (result != null) {
421          return Expr.make((ATerm)result.get(1));
422        }
423    
424        throw new RuntimeException("not a variable spec: " + term);
425      }
426    
427      //}}}
428      //{{{ public int getVarSourceStart()
429    
430      public int getVarSourceStart()
431      {
432        List<?> result = term.match(PAT_VAR);
433        if (result != null) {
434          return ((Integer)result.get(2)).intValue();
435        }
436    
437        throw new RuntimeException("not a variable spec: " + term);
438      }
439    
440      //}}}
441      //{{{ public int getVarSourceLineNr()
442    
443      public int getVarSourceLineNr()
444      {
445        List<?> result = term.match(PAT_VAR);
446        if (result != null) {
447          return ((Integer)result.get(3)).intValue();
448        }
449    
450        throw new RuntimeException("not a variable spec: " + term);
451      }
452    
453      //}}}
454      //{{{ public int getVarSourceStartColumn()
455    
456      public int getVarSourceStartColumn()
457      {
458        List<?> result = term.match(PAT_VAR);
459        if (result != null) {
460          return ((Integer)result.get(4)).intValue();
461        }
462    
463        throw new RuntimeException("not a variable spec: " + term);
464      }
465    
466      //}}}
467      //{{{ public int getVarSourceLength()
468    
469      public int getVarSourceLength()
470      {
471        List<?> result = term.match(PAT_VAR);
472        if (result != null) {
473          return ((Integer)result.get(5)).intValue();
474        }
475    
476        throw new RuntimeException("not a variable spec: " + term);
477      }
478    
479      //}}}
480    
481      //{{{ public boolean isVarUnknown()
482    
483      public boolean isVarUnknown()
484      {
485        List<?> result = term.match(PAT_VAR_UNKNOWN);
486        return result != null;
487      }
488    
489      //}}}
490      //{{{ public String getVarUnknownMessage()
491    
492      public String getVarUnknownMessage()
493      {
494        List<?> result = term.match(PAT_VAR_UNKNOWN);
495        if (result != null) {
496          return (String)result.get(0);
497        }
498        throw new RuntimeException("not a var-unknown spec: " + term);
499      }
500    
501      //}}}
502    
503      //{{{ public boolean isBreak()
504    
505      public boolean isBreak()
506      {
507        return term.isEqual(factory.parse("break"));
508      }
509    
510      //}}}
511    
512      //{{{ public boolean isSourcePath()
513    
514      public boolean isSourcePath()
515      {
516        List<?> result = term.match(PAT_SOURCE_PATH);
517        return result != null;
518      }
519    
520      //}}}
521      //{{{ public String getSourcePath()
522    
523      public String getSourcePath()
524      {
525        List<?> result = term.match(PAT_SOURCE_PATH);
526        if (result != null) {
527          return (String)result.get(0);
528        }
529    
530        throw new RuntimeException("not a source path: " + term);
531      }
532    
533      //}}}
534    
535      //{{{ public boolean isSourceList()
536    
537      public boolean isSourceList()
538      {
539        List<?> result = term.match(PAT_SOURCE_LIST);
540        return result != null;
541      }
542    
543      //}}}
544      //{{{ public Iterator sourceIterator()
545    
546      public Iterator<String> sourceIterator()
547      {
548        List<?> result = term.match(PAT_SOURCE_LIST);
549        if (result != null) {
550          return new StringIterator((ATermList)result.get(0));
551        }
552    
553        throw new RuntimeException("not a source-list: " + term);
554      }
555    
556      //}}}
557    
558      //{{{ public boolean isStackTrace()
559    
560      public boolean isStackTrace()
561      {
562        return term.match(PAT_STACK_TRACE) != null;
563      }
564    
565      //}}}
566      //{{{ public Iterator frameIterator()
567    
568      public Iterator<Expr> frameIterator()
569      {
570        List<?> result = term.match(PAT_STACK_TRACE);
571        if (result != null) {
572          return new ExprIterator((ATermList)result.get(0));
573        }
574    
575        throw new RuntimeException("not a stacktrace: " + term);
576      }
577    
578      //}}}
579      //{{{ public boolean isStackFrame()
580    
581      public boolean isStackFrame()
582      {
583        return term.match(PAT_STACK_FRAME) != null;
584      }
585    
586      //}}}
587      //{{{ public int getFrameDepth()
588    
589      public int getFrameDepth()
590      {
591        List<?> result = term.match(PAT_STACK_FRAME);
592        if (result != null) {
593          return ((Integer)result.get(0)).intValue();
594        }
595        throw new RuntimeException("not a stackframe: " + term);
596      }
597    
598      //}}}
599      //{{{ public String getFrameName()
600    
601      public String getFrameName()
602      {
603        List<?> result = term.match(PAT_STACK_FRAME);
604        if (result != null) {
605          return (String)result.get(1);
606        }
607        throw new RuntimeException("not a stackframe: " + term);
608      }
609    
610      //}}}
611      //{{{ public Expr getFrameLocation()
612    
613      public Expr getFrameLocation()
614      {
615        List<?> result = term.match(PAT_STACK_FRAME);
616        if (result != null) {
617          return new Expr((ATerm)result.get(2));
618        }
619        throw new RuntimeException("not a stackframe: " + term);
620      }
621    
622      //}}}
623      //{{{ public Expr getFrameVariables()
624    
625      public Expr getFrameVariables()
626      {
627        List<?> result = term.match(PAT_STACK_FRAME);
628        if (result != null) {
629          return new Expr((ATerm)result.get(3));
630        }
631        throw new RuntimeException("not a stackframe: " + term);
632      }
633    
634      //}}}
635    
636      //{{{ public Iterator iterator()
637    
638      public Iterator<Expr> iterator()
639      {
640        return new ExprIterator(term);
641      }
642    
643      //}}}
644    
645      //{{{ public ATerm  toTerm()
646    
647      public ATerm  toTerm()
648      {
649        return term;
650      }
651    
652      //}}}
653      //{{{ public String toString()
654    
655      public String toString()
656      {
657        if (isVariable()) {
658          return getVariableName() + " = " + getVariableValue();
659        } else if (isLocation() && !isLocationUnknown()) {
660          return getLocationShortFile() + " "
661            + getLocationStartLine() + "," + getLocationStartColumn()
662            + "-"
663            + getLocationEndLine() + "," + getLocationEndColumn();
664        }
665          
666        return term.toString();
667      }
668    
669      //}}}
670    }
671    
672    class ExprIterator
673      implements Iterator<Expr>
674    {
675      private ATerm term;
676    
677      //{{{ public ExprIterator(ATerm term)
678    
679      public ExprIterator(ATerm term)
680      {
681        this.term = term;
682      }
683    
684      //}}}
685    
686      //{{{ public boolean hasNext()
687    
688      public boolean hasNext()
689      {
690        if (term == null || (term.getType() == ATerm.LIST && 
691                             ((ATermList)term).isEmpty())) {
692          return false;
693        }
694    
695        return true;
696      }
697    
698      //}}}
699      //{{{ public Object next()
700    
701      public Expr next()
702      {
703        ATerm result;
704    
705        if (term.getType() == ATerm.LIST) {
706          result = ((ATermList)term).getFirst();
707          term = ((ATermList)term).getNext();
708        } else {
709          result = term;
710          term = null;
711        }
712    
713        return new Expr(result);
714      }
715    
716      //}}}
717      //{{{ public void remove()
718    
719      public void remove()
720      {
721        throw new UnsupportedOperationException();
722      }
723    
724      //}}}
725    }
726    
727    class StringIterator
728      implements Iterator<String>
729    {
730      private ATermList list;
731    
732      //{{{ public StringIterator(ATermList list)
733    
734      public StringIterator(ATermList list)
735      {
736        this.list = list;
737      }
738    
739      //}}}
740      //{{{ public boolean hasNext()
741    
742      public boolean hasNext()
743      {
744        if (list.isEmpty()) {
745          return false;
746        }
747    
748        return true;
749      }
750    
751      //}}}
752      //{{{ public Object next()
753    
754      public String next()
755      {
756        ATerm result;
757    
758        result = list.getFirst();
759        list   = list.getNext();
760    
761        return ((ATermAppl)result).getAFun().getName();
762      }
763    
764      //}}}
765      //{{{ public void remove()
766    
767      public void remove()
768      {
769        throw new UnsupportedOperationException();
770      }
771    
772      //}}}
773    }
774