Merge remote-tracking branch 'upstream/master'

This commit is contained in:
max99x 2011-07-08 12:53:20 +03:00
Родитель b84bb001de 1a599856b4
Коммит 8ffd5c52ca
10 изменённых файлов: 1494 добавлений и 859 удалений

Просмотреть файл

@ -28,9 +28,9 @@
%\maketitle
\begin{abstract}
We present Emscripten, an LLVM-to-JavaScript compiler. Emscripten compiles
LLVM (Low Level Virtual Machine) assembly code into standard JavaScript, which opens up two avenues for running code written
in languages other than JavaScript on the web: (1) Compile code directly into LLVM bitcode, and
We present Emscripten, a compiler from LLVM (Low Level Virtual Machine) assembly to JavaScript. This
opens up two avenues for running code written
in languages other than JavaScript on the web: (1) Compile code directly into LLVM assemby, and
then compile that into JavaScript using Emscripten, or (2) Compile
a language's entire runtime into LLVM and then JavaScript, as in the previous
approach, and then use the compiled runtime to run code written in that language. For example, the
@ -107,8 +107,8 @@ not Python, so for example division of integers can yield unexpected results
but in JavaScript and in Pyjamas a floating-point number can be generated).
In this paper we present another project along those lines: \textbf{Emscripten},
which compiles LLVM assembly code into JavaScript. LLVM (the Low Level Virtual
Machine\footnote{\url{http://llvm.org/}}) is a compiler project primarily focused on C, C++ and
which compiles LLVM (Low Level Virtual Machine\footnote{\url{http://llvm.org/}}) assembly into JavaScript.
LLVM is a compiler project primarily focused on C, C++ and
Objective-C. It compiles those languages through a \emph{frontend} (the
main ones of which are Clang and LLVM-GCC) into the
LLVM intermediary representation (which can be machine-readable

Просмотреть файл

@ -681,7 +681,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
+ makeFunctionCall(item.ident, item.params, item.funcData) + ' '
+ '} catch(e) { '
+ 'if (ABORT) throw e; __THREW__ = true; '
+ (EXCEPTION_DEBUG ? 'print("Exception: " + e + " : " + e.stack + ", currently at: " + (new Error().stack)); ' : '')
+ (EXCEPTION_DEBUG ? 'print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
+ 'return null } })(); if (!__THREW__) { ' + makeBranch(item.toLabel, item.currLabelId)
+ ' } else { ' + makeBranch(item.unwindLabel, item.currLabelId) + ' }';
return ret;

Просмотреть файл

@ -482,7 +482,7 @@ function __shutdownRuntime__() {
if (typeof func === 'number') {
func = FUNCTION_TABLE[func];
}
func(atexit.arg);
func(atexit.arg || null);
}
// allow browser to GC, set heaps to null?

Просмотреть файл

@ -2426,8 +2426,9 @@ if 'benchmark' not in sys.argv:
'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000',
args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''])
### Test cases in separate files
# Test cases in separate files. Note that these files may contain invalid .ll!
# They are only valid enough for us to read for test purposes, not for llvm-as
# to process.
def test_cases(self):
global CHECK_OVERFLOWS; CHECK_OVERFLOWS = 0
if LLVM_OPTS: return self.skip() # Our code is not exactly 'normal' llvm assembly
@ -2505,6 +2506,7 @@ if 'benchmark' not in sys.argv:
### Integration tests
def test_scriptaclass(self):
header_filename = os.path.join(self.get_dir(), 'header.h')
header = '''
struct ScriptMe {
int value;
@ -2515,8 +2517,9 @@ if 'benchmark' not in sys.argv:
void mulVal(int mul);
};
'''
header_filename = os.path.join(self.get_dir(), 'header.h')
open(header_filename, 'w').write(header)
h = open(header_filename, 'w')
h.write(header)
h.close()
src = '''
#include "header.h"
@ -2548,23 +2551,100 @@ if 'benchmark' not in sys.argv:
# Way 2: use CppHeaderParser
header = '''
#include <stdio.h>
class Parent {
protected:
int value;
public:
Parent(int val);
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; }
};
class Child2 : Parent {
public:
Child2() : Parent(9) { printf("Child2:%d\\n", value); };
int getValCube() { return value*value*value; }
private:
void doSomethingSecret() { printf("security breached!\\n"); }; // we should not be able to do this
};
'''
open(header_filename, 'w').write(header)
basename = os.path.join(self.get_dir(), 'bindingtest')
Popen(['python', BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=STDOUT).communicate()[0]
output = Popen(['python', BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=STDOUT).communicate()[0]
assert 'Traceback' not in output, 'Failure in binding generation: ' + output
src = '''
#include "header.h"
ScriptMe::ScriptMe(int val) : value(val) { }
int ScriptMe::getVal() { return value; }
void ScriptMe::mulVal(int mul) { value *= mul; }
Parent::Parent(int val) : value(val) { printf("Parent:%d\\n", val); }
void Parent::mulVal(int mul) { value *= mul; }
#include "bindingtest.c"
'''
script_src_2 = '''
var sme = new ScriptMe(83);
var sme = new Parent(42);
sme.mulVal(2);
print('*' + sme.getVal() + '*');
print('*')
print(sme.getVal());
print('c1');
var c1 = new Child1();
print(c1.getVal());
c1.mulVal(2);
print(c1.getVal());
print(c1.getValSqr());
print(c1.getValSqr_2(3));
print('c1 v2');
c1 = new Child1_2(8);
print(c1.getVal());
c1.mulVal(2);
print(c1.getVal());
print(c1.getValSqr());
print(c1.getValSqr_2(3));
print('c2')
var c2 = new Child2();
print(c2.getVal());
c2.mulVal(2);
print(c2.getVal());
print(c2.getValCube());
var succeeded;
try {
succeeded = 0;
print(c2.doSomethingSecret()); // should fail since private
succeeded = 1;
} catch(e) {}
print(succeeded);
try {
succeeded = 0;
print(c2.getValSqr()); // function from the other class
succeeded = 1;
} catch(e) {}
print(succeeded);
try {
succeeded = 0;
c2.getValCube(); // sanity
succeeded = 1;
} catch(e) {}
print(succeeded);
print('*ok*');
'''
@ -2575,7 +2655,33 @@ if 'benchmark' not in sys.argv:
'// {{MODULE_ADDITIONS}'
)
open(filename, 'w').write(src)
self.do_test(src, '*166*\n*ok*', post_build=post2)
self.do_test(src, '''*
84
c1
Parent:7
Child1:7
7
14
196
588
c1 v2
Parent:16
Child1:15
15
30
900
2700
c2
Parent:9
Child2:9
9
18
5832
0
0
1
*ok*
''', post_build=post2)
### Tests for tools

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,669 +0,0 @@
#!/usr/bin/python
#
# Author: Jashua R. Cloutier (contact via sourceforge username:senexcanis)
#
# Copyright (C) 2010, Jashua R. Cloutier
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# * Neither the name of Jashua R. Cloutier nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#
# The CppHeaderParser.py script is written in Python 2.4 and released to
# the open source community for continuous improvements under the BSD
# 2.0 new license, which can be found at:
#
# http://www.opensource.org/licenses/bsd-license.php
#
"""Parse C++ header files and generate a data structure
representing the class
"""
import ply.lex as lex
import os
import sys
import re
import inspect
def lineno():
"""Returns the current line number in our program."""
return inspect.currentframe().f_back.f_lineno
__version__ = "1.9"
version = "1.9"
tokens = [
'NUMBER',
'NAME',
'OPEN_PAREN',
'CLOSE_PAREN',
'OPEN_BRACE',
'CLOSE_BRACE',
'COLON',
'SEMI_COLON',
'COMMA',
'COMMENT_SINGLELINE',
'COMMENT_MULTILINE',
'PRECOMP_MACRO',
'PRECOMP_MACRO_CONT',
'ASTERISK',
'AMPERSTAND',
'EQUALS',
'MINUS',
'PLUS',
'DIVIDE',
'CHAR_LITERAL',
'STRING_LITERAL',
'OPERATOR_DIVIDE_OVERLOAD',
'NEW_LINE',
]
t_ignore = " \t\r[].|!?%@"
t_NUMBER = r'[0-9][0-9XxA-Fa-f]*'
t_NAME = r'[<>A-Za-z_~][A-Za-z0-9_]*'
t_OPERATOR_DIVIDE_OVERLOAD = r'/='
t_OPEN_PAREN = r'\('
t_CLOSE_PAREN = r'\)'
t_OPEN_BRACE = r'{'
t_CLOSE_BRACE = r'}'
t_SEMI_COLON = r';'
t_COLON = r':'
t_COMMA = r','
t_PRECOMP_MACRO = r'\#.*'
t_PRECOMP_MACRO_CONT = r'.*\\\n'
def t_COMMENT_SINGLELINE(t):
r'\/\/.*\n'
global doxygenCommentCache
if t.value.startswith("///") or t.value.startswith("//!"):
if doxygenCommentCache:
doxygenCommentCache += "\n"
if t.value.endswith("\n"):
doxygenCommentCache += t.value[:-1]
else:
doxygenCommentCache += t.value
t_ASTERISK = r'\*'
t_MINUS = r'\-'
t_PLUS = r'\+'
t_DIVIDE = r'/[^/]'
t_AMPERSTAND = r'&'
t_EQUALS = r'='
t_CHAR_LITERAL = "'.'"
#found at http://wordaligned.org/articles/string-literals-and-regular-expressions
#TODO: This does not work with the string "bla \" bla"
t_STRING_LITERAL = r'"([^"\\]|\\.)*"'
#Found at http://ostermiller.org/findcomment.html
def t_COMMENT_MULTILINE(t):
r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/'
global doxygenCommentCache
if t.value.startswith("/**") or t.value.startswith("/*!"):
#not sure why, but get double new lines
v = t.value.replace("\n\n", "\n")
#strip prefixing whitespace
v = re.sub("\n[\s]+\*", "\n*", v)
doxygenCommentCache += v
def t_NEWLINE(t):
r'\n+'
t.lexer.lineno += len(t.value)
def t_error(v):
print("Lex error: ", v)
lex.lex()
debug = 0
supportedAccessSpecifier = [
'public',
'protected',
'private'
]
doxygenCommentCache = ""
def is_namespace(nameStack):
"""Determines if a namespace is being specified"""
if len(nameStack) == 0:
return False
if nameStack[0] == "namespace":
return True
return False
def is_enum_namestack(nameStack):
"""Determines if a namestack is an enum namestack"""
if len(nameStack) == 0:
return False
if nameStack[0] == "enum":
return True
if len(nameStack) > 1 and nameStack[0] == "typedef" and nameStack[1] == "enum":
return True
return False
class CppParseError(Exception): pass
class CppClass(dict):
"""Takes a name stack and turns it into a class
Contains the following Keys:
self['name'] - Name of the class
self['doxygen'] - Doxygen comments associated with the class if they exist
self['inherits'] - List of Classes that this one inherits where the values
are of the form {"access": Anything in supportedAccessSpecifier
"class": Name of the class
self['methods'] - Dictionary where keys are from supportedAccessSpecifier
and values are a lists of CppMethod's
self['properties'] - Dictionary where keys are from supportedAccessSpecifier
and values are lists of CppVariable's
self['enums'] - Dictionary where keys are from supportedAccessSpecifier and
values are lists of CppEnum's
An example of how this could look is as follows:
#self =
{
'name': ""
'inherits':[]
'methods':
{
'public':[],
'protected':[],
'private':[]
},
'properties':
{
'public':[],
'protected':[],
'private':[]
},
'enums':
{
'public':[],
'protected':[],
'private':[]
}
}
"""
def __init__(self, nameStack):
if (debug): print("Class: ", nameStack)
if (len(nameStack) < 2):
print("Error detecting class")
return
global doxygenCommentCache
if len(doxygenCommentCache):
self["doxygen"] = doxygenCommentCache
doxygenCommentCache = ""
self["name"] = nameStack[1]
inheritList = []
if ":" in nameStack:
nameStack = nameStack[nameStack.index(":") + 1:]
while len(nameStack):
tmpStack = []
tmpInheritClass = {"access":"private"}
if "," in nameStack:
tmpStack = nameStack[:nameStack.index(",")]
nameStack = nameStack[nameStack.index(",") + 1:]
else:
tmpStack = nameStack
nameStack = []
if len(tmpStack) == 0:
break;
elif len(tmpStack) == 1:
tmpInheritClass["class"] = tmpStack[0]
elif len(tmpStack) == 2:
tmpInheritClass["access"] = tmpStack[0]
tmpInheritClass["class"] = tmpStack[1]
else:
print("Warning: Cant figure out class inheriting %s\n"%(" ".join(tmpStack)))
continue
inheritList.append(tmpInheritClass)
methodAccessSpecificList = {}
propertyAccessSpecificList = {}
enumAccessSpecificList = {}
for accessSpecifier in supportedAccessSpecifier:
methodAccessSpecificList[accessSpecifier] = []
propertyAccessSpecificList[accessSpecifier] = []
enumAccessSpecificList[accessSpecifier] = []
self['inherits'] = inheritList
self['methods'] = methodAccessSpecificList
self['properties'] = propertyAccessSpecificList
self['enums'] = enumAccessSpecificList
self['namespace'] = ""
def __repr__(self):
"""Convert class to a string"""
namespace_prefix = ""
if self["namespace"]: namespace_prefix = self["namespace"] + "::"
rtn = "class %s\n"%(namespace_prefix + self["name"])
try:
print(self["doxygen"], end=' ')
except: pass
if "inherits" in list(self.keys()):
rtn += "Inherits: "
for inheritClass in self["inherits"]:
rtn += "%s %s, "%(inheritClass["access"], inheritClass["class"])
rtn += "\n"
rtn += "{\n"
for accessSpecifier in supportedAccessSpecifier:
rtn += "%s\n"%(accessSpecifier)
#Enums
if (len(self["enums"][accessSpecifier])):
rtn += " // Enums\n"
for enum in self["enums"][accessSpecifier]:
rtn += " %s\n"%(repr(enum))
#Properties
if (len(self["properties"][accessSpecifier])):
rtn += " // Properties\n"
for property in self["properties"][accessSpecifier]:
rtn += " %s\n"%(repr(property))
#Methods
if (len(self["methods"][accessSpecifier])):
rtn += " // Method\n"
for method in self["methods"][accessSpecifier]:
rtn += " %s\n"%(repr(method))
rtn += "}\n"
return rtn
class CppMethod(dict):
"""Takes a name stack and turns it into a method
Contains the following Keys:
self['rtnType'] - Return type of the method (ex. "int")
self['name'] - Name of the method (ex. "getSize")
self['doxygen'] - Doxygen comments associated with the method if they exist
self['parameters'] - List of CppVariables
"""
def __init__(self, nameStack, curClass):
if (debug): print("Method: ", nameStack)
global doxygenCommentCache
if len(doxygenCommentCache):
self["doxygen"] = doxygenCommentCache
doxygenCommentCache = ""
if "operator" in nameStack:
self["rtnType"] = " ".join(nameStack[:nameStack.index('operator')])
self["name"] = "".join(nameStack[nameStack.index('operator'):nameStack.index('(')])
else:
self["rtnType"] = " ".join(nameStack[:nameStack.index('(') - 1])
self["name"] = " ".join(nameStack[nameStack.index('(') - 1:nameStack.index('(')])
if len(self["rtnType"]) == 0 or self["name"] == curClass:
self["rtnType"] = "void"
paramsStack = nameStack[nameStack.index('(') + 1: ]
#Remove things from the stack till we hit the last paren, this helps handle abstract and normal methods
while (paramsStack[-1] != ")"):
paramsStack.pop()
paramsStack.pop()
params = []
#See if there is a doxygen comment for the variable
doxyVarDesc = {}
#TODO: Put this into a class
if "doxygen" in self:
doxyLines = self["doxygen"].split("\n")
lastParamDesc = ""
for doxyLine in doxyLines:
if " @param " in doxyLine or " \param " in doxyLine:
try:
#Strip out the param
doxyLine = doxyLine[doxyLine.find("param ") + 6:]
(var, desc) = doxyLine.split(" ", 1)
doxyVarDesc[var] = desc.strip()
lastParamDesc = var
except: pass
elif " @return " in doxyLine or " \return " in doxyLine:
lastParamDesc = ""
# not handled for now
elif lastParamDesc:
try:
doxyLine = doxyLine.strip()
if " " not in doxyLine:
lastParamDesc = ""
continue
doxyLine = doxyLine[doxyLine.find(" ") + 1:]
doxyVarDesc[lastParamDesc] += " " + doxyLine
except: pass
#Create the variable now
while (len(paramsStack)):
if (',' in paramsStack):
params.append(CppVariable(paramsStack[0:paramsStack.index(',')], doxyVarDesc=doxyVarDesc))
paramsStack = paramsStack[paramsStack.index(',') + 1:]
else:
param = CppVariable(paramsStack, doxyVarDesc=doxyVarDesc)
if len(list(param.keys())):
params.append(param)
break
self["parameters"] = params
class CppVariable(dict):
"""Takes a name stack and turns it into a method
Contains the following Keys:
self['type'] - Type for the variable (ex. "const string &")
self['name'] - Name of the variable (ex. "numItems")
self['namespace'] - Namespace containing the enum
self['desc'] - Description of the variable if part of a method (optional)
self['doxygen'] - Doxygen comments associated with the method if they exist
self['defaltValue'] - Default value of the variable, this key will only
exist if there is a default value
"""
def __init__(self, nameStack, **kwargs):
if (debug): print("Variable: ", nameStack)
if (len(nameStack) < 2):
return
global doxygenCommentCache
if len(doxygenCommentCache):
self["doxygen"] = doxygenCommentCache
doxygenCommentCache = ""
if ("=" in nameStack):
self["type"] = " ".join(nameStack[:nameStack.index("=") - 1])
self["name"] = nameStack[nameStack.index("=") - 1]
self["defaltValue"] = " ".join(nameStack[nameStack.index("=") + 1:])
else:
self["type"] = " ".join(nameStack[:-1])
self["name"] = nameStack[-1]
self["type"] = self["type"].replace(" :",":")
self["type"] = self["type"].replace(": ",":")
self["type"] = self["type"].replace(" <","<")
self["type"] = self["type"].replace(" >",">")
#Optional doxygen description
try:
self["desc"] = kwargs["doxyVarDesc"][self["name"]]
except: pass
class CppEnum(dict):
"""Takes a name stack and turns it into an Enum
Contains the following Keys:
self['name'] - Name of the enum (ex. "ItemState")
self['namespace'] - Namespace containing the enum
self['values'] - List of values where the values are a dictionary of the
form {"name": name of the key (ex. "PARSING_HEADER"),
"value": Specified value of the enum, this key will only exist
if a value for a given enum value was defined
}
"""
def __init__(self, nameStack):
if len(nameStack) < 4 or "{" not in nameStack or "}" not in nameStack:
#Not enough stuff for an enum
return
global doxygenCommentCache
if len(doxygenCommentCache):
self["doxygen"] = doxygenCommentCache
doxygenCommentCache = ""
valueList = []
#Figure out what values it has
valueStack = nameStack[nameStack.index('{') + 1: nameStack.index('}')]
while len(valueStack):
tmpStack = []
if "," in valueStack:
tmpStack = valueStack[:valueStack.index(",")]
valueStack = valueStack[valueStack.index(",") + 1:]
else:
tmpStack = valueStack
valueStack = []
if len(tmpStack) == 1:
valueList.append({"name": tmpStack[0]})
elif len(tmpStack) >= 3 and tmpStack[1] == "=":
valueList.append({"name": tmpStack[0], "value": " ".join(tmpStack[2:])})
elif len(tmpStack) == 2 and tmpStack[1] == "=":
if (debug): print("Missed value for %s"%tmpStack[0])
valueList.append({"name": tmpStack[0]})
if len(valueList):
self["values"] = valueList
else:
#An enum without any values is useless, dont bother existing
return
#Figure out if it has a name
preBraceStack = nameStack[:nameStack.index("{")]
postBraceStack = nameStack[nameStack.index("}") + 1:]
if (len(preBraceStack) == 2 and "typedef" not in nameStack):
self["name"] = preBraceStack[1]
elif len(postBraceStack) and "typedef" in nameStack:
self["name"] = " ".join(postBraceStack)
#See if there are instances of this
if "typedef" not in nameStack and len(postBraceStack):
self["instances"] = []
for var in postBraceStack:
if "," in var:
continue
self["instances"].append(var)
self["namespace"] = ""
class CppHeader:
"""Parsed C++ class header
Variables produced:
self.classes - Dictionary of classes found in a given header file where the
key is the name of the class
"""
def __init__(self, headerFileName, argType = "file"):
if (argType == "file"):
self.headerFileName = os.path.expandvars(headerFileName)
self.mainClass = os.path.split(self.headerFileName)[1][:-2]
headerFileStr = ""
# if headerFileName[-2:] != ".h":
# raise Exception("file must be a header file and end with .h")
elif argType == "string":
self.headerFileName = ""
self.mainClass = "???"
headerFileStr = headerFileName
else:
raise Exception("Arg type must be either file or string")
self.curClass = ""
self.classes = {}
self.enums = []
self.nameStack = []
self.nameSpaces = []
self.curAccessSpecifier = 'private'
if (len(self.headerFileName)):
headerFileStr = "\n".join(open(self.headerFileName).readlines())
self.braceDepth = 0
lex.input(headerFileStr)
curLine = 0
curChar = 0
try:
while True:
tok = lex.token()
# Example: LexToken(COLON,';',1,373)
# where (tok.name, tok.value, ?, ?)
if not tok:
break
curLine = tok.lineno
curChar = tok.lexpos
if (tok.type == 'OPEN_BRACE'):
if len(self.nameStack) and is_namespace(self.nameStack):
self.nameSpaces.append(self.nameStack[1])
if len(self.nameStack) and not is_enum_namestack(self.nameStack):
self.evaluate_stack()
else:
self.nameStack.append(tok.value)
self.braceDepth += 1
elif (tok.type == 'CLOSE_BRACE'):
if self.braceDepth == 0:
continue
if (self.braceDepth == len(self.nameSpaces)):
tmp = self.nameSpaces.pop()
if len(self.nameStack) and is_enum_namestack(self.nameStack):
self.nameStack.append(tok.value)
elif self.braceDepth < 10:
self.evaluate_stack()
else:
self.nameStack = []
self.braceDepth -= 1
if (self.braceDepth == 0):
self.curClass = ""
if (tok.type == 'OPEN_PAREN'):
self.nameStack.append(tok.value)
elif (tok.type == 'CLOSE_PAREN'):
self.nameStack.append(tok.value)
elif (tok.type == 'EQUALS'):
self.nameStack.append(tok.value)
elif (tok.type == 'COMMA'):
self.nameStack.append(tok.value)
elif (tok.type == 'NUMBER'):
self.nameStack.append(tok.value)
elif (tok.type == 'MINUS'):
self.nameStack.append(tok.value)
elif (tok.type == 'PLUS'):
self.nameStack.append(tok.value)
elif (tok.type == 'STRING_LITERAL'):
self.nameStack.append(tok.value)
elif (tok.type == 'NAME' or tok.type == 'AMPERSTAND' or tok.type == 'ASTERISK'):
if (tok.value == 'class'):
self.nameStack.append(tok.value)
elif (tok.value in supportedAccessSpecifier and self.braceDepth == len(self.nameSpaces) + 1):
self.curAccessSpecifier = tok.value
else:
self.nameStack.append(tok.value)
elif (tok.type == 'COLON'):
#Dont want colon to be first in stack
if len(self.nameStack) == 0:
continue
self.nameStack.append(tok.value)
elif (tok.type == 'SEMI_COLON'):
if (self.braceDepth < 10):
self.evaluate_stack()
except:
raise CppParseError("Not able to parse %s on line %d evaluating \"%s\"\nError around: %s"
% (self.headerFileName, tok.lineno, tok.value, " ".join(self.nameStack)))
def evaluate_stack(self):
"""Evaluates the current name stack"""
global doxygenCommentCache
if (debug): print("Evaluating stack %s at..."%self.nameStack)
if (len(self.curClass)):
if (debug): print("%s (%s) "%(self.curClass, self.curAccessSpecifier), end=' ')
if (len(self.nameStack) == 0):
if (debug): print("line ",lineno())
if (debug): print("(Empty Stack)")
return
elif (self.nameStack[0] == "namespace"):
#Taken care of outside of here
pass
elif (self.nameStack[0] == "class"):
if (debug): print("line ",lineno())
self.evaluate_class_stack()
elif (self.nameStack[0] == "struct"):
if (debug): print("line ",lineno())
self.curAccessSpecifier = "public"
self.evaluate_class_stack()
elif (len(self.curClass) == 0):
if (debug): print("line ",lineno())
if is_enum_namestack(self.nameStack):
self.evaluate_enum_stack()
self.nameStack = []
doxygenCommentCache = ""
return
elif (self.braceDepth < 1):
if (debug): print("line ",lineno())
#Ignore global stuff for now
if (debug): print("Global stuff: ", self.nameStack)
self.nameStack = []
doxygenCommentCache = ""
return
elif (self.braceDepth > len(self.nameSpaces) + 1):
if (debug): print("line ",lineno())
self.nameStack = []
doxygenCommentCache = ""
return
elif is_enum_namestack(self.nameStack):
if (debug): print("line ",lineno())
#elif self.nameStack[0] == "enum":
self.evaluate_enum_stack()
elif ('(' in self.nameStack):
if (debug): print("line ",lineno())
self.evaluate_method_stack()
else:
if (debug): print("line ",lineno())
self.evaluate_property_stack()
self.nameStack = []
doxygenCommentCache = ""
def evaluate_class_stack(self):
"""Create a Class out of the name stack (but not its parts)"""
#dont support sub classes today
if self.braceDepth != len(self.nameSpaces):
return
newClass = CppClass(self.nameStack)
if len(list(newClass.keys())):
self.curClass = newClass["name"]
self.classes[self.curClass] = newClass
else:
self.curClass = ""
newClass["namespace"] = self.cur_namespace()
def evaluate_method_stack(self):
"""Create a method out of the name stack"""
newMethod = CppMethod(self.nameStack, self.curClass)
if len(list(newMethod.keys())):
self.classes[self.curClass]["methods"][self.curAccessSpecifier].append(newMethod)
def evaluate_property_stack(self):
"""Create a Property out of the name stack"""
newVar = CppVariable(self.nameStack)
if len(list(newVar.keys())):
self.classes[self.curClass]["properties"][self.curAccessSpecifier].append(newVar)
def evaluate_enum_stack(self):
"""Create an Enum out of the name stack"""
newEnum = CppEnum(self.nameStack)
if len(list(newEnum.keys())):
if len(self.curClass):
newEnum["namespace"] = self.cur_namespace()
self.classes[self.curClass]["enums"][self.curAccessSpecifier].append(newEnum)
else:
newEnum["namespace"] = self.cur_namespace()
# print "Adding global enum"
self.enums.append(newEnum)
#This enum has instances, turn them into properties
if "instances" in newEnum:
instanceType = "enum"
if "name" in newEnum:
instanceType = newEnum["name"]
for instance in newEnum["instances"]:
self.nameStack = [instanceType, instance]
self.evaluate_property_stack()
del newEnum["instances"]
def cur_namespace(self, add_double_colon = False):
rtn = ""
i = 0
while i < len(self.nameSpaces):
rtn += self.nameSpaces[i]
if add_double_colon or i < len(self.nameSpaces) - 1:
rtn += "::"
i+=1
return rtn
def __repr__(self):
rtn = ""
for className in list(self.classes.keys()):
rtn += repr(self.classes[className])
return rtn

Просмотреть файл

@ -1,9 +1,4 @@
# CppHeaderParser package
# Author: Jashua Cloutier (contact via sourceforge username:senexcanis)
import sys
if sys.version_info[0] == 2:
from CppHeaderParser import *
else:
from CppHeaderParser3 import *
from CppHeaderParser import *
#__all__ = ['CppHeaderParser']

Просмотреть файл

@ -1,5 +1,8 @@
#include <vector>
#include <string>
typedef char* string;
using namespace std;
class SampleClass
{
@ -32,7 +35,7 @@ public:
*********************************/
unsigned int meth4();
private:
void * meth5(){return NULL};
void * meth5(){return NULL}; // invalid c++, fixing parser anyways.
/// prop1 description
string prop1;
@ -62,3 +65,83 @@ namespace Alpha
};
};
}
// tests by hart //
namespace Gamma {
typedef std::string mystring;
}
typedef std::string _StringBase;
typedef _StringBase String;
namespace Theta {
class ThetaClass {
public:
ThetaClass();
~ThetaClass();
protected:
struct mystruct {
bool xxx;
};
void this_method_protected();
}
struct ThetaStruct {
bool test1;
};
class ThetaClass2 {
public:
ThetaClass2();
static inline void static_inlined_method();
inline friend void myfriendmethod();
static std::vector<float> returns_std_vector();
float operator + ();
template<typename AAA> std::vector<float> template_method( const AAA & aaa );
}
inline int ThetaClass::method_defined_outside() {
return 1;
}
inline ThetaClass::operator ThetaClass() const
{
return ThetaClass();
}
}
struct FreeStruct {
bool freestructs_boolvar;
float freestructs_floatvar;
};
namespace A {
class FixMe {
virtual ~__forced_unwind() throw();
virtual void purevirt() = 0;
int realMethod() {
return 1
}
}; // legal to end class with }; ?
class SubClassFixMe : public FixMe {
public:
void purevirt();
}
namespace B {
}
class StillAbstract : public FixMe {
public:
void somemethod();
pointer operator->() const { return &(operator*()); } // example of operator used in method def
}
}
namespace C __attribute__ ((__visibility__ ("default"))) {
}

Просмотреть файл

@ -48,4 +48,27 @@ print "\nNamespace for OmegaClass is:"
print cppHeader.classes["OmegaClass"]["namespace"]
print "\nType for omegaString is:"
print cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"]
print cppHeader.classes["AlphaClass"]["properties"]["public"][0]["type"]
# by hart
print 'global typedefs:'
print cppHeader.typedefs
print 'order of classes:'
for cls in cppHeader.classes_order:
print '\t', cls['name']
print 'order of typedefs:'
for name in cppHeader.typedefs_order:
print '\t', name
print cppHeader.classes['ThetaClass']
print '_'*80
print cppHeader.classes['ThetaClass2']
print cppHeader.structs
print cppHeader.namespaces
print cppHeader.classes['FixMe']

Просмотреть файл

@ -16,6 +16,12 @@ We generate the following:
* BASENAME.js: JavaScript bindings file, with generated JavaScript wrapper
objects. This is a high-level wrapping, using native JS classes.
The C bindings file is basically a tiny C wrapper around the C++ code.
It's only purpose is to make it easy to access the C++ code in the JS
bindings, and to prevent DFE from removing the code we care about. The
JS bindings do more serious work, creating class structures in JS and
linking them to the C bindings.
'''
import os, sys, glob
@ -50,62 +56,89 @@ for header in sys.argv[2:]:
classes[cname] = clazz
# Second pass - generate bindings
# TODO: Bind virtual functions using dynamic binding in the C binding code
funcs = []
funcs = {} # name -> # of copies in the original, and originalname in a copy
gen_c = open(basename + '.c', 'w')
gen_js = open(basename + '.js', 'w')
gen_c.write('extern "C" {\n')
for cname, clazz in classes.iteritems():
print 'Generating', cname
# TODO: Generate all parent class (recursively) data too
constructor_counter = 0
def generate_class(generating_cname, cname, clazz):
inherited = generating_cname != cname
for method in clazz['methods']['public']:
#print ' ', method['name'], method
print ' ', method['name'], method
mname = method['name']
args = method['parameters']
constructor = mname == cname
if constructor and inherited: continue
# C
ret = (cname + ' *') if constructor else method['rtnType']
callprefix = 'new ' if constructor else 'self->'
typedargs = ', '.join( ([] if constructor else [cname + ' * self']) + map(lambda arg: arg['type'] + ' ' + arg['name'], args) )
justargs = ', '.join(map(lambda arg: arg['name'], args))
fullname = cname + '__' + mname
fullname = 'emscripten_bind_' + generating_cname + '__' + mname
generating_cname_suffixed = generating_cname
mname_suffixed = mname
count = funcs.setdefault(fullname, 0)
funcs[fullname] += 1
# handle overloading
if count > 0:
suffix = '_' + str(count+1)
funcs[fullname + suffix] = fullname # this should never change
fullname += suffix
mname_suffixed += suffix
if constructor:
generating_cname_suffixed += suffix
gen_c.write('''
%s emscripten_bind_%s(%s) {
%s %s(%s) {
return %s%s(%s);
}
''' % (ret, fullname, typedargs, callprefix, mname, justargs))
funcs.append('emscripten_bind_' + fullname)
# JS
if constructor:
gen_js.write('''
dupe = type(funcs[fullname]) is str
if not dupe:
gen_js.write('''
function %s(%s) {
this.ptr = _emscripten_bind_%s(%s);
this.ptr = _%s(%s);
}
''' % (cname + (str(constructor_counter) if constructor_counter > 0 else ''), justargs, fullname, justargs))
constructor_counter += 1
else: # TODO: handle case of multiple constructors
''' % (generating_cname_suffixed, justargs, fullname, justargs))
else:
gen_js.write('''
function %s(%s) {
this.ptr = _%s(%s);
}
%s.prototype = %s.prototype;
''' % (generating_cname_suffixed, justargs, fullname, justargs, generating_cname_suffixed, cname))
else:
gen_js.write('''
%s.prototype.%s = function(%s) {
%s_emscripten_bind_%s(this.ptr%s);
%s_%s(this.ptr%s);
}
''' % (cname, mname, justargs, 'return ' if ret != 'void' else '', fullname, (', ' if len(justargs) > 0 else '') + justargs))
''' % (generating_cname, mname_suffixed, justargs, 'return ' if ret != 'void' else '', fullname, (', ' if len(justargs) > 0 else '') + justargs))
for cname, clazz in classes.iteritems():
generate_class(cname, cname, clazz)
# In addition, generate all methods of parent classes. We do not inherit in JS (how would we do multiple inheritance etc.?)
for parent in clazz['inherits']:
generate_class(cname, parent['class'], classes[parent['class']])
# Finish up
funcs = funcs.keys()
gen_c.write('''
}