1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# SPDX-FileCopyrightText: 2014 Denis Steckelmacher <steckdenis@yahoo.fr> 5# 6# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 7 8from jsgenerator import * 9 10def license(): 11 # Print the license of the generated file (the same as the one of this file) 12 print(""" 13/* 14 * ==== FILE AUTOGENERATED FROM .idl FILES UNDER THE FOLLOWING LICENSE ==== 15 * 16 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 27 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 28 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 34 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 35 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 */ 39""") 40 41def get_type(decl): 42 typename = ' '.join(decl[0:-1]) 43 44 if typename == 'void': 45 typename = '' 46 elif typename == 'any': 47 typename = '_mixed' 48 elif typename == 'boolean' or typename == 'bool': 49 typename = 'true' 50 elif typename == 'DOMString': 51 typename = "''" 52 elif typename == 'DOMObject': 53 typename = 'new Object()' 54 elif typename == 'DOMTimeStamp': 55 typename = 'new Date()' 56 elif 'unsigned' in typename or ' short' in typename or ' int' in typename or ' long' in typename or typename in ['short', 'int', 'long']: 57 typename = '1' 58 elif typename == 'float' or typename == 'double': 59 typename = '1.0' 60 elif typename == 'Array': 61 typename = '[]' 62 elif 'Callback' in typename or 'Handler' in typename: 63 typename = 'function(){}' 64 elif 'Constructor' in typename: 65 typename = typename.replace('Constructor', '') 66 else: 67 typename = 'new %s()' % typename 68 69 return typename 70 71def get_name(decl): 72 return decl[-1] 73 74member_decl = [] 75param_decl = [] 76params = [] 77skip_end_of_line = False 78in_module = False 79in_interface = False 80in_inherit = False 81in_param = False 82cl = None 83 84def parse(token): 85 global member_decl, param_decl, params, skip_end_of_line, in_module, in_interface, in_inherit, in_param, cl 86 87 if token in ['in', 'readonly', 'optional', 'attribute', 'getter', 'setter', '{', '}']: 88 pass 89 elif token == 'raises': 90 skip_end_of_line = True 91 elif token == 'module': 92 in_module = True 93 elif token == 'interface': 94 in_module = False 95 in_interface = True 96 elif in_module: 97 # Skip the module declaration 98 pass 99 elif in_interface: 100 # Interface name 101 cl = Class(token) 102 in_interface = False 103 104 if token == 'DOMWindow': 105 # Export window, the only thing that should be exposed to the outside world 106 print('module.exports = DOMWindow;') 107 108 elif token == ';': 109 # End the current declaration 110 if len(member_decl) == 0: 111 # When the end of a class is reached, an empty declaration is produced 112 cl.print() 113 return 114 115 if in_param: 116 # Declare a method 117 cl.member(F(get_type(member_decl), get_name(member_decl), \ 118 *[(get_name(p), get_type(p)) for p in params] 119 )) 120 else: 121 # Declare a member variable 122 if get_type(member_decl) is not None and get_name(member_decl)[0].isalpha(): 123 cl.member(Var(get_type(member_decl), get_name(member_decl))) 124 125 member_decl.clear() 126 params.clear() 127 skip_end_of_line = False 128 in_param = False 129 elif skip_end_of_line: 130 # Skip everything until the colon 131 pass 132 elif token == ':': 133 in_inherit = True 134 elif in_inherit: 135 cl.prototype(token) 136 in_inherit = False 137 elif token == '(': 138 # Begin the parameter list 139 in_param = True 140 elif token == ')' or token == ',': 141 # End of a parameter 142 if len(param_decl) != 0: 143 params.append(param_decl[:]) 144 param_decl.clear() 145 146 pass 147 elif in_param: 148 # Add a token to the parameter declaration 149 param_decl.append(token) 150 else: 151 # Add a token to the member declaration 152 member_decl.append(token) 153 154def tokenize(data): 155 token = '' 156 prev_c = '' 157 c = '' 158 next_c = '' 159 in_comment = 'none' 160 bracket_depth = 0 161 162 for i in range(len(data) + 1): 163 prev_c = c 164 c = next_c 165 166 if i < len(data): 167 next_c = data[i] 168 169 # Handle single-line and multi-line comments 170 if in_comment == 'singleline': 171 if c == '\n': 172 in_comment = 'none' 173 continue 174 175 if in_comment == 'multiline': 176 if prev_c == '*' and c == '/': 177 in_comment = 'none' 178 continue 179 180 if c == '/' and next_c == '*': 181 in_comment = 'multiline' 182 continue 183 184 if c == '/' and next_c == '/': 185 in_comment = 'singleline' 186 continue 187 188 if c == '#': 189 # Skip preprocessor macros: consider them as comments 190 in_comment = 'singleline' 191 continue 192 193 # Skip hints between brackets 194 if c == '[': 195 bracket_depth += 1 196 continue 197 elif c == ']': 198 bracket_depth -= 1 199 continue 200 201 if bracket_depth > 0: 202 continue 203 204 # Spaces are used to separate tokens 205 if not c.isalnum() or not token.isalnum(): 206 if token != '': 207 parse(token) 208 token = '' 209 210 if c.isspace(): 211 continue 212 213 token += c 214 215def main(): 216 license() 217 218 for fl in sys.argv[1:]: 219 f = open(fl, 'r') 220 tokenize(f.read()) 221 f.close() 222 223if __name__ == '__main__': 224 if len(sys.argv) < 2: 225 print('Usage: idltojs.py <idl...>') 226 else: 227 main() 228