/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editor.scriptdoc.parsing.reader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.editor.js.JSPlugin;
import com.aptana.ide.editor.js.runtime.Assignment;
import com.aptana.ide.editor.js.runtime.Environment;
import com.aptana.ide.editor.js.runtime.FunctionBase;
import com.aptana.ide.editor.js.runtime.IFunction;
import com.aptana.ide.editor.js.runtime.IObject;
import com.aptana.ide.editor.js.runtime.NativeConstructorBase;
import com.aptana.ide.editor.js.runtime.ObjectBase;
import com.aptana.ide.editor.js.runtime.Property;
import com.aptana.ide.editor.js.runtime.Reference;
import com.aptana.ide.editor.scriptdoc.parsing.AliasEntry;
import com.aptana.ide.editor.scriptdoc.parsing.FunctionDocumentation;
import com.aptana.ide.editor.scriptdoc.parsing.MixinDocumentation;
import com.aptana.ide.editor.scriptdoc.parsing.PropertyDocumentation;
import com.aptana.ide.editor.scriptdoc.parsing.ScriptDoc;
import com.aptana.ide.editor.scriptdoc.parsing.TypedDescription;
import com.aptana.ide.editors.managers.FileContextManager;
import com.aptana.ide.io.TabledInputStream;
import com.aptana.ide.lexer.Range;
import com.aptana.ide.metadata.UserAgent;
/**
* @author Kevin Lindsey
*/
public class NativeObjectsReader2
{
private class FunctionDocumentationPair
{
private IObject _function;
private FunctionDocumentation _documentation;
private String _typeName;
/**
* FunctionDocumentationPair
*
* @param function
* @param documentation
*/
public FunctionDocumentationPair(IObject function, FunctionDocumentation documentation)
{
this._function = function;
this._documentation = documentation;
this._typeName = this._documentation.getName();
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj)
{
boolean result = false;
if (obj == this)
{
result = true;
}
else if (obj instanceof FunctionDocumentation)
{
((FunctionDocumentation) obj).getName().equals(this.getTypeName());
}
return result;
}
/**
* @return the documentation
*/
public FunctionDocumentation getDocumentation()
{
return this._documentation;
}
/**
* @return the function
*/
public IObject getFunction()
{
return this._function;
}
public String[] getSuperTypes()
{
return this._documentation.getExtends().getTypes();
}
/**
* @return the name
*/
public String getTypeName()
{
return this._typeName;
}
/**
* @see java.lang.Object#hashCode()
*/
public int hashCode()
{
return this._typeName.hashCode();
}
}
private static final String CONSTRUCTOR = "constructor"; //$NON-NLS-1$
private static final String CTOR = "#ctor"; //$NON-NLS-1$
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final String GLOBAL = "Global"; //$NON-NLS-1$
private static final String MATH = "Math"; //$NON-NLS-1$
private static final String OBJECT = "Object"; //$NON-NLS-1$
private static final String PROTOTYPE = "prototype"; //$NON-NLS-1$
private static final String WINDOW = "Window"; //$NON-NLS-1$
private static final int FILE_OFFSET = Range.Empty.getStartingOffset();
private int _fileIndex;
private Environment _environment;
private ScriptDoc _docs;
private String _userAgent;
private List<Assignment> _assignments;
/**
* Create a new instance of NativeObjectsReader
*
* @param env
* The JavaScript environment to populate when reading native object documentation
*/
public NativeObjectsReader2(Environment env)
{
this._environment = env;
this._userAgent = EMPTY_STRING;
this._fileIndex = FileContextManager.BUILT_IN_FILE_INDEX;
this._assignments = new ArrayList<Assignment>();
}
/**
* copyProperties
*
* @param source
* @param target
*/
private void copyProperties(IObject source, IObject target)
{
if (source != null && source != ObjectBase.UNDEFINED && target != null && target != ObjectBase.UNDEFINED)
{
// merge parent prototype into child prototype
String[] names = source.getPropertyNames(true);
for (String name : names)
{
if (target.hasLocalProperty(name) == false)
{
this.putLocalProperty(target, name, source.getProperty(name));
}
}
}
}
/**
* createFunction
*
* @return function instance
*/
private IObject createFunction()
{
return this._environment.createFunction(this._fileIndex, Range.Empty);
}
/**
* createNamespace
*
* @param root
* @param fullyQualifiedType
* @return Reference
*/
private Reference createNamespace(IObject root, String fullyQualifiedType)
{
String[] parts = fullyQualifiedType.split("\\."); //$NON-NLS-1$
IObject current = root;
// handle namespace
for (int i = 0; i < parts.length - 1; i++)
{
String propertyName = parts[i];
if (current.hasProperty(propertyName))
{
current = current.getPropertyValue(propertyName, this._fileIndex, FILE_OFFSET);
}
else
{
// create property
IObject instance = this._environment.createObject(this._fileIndex, Range.Empty);
// current.putPropertyValue(propertyName, instance, this._fileIndex, Property.DONT_DELETE);
this.putPropertyValue(current, propertyName, instance, Property.NONE); //Property.DONT_DELETE);
// create user agent
UserAgent ua = new UserAgent();
ua.setDescription(""); //$NON-NLS-1$
ua.setOs(""); //$NON-NLS-1$
ua.setOsVersion(""); //$NON-NLS-1$
ua.setPlatform(this.getUserAgent());
ua.setVersion(""); //$NON-NLS-1$
// create documentation
PropertyDocumentation documentation = new PropertyDocumentation();
documentation.setName(propertyName);
documentation.setUserAgent(this.getUserAgent());
documentation.addUserAgent(ua);
// associate documentation with instance
instance.setDocumentation(documentation);
current = instance;
}
}
String name = parts[parts.length - 1];
return new Reference(current, name);
}
/**
* getAssignments
*
* @return
*/
public Assignment[] getAssignments()
{
// return empty hash for now
return this._assignments.toArray(new Assignment[this._assignments.size()]);
}
/**
* getFileIndex
*/
public int getFileIndex()
{
return this._fileIndex;
}
/**
* Get the underlying ScriptDoc that was created during loading of the documentation data
*
* @return ScriptDoc
*/
public ScriptDoc getScriptDoc()
{
return this._docs;
}
/**
* @return Returns the userAgent.
*/
public String getUserAgent()
{
return this._userAgent;
}
/**
* Load the native objects from the specified input stream
*
* @param stream
* The stream containing the binary native objects documentation
* @throws IOException
*/
public void load(InputStream stream) throws IOException
{
this.load(stream, true);
}
/**
* Load the native objects from the specified input stream
*
* @param stream
* The stream containing the binary native objects documentation
* @param autoCreate
* A flag indicating that objects should be created if they are in the documentation but not in the
* environment
* @throws IOException
*/
public void load(InputStream stream, boolean autoCreate) throws IOException
{
// process the resulting documentation
this._docs = new ScriptDoc();
//DataInputStream input = new DataInputStream(stream);
TabledInputStream input = new TabledInputStream(stream);
this._docs.read(input);
// post-process the doc data
this.postProcess(autoCreate);
}
/**
* Load the native objects from the specified input stream
*
* @param stream
* The stream containing the native objects documentation
* @throws ScriptDocInitializationException
* @throws ScriptDocException
*/
public void loadXML(InputStream stream) throws ScriptDocInitializationException, ScriptDocException
{
this.loadXML(stream, true);
}
/**
* Load the native objects from the specified input stream
*
* @param stream
* The stream containing the native objects documentation
* @param autoCreate
* A flag indicating that objects should be created if they are in the documentation but not in the
* environment
* @throws ScriptDocInitializationException
* @throws ScriptDocException
*/
public void loadXML(InputStream stream, boolean autoCreate) throws ScriptDocInitializationException, ScriptDocException
{
try
{
// create a new documentation reader
ScriptDocReader reader = new ScriptDocReader();
// load the specified document stream
reader.loadXML(stream);
// process the resulting documentation
this._docs = reader.getDocumentation();
// post-process the doc data
this.postProcess(autoCreate);
}
catch (IllegalStateException e)
{
IdeLog.logError(JSPlugin.getDefault(), Messages.NativeObjectsReader2_ERR_Loading_scriptdoc_file, e);
}
}
/**
* Load the specified native objects documentation file
*
* @param filename
* The name of the file to load
* @throws ScriptDocInitializationException
* @throws ScriptDocException
*/
public void loadXML(String filename) throws ScriptDocInitializationException, ScriptDocException
{
this.loadXML(filename, true);
}
/**
* Load the specified native objects documentation file
*
* @param filename
* The name of the file to load
* @param autoCreate
* A flag indicating that objects should be created if they are in the documentation but not in the
* environment
* @throws ScriptDocException
* @throws ScriptDocInitializationException
*/
public void loadXML(String filename, boolean autoCreate) throws ScriptDocInitializationException, ScriptDocException
{
FileInputStream istream = null;
try
{
// create stream
istream = new FileInputStream(filename);
// load stream
this.loadXML(istream, autoCreate);
}
catch (IllegalStateException e)
{
IdeLog.logError(JSPlugin.getDefault(), Messages.NativeObjectsReader2_ERR_Loading_scriptdoc_file, e);
}
catch (FileNotFoundException e)
{
String msg = Messages.NativeObjectsReader_UnalbeToLocateXMLFile + filename;
ScriptDocException de = new ScriptDocException(msg, e);
throw de;
}
finally
{
try
{
// close stream
istream.close();
}
catch (IOException e)
{
String msg = Messages.NativeObjectsReader_IOError;
ScriptDocException de = new ScriptDocException(msg, e);
throw de;
}
}
}
/**
* Post-process the docs that were read in
*
* @param docs
* @param autoCreate
*/
private void postProcess(boolean autoCreate)
{
if (this._environment != null)
{
// process functions first so we'll have constructors when creating
// properties later
FunctionDocumentation[] functions = this._docs.getFunctions();
IObject[] functionInstances = new IObject[functions.length];
for (int i = 0; i < functions.length; i++)
{
FunctionDocumentation currentFunction = functions[i];
// set user agent
currentFunction.setUserAgent(this._userAgent);
// process function
functionInstances[i] = this.processFunction(currentFunction, autoCreate);
}
// process properties
PropertyDocumentation[] properties = this._docs.getProperties();
for (int i = 0; i < properties.length; i++)
{
PropertyDocumentation currentProperty = properties[i];
// set user agent
currentProperty.setUserAgent(this._userAgent);
// process properties
this.processProperty(currentProperty, autoCreate);
}
// process mix-ins
this.processMixins(functions, functionInstances);
// process inheritance last so we get all properties and mix-ins that
// were added to the super classes
this.processInheritance(functions, functionInstances);
// process aliases
this.processAliases();
}
}
/**
* processAliases
*/
private void processAliases()
{
IObject global = this._environment.getGlobal();
for (AliasEntry alias : this._docs.getAliases())
{
Reference aliasProperty = this.createNamespace(global, alias.name);
Reference aliasedProperty = this.createNamespace(global, alias.type);
// aliasProperty.setValue(aliasedProperty.getValue(this._fileIndex, FILE_OFFSET), this._fileIndex);
this.putPropertyValue(
aliasProperty.getObjectBase(),
aliasProperty.getPropertyName(),
aliasedProperty.getValue(this._fileIndex, FILE_OFFSET),
Property.NONE
);
}
}
/**
* Incorporate the current class document into the JavaScript environment
*
* @param documentation
* The class document to process
* @param autoCreate
*/
private IObject processFunction(FunctionDocumentation documentation, boolean autoCreate)
{
IObject[] info = processOwningType(documentation);
IObject root = info[0];
IObject prototype = info[1];
// get function name
String name = documentation.getName();
// setup flags relating to dotted names
boolean dottedName = (name.indexOf('.') != -1);
// see if this exists already
IObject targetFunction = null;
// adjust constructor names
if (name.equals(CTOR))
{
name = CONSTRUCTOR;
documentation.setIsConstructor(true);
targetFunction = root;
}
if (targetFunction == null && documentation.getIsInstance() && prototype.hasLocalProperty(name))
{
targetFunction = prototype.getPropertyValue(name, this._fileIndex, FILE_OFFSET);
}
// if nothing, try as a namespaced function
if ((targetFunction == null || targetFunction == ObjectBase.UNDEFINED) && dottedName)
{
Reference ref = this.createNamespace(root, name);
name = ref.getPropertyName();
root = ref.getObjectBase();
prototype = root.getPropertyValue(PROTOTYPE, this._fileIndex, FILE_OFFSET);
targetFunction = ref.getValue(this._fileIndex, FILE_OFFSET);
}
// if nothing, try as static property
if (targetFunction == null || targetFunction == ObjectBase.UNDEFINED)
{
if (root.hasLocalProperty(name))
{
targetFunction = root.getPropertyValue(name, this._fileIndex, FILE_OFFSET);
}
}
// if still nothing, then create it
if (targetFunction == null || targetFunction == ObjectBase.UNDEFINED)
{
IObject newFunction = this.createFunction();
if (documentation.getIsInstance() == false)
{
// root.putPropertyValue(name, newFunction, this._fileIndex, Property.DONT_DELETE | Property.DONT_ENUM);
this.putPropertyValue(root, name, newFunction, Property.DONT_DELETE | Property.DONT_ENUM);
}
else
{
// prototype.putPropertyValue(name, newFunction, this._fileIndex, Property.DONT_DELETE | Property.DONT_ENUM);
this.putPropertyValue(prototype, name, newFunction, Property.DONT_DELETE | Property.DONT_ENUM);
}
targetFunction = newFunction;
}
// // process any types this inherits from
// String[] types = (documentation != null && documentation.getExtends() != null) ? documentation.getExtends().getTypes() : null;
//
// processParentType(targetFunction, documentation, types);
// associate documentation with object, but don't override documentation for built-ins
if (targetFunction instanceof NativeConstructorBase == false)
{
targetFunction.setDocumentation(documentation);
}
return targetFunction;
}
/**
* processInheritance
*
* @param functions
* @param functionInstances
*/
private void processInheritance(FunctionDocumentation[] functions, IObject[] functionInstances)
{
FunctionDocumentationPair[] pairs = this.sortByInheritanceDependency(functions, functionInstances);
// setup any inheritance
for (FunctionDocumentationPair pair : pairs)
{
IObject functionInstance = pair.getFunction();
FunctionDocumentation documentation = pair.getDocumentation();
String[] types = new String[0];
if (documentation != null)
{
TypedDescription typeInfo = documentation.getExtends();
if (typeInfo != null)
{
types = typeInfo.getTypes();
}
}
for (int i = types.length - 1; i >= 0; i--)
{
String superTypeName = types[i];
// process all non-Object types
if (superTypeName.equals(OBJECT) == false)
{
Reference ref = this.createNamespace(this._environment.getGlobal(), superTypeName);
IObject superTypeConstructor = ref.getValue(this._fileIndex, FILE_OFFSET);
// see if the super type already exists
if (superTypeConstructor != null && superTypeConstructor != ObjectBase.UNDEFINED)
{
Property parentPrototypeProperty = superTypeConstructor.getProperty(PROTOTYPE);
IObject parentPrototype = parentPrototypeProperty.getAssignment(0);
Property childPrototypeProperty = functionInstance.getProperty(PROTOTYPE);
IObject childPrototype = childPrototypeProperty.getAssignment(0);
// merge parent prototype into child prototype
this.copyProperties(parentPrototype, childPrototype);
}
}
}
}
}
/**
* processMixins
* @param functions
* @param functionInstances
*/
private void processMixins(FunctionDocumentation[] functions, IObject[] functionInstances)
{
// setup any inheritance
for (int i = 0; i < functions.length; i++)
{
IObject functionInstance = functionInstances[i];
FunctionDocumentation documentation = functions[i];
MixinDocumentation[] mixins = new MixinDocumentation[0];
if (documentation != null)
{
mixins = documentation.getMixins();
}
for (int j = mixins.length - 1; j >= 0; j--)
{
MixinDocumentation mixin = mixins[j];
String type = mixin.getType();
// process all non-Object types
if (type.equals(OBJECT) == false)
{
IObject sourceObject = this._environment.getGlobal().getPropertyValue(type, this._fileIndex, FILE_OFFSET);
if (sourceObject != null && sourceObject != ObjectBase.UNDEFINED)
{
IObject targetObject = functionInstance;
if (mixin.getSourceInstanceProperties() == false)
{
// grab prototype
sourceObject = sourceObject.getProperty(PROTOTYPE).getAssignment(0);
}
if (mixin.getTargetInstanceProperties() == false)
{
// grab prototype
targetObject = targetObject.getProperty(PROTOTYPE).getAssignment(0);
}
this.copyProperties(sourceObject, targetObject);
}
}
}
}
}
/**
* processOwningType
*
* @return Reference
*/
private IObject[] processOwningType(FunctionDocumentation documentation)
{
IObject root = this._environment.getGlobal();
IObject prototype = ObjectBase.UNDEFINED;
String owningType = EMPTY_STRING;
// return owning type from docs
if (documentation.getMemberOf().getTypes().length > 0)
{
owningType = documentation.getMemberOf().getTypes()[0];
}
// global level function like 'Date'
if (owningType.equals(EMPTY_STRING))
{
prototype = root;
documentation.getReturn().clearTypes();
documentation.getReturn().addType(documentation.getName());
}
// note: docs like Math come from xml0, and are in Window in the xml
else if (owningType.equals(GLOBAL) == false && owningType.equals(WINDOW) == false)
{
// global level function
IObject ob = root.getPropertyValue(owningType, this._fileIndex, FILE_OFFSET);
if (ob == ObjectBase.UNDEFINED && owningType.indexOf('.') != -1) //$NON-NLS-1$
{
Reference ref = this.createNamespace(root, owningType);
owningType = ref.getPropertyName();
root = ref.getObjectBase();
ob = ref.getValue(this._fileIndex, FILE_OFFSET);
}
if (ob == ObjectBase.UNDEFINED)
{
// root.putPropertyValue(
// owningType,
// this.createFunction(),
// this._fileIndex,
// Property.DONT_DELETE | Property.DONT_ENUM
// );
this.putPropertyValue(root, owningType, this.createFunction(), Property.DONT_DELETE | Property.DONT_ENUM);
// create documentation
FunctionDocumentation fDoc = new FunctionDocumentation();
fDoc.setName(owningType);
fDoc.setIsConstructor(true);
// associate documentation with owning type
ob = root.getPropertyValue(owningType, this._fileIndex, FILE_OFFSET);
ob.setDocumentation(fDoc);
}
root = ob;
prototype = ob.getPropertyValue(PROTOTYPE, this._fileIndex, FILE_OFFSET);
}
else
{
prototype = root.getPropertyValue(PROTOTYPE, this._fileIndex, FILE_OFFSET);
// for built in's, global prototype isn't set yet, but uncreated instances (like parseInt) can go on global
// as well.
if (prototype == null || prototype == ObjectBase.UNDEFINED)
{
prototype = root;
}
}
return new IObject[] { root, prototype };
}
/**
* processProperty
*
* @param documentation
* @param autoCreate
*/
private void processProperty(PropertyDocumentation documentation, boolean autoCreate)
{
IObject[] info = this.processPropertyType(documentation);
IObject root = info[0];
IObject prototype = info[1];
// determine if this property is static
boolean isStatic = (documentation != null && documentation.getIsInstance() == false);
// get property name
String name = documentation.getName();
// see if we have the property
IObject propertyObject = null;
if (isStatic == false && prototype.hasLocalProperty(name))
{
propertyObject = prototype.getPropertyValue(name, this._fileIndex, FILE_OFFSET);
}
// if nothing, try accessing as a static property
if ((propertyObject == null || propertyObject == ObjectBase.UNDEFINED) && isStatic)
{
if (root.hasLocalProperty(name))
{
propertyObject = root.getPropertyValue(name, this._fileIndex, FILE_OFFSET);
}
}
// if still nothing, create the object
if (propertyObject == null || propertyObject == ObjectBase.UNDEFINED)
{
String[] types = documentation.getReturn().getTypes();
IObject type = null;
IObject newobj = null;
if (types != null && types.length > 0)
{
String typeName = types[0];
Reference ref = this.createNamespace(this._environment.getGlobal(), typeName);
type = ref.getValue(this._fileIndex, FILE_OFFSET);
}
if (type instanceof IFunction)
{
newobj = ((IFunction) type).construct(this._environment, FunctionBase.EmptyArgs, this._fileIndex, Range.Empty);
}
else
{
newobj = this._environment.createObject(this._fileIndex, Range.Empty);
}
if (isStatic)
{
// root.putPropertyValue(name, newobj, this._fileIndex, Property.DONT_DELETE | Property.DONT_ENUM);
this.putPropertyValue(root, name, newobj, Property.DONT_DELETE | Property.DONT_ENUM);
}
else
{
// prototype.putPropertyValue(name, newobj, this._fileIndex, Property.DONT_DELETE | Property.DONT_ENUM);
this.putPropertyValue(prototype, name, newobj, Property.DONT_DELETE | Property.DONT_ENUM);
}
propertyObject = newobj;
}
// process owning type
propertyObject.setDocumentation(documentation);
// processParentType(propertyObject, documentation, documentation.getMemberOf().getTypes());
}
/**
* processPropertyType
*
* @return IObject[]
*/
private IObject[] processPropertyType(PropertyDocumentation propertyDoc)
{
IObject root = this._environment.getGlobal();
IObject prototype = ObjectBase.UNDEFINED;
String name = propertyDoc.getName();
String type = propertyDoc.getMemberOf().getTypes()[0];
// Math is a special case for a return type, so we'll leave this
if (name.equals(MATH))
{
TypedDescription desc = propertyDoc.getReturn();
desc.clearTypes();
desc.addType(MATH); //$NON-NLS-1$
}
// note: docs like Math come from xml0, and are in Window in the xml
if (type.equals(GLOBAL) == false && type.equals(WINDOW) == false)
{
// global level function
IObject ob = root.getPropertyValue(type, this._fileIndex, FILE_OFFSET);
if (ob == ObjectBase.UNDEFINED && type.indexOf('.') != -1) //$NON-NLS-1$
{
Reference ref = this.createNamespace(root, type);
type = ref.getPropertyName();
root = ref.getObjectBase();
ob = ref.getValue(this._fileIndex, FILE_OFFSET);
}
if (ob == ObjectBase.UNDEFINED)
{
// root.putPropertyValue(
// type,
// this.createFunction(),
// this._fileIndex,
// Property.DONT_DELETE | Property.DONT_ENUM
// );
this.putPropertyValue(root, type, this.createFunction(), Property.DONT_DELETE | Property.DONT_ENUM);
// create documentation
FunctionDocumentation fDoc = new FunctionDocumentation();
fDoc.setName(type);
fDoc.setIsConstructor(true);
// associate documentation with owning type
ob = root.getPropertyValue(type, this._fileIndex, FILE_OFFSET);
ob.setDocumentation(fDoc);
}
root = ob;
prototype = ob.getPropertyValue(PROTOTYPE, this._fileIndex, FILE_OFFSET);
}
else
{
prototype = root.getPropertyValue(PROTOTYPE, this._fileIndex, FILE_OFFSET);
}
return new IObject[] { root, prototype };
}
/**
* putLocalProperty
*
* @param parentObject
* @param propertyName
* @param property
*/
private void putLocalProperty(IObject parentObject, String propertyName, Property property)
{
// set property
parentObject.putLocalProperty(propertyName, property);
// create reference and assignment
Reference reference = new Reference(parentObject, propertyName);
Assignment assignment = new Assignment(reference, null);
// add to list of updated properties
this._assignments.add(assignment);
}
/**
* putPropertyValue
*
* @param parentObject
* @param propertyName
* @param value
* @param attributes
*/
private void putPropertyValue(IObject parentObject, String propertyName, IObject value, int attributes)
{
// set property value
parentObject.putPropertyValue(propertyName, value, this._fileIndex, attributes);
// create reference and assignment
Reference reference = new Reference(parentObject, propertyName);
Assignment assignment = new Assignment(reference, value);
// add to list of updated properties
this._assignments.add(assignment);
}
/**
* setFileIndex
*
* @param fileIndex
*/
public void setFileIndex(int fileIndex)
{
this._fileIndex = fileIndex;
}
/**
* @param userAgent The userAgent to set.
*/
public void setUserAgent(String userAgent)
{
this._userAgent = userAgent;
}
/**
* FunctionDocumentationPair
*
* @param functions
* @param functionInstances
* @return
*/
private FunctionDocumentationPair[] sortByInheritanceDependency(FunctionDocumentation[] functions, IObject[] functionInstances)
{
SimpleDependencyGraph<FunctionDocumentationPair> graph = new SimpleDependencyGraph<FunctionDocumentationPair>();
// generate mappings and vertices
for (int i = 0; i < functions.length; i++)
{
// combine function and documentation
FunctionDocumentationPair pair = new FunctionDocumentationPair(functionInstances[i], functions[i]);
// get type name
String type = pair.getTypeName();
if (CTOR.equals(type) == false)
{
// store reference into graph for later lookup by name
graph.addMapping(type, pair);
// add vertex
graph.addVertex(type);
}
}
// process all vertices
for (FunctionDocumentation documentation : functions)
{
String type = documentation.getName();
if (CTOR.equals(type) == false)
{
for (String superType : documentation.getExtends().getTypes())
{
if ("Object".equals(superType) == false && CTOR.equals(superType) == false) //$NON-NLS-1$
{
graph.addEdge(type, superType);
}
}
}
}
// sort
String[] types = graph.topologicalSort();
// build result
FunctionDocumentationPair[] result = new FunctionDocumentationPair[types.length];
for (int i = 0; i < types.length; i++)
{
result[i] = graph.getItem(types[i]);
}
return result;
}
}