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 | } |