| 1 | package uk.co.zonetora.fj.passes; |
| 2 | |
| 3 | import java.util.ArrayDeque; |
| 4 | import java.util.ArrayList; |
| 5 | import java.util.Deque; |
| 6 | import java.util.List; |
| 7 | |
| 8 | import uk.co.zonetora.fj.ast.analysis.DepthFirstAdapter; |
| 9 | import uk.co.zonetora.fj.ast.node.ACastTerm; |
| 10 | import uk.co.zonetora.fj.ast.node.AFieldAccessTerm; |
| 11 | import uk.co.zonetora.fj.ast.node.AMethodCallTerm; |
| 12 | import uk.co.zonetora.fj.ast.node.AObjectCreationNonLeftRecTerm; |
| 13 | import uk.co.zonetora.fj.ast.node.ATermListTermList; |
| 14 | import uk.co.zonetora.fj.ast.node.AThisNonLeftRecTerm; |
| 15 | import uk.co.zonetora.fj.ast.node.AVariableNonLeftRecTerm; |
| 16 | import uk.co.zonetora.fj.ast.node.Node; |
| 17 | import uk.co.zonetora.fj.ast.node.PTerm; |
| 18 | import uk.co.zonetora.fj.model.ArgumentName; |
| 19 | import uk.co.zonetora.fj.model.Cast; |
| 20 | import uk.co.zonetora.fj.model.ClassName; |
| 21 | import uk.co.zonetora.fj.model.FieldAccess; |
| 22 | import uk.co.zonetora.fj.model.FieldName; |
| 23 | import uk.co.zonetora.fj.model.Method; |
| 24 | import uk.co.zonetora.fj.model.MethodInvocation; |
| 25 | import uk.co.zonetora.fj.model.MethodName; |
| 26 | import uk.co.zonetora.fj.model.ObjectCreation; |
| 27 | import uk.co.zonetora.fj.model.Term; |
| 28 | import uk.co.zonetora.fj.model.Variable; |
| 29 | |
| 30 | public class TermBuilder extends DepthFirstAdapter { |
| 31 | |
| 32 | final Deque<Term> termStack; |
| 33 | final Deque<Deque<Term>> backupStack; |
| 34 | |
| 35 | public TermBuilder() { |
| 36 | this.termStack = new ArrayDeque<Term>(); |
| 37 | this.backupStack = new ArrayDeque<Deque<Term>>(); |
| 38 | } |
| 39 | |
| 40 | public Term buildTerm(PTerm term) { |
| 41 | term.apply(this); |
| 42 | return termStack.pop(); |
| 43 | } |
| 44 | |
| 45 | @Override |
| 46 | public void caseAVariableNonLeftRecTerm(AVariableNonLeftRecTerm node) { |
| 47 | ArgumentName aname = new ArgumentName(node.getIdentifier().getText().trim()); |
| 48 | termStack.push(new Variable(aname)); |
| 49 | }; |
| 50 | |
| 51 | @Override |
| 52 | public void caseAThisNonLeftRecTerm(AThisNonLeftRecTerm node) { |
| 53 | termStack.push(new Variable(Method.getThisArgName())); |
| 54 | } |
| 55 | |
| 56 | @Override |
| 57 | public void caseATermListTermList(ATermListTermList node) { |
| 58 | node.getTerm().apply(this); |
| 59 | for(Node n : (List<? extends Node>) node.getCommaTerm()) { |
| 60 | n.apply(this); |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | @Override |
| 65 | public void caseAFieldAccessTerm(AFieldAccessTerm node) { |
| 66 | node.getNonLeftRecTerm().apply(this); |
| 67 | Term path = termStack.pop(); |
| 68 | |
| 69 | FieldName field = new FieldName(node.getIdentifier().getText().trim()); |
| 70 | termStack.push(new FieldAccess(path, field)); |
| 71 | } |
| 72 | |
| 73 | @Override |
| 74 | public void caseAMethodCallTerm(AMethodCallTerm node) { |
| 75 | node.getNonLeftRecTerm().apply(this); |
| 76 | Term path = termStack.pop(); |
| 77 | |
| 78 | MethodName methodName = new MethodName(node.getIdentifier().getText().trim()); |
| 79 | |
| 80 | preserveTermStack(); |
| 81 | node.getTermList().apply(this); |
| 82 | List<Term> visitedTerms = restoreTermStack(); |
| 83 | |
| 84 | termStack.push(new MethodInvocation(path, methodName, visitedTerms)); |
| 85 | } |
| 86 | |
| 87 | @Override |
| 88 | public void caseAObjectCreationNonLeftRecTerm(AObjectCreationNonLeftRecTerm node) { |
| 89 | ClassName className = new ClassName(node.getIdentifier().getText().trim()); |
| 90 | |
| 91 | preserveTermStack(); |
| 92 | node.getTermList().apply(this); |
| 93 | List<Term> visitedTerms = restoreTermStack(); |
| 94 | |
| 95 | termStack.push(new ObjectCreation(className, visitedTerms)); |
| 96 | }; |
| 97 | |
| 98 | @Override |
| 99 | public void caseACastTerm(ACastTerm node) { |
| 100 | ClassName className = new ClassName(node.getIdentifier().getText().trim()); |
| 101 | |
| 102 | node.getNonLeftRecTerm().apply(this); |
| 103 | |
| 104 | Term castedTerm = termStack.pop(); |
| 105 | |
| 106 | termStack.push(new Cast(className, castedTerm)); |
| 107 | } |
| 108 | |
| 109 | private void preserveTermStack() { |
| 110 | backupStack.push(new ArrayDeque<Term>(termStack)); |
| 111 | } |
| 112 | |
| 113 | private List<Term> restoreTermStack() { |
| 114 | Deque<Term> old = backupStack.pop(); |
| 115 | List<Term> current = new ArrayList<Term>(termStack); |
| 116 | termStack.clear(); |
| 117 | termStack.addAll(old); |
| 118 | return current; |
| 119 | } |
| 120 | |
| 121 | } |