Skip to content
Browse files

Multiple inheritance, fixes & stuff

  • Loading branch information...
1 parent 4ffade9 commit 5212b15249d2e1bc24bcc2e2c35a7d8b1412d176 @codeboost committed May 25, 2011
Showing with 644 additions and 198 deletions.
  1. +25 −9 bealoader.js
  2. +5 −1 beaparser.js
  3. +4 −2 beaproc.js
  4. +19 −11 beautils.js
  5. +203 −61 classconvert.js
  6. +56 −13 mgr.js
  7. +1 −1 snippets.js
  8. +23 −12 src/bealoader.coffee
  9. +6 −1 src/beaparser.coffee
  10. +3 −3 src/beaproc.coffee
  11. +22 −9 src/beautils.coffee
  12. +226 −63 src/classconvert.coffee
  13. +50 −11 src/mgr.coffee
  14. +1 −1 src/snippets.coffee
View
34 bealoader.js
@@ -59,17 +59,22 @@
})) {
return this.warn("File " + fileName + " already included!", node);
}
+ console.log('Included file ' + fileName);
return this.parseFile(fileName);
};
RecursiveParser.prototype.processIncludes = function(root) {
- var children;
+ var children, gr;
children = root.children;
+ gr = 0;
_.each(root.children, __bind(function(node, i) {
var ret, retc, _ref;
if (node.type() === '@include') {
ret = this.include(node);
retc = (_ref = ret != null ? ret.children : void 0) != null ? _ref : [];
- return children = children.slice(0, i).concat(retc, children.slice(i + 1));
+ children = children.slice(0, i + gr).concat(retc, children.slice(i + gr + 1));
+ if (retc.length) {
+ return gr = gr + retc.length - 1;
+ }
}
}, this));
root.children = children;
@@ -123,7 +128,9 @@
manual: false,
typeManager: this.typeMgr,
logger: this,
- mtypes: false
+ mtypes: false,
+ derivedPrefix: '_D_',
+ environ: {}
};
this.stats = {
classes: 0,
@@ -184,17 +191,17 @@
node: classNode
});
if (!/^@static\s+/.test(classNode.text)) {
- return this.typeMgr.addWrapped(classNode, namespace);
+ return this.typeMgr.addClassNode(classNode, namespace);
}
};
BeaLoader.prototype.addConst = function(node) {
return _.each(node.children, __bind(function(con) {
return this.constants.push(con.text);
}, this));
};
- BeaLoader.prototype.namespace = function(nsNode) {
+ BeaLoader.prototype.parseNamespace = function(nsNode) {
var nsname;
- nsname = nsNode.text.replace(/^@namespace\s+/, '');
+ nsname = nsNode.text.replace(/^@namespace\s*/, '');
return _.each(nsNode.children, __bind(function(node) {
switch (node.type()) {
case "@class":
@@ -205,6 +212,10 @@
return this.typeMgr.add(node, nsname);
case "@comment":
return false;
+ case "}":
+ case "};":
+ case "{":
+ return false;
default:
return this.warn("Unexpected '" + (node.type()) + "' within namespace " + nsname, node);
}
@@ -277,8 +288,8 @@
hFile.add(this.header);
}
nsBea = cppFile.add(new CodeBlock.NamespaceBlock("bea"));
- nsBea.add(this.typeMgr.createConversions());
convClasses = [];
+ this.options.typeMgr = this.typeMgr;
_.each(this.classes, __bind(function(cl) {
var cv, ret;
this.stats.classes++;
@@ -293,6 +304,7 @@
convClasses.push(ret.eClassName);
return hFile.add(ret.decla);
}, this));
+ nsBea.add(this.typeMgr.createConversions());
if (this.constants.length) {
nsCPP = cppFile.add(new CodeBlock.NamespaceBlock(this.targetNamespace));
nsH = hFile.add(new CodeBlock.NamespaceBlock(this.targetNamespace));
@@ -359,7 +371,7 @@
out = {
cpp: cppFile.render()
};
- fs.writeFileSync(outFilename, out.cpp, 'ascii');
+ fs.writeFileSync(this.files.cppm, out.cpp, 'ascii');
return out;
};
BeaLoader.prototype.CONVERT = function() {
@@ -383,7 +395,7 @@
case "@targetNamespace":
return this.setTargetNamespace(node);
case "@namespace":
- return this.namespace(node);
+ return this.parseNamespace(node);
case "@header":
return this.addHeader(node);
case "@cpp":
@@ -392,6 +404,10 @@
return this.addConst(node);
case "@comment":
return false;
+ case "}":
+ case "};":
+ case "{":
+ return false;
default:
return this.warn("Unknown directive: " + (node.type()), node);
}
View
6 beaparser.js
@@ -11,6 +11,9 @@
this.parent = null;
}
BeaNode.prototype.addChild = function(node) {
+ if (typeof node === "string") {
+ node = new BeaNode(node, this.level + 1, this.fileName);
+ }
node.parent = this;
this.children.push(node);
return node;
@@ -83,10 +86,11 @@
if (!txt.length) {
return null;
}
+ txt = txt.replace(/\t/g, ' ');
node = new BeaNode(txt, level, this.fileName, linenumber + 1);
if (level === this.curNode.level) {
this.curNode.parent.addChild(node);
- } else if (level === this.curNode.level + 1) {
+ } else if (level >= this.curNode.level + 1) {
this.curNode.addChild(node);
} else if (level < this.curNode.level) {
tmp = this.curNode;
View
6 beaproc.js
@@ -33,6 +33,8 @@
if (args["-o"]) {
bea.outDir = args["-o"];
}
- bealoader.doConvert(bea, beaFile);
- console.log("Exit");
+ debugIt(function() {
+ bealoader.doConvert(bea, beaFile);
+ return console.log("Exit");
+ });
}).call(this);
View
30 beautils.js
@@ -107,13 +107,9 @@
if (argsStart === -1 || argsEnd === -1) {
return false;
}
- args = str.slice(argsStart + 1, argsEnd);
- decla = str.slice(0, argsStart);
- isPure = false;
- if (/\s*=\s*0/.test(decla)) {
- isPure = true;
- decla = decla.replace(/\s*=\s*0;*/, '');
- }
+ args = trim(str.slice(argsStart + 1, argsEnd));
+ decla = trim(str.slice(0, argsStart));
+ isPure = /\s*=\s*0/.test(str);
parseArgs = function(args) {
var char, cur, paran, ret, symbol, _i, _len;
if (args.length === 0) {
@@ -179,12 +175,24 @@
});
};
parseClassDirective = function(node) {
- var className, exposedName, tmp, _ref;
- className = (node.text.replace(/^\s*@class\s+|^\s*@static\s+/, '')).replace(/\'|\"/g, '');
+ var className, derived, exposedName, ret, tmp, _derived, _ref, _ref2;
+ className = node.text.replace(/{\s*$/, '');
+ className = (className.replace(/^\s*@class\s+|^\s*@static\s+/, '')).replace(/\'|\"/g, '');
+ _ref = className.split(' : '), className = _ref[0], _derived = _ref[1];
+ if (_derived) {
+ derived = _.map(_derived.split(','), function(derived) {
+ return derived.replace(/\s*public\s+/, '').replace(/^\s+|\s+$/, '');
+ });
+ }
tmp = className.split(' ');
className = tmp[0];
- exposedName = ((_ref = tmp[1]) != null ? _ref : className).replace(/\s+/g, '_');
- return [className, exposedName];
+ exposedName = ((_ref2 = tmp[1]) != null ? _ref2 : className).replace(/\s+/g, '_');
+ ret = {
+ className: className,
+ exposedName: exposedName,
+ parentClass: derived
+ };
+ return ret;
};
exports.u = {
parseArg: parseArg,
View
264 classconvert.js
@@ -40,45 +40,80 @@
this.namespace = '';
this.nsBlock = null;
this.accessors = {};
- this.hasPostAllocator = false;
this.destructorNode = null;
this.typeManager = this.options.typeManager;
this.logger = this.options.logger;
+ this.virtCount = 0;
+ this.environ = this.options.environ;
+ this.virtualCount = 0;
}
ClassConverter.prototype.warn = function(msg, node) {
this.logger.warn(msg, node);
return false;
};
ClassConverter.prototype.processClass = function(cl, targetNamespace) {
- var declaNs, derivedDecla, ret, _ref;
+ var cldef, declaNs, derivedDecla, ret;
this.namespace = cl.namespace;
if (/^@static\s+/.test(cl.node.text)) {
this.isStatic = true;
} else {
this.isStatic = false;
}
- _ref = beautils.parseClassDirective(cl.node), this.className = _ref[0], this.exposedName = _ref[1];
+ cldef = beautils.parseClassDirective(cl.node);
+ this.className = cldef.className;
+ this.exposedName = cldef.exposedName;
+ this.parentClass = cldef.parentClass;
+ if (this.parentClass) {
+ _.each(this.parentClass, __bind(function(parentClass) {
+ var parentFns, parentType;
+ parentType = new beautils.Type(parentClass, this.namespace);
+ parentFns = this.environ[parentType.namespace][parentType.rawType];
+ if (!parentFns) {
+ return this.warn("Unkown base class '" + parentClass + "'", cl.node);
+ } else {
+ _.extend(this.classFns, parentFns.fns);
+ delete this.classFns["__constructor"];
+ delete this.classFns["__destructor"];
+ return this.virtualCount += parentFns.virtualCount;
+ }
+ }, this));
+ }
+ this.nsBlock = new CodeBlock.NamespaceBlock(targetNamespace);
this.nativeClassName = this.className;
+ this.classType = new beautils.Type(this.nativeClassName, this.namespace);
this.className = 'J' + this.nativeClassName;
- this.classType = (new beautils.Type(this.nativeClassName, this.namespace)).fullType();
- this.nsBlock = new CodeBlock.NamespaceBlock(targetNamespace);
- _.each(cl.node.children, __bind(function(child) {
- return this.processFunNode(child);
- }, this));
- if (this.virtual) {
- derivedDecla = this.createDerivedClass();
+ if (!this.isStatic) {
+ if (!cl.node.findChild("@postAllocator")) {
+ cl.node.addChild("@postAllocator");
+ }
}
- this.globalBlock = new CodeBlock.CodeBlock;
- if (!this.options.manual) {
- if (!this.isStatic) {
- this.globalBlock.add("DECLARE_EXPOSED_CLASS(" + this.classType + ");");
- if (!this.classFns["__constructor"]) {
- this.warn("No constructor defined for " + this.className + "!", cl.node);
- }
+ _.each(cl.node.children, __bind(function(child) {
+ if (/^public\s*:/.test(child.text)) {
+ return _.each(child.children, __bind(function(chld) {
+ return this.processFunNode(chld);
+ }, this));
+ } else if (/^private\s*:|^protected\s*:/.test(child.text)) {
+ return this.warn('Private and protected members ignored.', child);
} else {
- this.globalBlock.add("DECLARE_STATIC(" + targetNamespace + "::" + this.className + ");");
+ return this.processFunNode(child);
}
+ }, this));
+ if (!this.environ[this.namespace]) {
+ this.environ[this.namespace] = {};
}
+ this.environ[this.namespace][this.nativeClassName] = {
+ fns: this.classFns,
+ virtualCount: this.virtualCount
+ };
+ if (this.virtualCount > 0) {
+ this.baseType = this.classType;
+ this.nativeClassName = this.options.derivedPrefix + this.nativeClassName;
+ this.classType = new beautils.Type(this.nativeClassName, targetNamespace);
+ }
+ if (!this.isStatic) {
+ this.options.typeManager.addWrapped(this.classType, this.baseType);
+ }
+ this.globalBlock = new CodeBlock.CodeBlock;
if (!this.options.manual && this.destructorNode) {
this.nsBlock.add(this.createDestructor());
}
@@ -100,6 +135,21 @@
if (!this.options.manual) {
declaNs = new CodeBlock.NamespaceBlock(targetNamespace);
declaNs.add(this.createDeclaration());
+ if (this.virtualCount > 0) {
+ derivedDecla = this.createDerivedClass();
+ declaNs.add(derivedDecla.decla);
+ this.nsBlock.add(derivedDecla.impl);
+ }
+ }
+ if (!this.options.manual) {
+ if (!this.isStatic) {
+ this.globalBlock.add("DECLARE_EXPOSED_CLASS(" + (this.classType.fullType()) + ");");
+ if (!this.classFns["__constructor"]) {
+ this.warn("No constructor defined for " + this.className + "!", cl.node);
+ }
+ } else {
+ this.globalBlock.add("DECLARE_STATIC(" + targetNamespace + "::" + this.className + ");");
+ }
}
ret = {
global: this.globalBlock,
@@ -112,35 +162,65 @@
return ret;
};
ClassConverter.prototype.processFunNode = function(node) {
- var callNode, fn, isManual, isPostAllocator, nodeText, str;
+ var accType, callNode, fn, fspace, isManual, nodeText, str, _accName;
+ if (/^\/\//.test(node.text)) {
+ return false;
+ }
if (/^@noexpose/.test(node.text)) {
this.exposed = false;
return false;
}
- isManual = /^@manual\s+/.test(node.text);
- if (isManual) {
- str = node.text.substring(7);
+ if (/^@manual\s+/.test(node.text)) {
+ isManual = true;
+ str = node.text.replace(/^@manual\s+/, '');
} else {
str = node.text;
}
- if (/^\@accessor\s+/.test(node.text)) {
+ str = str.replace(/\s*\/\/.*$/g, '');
+ if (/^\@accessor\s+/.test(str)) {
return this.parseAccessor(node);
}
- isPostAllocator = false;
- if (/^\@postAllocator/.test(node.text)) {
+ if (/^\@postAllocator/.test(str)) {
if (this.isStatic) {
- return this.warn("Postallocator for static class ignored");
+ return this.warn("Postallocator for static class ignored", node);
}
str = "void __postAllocator()";
- this.hasPostAllocator = true;
}
- if (/^\@destructor/.test(node.text)) {
+ if (/^~|^virtual\s+~/.test(str)) {
+ return false;
+ }
+ if (/^\@destructor/.test(str)) {
if (this.isStatic) {
- return this.warn("Destructor for static class ignored");
+ return this.warn("Destructor for static class ignored", node);
}
this.destructorNode = node;
return true;
}
+ str = str.replace(/;\s*$/, '');
+ if (str.indexOf("(") === -1 && /\s+/.test(str)) {
+ str = str.replace(/\s+/g, ' ');
+ fspace = str.indexOf(' ');
+ accType = str.slice(0, fspace);
+ _accName = str.slice(fspace);
+ _.each(_accName.split(','), __bind(function(accName) {
+ var accessor;
+ accName = beautils.trim(accName);
+ if (!accName.length) {
+ return false;
+ }
+ accessor = {
+ type: new beautils.Type(accType, this.namespace),
+ name: accName,
+ read: "_this->" + accName,
+ write: "_this->" + accName + " = _accValue;"
+ };
+ return this.addAccessor(accessor, node);
+ }, this));
+ return true;
+ }
+ if (/\s+operator\s*[=\+\/\\\*<>\^\-]*/.test(str)) {
+ return this.warn('Operator overloading not supported. Declaration ignored', node);
+ }
fn = beautils.parseDeclaration(str, this.namespace);
if (!fn) {
return this.warn("Cannot parse method declaration: '" + str + "'. Ignoring.", node);
@@ -157,8 +237,9 @@
fn.requiredArgs = this.requiredArgs(fn.args);
fn.sublines = node.children;
fn.node = node;
+ fn.parentClass = this.nativeClassName;
if (fn.virtual) {
- this.virtual = true;
+ this.virtualCount++;
}
callNode = _.detect(fn.sublines, function(subline) {
return /^\@call/.test(subline.text);
@@ -179,6 +260,12 @@
}
return true;
};
+ ClassConverter.prototype.addAccessor = function(accessor, node) {
+ if (this.accessors[accessor.name]) {
+ return this.warn("Accessor: '" + accessor.name + "': accessor already defined. Second definition ignored", node);
+ }
+ return this.accessors[accessor.name] = accessor;
+ };
ClassConverter.prototype.parseAccessor = function(node) {
var accessor, parts, read, write, _ref, _ref2;
parts = node.text.match(/^\@accessor\s+(\w+)\s+(\w+)/);
@@ -189,9 +276,6 @@
name: parts[1],
type: parts[2]
};
- if (this.accessors[accessor.name]) {
- return this.warn("Accessor: '" + accessor.name + "': accessor already defined. Second definition ignored", node);
- }
if (!accessor.type) {
accessor.type = 'int';
this.warn("Accessor '" + accessor.name + "' : type not defined, int assumed", node);
@@ -208,7 +292,7 @@
accessor.read = (_ref = read != null ? read.text.replace(/^@get\s*/, '') : void 0) != null ? _ref : "";
accessor.write = (_ref2 = write != null ? write.text.replace(/^@set\s*/, '') : void 0) != null ? _ref2 : "";
accessor.node = node;
- return this.accessors[accessor.name] = accessor;
+ return this.addAccessor(accessor);
};
ClassConverter.prototype.createDeclaration = function() {
var block, decBlock;
@@ -243,38 +327,89 @@
return decBlock;
};
ClassConverter.prototype.createDerivedClass = function() {
- var classBlock, constructors, public, vfuncs;
- classBlock = new CodeBlock.ClassBlock("class bea_" + this.classType + " : public " + this.classType + ", public bea::DerivedClass");
+ var classBlock, constructors, implBlock, public, publicd, publicv, vfuncs;
+ classBlock = new CodeBlock.ClassBlock("class " + this.nativeClassName + " : public " + (this.baseType.fullType()) + ", public bea::DerivedClass");
public = classBlock.add(new CodeBlock.CodeBlock("public:", false));
constructors = _.detect(this.classFns, function(fn) {
return fn.name === '__constructor';
});
- _.each(constructors, function(constr) {
+ _.each(constructors, __bind(function(constr) {
var cargs, dargs;
- dargs = _.map(constr.args, arg(arg.org));
- cargs = _.map(constr.args, arg(arg.name));
- return public.add("bea_" + this.classType + "(" + (dargs.join(', ')) + ") : " + this.classType + "(" + (cargs.join(', ')) + "){}");
- });
- vfuncs = _.select(this.classFns, function(fn) {
- return fn.virtual;
+ dargs = _.map(constr.args, function(arg) {
+ return arg.org;
+ });
+ cargs = _.map(constr.args, function(arg) {
+ return arg.name;
+ });
+ return public.add("" + this.nativeClassName + "(" + (dargs.join(', ')) + ") : " + (this.baseType.fullType()) + "(" + (cargs.join(', ')) + "){}");
+ }, this));
+ vfuncs = [];
+ _.each(this.classFns, function(fn) {
+ return _.each(fn, function(over) {
+ if (over.virtual) {
+ return vfuncs.push(over);
+ }
+ });
});
- public.add("//Virtual functions");
- return _.each(vfuncs, function(vfunc) {
- var cargs, dargs, ret;
- dargs = _.map(vfunc.args, arg(arg.org));
- cargs = _.map(vfun.args, arg(arg.name));
+ implBlock = new CodeBlock.CodeBlock;
+ publicv = public.add(new CodeBlock.CodeBlock("", false));
+ publicv.add("//JS: These virtual functions will only be called from Javascript");
+ publicd = public.add(new CodeBlock.CodeBlock("", false));
+ publicd.add("//Native: These virtual functions will only be called from native code");
+ _.each(vfuncs, __bind(function(vfunc) {
+ var arglist, cargs, castBack, cif, dargs, fn, funcontents, nativeType, ret, vfuncdecla;
+ dargs = _.map(vfunc.args, function(arg) {
+ return arg.org;
+ });
+ cargs = _.map(vfunc.args, function(arg) {
+ return arg.name;
+ });
+ vfunc.callAs = "_d_" + vfunc.name;
ret = 'return';
if (vfunc.type.rawType === 'void') {
ret = '';
}
- return public.add("inline " + (vfunc.type.fullType()) + " bea_" + vfunc.name + "(" + (dargs.join(', ')) + "){" + ret + " " + this.classType + "::" + vfunc.name + "(" + (cargs.join(', ')) + ");}");
- });
+ if (vfunc.pure) {
+ funcontents = "throw bea::Exception(\"'" + vfunc.name + "' : pure virtual function not defined.\");";
+ } else {
+ funcontents = "" + ret + " " + (this.baseType.fullType()) + "::" + vfunc.name + "(" + (cargs.join(', ')) + ");";
+ }
+ publicv.add(new CodeBlock.FunctionBlock("inline " + vfunc.type.org + " _d_" + vfunc.name + "(" + (dargs.join(', ')) + ")")).add(funcontents);
+ vfuncdecla = "" + vfunc.type.org + " " + vfunc.name + "(" + (dargs.join(', ')) + ")";
+ publicd.add(vfuncdecla + ';');
+ fn = implBlock.add(new CodeBlock.FunctionBlock("" + vfunc.type.org + " " + this.nativeClassName + "::" + vfunc.name + "(" + (dargs.join(', ')) + ")"));
+ fn.add("v8::HandleScope v8scope; v8::Handle<v8::Value> v8retVal;");
+ cif = fn.add(new CodeBlock.CodeBlock("if (bea_derived_hasOverride(\"" + vfunc.name + "\"))"));
+ arglist = _.map(vfunc.args, __bind(function(arg) {
+ return snippets.ToJS(arg.type.org, arg.name, '');
+ }, this));
+ if (vfunc.args.length > 0) {
+ cif.add("v8::Handle<v8::Value> v8args[" + vfunc.args.length + "] = {" + (arglist.join(', ')) + "};");
+ } else {
+ cif.add("v8::Handle<v8::Value> v8args[1];");
+ }
+ cif.add("v8retVal = bea_derived_callJS(\"" + vfunc.name + "\", " + vfunc.args.length + ", v8args);");
+ fn.add("if (v8retVal.IsEmpty()) " + ret + " _d_" + vfunc.name + "(" + (cargs.join(', ')) + ");");
+ if (vfunc.type.rawType !== 'void') {
+ nativeType = this.nativeType(vfunc.type);
+ if (nativeType.indexOf('*') !== -1 && !vfunc.type.isPointer) {
+ castBack = '*';
+ } else {
+ castBack = '';
+ }
+ return fn.add(("return " + castBack) + snippets.FromJS(nativeType, "v8retVal", 0));
+ }
+ }, this));
+ return {
+ decla: classBlock,
+ impl: implBlock
+ };
};
ClassConverter.prototype.createInitFn = function() {
var initFn;
initFn = new CodeBlock.FunctionBlock(snippets.decl.InitJSObject(this.className));
if (!this.isStatic) {
- initFn.add(snippets.impl.exposeClass(this.classType, this.exposedName));
+ initFn.add(snippets.impl.exposeClass(this.classType.fullType(), this.exposedName));
} else {
initFn.add(snippets.impl.exposeObject(this.className, this.exposedName));
}
@@ -324,10 +459,10 @@
}
block.add("//Get Accessor " + name + " (" + (this.nativeType(accessor.type)) + ")");
fn = block.add(new CodeBlock.FunctionBlock(snippets.impl.accessorGet(this.className, name)));
- fn.add(snippets.impl.accessorGetImpl("" + this.classType + "*", this.nativeType(accessor.type), accessor.read));
+ fn.add(snippets.impl.accessorGetImpl("" + (this.classType.fullType()) + "*", this.nativeType(accessor.type), accessor.read));
block.add("//Set Accessor " + name + " (" + (this.nativeType(accessor.type)) + ")");
fn = block.add(new CodeBlock.FunctionBlock(snippets.impl.accessorSet(this.className, name)));
- fn.add(snippets.impl.accessorSetImpl("" + this.classType + "*", this.nativeType(accessor.type), accessor.write));
+ fn.add(snippets.impl.accessorSetImpl("" + (this.classType.fullType()) + "*", this.nativeType(accessor.type), accessor.write));
this.logger.stats.accessors++;
return block;
};
@@ -382,15 +517,18 @@
}, this));
};
ClassConverter.prototype.createCall = function(block, overload) {
- var argList, fnName, fnRet, fncall, names, nativeType, retVal, tmp, _ref;
+ var argList, fnName, fnRet, fncall, names, nativeType, retVal, tmp, _ref, _ref2;
if (overload.manual) {
block.add('//TODO: Enter code here');
block.add('return args.This();');
return block;
}
this.convertArguments(block, overload.args);
if (!this.isStatic && overload.name !== "__constructor") {
- block.add(("" + this.classType + "* _this = ") + snippets.FromJS(this.classType + '*', "args.This()", 0));
+ block.add(("" + (this.classType.fullType()) + "* _this = ") + snippets.FromJS(this.classType.fullType() + '*', "args.This()", 0));
+ }
+ if (overload.name === '__postAllocator' && this.virtualCount > 0) {
+ block.add('_this->bea_derived_setInstance(args.This());');
}
_.each(overload.sublines, __bind(function(line) {
return block.add(new CodeBlock.Code(line.text));
@@ -414,7 +552,7 @@
fnRet = nativeType + ' fnRetVal';
retVal = "return " + snippets.ToJS(nativeType, "fnRetVal");
}
- fnName = overload.name;
+ fnName = (_ref = overload.callAs) != null ? _ref : overload.name;
if (this.isStatic) {
fnName = this.namespace + '::' + fnName;
} else {
@@ -425,18 +563,22 @@
}
}
if (fnName.length) {
- if ((_ref = overload.callText) != null ? _ref.length : void 0) {
+ if ((_ref2 = overload.callText) != null ? _ref2.length : void 0) {
fncall = new CodeBlock.CodeBlock(overload.callText, false);
} else {
if (!this.typeManager.isWrapped(overload.type)) {
fncall = new FnCall(fnRet, fnName, argList);
} else {
if (overload.name === '__constructor') {
- fncall = new FnCall(fnRet, 'new ' + overload.type.fullType(), argList);
+ fncall = new FnCall(fnRet, 'new ' + this.classType.fullType(), argList);
retVal = "return v8::External::New(fnRetVal);";
} else {
- tmp = new FnCall('', fnName, argList);
- fncall = new FnCall(fnRet, 'new ' + overload.type.fullType(), tmp.render(''));
+ if (!overload.type.isPointer) {
+ tmp = new FnCall('', fnName, argList);
+ fncall = new FnCall(fnRet, 'new ' + overload.type.fullType(), tmp.render(''));
+ } else {
+ fncall = new FnCall(fnRet, fnName, argList);
+ }
}
}
}
@@ -502,7 +644,7 @@
var fnBlock;
fnBlock = new CodeBlock.FunctionBlock(snippets.impl.destructor(this.className, "__destructor"));
fnBlock.add("DESTRUCTOR_BEGIN();");
- fnBlock.add(("" + this.classType + "* _this = ") + snippets.FromJS(this.classType + '*', "value", 0));
+ fnBlock.add(("" + (this.classType.fullType()) + "* _this = ") + snippets.FromJS(this.classType.fullType() + '*', "value", 0));
_.each(this.destructorNode.children, __bind(function(line) {
return fnBlock.add(new CodeBlock.Code(line.text));
}, this));
View
69 mgr.js
@@ -11,13 +11,28 @@
this.namespaces = namespaces;
this.types = [];
}
- TypeManager.prototype.addWrapped = function(node, namespace) {
- var t, type;
- type = beautils.parseClassDirective(node)[0];
- t = new beautils.Type(type, namespace);
- t.wrapped = true;
- t.manual = false;
- return this.types.push(t);
+ TypeManager.prototype.addWrapped = function(type, baseType) {
+ type.wrapped = true;
+ type.manual = false;
+ if (!this.isWrapped(type)) {
+ this.types.push(type);
+ }
+ if (baseType) {
+ this.types.push(baseType);
+ baseType.alias = type.fullType();
+ baseType.manual = false;
+ return baseType.wrapped = true;
+ }
+ };
+ TypeManager.prototype.addClassNode = function(classNode, namespace) {
+ var cl, cltype;
+ cl = beautils.parseClassDirective(classNode);
+ cltype = new beautils.Type(cl.className, namespace);
+ cltype.wrapped = true;
+ cltype.manual = false;
+ if (!this.findWrapped(cltype)) {
+ return this.types.push(cltype);
+ }
};
TypeManager.prototype.isWrapped = function(type) {
var wrapped;
@@ -28,6 +43,15 @@
return wt.rawType === type.rawType && wt.namespace === type.namespace;
});
};
+ TypeManager.prototype.findWrapped = function(type) {
+ var wrapped;
+ wrapped = _.filter(this.types, function(t) {
+ return t.wrapped;
+ });
+ return _.detect(wrapped, function(wt) {
+ return wt.rawType === type.rawType && wt.namespace === type.namespace;
+ });
+ };
TypeManager.prototype.knownType = function(type) {
return type.isNative() || _.any(this.types, function(wt) {
return wt.rawType === type.rawType && wt.namespace === type.namespace;
@@ -76,14 +100,17 @@
return this.types.push(type);
};
TypeManager.prototype.getMembers = function(typeNode, type, namespace) {
- var members;
+ var children, members;
if (type.alias) {
return [];
}
members = [];
if (!type.manual) {
- members = _.map(typeNode.children, function(line) {
- return new beautils.Argument(line.text, namespace);
+ children = _.select(typeNode.children, function(n) {
+ return !/^\s*\/\//.test(n.text);
+ });
+ members = _.map(children, function(line) {
+ return new beautils.Argument(line.text.replace(';', '').replace(/\/\/.*$/, ''), namespace);
});
} else {
members = _.map(typeNode.children, function(line) {
@@ -96,7 +123,11 @@
var fnBlock;
fnBlock = new CodeBlock.CodeBlock;
if (type.wrapped) {
- fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::Is(v);");
+ if (!type.alias) {
+ fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::Is(v);");
+ } else {
+ fnBlock.add("return " + snippets.Is(type.alias + '*', 'v'));
+ }
return fnBlock;
}
if (type.alias) {
@@ -115,7 +146,11 @@
var fnBlock, memstr;
fnBlock = new CodeBlock.CodeBlock;
if (type.wrapped) {
- fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::FromJS(v, nArg);");
+ if (!type.alias) {
+ fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::FromJS(v, nArg);");
+ } else {
+ fnBlock.add("return " + snippets.FromJS(type.alias + '*', 'v', 'nArg'));
+ }
return fnBlock;
}
if (type.alias) {
@@ -146,7 +181,15 @@
var fnBlock;
fnBlock = new CodeBlock.CodeBlock;
if (type.wrapped) {
- fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::ToJS(v);");
+ if (!type.alias) {
+ fnBlock.add("return bea::ExposedClass<" + (fixt(type.fullType())) + ">::ToJS(v);");
+ } else {
+ fnBlock.add("return " + snippets.ToJS(type.alias + '*', "static_cast<" + (fixt(type.alias)) + "*>(v)"));
+ }
+ return fnBlock;
+ }
+ if (type.alias) {
+ fnBlock.add("return " + snippets.ToJS(type.alias, "v"));
return fnBlock;
}
fnBlock.add("v8::HandleScope scope;");
View
2 snippets.js
@@ -97,7 +97,7 @@
if (impl.length === 0) {
impl = '//TODO: Set value here';
}
- return "v8::HandleScope scope;\n" + thisType + " _this = bea::Convert<" + (fixt(thisType)) + ">::FromJS(info.Holder(), 0); \n" + accessorType + " value = bea::Convert<" + (fixt(accessorType)) + ">::FromJS(v, 0);\n" + impl;
+ return "v8::HandleScope scope;\n" + thisType + " _this = bea::Convert<" + (fixt(thisType)) + ">::FromJS(info.Holder(), 0); \n" + accessorType + " _accValue = bea::Convert<" + (fixt(accessorType)) + ">::FromJS(v, 0);\n" + impl;
};
exports.impl.exposeClass = function(classType, exposedName) {
return "bea::ExposedClass<" + (fixt(classType)) + ">* obj = EXPOSE_CLASS(" + classType + ", \"" + exposedName + "\");";
View
35 src/bealoader.coffee
@@ -47,18 +47,20 @@ class RecursiveParser
if _.any(@includes, (nf) -> nf == fileName) then return @warn "File #{fileName} already included!", node
+ console.log 'Included file ' + fileName
+
return @parseFile fileName
processIncludes: (root) ->
children = root.children
-
+ gr = 0
_.each root.children, (node, i) =>
if node.type() == '@include'
ret = @include node
retc = ret?.children ? []
- children = children.slice(0, i).concat(retc, children.slice(i + 1))
-
+ children = children.slice(0, i + gr).concat(retc, children.slice(i + gr + 1))
+ if retc.length then gr = gr + retc.length - 1
root.children = children
return root
@@ -104,6 +106,8 @@ class BeaLoader extends MessageLogger
typeManager: @typeMgr
logger: this
mtypes: false
+ derivedPrefix: '_D_'
+ environ: {}
@stats =
classes: 0 #number of classes converted
converted: 0 #number of functions converted
@@ -157,20 +161,21 @@ class BeaLoader extends MessageLogger
node: classNode
if not /^@static\s+/.test classNode.text
- @typeMgr.addWrapped classNode, namespace
+ @typeMgr.addClassNode classNode, namespace
addConst: (node) ->
_.each node.children, (con) =>
@constants.push con.text
- namespace: (nsNode) ->
- nsname = nsNode.text.replace /^@namespace\s+/, ''
+ parseNamespace: (nsNode) ->
+ nsname = nsNode.text.replace /^@namespace\s*/, ''
_.each nsNode.children, (node) =>
switch node.type()
when "@class" then @addClass node, nsname
when "@static" then @addClass node, nsname
when "@type" then @typeMgr.add node, nsname
when "@comment" then false
+ when "}", "};", "{" then false
else @warn "Unexpected '#{node.type()}' within namespace #{nsname}", node
addHeader: (hNode) ->
@@ -236,13 +241,15 @@ class BeaLoader extends MessageLogger
if @header then hFile.add @header
nsBea = cppFile.add new CodeBlock.NamespaceBlock "bea"
-
- nsBea.add @typeMgr.createConversions()
-
+
convClasses = []
+
+
+ @options.typeMgr = @typeMgr
_.each @classes, (cl) =>
@stats.classes++
+
cv = new ClassConverter(@options)
ret = cv.processClass cl, @targetNamespace
@@ -257,7 +264,10 @@ class BeaLoader extends MessageLogger
#the declarations
hFile.add ret.decla
-
+
+ #create type conversions
+ nsBea.add @typeMgr.createConversions()
+
if @constants.length
nsCPP = cppFile.add new CodeBlock.NamespaceBlock @targetNamespace
@@ -323,7 +333,7 @@ class BeaLoader extends MessageLogger
out =
cpp: cppFile.render()
- fs.writeFileSync outFilename, out.cpp, 'ascii'
+ fs.writeFileSync @files.cppm, out.cpp, 'ascii'
return out
CONVERT: ()->
@@ -347,11 +357,12 @@ class BeaLoader extends MessageLogger
switch node.type()
when "@project" then @setProject node
when "@targetNamespace" then @setTargetNamespace node
- when "@namespace" then @namespace node
+ when "@namespace" then @parseNamespace node
when "@header" then @addHeader node
when "@cpp" then @addCpp node
when "@const" then @addConst node
when "@comment" then false
+ when "}", "};", "{" then false
else @warn "Unknown directive: #{node.type()}", node
if _.isEmpty @targetNamespace
View
7 src/beaparser.coffee
@@ -5,6 +5,7 @@ class BeaNode
@parent = null
addChild: (node)->
+ if typeof node == "string" then node = new BeaNode node, @level + 1, @fileName
node.parent = this
@children.push node
node
@@ -44,6 +45,7 @@ class BeaParser
#Indentation determines the node's level
#Throws exception if indentation is invalid
parseLine: (txt, linenumber) ->
+
level = txt.match(/(^\s+)/g)?[0].length; level?=0; level++
rawTxt = txt.replace(/^\s+|\s+$/g, '')
@@ -67,11 +69,14 @@ class BeaParser
return null unless txt.length
+ #replace all tab chars with spaces
+ txt = txt.replace /\t/g, ' '
+
node = new BeaNode txt, level, @fileName, linenumber + 1
if level == @curNode.level
@curNode.parent.addChild node
- else if level == @curNode.level + 1
+ else if level >= @curNode.level + 1
@curNode.addChild node
else if level < @curNode.level
#walk up until we find the parent
View
6 src/beaproc.coffee
@@ -28,6 +28,6 @@ if args["-manual"] || args["-m"] then bea.options.manual = true
if args["-mtypes"] || args["-mt"] then bea.options.mtypes = true
if args["-force"] || args["-f"] then bea.options.force = true
if args["-o"] then bea.outDir = args["-o"]
-
-bealoader.doConvert bea, beaFile
-console.log "Exit"
+debugIt ->
+ bealoader.doConvert bea, beaFile
+ console.log "Exit"
View
31 src/beautils.coffee
@@ -97,17 +97,18 @@ class Argument
parseDeclaration = (str, namespace) ->
+
+
argsStart = str.indexOf '('
argsEnd = str.lastIndexOf ')'
return false if argsStart is -1 or argsEnd is -1
+
- args = str.slice argsStart + 1, argsEnd
- decla = str.slice(0, argsStart);
- isPure = false
- if /\s*=\s*0/.test decla
- isPure = true
- decla = decla.replace /\s*=\s*0;*/, ''
+ args = trim str.slice(argsStart + 1, argsEnd)
+ decla = trim(str.slice(0, argsStart))
+
+ isPure = /\s*=\s*0/.test str
parseArgs = (args) ->
if args.length == 0 then return []
@@ -163,12 +164,24 @@ hasOverload = (list, overload) ->
isSameOverload over, overload
parseClassDirective = (node) ->
- className = (node.text.replace /^\s*@class\s+|^\s*@static\s+/, '').replace(/\'|\"/g, '')
+ className = node.text.replace /{\s*$/, ''
+ className = (className.replace /^\s*@class\s+|^\s*@static\s+/, '').replace(/\'|\"/g, '')
+
+ [className, _derived] = className.split ' : '
+
+ if _derived
+ derived = _.map _derived.split(','), (derived) ->
+ derived.replace(/\s*public\s+/, '').replace /^\s+|\s+$/, ''
+
tmp = className.split ' '
className = tmp[0]
exposedName = (tmp[1] ? className).replace(/\s+/g, '_')
- return [className, exposedName]
-
+ ret =
+ className: className
+ exposedName: exposedName
+ parentClass: derived
+ return ret
+
exports.u =
parseArg: parseArg
tabify: tabify
View
289 src/classconvert.coffee
@@ -20,17 +20,20 @@ class FnCall
class ClassConverter
constructor: (@options)->
@classFns = {}
+
@className = ""
@nativeClassName = ""
@virtual = false #has virtual functions
@exposed = true
@namespace = ''
@nsBlock = null
@accessors = {}
- @hasPostAllocator = false
@destructorNode = null
@typeManager = @options.typeManager
@logger = @options.logger
+ @virtCount = 0
+ @environ = @options.environ;
+ @virtualCount = 0
warn: (msg, node) ->
@logger.warn msg, node
@@ -42,38 +45,74 @@ class ClassConverter
@namespace = cl.namespace
if /^@static\s+/.test cl.node.text then @isStatic = true else @isStatic = false
- [@className, @exposedName] = beautils.parseClassDirective cl.node
+ cldef = beautils.parseClassDirective cl.node
+
+ @className = cldef.className
+ @exposedName = cldef.exposedName
+ @parentClass = cldef.parentClass
+
+
+ #inherit from parent
+ if @parentClass
+ _.each @parentClass, (parentClass) =>
+ parentType = new beautils.Type parentClass, @namespace
+ parentFns = @environ[parentType.namespace][parentType.rawType]
+ if !parentFns
+ @warn "Unkown base class '#{parentClass}'", cl.node
+ else
+ #inherit all non-virtual members from parent
+ #virtual functions: if defined
+ _.extend @classFns, parentFns.fns
+ delete @classFns["__constructor"]
+ delete @classFns["__destructor"]
+ @virtualCount += parentFns.virtualCount
+
+ @nsBlock = new CodeBlock.NamespaceBlock targetNamespace
@nativeClassName = @className
+ @classType = new beautils.Type @nativeClassName, @namespace
@className = 'J' + @nativeClassName
- @classType = (new beautils.Type @nativeClassName, @namespace).fullType();
- @nsBlock = new CodeBlock.NamespaceBlock targetNamespace
+
+ #make sure there is a postAllocator defined for
+ if !@isStatic
+ if !cl.node.findChild "@postAllocator" then cl.node.addChild "@postAllocator"
- #parse all functions
- _.each cl.node.children, (child) => @processFunNode child
- #has virtual functions?
- if @virtual
- #generate derived class block
- #change className to bea_className
- #function call will be _this->bea_functionName(arguments)
- derivedDecla = @createDerivedClass();
-
+ #parse all functions
+ _.each cl.node.children, (child) =>
+ if /^public\s*:/.test child.text
+ _.each child.children, (chld) => @processFunNode chld
+ else if /^private\s*:|^protected\s*:/.test child.text
+ @warn 'Private and protected members ignored.', child
+ else
+ @processFunNode child
+
+ #save raw processed class in the global 'environ' thing
+ #we may revisit this class if another class derives from it
+ if !@environ[@namespace]
+ @environ[@namespace] = {}
+
+ @environ[@namespace][@nativeClassName] =
+ fns: @classFns
+ virtualCount: @virtualCount
+
+ #if virtual functions are defined, create a derived class which acts
+ #as the native class
+ if @virtualCount > 0
+ @baseType = @classType
+ @nativeClassName = @options.derivedPrefix + @nativeClassName
+ @classType = new beautils.Type @nativeClassName, targetNamespace
+ #@options.typeMgr.addDerivedClass(@baseType, @nativeType)
+
+ if not @isStatic
+ @options.typeManager.addWrapped @classType, @baseType
- @globalBlock = new CodeBlock.CodeBlock
+
- if not @options.manual
- if not @isStatic
- @globalBlock.add "DECLARE_EXPOSED_CLASS(#{@classType});"
-
- if !@classFns["__constructor"]
- @warn "No constructor defined for #{@className}!", cl.node
-
- else
- @globalBlock.add "DECLARE_STATIC(#{targetNamespace}::#{@className});"
+ @globalBlock = new CodeBlock.CodeBlock
#produce destructor
if !@options.manual && @destructorNode
@@ -95,6 +134,28 @@ class ClassConverter
if !@options.manual #only cpp must be generated for manual
declaNs = new CodeBlock.NamespaceBlock targetNamespace
declaNs.add @createDeclaration()
+
+ #has virtual functions?
+ if @virtualCount > 0
+ #generate derived class block
+ #change className to bea_className
+ #function call will be _this->bea_functionName(arguments)
+ derivedDecla = @createDerivedClass();
+ declaNs.add derivedDecla.decla
+ @nsBlock.add derivedDecla.impl
+
+
+
+ if not @options.manual
+ if not @isStatic
+ @globalBlock.add "DECLARE_EXPOSED_CLASS(#{@classType.fullType()});"
+
+ if !@classFns["__constructor"]
+ @warn "No constructor defined for #{@className}!", cl.node
+
+ else
+ @globalBlock.add "DECLARE_STATIC(#{targetNamespace}::#{@className});"
+
ret =
global: @globalBlock
@@ -108,29 +169,64 @@ class ClassConverter
#Parse a function declaration and it's arguments and store the result in the @classFns hash
processFunNode: (node) ->
+
+ #ignore C++ comments
+ return false if /^\/\//.test node.text
#noexpose directive - means don't expose class to Javascript
if /^@noexpose/.test node.text
@exposed = false
return false
- isManual = /^@manual\s+/.test node.text
-
- if isManual then str = node.text.substring(7) else str = node.text
-
- if /^\@accessor\s+/.test node.text then return @parseAccessor node
+ if /^@manual\s+/.test node.text
+ isManual = true
+ str = node.text.replace /^@manual\s+/, ''
+ else
+ str = node.text
+
+
+ #remove end comments
+ str = str.replace /\s*\/\/.*$/g, ''
- isPostAllocator = false
+ return @parseAccessor node if /^\@accessor\s+/.test str
- if /^\@postAllocator/.test node.text
- if @isStatic then return @warn "Postallocator for static class ignored"
+ if /^\@postAllocator/.test str
+ if @isStatic then return @warn "Postallocator for static class ignored", node
str = "void __postAllocator()"
- @hasPostAllocator = true
- if /^\@destructor/.test node.text
- if @isStatic then return @warn "Destructor for static class ignored"
+ #destructor is something which starts with ~ or virtual ~
+
+ return false if /^~|^virtual\s+~/.test str #str = '@destructor'
+
+ if /^\@destructor/.test str
+ if @isStatic then return @warn "Destructor for static class ignored", node
@destructorNode = node
return true
+
+ str = str.replace /;\s*$/, ''
+
+ #If string doesn't look like a function call, but has a space,
+ #we assume that it is in the form Type name and we generate a r/w accessor for it
+ if str.indexOf("(") == -1 && /\s+/.test str
+ str = str.replace /\s+/g, ' '
+ fspace = str.indexOf ' '
+ accType = str.slice 0, fspace
+ _accName = str.slice fspace
+ #declared as int x, y
+ _.each _accName.split(','), (accName) =>
+ accName = beautils.trim(accName)
+ return false unless accName.length
+ accessor =
+ type: new beautils.Type accType, @namespace
+ name: accName
+ read: "_this->#{accName}"
+ write: "_this->#{accName} = _accValue;"
+ @addAccessor accessor, node
+ return true
+
+ if /\s+operator\s*[=\+\/\\\*<>\^\-]*/.test str
+ return @warn 'Operator overloading not supported. Declaration ignored', node
+
fn = beautils.parseDeclaration str, @namespace
#returns {
@@ -153,8 +249,10 @@ class ClassConverter
fn.requiredArgs = @requiredArgs fn.args
fn.sublines = node.children
fn.node = node
+ fn.parentClass = @nativeClassName
- if fn.virtual then @virtual = true
+ if fn.virtual
+ @virtualCount++
#check sublines for @call directive
callNode = _.detect fn.sublines, (subline) -> /^\@call/.test subline.text
@@ -164,15 +262,23 @@ class ClassConverter
fn.callText = _.compact([nodeText, callNode.toString()]).join '\n'
fn.sublines = _.without fn.sublines, callNode
+
+
if @classFns[fn.name]
- if not beautils.hasOverload(@classFns[fn.name], fn)
+ if not beautils.hasOverload @classFns[fn.name], fn
@classFns[fn.name].push fn
+
else
@classFns[fn.name] = [fn]
@classFns[fn.name].name = fn.name
@classFns[fn.name].type = fn.type
+
return true
-
+
+ addAccessor: (accessor, node) ->
+ if @accessors[accessor.name] then return @warn "Accessor: '#{accessor.name}': accessor already defined. Second definition ignored", node
+ @accessors[accessor.name] = accessor
+
#Parse an accessor node, add to @accessors
parseAccessor: (node) ->
parts = node.text.match /^\@accessor\s+(\w+)\s+(\w+)/
@@ -182,8 +288,6 @@ class ClassConverter
name: parts[1]
type: parts[2]
- if @accessors[accessor.name] then return @warn "Accessor: '#{accessor.name}': accessor already defined. Second definition ignored", node
-
if not accessor.type then accessor.type = 'int'; @warn "Accessor '#{accessor.name}' : type not defined, int assumed", node
read = node.childType "@get"
@@ -196,7 +300,7 @@ class ClassConverter
accessor.read = (read?.text.replace(/^@get\s*/, '')) ? ""
accessor.write = (write?.text.replace(/^@set\s*/, '')) ? ""
accessor.node = node
- @accessors[accessor.name] = accessor
+ @addAccessor accessor
#Create the class declaration. Include methods, accessors, and destructor. Included in the header file
createDeclaration: ->
@@ -232,48 +336,102 @@ class ClassConverter
return decBlock
+ #Creates a 'hidden' derived class from the original class in which
+ #the virtual functions are implemented
+ #TODO: This function needs cleanup
createDerivedClass: ->
- classBlock = new CodeBlock.ClassBlock "class bea_#{@classType} : public #{@classType}, public bea::DerivedClass"
+ classBlock = new CodeBlock.ClassBlock "class #{@nativeClassName} : public #{@baseType.fullType()}, public bea::DerivedClass"
public = classBlock.add (new CodeBlock.CodeBlock "public:", false)
#constructor
constructors = _.detect @classFns, (fn) -> fn.name == '__constructor'
- _.each constructors, (constr) ->
+ _.each constructors, (constr) =>
#declaration arguments
- dargs = _.map constr.args, (arg) arg.org
+ dargs = _.map constr.args, (arg) -> arg.org
#call arguments
- cargs = _.map constr.args, (arg) arg.name
+ cargs = _.map constr.args, (arg) -> arg.name
#bea_Derived() : Derived(){}
#bea_Derived(int k, CClass* ptr): Derived(k, ptr){}
- public.add "bea_#{@classType}(#{dargs.join ', '}) : #{@classType}(#{cargs.join(', ')}){}"
+ public.add "#{@nativeClassName}(#{dargs.join ', '}) : #{@baseType.fullType()}(#{cargs.join(', ')}){}"
#add virtual functions
+ vfuncs = []
+ _.each @classFns, (fn) -> _.each fn, (over) -> if over.virtual then vfuncs.push over
- vfuncs = _.select @classFns, (fn) -> fn.virtual
- public.add "//Virtual functions"
- _.each vfuncs, (vfunc) ->
- dargs = _.map vfunc.args, (arg) arg.org
- cargs = _.map vfun.args, (arg) arg.name
+ #native-called virtual functions go into the .cpp file
+ #this is because we may return specializations of Convert<> from these functions
+ #and this must not happen before the explicit specializations of Convert<> generated by TypeManager.
+
+ implBlock = new CodeBlock.CodeBlock
+
+ publicv = public.add new CodeBlock.CodeBlock "", false
+ publicv.add "//JS: These virtual functions will only be called from Javascript"
+ publicd = public.add new CodeBlock.CodeBlock "", false
+ publicd.add "//Native: These virtual functions will only be called from native code"
+
+ _.each vfuncs, (vfunc) =>
+ dargs = _.map vfunc.args, (arg) -> arg.org
+ cargs = _.map vfunc.args, (arg) -> arg.name
+
+ vfunc.callAs = "_d_" + vfunc.name
ret = 'return'
if vfunc.type.rawType == 'void' then ret = ''
- public.add "inline #{vfunc.type.fullType()} bea_#{vfunc.name}(#{dargs.join ', '}){#{ret} #{@classType}::#{vfunc.name}(#{cargs.join ', '});}"
-
+ if vfunc.pure
+ funcontents = "throw bea::Exception(\"'#{vfunc.name}' : pure virtual function not defined.\");"
+ else
+ funcontents = "#{ret} #{@baseType.fullType()}::#{vfunc.name}(#{cargs.join ', '});"
+
+ publicv.add(new CodeBlock.FunctionBlock "inline #{vfunc.type.org} _d_#{vfunc.name}(#{dargs.join ', '})").add funcontents
+
+
+ vfuncdecla = "#{vfunc.type.org} #{vfunc.name}(#{dargs.join ', '})"
+
+ publicd.add vfuncdecla + ';'
+
+
+ fn = implBlock.add new CodeBlock.FunctionBlock "#{vfunc.type.org} #{@nativeClassName}::#{vfunc.name}(#{dargs.join ', '})"
+ fn.add "v8::HandleScope v8scope; v8::Handle<v8::Value> v8retVal;"
+ cif = fn.add new CodeBlock.CodeBlock "if (bea_derived_hasOverride(\"#{vfunc.name}\"))"
+
+ arglist = _.map vfunc.args, (arg) =>
+ snippets.ToJS(arg.type.org, arg.name, '')
+
+ if vfunc.args.length > 0
+ cif.add "v8::Handle<v8::Value> v8args[#{vfunc.args.length}] = {#{arglist.join(', ')}};"
+ else
+ cif.add "v8::Handle<v8::Value> v8args[1];"
+
+ cif.add "v8retVal = bea_derived_callJS(\"#{vfunc.name}\", #{vfunc.args.length}, v8args);"
+
+ fn.add "if (v8retVal.IsEmpty()) #{ret} _d_#{vfunc.name}(#{cargs.join ', '});"
+
+ if vfunc.type.rawType != 'void'
+ nativeType = @nativeType(vfunc.type)
+ #shit, this is messy, but no time now
+ if nativeType.indexOf('*') != -1 && !vfunc.type.isPointer then castBack = '*' else castBack = ''
+ fn.add "return #{castBack}" + snippets.FromJS(nativeType, "v8retVal", 0)
+
+
+ return {
+ decla: classBlock
+ impl: implBlock
+ }
#Create the InitJSObject function, to be added to the CPP file.
#This function will be called by the exposing function
createInitFn: ->
initFn = new CodeBlock.FunctionBlock snippets.decl.InitJSObject(@className)
if not @isStatic
- initFn.add snippets.impl.exposeClass(@classType, @exposedName)
+ initFn.add snippets.impl.exposeClass(@classType.fullType(), @exposedName)
else
initFn.add snippets.impl.exposeObject(@className, @exposedName)
@@ -323,12 +481,12 @@ class ClassConverter
#Get accessor
block.add "//Get Accessor #{name} (#{@nativeType accessor.type})"
fn = block.add new CodeBlock.FunctionBlock(snippets.impl.accessorGet @className, name)
- fn.add (snippets.impl.accessorGetImpl "#{@classType}*", @nativeType(accessor.type), accessor.read)
+ fn.add (snippets.impl.accessorGetImpl "#{@classType.fullType()}*", @nativeType(accessor.type), accessor.read)
#Set accessor
block.add "//Set Accessor #{name} (#{@nativeType accessor.type})"
fn = block.add new CodeBlock.FunctionBlock(snippets.impl.accessorSet @className, name)
- fn.add (snippets.impl.accessorSetImpl "#{@classType}*", @nativeType(accessor.type), accessor.write)
+ fn.add (snippets.impl.accessorSetImpl "#{@classType.fullType()}*", @nativeType(accessor.type), accessor.write)
@logger.stats.accessors++
return block
@@ -346,7 +504,6 @@ class ClassConverter
nativeType = @nativeType arg.type
if arg.type.rawType == 'void' then @warn 'Type #{arg.type.fullType()} used as argument type.'
if not arg.value
- #return "#{nativeType} #{arg.name} = FromJS<#{nativeType}>(args[#{narg}], #{narg});"
return "#{nativeType} #{arg.name} = " + snippets.FromJS nativeType, "args[#{narg}]", narg
else
#value can be:
@@ -361,7 +518,6 @@ class ClassConverter
argv = argType.namespace + '::' + argv
if argType.wrapped and not arg.type.isPointer
argv = '&' + argv
- #return "#{nativeType} #{arg.name} = Optional<#{nativeType}>(args, #{narg}, #{argv});"
return "#{nativeType} #{arg.name} = " + snippets.Optional nativeType, narg, argv
#Generates the if clause for a type check used to determine which overload to call
@@ -397,8 +553,10 @@ class ClassConverter
@convertArguments block, overload.args
if !@isStatic && overload.name != "__constructor"
- block.add "#{@classType}* _this = " + snippets.FromJS @classType + '*', "args.This()", 0
+ block.add "#{@classType.fullType()}* _this = " + snippets.FromJS @classType.fullType() + '*', "args.This()", 0
+ if overload.name == '__postAllocator' && @virtualCount > 0
+ block.add '_this->bea_derived_setInstance(args.This());'
#add the C++ sublines
_.each overload.sublines, (line) => block.add new CodeBlock.Code line.text
@@ -425,7 +583,7 @@ class ClassConverter
#If we are processing a static class, the converted functions aren't part of a C++ class, so we just have to prepend the current namespace to the function call (eg. cv::add())
#In case of a class member, we need to convert args.This() to the wrapped type (our class type)
#and use the form _this->functionName() to call the member function. Crazy stuff.
- fnName = overload.name
+ fnName = overload.callAs ? overload.name
if @isStatic
fnName = @namespace + '::' + fnName
else
@@ -447,11 +605,16 @@ class ClassConverter
#Mat* fnRet = new Mat(cols, rows)
#Mat* fnRet = new Mat(*src)
if overload.name == '__constructor'
- fncall = new FnCall fnRet, 'new ' + overload.type.fullType(), argList
+ fncall = new FnCall fnRet, 'new ' + @classType.fullType(), argList
retVal = "return v8::External::New(fnRetVal);"
else
- tmp = new FnCall '', fnName, argList
- fncall = new FnCall fnRet, 'new ' + overload.type.fullType(), tmp.render('')
+ #Native function returns a wrapped type.
+ #if it's not a pointer, make one
+ if not overload.type.isPointer
+ tmp = new FnCall '', fnName, argList
+ fncall = new FnCall fnRet, 'new ' + overload.type.fullType(), tmp.render('')
+ else
+ fncall = new FnCall fnRet, fnName, argList
#finally, add the block
block.add fncall.render() #function call
@@ -514,7 +677,7 @@ class ClassConverter
#add the sublines to the function
fnBlock = new CodeBlock.FunctionBlock snippets.impl.destructor(@className, "__destructor")
fnBlock.add "DESTRUCTOR_BEGIN();"
- fnBlock.add "#{@classType}* _this = " + snippets.FromJS @classType + '*', "value", 0
+ fnBlock.add "#{@classType.fullType()}* _this = " + snippets.FromJS @classType.fullType() + '*', "value", 0
_.each @destructorNode.children, (line) => fnBlock.add new CodeBlock.Code line.text
fnBlock.add "DESTRUCTOR_END();"
@logger.stats.converted++
View
61 src/mgr.coffee
@@ -10,18 +10,41 @@ class TypeManager
@types = []
#add a 'wrapped' or exposed class to the list
- addWrapped: (node, namespace) ->
- [type] = beautils.parseClassDirective node
- t = new beautils.Type type, namespace
- t.wrapped = true
- t.manual = false
- @types.push t
+ addWrapped: (type, baseType) ->
+ type.wrapped = true
+ type.manual = false
+
+ if not @isWrapped type then @types.push type
+
+ if baseType
+ #tmp = @findWrapped baseType
+ #make sure it doesn't already exists in the list
+ #possibly added by the pre-parse step
+ @types.push baseType
+ #if tmp then baseType = tmp else
+ baseType.alias = type.fullType()
+ baseType.manual = false
+ baseType.wrapped = true
+
+
+ #parse class node and create a 'wrapped' type from the declaraiton
+ addClassNode: (classNode, namespace) ->
+ cl = beautils.parseClassDirective classNode
+ cltype = new beautils.Type cl.className, namespace
+ cltype.wrapped = true
+ cltype.manual = false
+ if not @findWrapped cltype then @types.push cltype
+
#Check if a type is 'Wrapped', eg. is an exposed class
isWrapped: (type) ->
wrapped = _.filter @types, (t) -> t.wrapped
_.any wrapped, (wt) -> wt.rawType == type.rawType && wt.namespace == type.namespace
+ findWrapped: (type) ->
+ wrapped = _.filter @types, (t) -> t.wrapped
+ _.detect wrapped, (wt) -> wt.rawType == type.rawType && wt.namespace == type.namespace
+
#Check if a type is native or is in the list of declared types
knownType: (type) ->
@@ -81,7 +104,9 @@ class TypeManager
if type.alias then return []
members = []
if not type.manual
- members = _.map typeNode.children, (line) -> new beautils.Argument line.text, namespace
+ children = _.select typeNode.children, (n) -> not /^\s*\/\//.test n.text #without the comments
+
+ members = _.map children, (line) -> new beautils.Argument line.text.replace(';', '').replace(/\/\/.*$/,''), namespace
else
members = _.map typeNode.children, (line) -> line.text
return members
@@ -94,7 +119,10 @@ class TypeManager
#Wrapped type -> forward to ExposedClass<T>::Is()
if type.wrapped
- fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::Is(v);"
+ if not type.alias
+ fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::Is(v);"
+ else
+ fnBlock.add "return " + snippets.Is type.alias + '*', 'v'
return fnBlock
#alias, eg. type Double is double -> return Is<alias>(v). Compiler should recursively detect the right type
@@ -119,12 +147,14 @@ class TypeManager
fnBlock = new CodeBlock.CodeBlock
if type.wrapped
- fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::FromJS(v, nArg);"
+ if not type.alias
+ fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::FromJS(v, nArg);"
+ else
+ fnBlock.add "return " + snippets.FromJS type.alias + '*', 'v', 'nArg'
return fnBlock
if type.alias
#type Double alias double -> return (Double)FromJS<double>(v, nArg);
-
fnBlock.add "return (#{type.fullType()})" + snippets.FromJS(type.alias, 'v', 'nArg')
return fnBlock
@@ -148,10 +178,19 @@ class TypeManager
#Create to ToJS<T> function
fnToJS: (type) ->
+
+ #return false unless !type.noToJS
fnBlock = new CodeBlock.CodeBlock
if type.wrapped
- fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::ToJS(v);"
+ if not type.alias
+ fnBlock.add "return bea::ExposedClass<#{fixt type.fullType()}>::ToJS(v);"
+ else
+ fnBlock.add "return " + snippets.ToJS type.alias + '*', "static_cast<#{fixt type.alias}*>(v)"
+ return fnBlock
+
+ if type.alias
+ fnBlock.add "return " + snippets.ToJS type.alias, "v"
return fnBlock
fnBlock.add "v8::HandleScope scope;"
View
2 src/snippets.coffee
@@ -81,7 +81,7 @@ exports.impl.accessorSetImpl = (thisType, accessorType, impl) ->
if impl.length == 0 then impl = '//TODO: Set value here'
"""v8::HandleScope scope;
#{thisType} _this = bea::Convert<#{fixt thisType}>::FromJS(info.Holder(), 0);
- #{accessorType} value = bea::Convert<#{fixt accessorType}>::FromJS(v, 0);
+ #{accessorType} _accValue = bea::Convert<#{fixt accessorType}>::FromJS(v, 0);
#{impl}
"""

0 comments on commit 5212b15

Please sign in to comment.
Something went wrong with that request. Please try again.