1 package net.sourceforge.jenesis4java.impl;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import net.sourceforge.jenesis4java.Block;
29 import net.sourceforge.jenesis4java.CodeWriter;
30 import net.sourceforge.jenesis4java.Expression;
31 import net.sourceforge.jenesis4java.ReplacingVisitor;
32 import net.sourceforge.jenesis4java.Lambda;
33 import net.sourceforge.jenesis4java.Type;
34 import net.sourceforge.jenesis4java.impl.MDeclaration.MFormalParameter;
35
36
37
38
39 public class MLambda extends MVM.MCodeable implements Lambda {
40
41 private static abstract class Parameter {
42
43 private static class TypedParameter extends Parameter {
44
45 private final MFormalParameter parameter;
46
47 public TypedParameter(MFormalParameter parameter) {
48 this.parameter = parameter;
49 }
50
51 @Override
52 public CodeWriter toCode(CodeWriter out) {
53 return parameter.toCode(out);
54 }
55
56 @Override
57 public void visit(ReplacingVisitor visitor) {
58 parameter.visit(visitor);
59 }
60 }
61
62 private static class ParameterName extends Parameter {
63
64 private final String parameterName;
65
66 public ParameterName(String parameterName) {
67 this.parameterName = parameterName;
68 }
69
70 @Override
71 public CodeWriter toCode(CodeWriter out) {
72 return out.write(parameterName);
73 }
74
75 @Override
76 public void visit(ReplacingVisitor visitor) {
77
78 }
79 }
80
81 public static Parameter createParameter(String parameterName) {
82 return new ParameterName(parameterName);
83 }
84
85 public static Parameter createParameter(MVM vm, Type type, String name) {
86 return new TypedParameter(new MFormalParameter(vm, type, name));
87 }
88
89 public abstract CodeWriter toCode(CodeWriter out);
90
91 public abstract void visit(ReplacingVisitor visitor);
92 }
93
94 private class ParameterHolder {
95
96
97 private Boolean typelessParameters;
98
99 private List<Parameter> parameterList = new ArrayList<>();
100
101 public void add(Type type, String name) {
102 if (typelessParameters != null && typelessParameters) {
103 throw new RuntimeException("Lambda parameters with and without type declaration cannot be mixed");
104 }
105 typelessParameters = false;
106 parameterList.add(Parameter.createParameter(MLambda.this.vm, type, name));
107 }
108
109 public void add(String name) {
110 if (typelessParameters != null && !typelessParameters) {
111 throw new RuntimeException("Lambda parameters with and without type declaration cannot be mixed");
112 }
113 typelessParameters = true;
114 parameterList.add(Parameter.createParameter(name));
115 }
116
117 public void toCode(CodeWriter out) {
118 if (parameterList.size() == 1 && typelessParameters) {
119
120 parameterList.get(0).toCode(out);
121 } else {
122 codeParameters(out);
123 }
124 }
125
126 private void codeParameters(CodeWriter out) {
127 boolean first = true;
128 out.write("(");
129 for (Parameter parameter : parameterList) {
130 if (!first) {
131 out.write(", ");
132 } else {
133 first = false;
134 }
135 parameter.toCode(out);
136 }
137 out.write(")");
138 }
139
140 public void visit(ReplacingVisitor visitor) {
141 for (Parameter parameter : parameterList) {
142 parameter.visit(visitor);
143 }
144 }
145 }
146
147 private ParameterHolder parameters = new ParameterHolder();
148
149 private Expression body;
150
151 private MStatement.BlockStatement bodyBlock;
152
153 public MLambda(MVM vm) {
154 super(vm);
155 }
156
157 @Override
158 public Lambda addParameter(Class<?> type, String name) {
159 addParameter(vm.newType(type), name);
160 return this;
161 }
162
163 @Override
164 public Lambda addParameter(Type type, String name) {
165 parameters.add(type, name);
166 return this;
167 }
168
169 @Override
170 public Lambda addParameter(String name) {
171 parameters.add(name);
172 return this;
173 }
174
175 @Override
176 public Lambda setBody(Expression body) {
177 this.body = body;
178 return this;
179 }
180
181 @Override
182 public Block newBodyBlock() {
183 bodyBlock = new MStatement.BlockStatement(vm);
184 return bodyBlock;
185 }
186
187 @Override
188 public CodeWriter toCode(CodeWriter out) {
189 parameters.toCode(out);
190 out.write(" -> ");
191 if (body != null) {
192 body.toCode(out);
193 } else if (bodyBlock != null) {
194 bodyBlock.writeBlock(out, vm.getStyle("lambda-block"));
195 } else {
196
197 MStatement.BlockStatement block = new MStatement.BlockStatement(vm);
198 block.newEmpty();
199 block.writeBlock(out, vm.getStyle("lambda-block"));
200 }
201 return out.write(';');
202 }
203
204 @Override
205 public void visit(ReplacingVisitor visitor) {
206 super.visit(visitor);
207 parameters.visit(visitor);
208
209 }
210 }