View Javadoc

1   /*	
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
4   	
5   	JNAerator is free software: you can redistribute it and/or modify
6   	it under the terms of the GNU Lesser General Public License as published by
7   	the Free Software Foundation, either version 3 of the License, or
8   	(at your option) any later version.
9   	
10  	JNAerator is distributed in the hope that it will be useful,
11  	but WITHOUT ANY WARRANTY; without even the implied warranty of
12  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  	GNU Lesser General Public License for more details.
14  	
15  	You should have received a copy of the GNU Lesser General Public License
16  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
17  */
18  package com.ochafik.lang.jnaerator;
19  
20  import java.util.ArrayList;
21  import java.util.Collections;
22  
23  import java.util.List;
24  
25  import com.ochafik.lang.jnaerator.TypeConversion.JavaPrim;
26  import com.ochafik.lang.jnaerator.TypeConversion.TypeConversionMode;
27  import com.ochafik.lang.jnaerator.parser.Arg;
28  import com.ochafik.lang.jnaerator.parser.DeclarationsHolder;
29  import com.ochafik.lang.jnaerator.parser.Declarator;
30  import com.ochafik.lang.jnaerator.parser.Expression;
31  import com.ochafik.lang.jnaerator.parser.Function;
32  import com.ochafik.lang.jnaerator.parser.Identifier;
33  import com.ochafik.lang.jnaerator.parser.Modifier;
34  import com.ochafik.lang.jnaerator.parser.Statement;
35  import com.ochafik.lang.jnaerator.parser.Struct;
36  import com.ochafik.lang.jnaerator.parser.TypeRef;
37  import com.ochafik.lang.jnaerator.parser.VariablesDeclaration;
38  import com.ochafik.lang.jnaerator.parser.Declarator.PointerStyle;
39  import com.ochafik.lang.jnaerator.parser.Expression.MemberRefStyle;
40  import com.ochafik.lang.jnaerator.parser.Expression.VariableRef;
41  import com.ochafik.lang.jnaerator.runtime.globals.GlobalCallback;
42  import com.ochafik.lang.jnaerator.runtime.globals.GlobalPointer;
43  import com.ochafik.lang.jnaerator.runtime.globals.GlobalPointerType;
44  import com.ochafik.lang.jnaerator.runtime.globals.GlobalStruct;
45  import com.sun.jna.Pointer;
46  import com.sun.jna.Structure;
47  import com.sun.jna.ptr.ByReference;
48  
49  import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*;
50  public class GlobalsGenerator {
51  	public GlobalsGenerator(Result result) {
52  		this.result = result;
53  	}
54  
55  	final Result result;
56  	
57  //	public static final class NAME {
58  //		private static NAME_holder NAME;
59  //		public static final class NAME_holder {
60  //			public String value;
61  //		}
62  //		public static synchronized NAME_holder get() {
63  //			if (NAME == null)
64  //				NAME = new NAME_holder((Pointer)null);
65  //			return NAME;
66  //		}
67  //		void test() {
68  //			GlobalsGenerator.NAME.get().value;
69  //		}
70  //	}
71  	
72  	@SuppressWarnings("unchecked")
73  	public void convertGlobals(VariablesDeclaration globals, Signatures signatures, DeclarationsHolder out, Expression nativeLibFieldExpr, Identifier callerLibraryName, String callerLibrary) throws UnsupportedConversionException {
74  		for (Declarator d : globals.getDeclarators()) {
75  			try {
76  				Identifier name = result.typeConverter.getValidJavaArgumentName(ident(d.resolveName()));
77   				TypeRef type = (TypeRef)d.mutateType(globals.getValueType());
78  				if (type == null)
79  					continue;
80  				
81  				boolean isCallback = result.callbacksByName.containsKey(ident(type.toString()));//type instanceof FunctionSignature;
82  				List<Modifier> modifiers = new ArrayList<Modifier>(type.getModifiers());
83  				modifiers.addAll(globals.getModifiers());
84  				
85  				type.setModifiers(Collections.EMPTY_LIST);
86  				
87  				if (	!isCallback && 
88  						!(Modifier.Extern.isContainedBy(modifiers) || Modifier.Dllexport.isContainedBy(modifiers) || Modifier.Dllimport.isContainedBy(modifiers))
89  						//|| Modifier.Const.isContainedBy(modifiers) && d.getDefaultValue() != null
90  						) {
91  					//result.declarationsConverter.convertCon
92  					continue;
93  				}
94  				
95  				
96  				if (true) {//!result.config.useJNADirectCalls) {
97  					if (!signatures.variablesSignatures.add(name.toString()))
98  						continue;
99  					
100 					boolean isPointer = type instanceof com.ochafik.lang.jnaerator.parser.TypeRef.Pointer;
101 					JavaPrim prim = result.typeConverter.getPrimitive(isPointer ? ((com.ochafik.lang.jnaerator.parser.TypeRef.Pointer)type).getTarget() : type, callerLibraryName);
102 					type.setMarkedAsResolved(false);
103 					TypeRef convertedType = result.typeConverter.convertTypeToJNA(type, TypeConversionMode.NativeParameter, callerLibraryName);
104 					String convTypStr = convertedType.toString();
105 					if (convTypStr.endsWith(".ByValue"))
106 						convTypStr = convTypStr.substring(0, convTypStr.length() - ".ByValue".length());
107 					boolean isStruct = result.structsFullNames.contains(ident(convTypStr));
108 					boolean isUnion = result.unionsFullNames.contains(ident(convTypStr));
109 					
110 					//if (result. convertedType)
111 					if (prim != null || isCallback || isStruct || isUnion) {
112 						TypeRef globalType = null;
113 						Expression extraArg = null;
114 						//Class<? extends Global> optionA;
115 						if (isUnion || isStruct) {
116 							globalType = typeRef(ident(GlobalStruct.class, expr(convertedType.clone())));
117 							extraArg = memberRef(expr(convertedType.clone()), MemberRefStyle.Dot, "class");
118 						} else if (isCallback) {
119 							globalType = typeRef(ident(GlobalCallback.class, expr(type.clone())));
120 							extraArg = memberRef(expr(type.clone()), MemberRefStyle.Dot, "class");
121 						} else if (isPointer) {
122 							Class<? extends ByReference> brt = TypeConversion.primToByReference.get(prim);
123 							if (brt != null) {
124 								globalType = typeRef(ident(GlobalPointerType.class, expr(typeRef(ident(brt)))));
125 								extraArg = classLiteral(brt);
126 							} else if (prim == JavaPrim.Void) {
127 								globalType = typeRef(GlobalPointer.class);
128 							}
129 						} else {
130 							Class<?> globalClass = TypeConversion.primToGlobal.get(prim);
131 							if (globalClass != null)
132 								globalType = typeRef(globalClass);
133 						}
134 						if (globalType != null) {
135 							List<Expression> constructorArgs = new ArrayList<Expression>();
136 							constructorArgs.add(nativeLibFieldExpr.clone());
137 							if (extraArg != null) {
138 								constructorArgs.add(extraArg);
139 							}
140 							constructorArgs.add(expr(name.toString()));
141 							VariablesDeclaration vd = new VariablesDeclaration(
142 									globalType, 
143 								new Declarator.DirectDeclarator(
144 									name.toString(), 
145 									new Expression.New(
146 										globalType.clone(),
147 										constructorArgs.toArray(new Expression[constructorArgs.size()])
148 									)
149 								)
150 							);
151 	
152 							vd.addModifiers(Modifier.Public, Modifier.Static, Modifier.Final);
153 							vd.importDetails(globals, false);
154 							vd.moveAllCommentsBefore();
155 							
156 							out.addDeclaration(vd);
157 							continue;
158 						}
159 					}
160 				}
161 				
162 				if (!signatures.classSignatures.add(name))
163 					continue;
164 				
165 				
166 				/// We get a pointer to the global, not the global itself
167 				Struct struct = result.declarationsConverter.publicStaticClass(name, null, Struct.Type.JavaClass, null);
168 				struct.addModifiers(Modifier.Final);
169 				struct.importDetails(globals, false);
170 				struct.moveAllCommentsBefore();
171 				
172 				TypeRef pointerType = new TypeRef.Pointer(type, PointerStyle.Pointer);
173 				
174 				TypeRef convPointerType = result.typeConverter.convertTypeToJNA(pointerType, TypeConversionMode.FieldType, callerLibraryName);
175 				TypeRef instType;
176 				boolean hasOffset, isPtr = false, isByRef = false;
177 				String convPointerTypeStr = convPointerType.toString();
178 				if (convPointerTypeStr.equals(Pointer.class.getName())) {
179 					isPtr = true;
180 					instType = convPointerType;
181 					hasOffset = false;
182 				} else if (TypeConversion.byReferenceClassesNames.contains(convPointerTypeStr)) {
183 					isByRef = true;
184 					instType = convPointerType;
185 					hasOffset = false;
186 				} else if (convPointerTypeStr.endsWith(".ByReference") && result.structsByName.get(convPointerTypeStr.substring(0, convPointerTypeStr.length() - ".ByReference".length())) != null) {
187 					instType = result.typeConverter.convertTypeToJNA(type, TypeConversionMode.PointedValue, callerLibraryName);//convPointerType;
188 					hasOffset = true;
189 				} else {
190 					Identifier instTypeName = ident(name + "_holder");
191 					Struct holderStruct = result.declarationsConverter.publicStaticClass(instTypeName, ident(Structure.class), Struct.Type.JavaClass, null);
192 					holderStruct.addModifiers(Modifier.Final);
193 					VariablesDeclaration vd = result.declarationsConverter.convertVariablesDeclaration("value", type, new int[1], callerLibraryName);
194 					if (vd.getValueType().toString().equals(Pointer.class.getName())) {
195 						isByRef = true;
196 						instType = convPointerType;
197 						hasOffset = false;	
198 					} else {
199 						holderStruct.addDeclaration(vd);
200 						Function pointerConstructor = new Function(Function.Type.JavaMethod, instTypeName, null, 
201 							new Arg("pointer", new TypeRef.SimpleTypeRef(Pointer.class.getName()))
202 						);
203 						hasOffset = false;
204 						pointerConstructor.setBody(new Statement.Block(
205 								new Statement.ExpressionStatement(methodCall("super")),
206 								new Statement.ExpressionStatement(methodCall("useMemory", varRef("pointer"), expr(0))),
207 								new Statement.ExpressionStatement(methodCall("read"))
208 						));
209 						holderStruct.addDeclaration(pointerConstructor);
210 						
211 						//holderStruct.addDeclaration(new VariablesDeclaration(convType, new Declarator.DirectDeclarator("value")).addModifiers(Modifier.Public));
212 						instType = new TypeRef.SimpleTypeRef(instTypeName);
213 						struct.addDeclaration(decl(holderStruct));
214 					}
215 				}
216 				Identifier instName = name;//"_";
217 				struct.addDeclaration(new VariablesDeclaration(instType, new Declarator.DirectDeclarator(instName.toString())).addModifiers(Modifier.Private, Modifier.Static));
218 				VariableRef instRef = new VariableRef(instName);
219 				Expression ptrExpr = methodCall(
220 					nativeLibFieldExpr.clone(),
221 					MemberRefStyle.Dot,
222 					"getGlobalVariableAddress",
223 					expr(name.toString())
224 				);
225 				List<Statement> initStats = new ArrayList<Statement>();
226 				initStats.add(new Statement.ExpressionStatement(
227 					expr(
228 						instRef.clone(),
229 						Expression.AssignmentOperator.Equal,
230 						isPtr ? ptrExpr :
231 						isByRef ? new Expression.New(instType) :
232 						new Expression.New(instType, new Expression.FunctionCall(null, ptrExpr, hasOffset ? expr(0) : null))
233 					)
234 				));
235 				if (isByRef)
236 					initStats.add(new Statement.ExpressionStatement(methodCall(instRef, MemberRefStyle.Dot, "setPointer", ptrExpr)));
237 	
238 				struct.addDeclaration(new Function(Function.Type.JavaMethod, ident("get"), instType).setBody(new Statement.Block(
239 					new Statement.If(
240 						expr(instRef, Expression.BinaryOperator.IsEqual, nullExpr()),
241 						initStats.size() == 1 ? initStats.get(0) : new Statement.Block(initStats),
242 						null
243 					),
244 					new Statement.Return(instRef.clone())
245 				)).addModifiers(Modifier.Public, Modifier.Static, Modifier.Synchronized));
246 				out.addDeclaration(decl(struct));
247 			} catch (Throwable t) {
248 				out.addDeclaration(result.declarationsConverter.skipDeclaration(d, t.toString()));
249 			}
250 		}
251 	}
252 
253 	public void convertGlobals(List<VariablesDeclaration> list, Signatures signatures, DeclarationsHolder out, Expression nativeLibFieldExpr, Identifier libraryNameExpression, String library) {		
254 		if (list == null)
255 			return;
256 		
257 		for (VariablesDeclaration v : list) {
258 			try {
259 				convertGlobals(v, signatures, out, nativeLibFieldExpr, libraryNameExpression, library);
260 			} catch (UnsupportedConversionException ex) {
261 				out.addDeclaration(result.declarationsConverter.skipDeclaration(v, ex.toString()));
262 			}
263 		}
264 	}
265 }