Skip to content

Commit

Permalink
webidl binder
Browse files Browse the repository at this point in the history
  • Loading branch information
kripken committed Apr 24, 2014
1 parent 55c1dfd commit 28ed391
Show file tree
Hide file tree
Showing 10 changed files with 5,792 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ var EXPORTED_FUNCTIONS = ['_main', '_malloc'];
var EXPORT_ALL = 0; // If true, we export all the symbols. Note that this does *not* affect LLVM, so it can
// still eliminate functions as dead. This just exports them on the Module object.
var EXPORT_BINDINGS = 0; // Export all bindings generator functions (prefixed with emscripten_bind_). This
// is necessary to use the bindings generator with asm.js
// is necessary to use the WebIDL binder or bindings generator with asm.js
var RETAIN_COMPILER_SETTINGS = 0; // Remembers the values of these settings, and makes them accessible
// through Runtime.getCompilerSetting and emscripten_get_compiler_setting.
// To see what is retained, look for compilerSettings in the generated code.
Expand Down
16 changes: 16 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5971,6 +5971,22 @@ def process(filename):
'''
self.do_run(src, '|hello|43|world|41|', post_build=post)

def test_webidl(self):
if self.emcc_args is None: return self.skip('requires emcc')

output = Popen([PYTHON, path_from_root('tools', 'webidl_binder.py'),
path_from_root('tests', 'webidl', 'test.idl'),
'glue']).communicate()[0]
assert os.path.exists('glue.cpp')
assert os.path.exists('glue.js')

self.emcc_args += ['--post-js', 'glue.js',
'--post-js', path_from_root('tests', 'webidl', 'post.js')]
shutil.copyfile(path_from_root('tests', 'webidl', 'test.h'), self.in_dir('test.h'))
shutil.copyfile(path_from_root('tests', 'webidl', 'test.cpp'), self.in_dir('test.cpp'))
src = open('test.cpp').read()
self.do_run(src, open(path_from_root('tests', 'webidl', 'output.txt')).read())

def test_typeinfo(self):
if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('fastcomp does not support RUNTIME_TYPE_INFO')

Expand Down
56 changes: 56 additions & 0 deletions tests/webidl/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Parent:42
*
84
c1
Parent:7
Child1:7
7
14
196
588
14
28
c1 v2
Parent:16
Child1:15
15
30
900
2700
c2
Parent:9
Child2:9
9
18
5832
0
0
1
*static*
*virtualf*
*virtualf*
*virtualf2*
Parent:9
Child2:9
*js virtualf replacement*
*js virtualf replacement*
*js virtualf2 replacement*
*js virtualf3 replacement 123*
caught: a JSImplementation must implement all functions, you forgot Child2JS::virtualFunc4.
*virtualf*
*virtualf*
*virtualf2*
*ok*
|hello|43|world|41|
12.35
10
object
10
11
object
10
11
21.12
198

done.
117 changes: 117 additions & 0 deletions tests/webidl/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@

// Part 1

var sme = new Module.Parent(42);
sme.mulVal(2);
Module.print('*')
Module.print(sme.getVal());

Module.print('c1');

var c1 = new Module.Child1();
Module.print(c1.getVal());
c1.mulVal(2);
Module.print(c1.getVal());
Module.print(c1.getValSqr());
Module.print(c1.getValSqr(3));
Module.print(c1.getValTimes()); // default argument should be 1
Module.print(c1.getValTimes(2));

Module.print('c1 v2');

c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2
Module.print(c1.getVal());
c1.mulVal(2);
Module.print(c1.getVal());
Module.print(c1.getValSqr());
Module.print(c1.getValSqr(3));

Module.print('c2')

var c2 = new Module.Child2();
Module.print(c2.getVal());
c2.mulVal(2);
Module.print(c2.getVal());
Module.print(c2.getValCube());
var succeeded;
try {
succeeded = 0;
Module.print(c2.doSomethingSecret()); // should fail since private
succeeded = 1;
} catch(e) {}
Module.print(succeeded);
try {
succeeded = 0;
Module.print(c2.getValSqr()); // function from the other class
succeeded = 1;
} catch(e) {}
Module.print(succeeded);
try {
succeeded = 0;
c2.getValCube(); // sanity
succeeded = 1;
} catch(e) {}
Module.print(succeeded);

Module.Child2.prototype.printStatic(); // static calls go through the prototype

// virtual function
c2.virtualFunc();
Module.Child2.prototype.runVirtualFunc(c2);
c2.virtualFunc2();

// extend a class from JS
var c3 = new Module.Child2JS;

c3.virtualFunc = function() {
Module.print('*js virtualf replacement*');
};
c3.virtualFunc2 = function() {
Module.print('*js virtualf2 replacement*');
};
c3.virtualFunc3 = function(x) {
Module.print('*js virtualf3 replacement ' + x + '*');
};

c3.virtualFunc();
Module.Child2.prototype.runVirtualFunc(c3);
c3.virtualFunc2();
c3.virtualFunc3(123); // this one is not replaced!
try {
c3.virtualFunc4(123);
} catch(e) {
Module.print('caught: ' + e);
}

c2.virtualFunc(); // original should remain the same
Module.Child2.prototype.runVirtualFunc(c2);
c2.virtualFunc2();
Module.print('*ok*');

// Part 2

var suser = new Module.StringUser("hello", 43);
suser.Print(41, "world");
suser.PrintFloat(12.3456);

var bv = new Module.RefUser(10);
var bv2 = new Module.RefUser(11);
Module.print(bv2.getValue(bv));

Module.print(typeof bv2.getMe());
Module.print(bv2.getMe().getValue(bv));
Module.print(bv2.getMe().getValue(bv2));

Module.print(typeof bv2.getCopy());
Module.print(bv2.getCopy().getValue(bv));
Module.print(bv2.getCopy().getValue(bv2));

bv2.getAnother().PrintFloat(21.12);

Module.print(new Module.Inner().get());
new Module.Inner().mul(2);

//

Module.print('\ndone.')

8 changes: 8 additions & 0 deletions tests/webidl/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "test.h"

Parent::Parent(int val) : value(val) { printf("Parent:%d\n", val); }
Parent::Parent(Parent *p, Parent *q) : value(p->value + q->value) { printf("Parent:%d\n", value); }
void Parent::mulVal(int mul) { value *= mul; }

#include "glue.cpp"

72 changes: 72 additions & 0 deletions tests/webidl/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <stdio.h>

// Part 1

class Parent {
protected:
int value;
public:
Parent(int val);
Parent(Parent *p, Parent *q); // overload constructor
int getVal() { return value; }; // inline should work just fine here, unlike Way 1 before
void mulVal(int mul);
};

class Child1 : public Parent {
public:
Child1() : Parent(7) { printf("Child1:%d\n", value); };
Child1(int val) : Parent(val*2) { value -= 1; printf("Child1:%d\n", value); };
int getValSqr() { return value*value; }
int getValSqr(int more) { return value*value*more; }
int getValTimes(int times=1) { return value*times; }
};

// Child2 has vtable, parent does not. Checks we cast child->parent properly - (Parent*)child is not a no-op, must offset
class Child2 : public Parent {
public:
Child2() : Parent(9) { printf("Child2:%d\n", value); };
int getValCube() { return value*value*value; }
static void printStatic() { printf("*static*\n"); }

virtual void virtualFunc() { printf("*virtualf*\n"); }
virtual void virtualFunc2() { printf("*virtualf2*\n"); }
static void runVirtualFunc(Child2 *self) { self->virtualFunc(); };
virtual void virtualFunc3(int x) { printf("*virtualf3: %d*\n", x); }
virtual void virtualFunc4(int x) { printf("*virtualf4: %d*\n", x); }

private:
void doSomethingSecret() { printf("security breached!\n"); }; // we should not be able to do this
};

// Part 2

#include <string.h>

class StringUser {
char *s;
int i;
public:
StringUser(char *string="NO", int integer=99) : s(strdup(string)), i(integer) {}
void Print(int anotherInteger, char *anotherString) {
printf("|%s|%d|%s|%d|\n", s, i, anotherString, anotherInteger);
}
void PrintFloat(float f) { printf("%.2f\n", f); }
};

struct RefUser {
int value;
RefUser(int x = 77) : value(x) {}
int getValue(RefUser b) { return b.value; }
RefUser &getMe() { return *this; }
RefUser getCopy() { return RefUser(value*2); }
StringUser getAnother() { return StringUser("another", 5); }
};

namespace Space {
struct Inner {
Inner() {}
int get() { return 198; }
Inner& operator*=(float x) { return *this; }
};
}

64 changes: 64 additions & 0 deletions tests/webidl/test.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

// Part 1

interface Parent {
void Parent(long val);
long getVal();
void mulVal(long mul);
};

interface Child1 {
void Child1(optional long val);
long getValSqr(optional long more);
long getValTimes(optional long times=1);
};

Child1 implements Parent;

interface Child2 {
void Child2();
long getValCube();
static void printStatic();
void virtualFunc();
void virtualFunc2();
void virtualFunc3(long x);
void virtualFunc4(long x);
static void runVirtualFunc(Child2 self);
};

Child2 implements Parent;

[JSImplementation="Child2"]
interface Child2JS {
void Child2JS();
void virtualFunc();
void virtualFunc2();
void virtualFunc3(long x);
void virtualFunc4(long x);
};

// Part 2

interface StringUser {
void StringUser();
void StringUser(DOMString str, long i);
void Print(long anotherInteger, DOMString anotherString);
void PrintFloat(float f);
};

interface RefUser {
void RefUser();
void RefUser(long value);
long getValue([Ref] RefUser b);
[Ref] RefUser getMe();
[Value] RefUser getCopy(); // must have zero-arg constructor
[Value] StringUser getAnother();
};

[Prefix="Space::"]
interface Inner {
void Inner();
long get();
[Operator="*=", Ref] Inner mul(float x);
};

Loading

0 comments on commit 28ed391

Please sign in to comment.