638 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			638 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C)2005-2019 Haxe Foundation
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
 * copy of this software and associated documentation files (the "Software"),
 | 
						|
 * to deal in the Software without restriction, including without limitation
 | 
						|
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						|
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
						|
 * Software is furnished to do so, subject to the following conditions:
 | 
						|
 *
 | 
						|
 * The above copyright notice and this permission notice shall be included in
 | 
						|
 * all copies or substantial portions of the Software.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
						|
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
						|
 * DEALINGS IN THE SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
package haxe.rtti;
 | 
						|
 | 
						|
import haxe.rtti.CType;
 | 
						|
import haxe.xml.Access;
 | 
						|
 | 
						|
/**
 | 
						|
	XmlParser processes the runtime type information (RTTI) which
 | 
						|
	is stored as a XML string in a static field `__rtti`.
 | 
						|
 | 
						|
	@see <https://haxe.org/manual/cr-rtti.html>
 | 
						|
**/
 | 
						|
class XmlParser {
 | 
						|
	public var root:TypeRoot;
 | 
						|
 | 
						|
	var curplatform:String;
 | 
						|
 | 
						|
	public function new() {
 | 
						|
		root = new Array();
 | 
						|
	}
 | 
						|
 | 
						|
	public function sort(?l:TypeRoot) {
 | 
						|
		if (l == null)
 | 
						|
			l = root;
 | 
						|
		l.sort(function(e1, e2) {
 | 
						|
			var n1 = switch e1 {
 | 
						|
				case TPackage(p, _, _): " " + p;
 | 
						|
				default: TypeApi.typeInfos(e1).path;
 | 
						|
			};
 | 
						|
			var n2 = switch e2 {
 | 
						|
				case TPackage(p, _, _): " " + p;
 | 
						|
				default: TypeApi.typeInfos(e2).path;
 | 
						|
			};
 | 
						|
			if (n1 > n2)
 | 
						|
				return 1;
 | 
						|
			return -1;
 | 
						|
		});
 | 
						|
		for (x in l)
 | 
						|
			switch (x) {
 | 
						|
				case TPackage(_, _, l):
 | 
						|
					sort(l);
 | 
						|
				case TClassdecl(c):
 | 
						|
					sortFields(c.fields);
 | 
						|
					sortFields(c.statics);
 | 
						|
				case TEnumdecl(_):
 | 
						|
				case TAbstractdecl(_):
 | 
						|
				case TTypedecl(_):
 | 
						|
			}
 | 
						|
	}
 | 
						|
 | 
						|
	function sortFields(a:Array<ClassField>) {
 | 
						|
		a.sort(function(f1:ClassField, f2:ClassField) {
 | 
						|
			var v1 = TypeApi.isVar(f1.type);
 | 
						|
			var v2 = TypeApi.isVar(f2.type);
 | 
						|
			if (v1 && !v2)
 | 
						|
				return -1;
 | 
						|
			if (v2 && !v1)
 | 
						|
				return 1;
 | 
						|
			if (f1.name == "new")
 | 
						|
				return -1;
 | 
						|
			if (f2.name == "new")
 | 
						|
				return 1;
 | 
						|
			if (f1.name > f2.name)
 | 
						|
				return 1;
 | 
						|
			return -1;
 | 
						|
		});
 | 
						|
	}
 | 
						|
 | 
						|
	public function process(x:Xml, platform:String) {
 | 
						|
		curplatform = platform;
 | 
						|
		xroot(new Access(x));
 | 
						|
	}
 | 
						|
 | 
						|
	// merge inline and not inline
 | 
						|
	function mergeRights(f1:ClassField, f2:ClassField) {
 | 
						|
		if (f1.get == RInline && f1.set == RNo && f2.get == RNormal && f2.set == RMethod) {
 | 
						|
			f1.get = RNormal;
 | 
						|
			f1.set = RMethod;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		return Type.enumEq(f1.get, f2.get) && Type.enumEq(f1.set, f2.set);
 | 
						|
	}
 | 
						|
 | 
						|
	function mergeDoc(f1:ClassField, f2:ClassField) {
 | 
						|
		if (f1.doc == null)
 | 
						|
			f1.doc = f2.doc;
 | 
						|
		else if (f2.doc == null)
 | 
						|
			f2.doc = f1.doc;
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	function mergeFields(f:ClassField, f2:ClassField) {
 | 
						|
		return TypeApi.fieldEq(f, f2)
 | 
						|
			|| (f.name == f2.name && (mergeRights(f, f2) || mergeRights(f2, f)) && mergeDoc(f, f2) && TypeApi.fieldEq(f, f2));
 | 
						|
	}
 | 
						|
 | 
						|
	public dynamic function newField(c:Classdef, f:ClassField) {}
 | 
						|
 | 
						|
	function mergeClasses(c:Classdef, c2:Classdef) {
 | 
						|
		// todo : compare supers & interfaces
 | 
						|
		if (c.isInterface != c2.isInterface)
 | 
						|
			return false;
 | 
						|
		if (curplatform != null)
 | 
						|
			c.platforms.push(curplatform);
 | 
						|
		if (c.isExtern != c2.isExtern)
 | 
						|
			c.isExtern = false;
 | 
						|
 | 
						|
		for (f2 in c2.fields) {
 | 
						|
			var found = null;
 | 
						|
			for (f in c.fields)
 | 
						|
				if (mergeFields(f, f2)) {
 | 
						|
					found = f;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			if (found == null) {
 | 
						|
				newField(c, f2);
 | 
						|
				c.fields.push(f2);
 | 
						|
			} else if (curplatform != null)
 | 
						|
				found.platforms.push(curplatform);
 | 
						|
		}
 | 
						|
		for (f2 in c2.statics) {
 | 
						|
			var found = null;
 | 
						|
			for (f in c.statics)
 | 
						|
				if (mergeFields(f, f2)) {
 | 
						|
					found = f;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			if (found == null) {
 | 
						|
				newField(c, f2);
 | 
						|
				c.statics.push(f2);
 | 
						|
			} else if (curplatform != null)
 | 
						|
				found.platforms.push(curplatform);
 | 
						|
		}
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	function mergeEnums(e:Enumdef, e2:Enumdef) {
 | 
						|
		if (e.isExtern != e2.isExtern)
 | 
						|
			return false;
 | 
						|
		if (curplatform != null)
 | 
						|
			e.platforms.push(curplatform);
 | 
						|
		for (c2 in e2.constructors) {
 | 
						|
			var found = null;
 | 
						|
			for (c in e.constructors)
 | 
						|
				if (TypeApi.constructorEq(c, c2)) {
 | 
						|
					found = c;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			if (found == null)
 | 
						|
				e.constructors.push(c2);
 | 
						|
			else if (curplatform != null)
 | 
						|
				found.platforms.push(curplatform);
 | 
						|
		}
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	function mergeTypedefs(t:Typedef, t2:Typedef) {
 | 
						|
		if (curplatform == null)
 | 
						|
			return false;
 | 
						|
		t.platforms.push(curplatform);
 | 
						|
		t.types.set(curplatform, t2.type);
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	function mergeAbstracts(a:Abstractdef, a2:Abstractdef) {
 | 
						|
		if (curplatform == null)
 | 
						|
			return false;
 | 
						|
		if (a.to.length != a2.to.length || a.from.length != a2.from.length)
 | 
						|
			return false;
 | 
						|
		for (i in 0...a.to.length)
 | 
						|
			if (!TypeApi.typeEq(a.to[i].t, a2.to[i].t))
 | 
						|
				return false;
 | 
						|
		for (i in 0...a.from.length)
 | 
						|
			if (!TypeApi.typeEq(a.from[i].t, a2.from[i].t))
 | 
						|
				return false;
 | 
						|
		if (a2.impl != null)
 | 
						|
			mergeClasses(a.impl, a2.impl);
 | 
						|
		a.platforms.push(curplatform);
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
	function merge(t:TypeTree) {
 | 
						|
		var inf = TypeApi.typeInfos(t);
 | 
						|
		var pack = inf.path.split(".");
 | 
						|
		var cur = root;
 | 
						|
		var curpack = new Array();
 | 
						|
		pack.pop();
 | 
						|
		for (p in pack) {
 | 
						|
			var found = false;
 | 
						|
			for (pk in cur)
 | 
						|
				switch (pk) {
 | 
						|
					case TPackage(pname, _, subs):
 | 
						|
						if (pname == p) {
 | 
						|
							found = true;
 | 
						|
							cur = subs;
 | 
						|
							break;
 | 
						|
						}
 | 
						|
					default:
 | 
						|
				}
 | 
						|
			curpack.push(p);
 | 
						|
			if (!found) {
 | 
						|
				var pk = new Array();
 | 
						|
				cur.push(TPackage(p, curpack.join("."), pk));
 | 
						|
				cur = pk;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		for (ct in cur) {
 | 
						|
			if (ct.match(TPackage(_)))
 | 
						|
				continue;
 | 
						|
			var tinf = TypeApi.typeInfos(ct);
 | 
						|
 | 
						|
			// compare params ?
 | 
						|
			if (tinf.path == inf.path) {
 | 
						|
				var sameType = true;
 | 
						|
				if ((tinf.doc == null) != (inf.doc == null)) {
 | 
						|
					if (inf.doc == null)
 | 
						|
						inf.doc = tinf.doc;
 | 
						|
					else
 | 
						|
						tinf.doc = inf.doc;
 | 
						|
				}
 | 
						|
				if (tinf.path == "haxe._Int64.NativeInt64")
 | 
						|
					continue;
 | 
						|
				if (tinf.module == inf.module && tinf.doc == inf.doc && tinf.isPrivate == inf.isPrivate)
 | 
						|
					switch (ct) {
 | 
						|
						case TClassdecl(c):
 | 
						|
							switch (t) {
 | 
						|
								case TClassdecl(c2):
 | 
						|
									if (mergeClasses(c, c2))
 | 
						|
										return;
 | 
						|
								default:
 | 
						|
									sameType = false;
 | 
						|
							}
 | 
						|
						case TEnumdecl(e):
 | 
						|
							switch (t) {
 | 
						|
								case TEnumdecl(e2):
 | 
						|
									if (mergeEnums(e, e2))
 | 
						|
										return;
 | 
						|
								default:
 | 
						|
									sameType = false;
 | 
						|
							}
 | 
						|
						case TTypedecl(td):
 | 
						|
							switch (t) {
 | 
						|
								case TTypedecl(td2):
 | 
						|
									if (mergeTypedefs(td, td2))
 | 
						|
										return;
 | 
						|
								default:
 | 
						|
							}
 | 
						|
						case TAbstractdecl(a):
 | 
						|
							switch (t) {
 | 
						|
								case TAbstractdecl(a2):
 | 
						|
									if (mergeAbstracts(a, a2))
 | 
						|
										return;
 | 
						|
								default:
 | 
						|
									sameType = false;
 | 
						|
							}
 | 
						|
						case TPackage(_, _, _):
 | 
						|
							sameType = false;
 | 
						|
					}
 | 
						|
				// we already have a mapping, but which is incompatible
 | 
						|
				var msg = if (tinf.module != inf.module) "module " + inf.module + " should be " + tinf.module; else if (tinf.doc != inf.doc)
 | 
						|
					"documentation is different";
 | 
						|
				else if (tinf.isPrivate != inf.isPrivate)
 | 
						|
					"private flag is different";
 | 
						|
				else if (!sameType)
 | 
						|
					"type kind is different";
 | 
						|
				else
 | 
						|
					"could not merge definition";
 | 
						|
				throw "Incompatibilities between " + tinf.path + " in " + tinf.platforms.join(",") + " and " + curplatform + " (" + msg + ")";
 | 
						|
			}
 | 
						|
		}
 | 
						|
		cur.push(t);
 | 
						|
	}
 | 
						|
 | 
						|
	function mkPath(p:String):Path {
 | 
						|
		return p;
 | 
						|
	}
 | 
						|
 | 
						|
	function mkTypeParams(p:String):TypeParams {
 | 
						|
		var pl = p.split(":");
 | 
						|
		if (pl[0] == "")
 | 
						|
			return new Array();
 | 
						|
		return pl;
 | 
						|
	}
 | 
						|
 | 
						|
	function mkRights(r:String):Rights {
 | 
						|
		return switch (r) {
 | 
						|
			case "null": RNo;
 | 
						|
			case "method": RMethod;
 | 
						|
			case "dynamic": RDynamic;
 | 
						|
			case "inline": RInline;
 | 
						|
			default: RCall(r);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	function xerror(c:Access):Dynamic {
 | 
						|
		return throw "Invalid " + c.name;
 | 
						|
	}
 | 
						|
 | 
						|
	function xroot(x:Access) {
 | 
						|
		for (c in x.x.elements())
 | 
						|
			merge(processElement(c));
 | 
						|
	}
 | 
						|
 | 
						|
	public function processElement(x:Xml) {
 | 
						|
		var c = new haxe.xml.Access(x);
 | 
						|
		return switch (c.name) {
 | 
						|
			case "class": TClassdecl(xclass(c));
 | 
						|
			case "enum": TEnumdecl(xenum(c));
 | 
						|
			case "typedef": TTypedecl(xtypedef(c));
 | 
						|
			case "abstract": TAbstractdecl(xabstract(c));
 | 
						|
			default: xerror(c);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	function xmeta(x:Access):MetaData {
 | 
						|
		var ml = [];
 | 
						|
		for (m in x.nodes.m) {
 | 
						|
			var pl = [];
 | 
						|
			for (p in m.nodes.e)
 | 
						|
				pl.push(p.innerHTML);
 | 
						|
			ml.push({name: m.att.n, params: pl});
 | 
						|
		}
 | 
						|
		return ml;
 | 
						|
	}
 | 
						|
 | 
						|
	function xoverloads(x:Access):Array<ClassField> {
 | 
						|
		var l = new Array();
 | 
						|
		for (m in x.elements) {
 | 
						|
			l.push(xclassfield(m));
 | 
						|
		}
 | 
						|
		return l;
 | 
						|
	}
 | 
						|
 | 
						|
	function xpath(x:Access):PathParams {
 | 
						|
		var path = mkPath(x.att.path);
 | 
						|
		var params = new Array();
 | 
						|
		for (c in x.elements)
 | 
						|
			params.push(xtype(c));
 | 
						|
		return {
 | 
						|
			path: path,
 | 
						|
			params: params,
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xclass(x:Access):Classdef {
 | 
						|
		var csuper = null;
 | 
						|
		var doc = null;
 | 
						|
		var tdynamic = null;
 | 
						|
		var interfaces = new Array();
 | 
						|
		var fields = new Array();
 | 
						|
		var statics = new Array();
 | 
						|
		var meta = [];
 | 
						|
		var isInterface = x.x.exists("interface");
 | 
						|
		for (c in x.elements)
 | 
						|
			switch (c.name) {
 | 
						|
				case "haxe_doc":
 | 
						|
					doc = c.innerData;
 | 
						|
				case "extends":
 | 
						|
					if (isInterface) {
 | 
						|
						interfaces.push(xpath(c));
 | 
						|
					} else {
 | 
						|
						csuper = xpath(c);
 | 
						|
					}
 | 
						|
				case "implements":
 | 
						|
					interfaces.push(xpath(c));
 | 
						|
				case "haxe_dynamic":
 | 
						|
					tdynamic = xtype(new Access(c.x.firstElement()));
 | 
						|
				case "meta":
 | 
						|
					meta = xmeta(c);
 | 
						|
				default:
 | 
						|
					if (c.x.exists("static"))
 | 
						|
						statics.push(xclassfield(c));
 | 
						|
					else
 | 
						|
						fields.push(xclassfield(c));
 | 
						|
			}
 | 
						|
		return {
 | 
						|
			file: if (x.has.file) x.att.file else null,
 | 
						|
			path: mkPath(x.att.path),
 | 
						|
			module: if (x.has.module) mkPath(x.att.module) else null,
 | 
						|
			doc: doc,
 | 
						|
			isPrivate: x.x.exists("private"),
 | 
						|
			isExtern: x.x.exists("extern"),
 | 
						|
			isFinal: x.x.exists("final"),
 | 
						|
			isInterface: isInterface,
 | 
						|
			params: mkTypeParams(x.att.params),
 | 
						|
			superClass: csuper,
 | 
						|
			interfaces: interfaces,
 | 
						|
			fields: fields,
 | 
						|
			statics: statics,
 | 
						|
			tdynamic: tdynamic,
 | 
						|
			platforms: defplat(),
 | 
						|
			meta: meta,
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xclassfield(x:Access, ?defPublic = false):ClassField {
 | 
						|
		var e = x.elements;
 | 
						|
		var t = xtype(e.next());
 | 
						|
		var doc = null;
 | 
						|
		var meta = [];
 | 
						|
		var overloads = null;
 | 
						|
		for (c in e)
 | 
						|
			switch (c.name) {
 | 
						|
				case "haxe_doc":
 | 
						|
					doc = c.innerData;
 | 
						|
				case "meta":
 | 
						|
					meta = xmeta(c);
 | 
						|
				case "overloads":
 | 
						|
					overloads = xoverloads(c);
 | 
						|
				default:
 | 
						|
					xerror(c);
 | 
						|
			}
 | 
						|
		return {
 | 
						|
			name:x.name, type:t, isPublic:x.x.exists("public") || defPublic, isFinal:x.x.exists("final"), isOverride:x.x.exists("override"),
 | 
						|
			line:if (x.has.line) Std.parseInt(x.att.line) else null, doc:doc, get:if (x.has.get) mkRights(x.att.get) else RNormal, set:if (x.has.set)
 | 
						|
				mkRights(x.att.set)
 | 
						|
			else
 | 
						|
				RNormal, params:if (x.has.params) mkTypeParams(x.att.params) else [], platforms:defplat(), meta:meta, overloads:overloads, expr:if (x.has.expr)
 | 
						|
				x.att.expr
 | 
						|
			else
 | 
						|
				null
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xenum(x:Access):Enumdef {
 | 
						|
		var cl = new Array();
 | 
						|
		var doc = null;
 | 
						|
		var meta = [];
 | 
						|
		for (c in x.elements)
 | 
						|
			if (c.name == "haxe_doc")
 | 
						|
				doc = c.innerData;
 | 
						|
			else if (c.name == "meta")
 | 
						|
				meta = xmeta(c);
 | 
						|
			else
 | 
						|
				cl.push(xenumfield(c));
 | 
						|
		return {
 | 
						|
			file: if (x.has.file) x.att.file else null,
 | 
						|
			path: mkPath(x.att.path),
 | 
						|
			module: if (x.has.module) mkPath(x.att.module) else null,
 | 
						|
			doc: doc,
 | 
						|
			isPrivate: x.x.exists("private"),
 | 
						|
			isExtern: x.x.exists("extern"),
 | 
						|
			params: mkTypeParams(x.att.params),
 | 
						|
			constructors: cl,
 | 
						|
			platforms: defplat(),
 | 
						|
			meta: meta,
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xenumfield(x:Access):EnumField {
 | 
						|
		var args = null;
 | 
						|
		var docElements = x.x.elementsNamed("haxe_doc");
 | 
						|
		var xdoc = if (docElements.hasNext()) docElements.next() else null;
 | 
						|
		var meta = if (x.hasNode.meta) xmeta(x.node.meta) else [];
 | 
						|
		if (x.has.a) {
 | 
						|
			var names = x.att.a.split(":");
 | 
						|
			var elts = x.elements;
 | 
						|
			args = new Array();
 | 
						|
			for (c in names) {
 | 
						|
				var opt = false;
 | 
						|
				if (c.charAt(0) == "?") {
 | 
						|
					opt = true;
 | 
						|
					c = c.substr(1);
 | 
						|
				}
 | 
						|
				args.push({
 | 
						|
					name: c,
 | 
						|
					opt: opt,
 | 
						|
					t: xtype(elts.next()),
 | 
						|
				});
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return {
 | 
						|
			name: x.name,
 | 
						|
			args: args,
 | 
						|
			doc: if (xdoc == null) null else new Access(xdoc).innerData,
 | 
						|
			meta: meta,
 | 
						|
			platforms: defplat(),
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xabstract(x:Access):Abstractdef {
 | 
						|
		var doc = null, impl = null, athis = null;
 | 
						|
		var meta = [], to = [], from = [];
 | 
						|
		for (c in x.elements)
 | 
						|
			switch (c.name) {
 | 
						|
				case "haxe_doc":
 | 
						|
					doc = c.innerData;
 | 
						|
				case "meta":
 | 
						|
					meta = xmeta(c);
 | 
						|
				case "to":
 | 
						|
					for (t in c.elements)
 | 
						|
						to.push({t: xtype(new Access(t.x.firstElement())), field: t.has.field ? t.att.field : null});
 | 
						|
				case "from":
 | 
						|
					for (t in c.elements)
 | 
						|
						from.push({t: xtype(new Access(t.x.firstElement())), field: t.has.field ? t.att.field : null});
 | 
						|
				case "impl":
 | 
						|
					impl = xclass(c.node.resolve("class"));
 | 
						|
				case "this":
 | 
						|
					athis = xtype(new Access(c.x.firstElement()));
 | 
						|
				default:
 | 
						|
					xerror(c);
 | 
						|
			}
 | 
						|
		return {
 | 
						|
			file: if (x.has.file) x.att.file else null,
 | 
						|
			path: mkPath(x.att.path),
 | 
						|
			module: if (x.has.module) mkPath(x.att.module) else null,
 | 
						|
			doc: doc,
 | 
						|
			isPrivate: x.x.exists("private"),
 | 
						|
			params: mkTypeParams(x.att.params),
 | 
						|
			platforms: defplat(),
 | 
						|
			meta: meta,
 | 
						|
			athis: athis,
 | 
						|
			to: to,
 | 
						|
			from: from,
 | 
						|
			impl: impl
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xtypedef(x:Access):Typedef {
 | 
						|
		var doc = null;
 | 
						|
		var t = null;
 | 
						|
		var meta = [];
 | 
						|
		for (c in x.elements)
 | 
						|
			if (c.name == "haxe_doc")
 | 
						|
				doc = c.innerData;
 | 
						|
			else if (c.name == "meta")
 | 
						|
				meta = xmeta(c);
 | 
						|
			else
 | 
						|
				t = xtype(c);
 | 
						|
		var types = new haxe.ds.StringMap();
 | 
						|
		if (curplatform != null)
 | 
						|
			types.set(curplatform, t);
 | 
						|
		return {
 | 
						|
			file: if (x.has.file) x.att.file else null,
 | 
						|
			path: mkPath(x.att.path),
 | 
						|
			module: if (x.has.module) mkPath(x.att.module) else null,
 | 
						|
			doc: doc,
 | 
						|
			isPrivate: x.x.exists("private"),
 | 
						|
			params: mkTypeParams(x.att.params),
 | 
						|
			type: t,
 | 
						|
			types: types,
 | 
						|
			platforms: defplat(),
 | 
						|
			meta: meta,
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	function xtype(x:Access):CType {
 | 
						|
		return switch (x.name) {
 | 
						|
			case "unknown":
 | 
						|
				CUnknown;
 | 
						|
			case "e":
 | 
						|
				CEnum(mkPath(x.att.path), xtypeparams(x));
 | 
						|
			case "c":
 | 
						|
				CClass(mkPath(x.att.path), xtypeparams(x));
 | 
						|
			case "t":
 | 
						|
				CTypedef(mkPath(x.att.path), xtypeparams(x));
 | 
						|
			case "x":
 | 
						|
				CAbstract(mkPath(x.att.path), xtypeparams(x));
 | 
						|
			case "f":
 | 
						|
				var args = new Array();
 | 
						|
				var aname = x.att.a.split(":");
 | 
						|
				var eargs = aname.iterator();
 | 
						|
				var evalues = x.has.v ? x.att.v.split(":").iterator() : null;
 | 
						|
				for (e in x.elements) {
 | 
						|
					var opt = false;
 | 
						|
					var a = eargs.hasNext() ? eargs.next() : null;
 | 
						|
					if (a == null)
 | 
						|
						a = "";
 | 
						|
					if (a.charAt(0) == "?") {
 | 
						|
						opt = true;
 | 
						|
						a = a.substr(1);
 | 
						|
					}
 | 
						|
					var v = evalues == null || !evalues.hasNext() ? null : evalues.next();
 | 
						|
					args.push({
 | 
						|
						name: a,
 | 
						|
						opt: opt,
 | 
						|
						t: xtype(e),
 | 
						|
						value: v == "" ? null : v
 | 
						|
					});
 | 
						|
				}
 | 
						|
				var ret = args[args.length - 1];
 | 
						|
				args.remove(ret);
 | 
						|
				CFunction(args, ret.t);
 | 
						|
			case "a":
 | 
						|
				var fields = new Array();
 | 
						|
				for (f in x.elements) {
 | 
						|
					var f = xclassfield(f, true);
 | 
						|
					f.platforms = new Array(); // platforms selection are on the type itself, not on fields
 | 
						|
					fields.push(f);
 | 
						|
				}
 | 
						|
				CAnonymous(fields);
 | 
						|
			case "d":
 | 
						|
				var t = null;
 | 
						|
				var tx = x.x.firstElement();
 | 
						|
				if (tx != null)
 | 
						|
					t = xtype(new Access(tx));
 | 
						|
				CDynamic(t);
 | 
						|
			default:
 | 
						|
				xerror(x);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	function xtypeparams(x:Access):Array<CType> {
 | 
						|
		var p = new Array();
 | 
						|
		for (c in x.elements)
 | 
						|
			p.push(xtype(c));
 | 
						|
		return p;
 | 
						|
	}
 | 
						|
 | 
						|
	function defplat() {
 | 
						|
		var l = new Array();
 | 
						|
		if (curplatform != null)
 | 
						|
			l.push(curplatform);
 | 
						|
		return l;
 | 
						|
	}
 | 
						|
}
 |