View Javadoc
1   package net.sourceforge.jenesis4java.impl;
2   
3   /*
4    * #%L
5    * Jenesis 4 Java Code Generator
6    * %%
7    * Copyright (C) 2000 - 2015 jenesis4java
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * #L%
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   * Implementation of the {@code Lambda} interface.
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  				// nothing to visit
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          // NOTE: initially null (i.e. undefined)
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                 // No parentheses around single parameter name
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             // create an empty block and write it
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         // TODO: body etc.
209     }
210 }