Skip to main content
summaryrefslogtreecommitdiffstats
blob: 2169082a1ad0ffd3e25861ecceb7e3457a8e5ed1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
/**********************************************************************
 * Copyright (c) 2004 Rational Software Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: 
 * IBM Rational Software - Initial API and implementation
***********************************************************************/
package org.eclipse.cdt.internal.core.parser.pst;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.internal.core.parser.pst.TypeInfo.PtrOp;

/**
 * @author aniefer
 *
 * To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Generation - Code and Comments
 */
public class TemplateSymbol	extends ParameterizedSymbol	implements ITemplateSymbol {
	
	protected TemplateSymbol ( ParserSymbolTable table, String name ){
		super( table, name, TypeInfo.t_template );
	}
	
	protected TemplateSymbol( ParserSymbolTable table, String name, ISymbolASTExtension obj ){
		super( table, name, obj );
	}
	
	public Object clone(){
		TemplateSymbol copy = (TemplateSymbol)super.clone();

		copy._defnParameterMap = ( _defnParameterMap != Collections.EMPTY_MAP ) ? (Map)((HashMap) _defnParameterMap).clone() : _defnParameterMap;
		copy._instantiations = ( _instantiations != Collections.EMPTY_MAP ) ? (Map)((HashMap) _instantiations).clone() : _instantiations;
		
		return copy;	
	}
	
	public IContainerSymbol getTemplatedSymbol(){
		Iterator iter = getContentsIterator();
		if( iter.hasNext() ){
			IContainerSymbol contained = (IContainerSymbol) iter.next();
			return contained;
		}
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.cdt.internal.core.parser.pst.IContainerSymbol#instantiate(java.util.List)
	 */
	public ISymbol instantiate( List arguments ) throws ParserSymbolTableException{
		if( getType() != TypeInfo.t_template &&
				( getType() != TypeInfo.t_templateParameter || 
						getTypeInfo().getTemplateParameterType() != TypeInfo.t_template ) )
		{
			return null;
		}
		
		ITemplateSymbol template = TemplateEngine.matchTemplatePartialSpecialization( this, arguments );
				
		if( template != null && template instanceof ISpecializedSymbol ){
			return template.instantiate( arguments );	
		}
		
		if( template == null ){
			template = this;
		}
		
		List paramList = template.getParameterList();
		int numParams = ( paramList != null ) ? paramList.size() : 0;
		
		if( numParams == 0 ){
			return null;				
		}

		HashMap map = new HashMap();
		Iterator paramIter = paramList.iterator();
		Iterator argIter = arguments.iterator();
		
		ISymbol param = null;
		TypeInfo arg = null;
		
		List actualArgs = new ArrayList( numParams );
		
		ISymbol templatedSymbol = template.getTemplatedSymbol();
		while( templatedSymbol != null && templatedSymbol.isTemplateInstance() ){
			templatedSymbol = templatedSymbol.getInstantiatedSymbol();
		}
		
		for( int i = 0; i < numParams; i++ ){
			param = (ISymbol) paramIter.next();
			
			param = TemplateEngine.translateParameterForDefinition ( templatedSymbol, param, getDefinitionParameterMap() );
			
			if( argIter.hasNext() ){
				arg = (TypeInfo) argIter.next();
				//If the argument is a template parameter, we can't instantiate yet, defer for later
				if( arg.isType( TypeInfo.t_type ) ){
					if( arg.getTypeSymbol() == null ) 
						throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplateArgument );
					else if( arg.getTypeSymbol().isType( TypeInfo.t_templateParameter ) )
						return deferredInstance( arguments );
				}
			} else {
				Object obj = param.getTypeInfo().getDefault();
				if( obj != null && obj instanceof TypeInfo ){
					arg = (TypeInfo) obj;
					if( arg.isType( TypeInfo.t_type ) && arg.getTypeSymbol().isType( TypeInfo.t_templateParameter ) ){
						if( map.containsKey( arg.getTypeSymbol() ) ){
							arg = (TypeInfo) map.get( arg.getTypeSymbol() );
						} else {
							throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplateArgument );
						}
					} else if( arg.isType( TypeInfo.t_type ) && arg.getTypeSymbol() instanceof IDeferredTemplateInstance ){
						IDeferredTemplateInstance deferred = (IDeferredTemplateInstance) arg.getTypeSymbol();
						arg = new TypeInfo( arg );
						arg.setTypeSymbol( deferred.instantiate( this, map ) );
					}
				} else {
					throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplateArgument );					
				}
			}
			
