Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py @ 1538:d1806b4e4839
moving OrthancStone/Samples/ as Applications/Samples/
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 11 Aug 2020 13:24:38 +0200 |
parents | StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py@433cf964838d |
children | f9e3a9c21c0f |
comparison
equal
deleted
inserted
replaced
1537:de8cf5859e84 | 1538:d1806b4e4839 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 # Stone of Orthanc | |
4 # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
5 # Department, University Hospital of Liege, Belgium | |
6 # Copyright (C) 2017-2020 Osimis S.A., Belgium | |
7 # | |
8 # This program is free software: you can redistribute it and/or | |
9 # modify it under the terms of the GNU Affero General Public License | |
10 # as published by the Free Software Foundation, either version 3 of | |
11 # the License, or (at your option) any later version. | |
12 # | |
13 # This program is distributed in the hope that it will be useful, but | |
14 # WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # Affero General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Affero General Public License | |
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | |
21 | |
22 # Ubuntu 20.04: | |
23 # sudo apt-get install python-clang-6.0 | |
24 # ./ParseWebAssemblyExports.py --libclang=libclang-6.0.so.1 ./Test.cpp | |
25 | |
26 # Ubuntu 18.04: | |
27 # sudo apt-get install python-clang-4.0 | |
28 # ./ParseWebAssemblyExports.py --libclang=libclang-4.0.so.1 ./Test.cpp | |
29 | |
30 # Ubuntu 14.04: | |
31 # ./ParseWebAssemblyExports.py --libclang=libclang-3.6.so.1 ./Test.cpp | |
32 | |
33 | |
34 import sys | |
35 import clang.cindex | |
36 import pystache | |
37 import argparse | |
38 | |
39 ## | |
40 ## Parse the command-line arguments | |
41 ## | |
42 | |
43 parser = argparse.ArgumentParser(description = 'Parse WebAssembly C++ source file, and create a basic JavaScript wrapper.') | |
44 parser.add_argument('--libclang', | |
45 default = '', | |
46 help = 'manually provides the path to the libclang shared library') | |
47 parser.add_argument('source', | |
48 help = 'Input C++ file') | |
49 | |
50 args = parser.parse_args() | |
51 | |
52 | |
53 | |
54 if len(args.libclang) != 0: | |
55 clang.cindex.Config.set_library_file(args.libclang) | |
56 | |
57 index = clang.cindex.Index.create() | |
58 | |
59 # PARSE_SKIP_FUNCTION_BODIES prevents clang from failing because of | |
60 # undefined types, which prevents compilation of functions | |
61 tu = index.parse(args.source, | |
62 [ '-DEMSCRIPTEN_KEEPALIVE=__attribute__((annotate("WebAssembly")))' ], | |
63 options = clang.cindex.TranslationUnit.PARSE_SKIP_FUNCTION_BODIES) | |
64 | |
65 | |
66 | |
67 TEMPLATE = ''' | |
68 const Stone = function() { | |
69 {{#enumerations}} | |
70 this.{{name}} = { | |
71 {{#values}} | |
72 {{name}}: {{value}}{{separator}} | |
73 {{/values}} | |
74 }; | |
75 | |
76 {{/enumerations}} | |
77 {{#functions}} | |
78 this._{{name}} = undefined; | |
79 {{/functions}} | |
80 }; | |
81 | |
82 Stone.prototype.Setup = function(Module) { | |
83 {{#functions}} | |
84 this._{{name}} = Module.cwrap('{{name}}', {{{returnType}}}, [ {{#args}}{{{type}}}{{^last}}, {{/last}}{{/args}} ]); | |
85 {{/functions}} | |
86 }; | |
87 | |
88 {{#functions}} | |
89 Stone.prototype.{{name}} = function({{#args}}{{name}}{{^last}}, {{/last}}{{/args}}) { | |
90 {{#hasReturn}}return {{/hasReturn}}this._{{name}}({{#args}}{{name}}{{^last}}, {{/last}}{{/args}}); | |
91 }; | |
92 | |
93 {{/functions}} | |
94 var stone = new Stone(); | |
95 ''' | |
96 | |
97 | |
98 | |
99 | |
100 # WARNING: Undefined types are mapped as "int" | |
101 | |
102 functions = [] | |
103 enumerations = [] | |
104 | |
105 def ToUpperCase(source): | |
106 target = source[0] | |
107 for c in source[1:]: | |
108 if c.isupper(): | |
109 target += '_' | |
110 target += c.upper() | |
111 return target | |
112 | |
113 | |
114 | |
115 def IsExported(node): | |
116 for child in node.get_children(): | |
117 if (child.kind == clang.cindex.CursorKind.ANNOTATE_ATTR and | |
118 child.displayname == 'WebAssembly'): | |
119 return True | |
120 | |
121 return False | |
122 | |
123 | |
124 def Explore(node): | |
125 if node.kind == clang.cindex.CursorKind.ENUM_DECL: | |
126 if IsExported(node): | |
127 name = node.spelling | |
128 values = [] | |
129 for value in node.get_children(): | |
130 if (value.spelling.startswith(name + '_')): | |
131 s = value.spelling[len(name) + 1:] | |
132 if len(values) > 0: | |
133 values[-1]['separator'] = ',' | |
134 values.append({ | |
135 'name' : ToUpperCase(s), | |
136 'value' : value.enum_value | |
137 }) | |
138 | |
139 enumerations.append({ | |
140 'name' : name, | |
141 'values' : values | |
142 }) | |
143 | |
144 if node.kind == clang.cindex.CursorKind.FUNCTION_DECL: | |
145 if IsExported(node): | |
146 f = { | |
147 'name' : node.spelling, | |
148 'args' : [], | |
149 } | |
150 | |
151 returnType = node.result_type.spelling | |
152 if returnType == 'void': | |
153 f['hasReturn'] = False | |
154 f['returnType'] = "null" | |
155 elif returnType == 'const char *': | |
156 f['hasReturn'] = True | |
157 f['returnType'] = "'string'" | |
158 elif returnType in [ 'int', 'unsigned int' ]: | |
159 f['hasReturn'] = True | |
160 f['returnType'] = "'int'" | |
161 else: | |
162 raise Exception('Unknown return type in function "%s()": %s' % (node.spelling, returnType)) | |
163 | |
164 for child in node.get_children(): | |
165 if child.kind == clang.cindex.CursorKind.PARM_DECL: | |
166 arg = { | |
167 'name' : child.displayname, | |
168 } | |
169 | |
170 argType = child.type.spelling | |
171 if argType == 'int': | |
172 arg['type'] = "'int'" | |
173 elif argType == 'const char *': | |
174 arg['type'] = "'string'" | |
175 else: | |
176 raise Exception('Unknown type for argument "%s" in function "%s()": %s' % | |
177 (child.displayname, node.spelling, argType)) | |
178 | |
179 f['args'].append(arg) | |
180 | |
181 if len(f['args']) != 0: | |
182 f['args'][-1]['last'] = True | |
183 | |
184 functions.append(f) | |
185 | |
186 for child in node.get_children(): | |
187 Explore(child) | |
188 | |
189 Explore(tu.cursor) | |
190 | |
191 | |
192 | |
193 print(pystache.render(TEMPLATE, { | |
194 'functions' : functions, | |
195 'enumerations' : enumerations | |
196 })) |