1 | package uk.co.zonetora.fj.passes; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.LinkedList; |
5 | import java.util.List; |
6 | |
7 | import uk.co.zonetora.fj.ast.analysis.DepthFirstAdapter; |
8 | import uk.co.zonetora.fj.ast.node.AClassDecl; |
9 | import uk.co.zonetora.fj.ast.node.ACommaField; |
10 | import uk.co.zonetora.fj.ast.node.ACommaParamArgList; |
11 | import uk.co.zonetora.fj.ast.node.AConstructorDecl; |
12 | import uk.co.zonetora.fj.ast.node.AEmptyFieldList; |
13 | import uk.co.zonetora.fj.ast.node.AEmptyParamDeclList; |
14 | import uk.co.zonetora.fj.ast.node.AFieldDecl; |
15 | import uk.co.zonetora.fj.ast.node.AFieldListFieldList; |
16 | import uk.co.zonetora.fj.ast.node.AFieldName; |
17 | import uk.co.zonetora.fj.ast.node.AIdentParamArg; |
18 | import uk.co.zonetora.fj.ast.node.AMethodDecl; |
19 | import uk.co.zonetora.fj.ast.node.AParamArgsParamDeclList; |
20 | import uk.co.zonetora.fj.ast.node.AThisFieldAssig; |
21 | import uk.co.zonetora.fj.ast.node.AThisParamArg; |
22 | import uk.co.zonetora.fj.ast.node.PFieldList; |
23 | import uk.co.zonetora.fj.ast.node.PParamArg; |
24 | import uk.co.zonetora.fj.ast.node.PParamDeclList; |
25 | import uk.co.zonetora.fj.ast.node.PTerm; |
26 | import uk.co.zonetora.fj.model.ArgumentName; |
27 | import uk.co.zonetora.fj.model.ClassDecl; |
28 | import uk.co.zonetora.fj.model.ClassName; |
29 | import uk.co.zonetora.fj.model.Constructor; |
30 | import uk.co.zonetora.fj.model.FieldName; |
31 | import uk.co.zonetora.fj.model.Method; |
32 | import uk.co.zonetora.fj.model.MethodName; |
33 | import uk.co.zonetora.fj.model.Term; |
34 | import uk.co.zonetora.fj.util.Tuple; |
35 | |
36 | public class BuildModel extends DepthFirstAdapter { |
37 | |
38 | private final List<ClassDecl> classes; |
39 | |
40 | private final List<FJException> exceptions; |
41 | |
42 | public BuildModel() { |
43 | this.classes = new ArrayList<ClassDecl>(); |
44 | this.exceptions = new ArrayList<FJException>(); |
45 | } |
46 | |
47 | @Override |
48 | public void caseAClassDecl(AClassDecl node) { |
49 | ClassName name = new ClassName(node.getClassname().getText().trim()); |
50 | ClassName extnds = new ClassName(node.getExtendsname().getText().trim()); |
51 | |
52 | Constructor ctor = buildConstructor((AConstructorDecl)node.getConstructorDecl()); |
53 | ClassDecl classDecl = new ClassDecl(name, extnds, ctor); |
54 | |
55 | for( Object o : node.getFieldDecl() ) { |
56 | AFieldDecl afd = (AFieldDecl) o; |
57 | Tuple<ClassName, FieldName> cnfn = getFieldDecl(afd); |
58 | classDecl.addField(cnfn.getX() , cnfn.getY()); |
59 | } |
60 | |
61 | for(Object o : node.getMethodDecl()) { |
62 | AMethodDecl amd = (AMethodDecl) o; |
63 | Method m = getMethodDecl(amd); |
64 | classDecl.addMethod(m); |
65 | } |
66 | |
67 | this.classes.add(classDecl); |
68 | |
69 | } |
70 | |
71 | |
72 | private Method getMethodDecl(AMethodDecl amd) { |
73 | ClassName returnType = new ClassName(amd.getClassname().getText().trim()); |
74 | MethodName methodName = new MethodName(amd.getMethodname().getText().trim()); |
75 | List<Tuple<ClassName, ArgumentName>> parameters = getFormalParameters(amd.getParamDeclList()); |
76 | |
77 | Term code = getTerm(amd.getTerm()); |
78 | |
79 | Method m = new Method(returnType, methodName, code); |
80 | |
81 | for(Tuple<ClassName, ArgumentName> argDecl : parameters) { |
82 | m.addArgument(argDecl.getX(), argDecl.getY()); |
83 | } |
84 | |
85 | return m; |
86 | } |
87 | |
88 | private Term getTerm(PTerm term) { |
89 | return new TermBuilder().buildTerm(term); |
90 | } |
91 | |
92 | private List<Tuple<ClassName, ArgumentName>> getFormalParameters( |
93 | PParamDeclList paramDeclList) { |
94 | |
95 | if(paramDeclList instanceof AEmptyParamDeclList) { |
96 | return new ArrayList<Tuple<ClassName,ArgumentName>>(); |
97 | } |
98 | AParamArgsParamDeclList paramArgs = (AParamArgsParamDeclList) paramDeclList; |
99 | |
100 | Tuple<ClassName, ArgumentName> firstArg = getFormalParameter(paramArgs.getParamArg()); |
101 | |
102 | List<Tuple<ClassName, ArgumentName>> otherArgs = getCommaFormalParameters(paramArgs.getCommaParamArgList()); |
103 | |
104 | List<Tuple<ClassName, ArgumentName>> ret = new ArrayList<Tuple<ClassName,ArgumentName>>(); |
105 | ret.add(firstArg); |
106 | ret.addAll(otherArgs); |
107 | return ret; |
108 | } |
109 | |
110 | @SuppressWarnings("unchecked") |
111 | private List<Tuple<ClassName, ArgumentName>> getCommaFormalParameters( |
112 | LinkedList commaParamArgList) { |
113 | List<Tuple<ClassName, ArgumentName>> ret = new ArrayList<Tuple<ClassName,ArgumentName>>(); |
114 | |
115 | for(Object o : commaParamArgList) { |
116 | ACommaParamArgList paramArg = (ACommaParamArgList) o; |
117 | ret.add(getFormalParameter(paramArg.getParamArg())); |
118 | } |
119 | |
120 | return ret; |
121 | } |
122 | |
123 | private Tuple<ClassName, ArgumentName> getFormalParameter(PParamArg paramArg) { |
124 | if(paramArg instanceof AIdentParamArg) { |
125 | AIdentParamArg arg = (AIdentParamArg) paramArg; |
126 | ClassName tipe = new ClassName(arg.getClassname().getText().trim()); |
127 | ArgumentName argName = new ArgumentName(arg.getParam().getText().trim()); |
128 | return new Tuple<ClassName, ArgumentName>(tipe, argName); |
129 | } else if (paramArg instanceof AThisParamArg) { |
130 | AThisParamArg arg = (AThisParamArg) paramArg; |
131 | ClassName tipe = new ClassName(arg.getIdentifier().getText().trim()); |
132 | ArgumentName argName = Method.getThisArgName(); |
133 | return new Tuple<ClassName, ArgumentName>(tipe, argName); |
134 | } else { |
135 | throw new RuntimeException("Precondition failure!"); |
136 | } |
137 | |
138 | } |
139 | |
140 | private Tuple<ClassName, FieldName> getFieldDecl(AFieldDecl afd) { |
141 | ClassName tipe = new ClassName(afd.getClassname().getText().trim()); |
142 | FieldName fieldName = new FieldName(afd.getFieldname().getText().trim()); |
143 | return new Tuple<ClassName, FieldName>(tipe, fieldName); |
144 | } |
145 | |
146 | private Constructor buildConstructor(AConstructorDecl constructorDecl) { |
147 | ClassName returnType = new ClassName(constructorDecl.getIdentifier().getText().trim()); |
148 | Constructor constructor = new Constructor(returnType); |
149 | |
150 | List<Tuple<ClassName,ArgumentName>> parameters = getFormalParameters(constructorDecl.getParamDeclList()); |
151 | for(Tuple<ClassName, ArgumentName> param : parameters) { |
152 | constructor.addArgument(param.getX(), new FieldName(param.getY().getArgName())); |
153 | } |
154 | |
155 | |
156 | List<FieldName> superFields = getSuperFieldNames(constructorDecl.getFieldList()); |
157 | for(FieldName f : superFields) { |
158 | constructor.addSuperField(f); |
159 | } |
160 | |
161 | for(Object o : constructorDecl.getThisFieldAssig()) { |
162 | AThisFieldAssig atfa = (AThisFieldAssig) o; |
163 | FieldName f; |
164 | try { |
165 | f = getThisFieldAssig(atfa); |
166 | } catch (FJException e) { |
167 | System.err.println(e.getMessage()); |
168 | addException(e); |
169 | continue; |
170 | } |
171 | constructor.addLocalField(f); |
172 | } |
173 | return constructor; |
174 | |
175 | } |
176 | |
177 | private void addException(FJException e) { |
178 | this.exceptions.add(e); |
179 | } |
180 | |
181 | private FieldName getThisFieldAssig(AThisFieldAssig atfa) throws FJException { |
182 | FieldName left = new FieldName(atfa.getLeftField().getText().trim()); |
183 | FieldName right = new FieldName(atfa.getRightField().getText().trim()); |
184 | |
185 | if(!left.equals(right)) { |
186 | throw new FJException("Constructor with field assignment that is not a mirror in: this." + (left.getFieldName()) + " = " + (right.getFieldName())); |
187 | } |
188 | |
189 | return left; |
190 | } |
191 | |
192 | private List<FieldName> getSuperFieldNames(PFieldList fieldList) { |
193 | if (fieldList instanceof AEmptyFieldList ) { |
194 | return new ArrayList<FieldName>(); |
195 | } |
196 | |
197 | AFieldListFieldList aFieldList = (AFieldListFieldList) fieldList; |
198 | |
199 | FieldName first = getFieldName((AFieldName) aFieldList.getFieldName()); |
200 | |
201 | List<FieldName> ret = new ArrayList<FieldName>(); |
202 | ret.add(first); |
203 | |
204 | for(Object o : aFieldList.getCommaField()) { |
205 | ACommaField acf = (ACommaField) o; |
206 | ret.add(getFieldName((AFieldName) acf.getFieldName())); |
207 | } |
208 | |
209 | return ret; |
210 | } |
211 | |
212 | private FieldName getFieldName(AFieldName fieldName) { |
213 | return new FieldName(fieldName.getIdentifier().getText().trim()); |
214 | } |
215 | |
216 | public List<ClassDecl> getClasses() { |
217 | return this.classes; |
218 | } |
219 | } |