			if( TemplateEngine.matchTemplateParameterAndArgument( param, arg ) ){
				map.put( param, arg );
				actualArgs.add( arg );
			} else {
				throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplateArgument );
			}
		}
		
		IContainerSymbol instance = findInstantiation( actualArgs );
		if( instance != null ){
			return instance;
		} 
		if( template.isType( TypeInfo.t_templateParameter ) ){
			//template template parameter.  must defer instantiation
			return deferredInstance( arguments );
		} 
		
		IContainerSymbol symbol = template.getTemplatedSymbol(); 
		ISymbol temp = TemplateEngine.checkForTemplateExplicitSpecialization( template, symbol, actualArgs );
		symbol = (IContainerSymbol) ( temp != null ? temp : symbol);
			
		instance = (IContainerSymbol) symbol.instantiate( template, map );
		addInstantiation( instance, actualArgs );
		
		processDeferredInstantiations();
		
		return instance;		
	}
	
	public ISymbol instantiate( ITemplateSymbol template, Map argMap ) throws ParserSymbolTableException{
		if( !isTemplateMember() ){
			return null;
		}
		
		TemplateSymbol newTemplate = (TemplateSymbol) super.instantiate( template, argMap );
		
		//we don't want to instantiate the template parameters, just the defaults if there are any
		Iterator iter = newTemplate.getParameterList().iterator();
		ISymbol param = null;
		while( iter.hasNext() ){
			param = (ISymbol) iter.next();
			Object obj = param.getTypeInfo().getDefault();
			if( obj instanceof TypeInfo ){
				param.getTypeInfo().setDefault( TemplateEngine.instantiateTypeInfo( (TypeInfo) obj, template, argMap ) );
			}
		}	
		
		return newTemplate;
	}
	
	public void addParameter( ISymbol param ) {
		throw new ParserSymbolTableError( ParserSymbolTableError.r_OperationNotSupported );
	}
	
	public void addTemplateParameter( ISymbol param ) throws ParserSymbolTableException {
		if( isType( TypeInfo.t_template ) || getTypeInfo().getTemplateParameterType() == TypeInfo.t_template ){
			if( !isAllowableTemplateParameter( param ) ){
				throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTemplateParameter );
			}
			modifyTemplateParameter( param );
		}
		
		super.addParameter( param );
	}
	
	private boolean isAllowableTemplateParameter( ISymbol param ) {
		if( !param.isType( TypeInfo.t_templateParameter ) )
			return false;
		
		if(  !getName().equals( ParserSymbolTable.EMPTY_NAME ) && param.getName().equals( getName() ) ){
			return false;
		}
		
		if( param.getTypeInfo().getTemplateParameterType() != TypeInfo.t_typeName &&
			param.getTypeInfo().getTemplateParameterType() != TypeInfo.t_template )
		{
			TypeInfo info = param.getTypeInfo();
			//a non-type template parameter shall have one of the following:
			//integral or enumeration type
			//pointer to object or pointer to function
			//reference to object or reference to function
			//pointer to member

			//14.1-7
			//A non-type template-parameter shall not be declared to have floating point, class or void type
			if( info.getPtrOperators().size() == 0 )
				if( info.getTemplateParameterType() == TypeInfo.t_float        ||
					info.getTemplateParameterType() == TypeInfo.t_double       ||
					info.getTemplateParameterType() == TypeInfo.t_class        ||
					info.getTemplateParameterType() == TypeInfo.t_struct       ||
					info.getTemplateParameterType() == TypeInfo.t_union        ||
					info.getTemplateParameterType() == TypeInfo.t_enumeration  ||
					info.getTemplateParameterType() == TypeInfo.t_void         )
				{
					return false;
				}
		}
		return true;			
	}
	
	private void modifyTemplateParameter( ISymbol param ){
		List ptrs = param.getPtrOperators();
		if( ptrs.size() > 0 ){
			PtrOp op = (PtrOp) ptrs.get( 0 );
			if( op.getType() == PtrOp.t_array ){
				op.setType( PtrOp.t_pointer );
			}
		} else if ( param.isType( TypeInfo.t_type ) && param.getTypeSymbol().isType( TypeInfo.t_function ) ){
			param.addPtrOperator( new PtrOp( PtrOp.t_pointer ) );
		}
	}
	




	/* (non-Javadoc)
	 * @see org.eclipse.cdt.internal.core.parser.pst.IParameterizedSymbol#hasSpecializations()
	 */
	public boolean hasSpecializations(){
		return !_specializations.isEmpty();
	}
	
	public void addExplicitSpecialization( ISymbol symbol, List args ) throws ParserSymbolTableException{
		
		List actualArgs = TemplateEngine.verifyExplicitArguments( this, args, symbol );
		
		if( _explicitSpecializations == Collections.EMPTY_MAP )
			_explicitSpecializations = new HashMap();
		
		Map specs = null;
		List key = null;
		
		Iterator iter = _explicitSpecializations.keySet().iterator();
		while( iter.hasNext() ){
			List list = (List) iter.next();
			if( list.equals( args ) ){
				key = list;
				break;
			}
		}
		
		if( key != null ){
			specs = (Map) _explicitSpecializations.get( key );
		} else {
			specs = new HashMap();
			_explicitSpecializations.put( new ArrayList( actualArgs ), specs );
		}
		
		ISymbol found = null;
		try{
			if( symbol.isType( TypeInfo.t_function ) || symbol.isType( TypeInfo.t_constructor ) ){
				List params = ((IParameterizedSymbol) symbol).getParameterList();
				int size = params.size();
				List fnArgs = new ArrayList( size );
				for( int i = 0; i < size; i++){
					fnArgs.add( ((ISymbol)params.get(i)).getTypeInfo() );
				}
				found = getTemplatedSymbol().lookupMethodForDefinition( symbol.getName(), fnArgs );
			} else {
				found = getTemplatedSymbol().lookupMemberForDefinition( symbol.getName() );
			}
		} catch (ParserSymbolTableException e) {
		}
		if( found == null && getTemplatedSymbol().getName().equals( symbol.getName() ) ){
			found = getTemplatedSymbol();
			
			IContainerSymbol instance = findInstantiation( actualArgs );
			if( instance != null ){
				_instantiations.remove( findArgumentsFor( instance ) );
			}
		}

		if( found != null ){
			//in defining the explicit specialization for a member function, the factory would have set 
			//the specialization as the definition of the original declaration, which it is not
			if( found.getTypeInfo().isForwardDeclaration() && found.getTypeSymbol() == symbol )
				found.setTypeSymbol( null );
			
			//TODO, once we can instantiate members as we need them instead of at the same time as the class
			//then found should stay as the instance, for now though, we need the original (not 100% correct
			//but the best we can do for now)
			while( found.isTemplateInstance() ){
				found = found.getInstantiatedSymbol();
			}
		}
		
		if( found != null ){
			symbol.setIsTemplateMember( true );
			symbol.setContainingSymbol( found.getContainingSymbol() );
			specs.put( found, symbol );
		}
	}

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.internal.core.parser.pst.IParameterizedSymbol#addSpecialization(org.eclipse.cdt.internal.core.parser.pst.IParameterizedSymbol)
	 */
	public void addSpecialization( ISpecializedSymbol spec ){
		if( _specializations == Collections.EMPTY_LIST )
			_specializations = new ArrayList(4);
		
		_specializations.add( spec );
		
		spec.setContainingSymbol( getContainingSymbol() );	
		spec.setPrimaryTemplate( this );
	}

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.internal.core.parser.pst.IParameterizedSymbol#getSpecializations()
	 */
	public List getSpecializations() {
		return _specializations;
	}
	
	public void addInstantiation( IContainerSymbol instance, List args ){
		List key = new ArrayList( args );
		if( _instantiations == Collections.EMPTY_MAP ){
			_instantiations = new HashMap();
		}
		_instantiations.put( key, instance );
	}
	
	public IContainerSymbol findInstantiation( List arguments ){
		if( _instantiations == Collections.EMPTY_MAP ){
			return null;
		}
		
		//TODO: we could optimize this by doing something other than a linear search.
		Iterator iter = _instantiations.keySet().iterator();
		List args = null;
		while( iter.hasNext() ){
			args = (List) iter.next();
			
			if( args.equals( arguments ) ){
				return (IContainerSymbol) _instantiations.get( args );
			}
		}
		return null;
	}
	
	public List findArgumentsFor( IContainerSymbol instance ){
		if( instance == null || !instance.isTemplateInstance() )
			return null;
		
		ITemplateSymbol template = (ITemplateSymbol) instance.getInstantiatedSymbol().getContainingSymbol();
		if( template != this )
			return null;
		
		Iterator iter = _instantiations.keySet().iterator();
		while( iter.hasNext() ){
			List args = (List) iter.next();
			if( _instantiations.get( args ) == instance ){
				return args;
			}
		}
		
		return null;
	}
	
	public void removeInstantiation( IContainerSymbol symbol ){
		List args = findArgumentsFor( symbol );
		if( args != null ){
			_instantiations.remove( args );
		}
	}
	
	public Map getDefinitionParameterMap(){
		return _defnParameterMap;
	}
	
	protected void addToDefinitionParameterMap( ISymbol newSymbol, Map defnMap ){
		if( _defnParameterMap == Collections.EMPTY_MAP )
			_defnParameterMap = new HashMap();
		_defnParameterMap.put( newSymbol, defnMap );
	}
	
	public IDeferredTemplateInstance deferredInstance( List args ){
		return new DeferredTemplateInstance( getSymbolTable(), this, args );
	}

	public Map getExplicitSpecializations() {
		return _explicitSpecializations;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.internal.core.parser.pst.ITemplateSymbol#registerDeferredInstatiation(org.eclipse.cdt.internal.core.parser.pst.ParameterizedSymbol, org.eclipse.cdt.internal.core.parser.pst.ISymbol, org.eclipse.cdt.internal.core.parser.pst.ITemplateSymbol.DeferredKind)
	 */
	public void registerDeferredInstatiation( Object obj0, Object obj1, DeferredKind kind, Map argMap ) {
		if( _deferredInstantiations == Collections.EMPTY_LIST )
			_deferredInstantiations = new ArrayList(8);
		
		_deferredInstantiations.add( new Object [] { obj0, obj1, kind, argMap } );
	}

	
	protected void processDeferredInstantiations() throws ParserSymbolTableException{
		if( _deferredInstantiations == Collections.EMPTY_LIST )
			return;
		
		int size = _deferredInstantiations.size();
		for( int i = 0; i < size; i++ ){
			Object [] objs = (Object [])_deferredInstantiations.get(i);
			
			DeferredKind kind = (DeferredKind) objs[2];
			
			if( kind == DeferredKind.PARENT ){
				DerivableContainerSymbol d = (DerivableContainerSymbol) objs[0];
				d.instantiateDeferredParent( (ISymbol) objs[ 1 ], this, (Map) objs[3] );
			} else if( kind == DeferredKind.RETURN_TYPE ){
				ParameterizedSymbol p = (ParameterizedSymbol) objs[0];
				p.instantiateDeferredReturnType( (ISymbol) objs[1], this, (Map) objs[3] );
			} else if( kind == DeferredKind.TYPE_SYMBOL ){
				TemplateEngine.instantiateDeferredTypeInfo( (TypeInfo) objs[0], this, (Map) objs[3] );
			}
		}
	}
	
	private		List  _specializations         = Collections.EMPTY_LIST;	//template specializations
	private     Map	  _explicitSpecializations = Collections.EMPTY_MAP;		//explicit specializations
	private		Map	  _defnParameterMap        = Collections.EMPTY_MAP;		//members could be defined with different template parameter names
	private 	Map	  _instantiations          = Collections.EMPTY_MAP;
	private     List  _deferredInstantiations  = Collections.EMPTY_LIST;	//used to avoid recursive loop
		
	
}

Back to the top