File indexing completed on 2024-05-19 04:42:04

0001 #!/usr/bin/env python3
0002 # -*- coding: utf-8 -*-
0003 #
0004 # SPDX-FileCopyrightText: 2014 Denis Steckelmacher <steckdenis@yahoo.fr>
0005 #
0006 # SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 
0008 from jsgenerator import *
0009 
0010 def license():
0011     # Print the license of the generated file (the same as the one of this file)
0012     print("""
0013 /*
0014  * ==== FILE AUTOGENERATED FROM .idl FILES UNDER THE FOLLOWING LICENSE ====
0015  *
0016  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
0028  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0030  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
0031  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0032  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0033  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0034  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
0035  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0036  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0037  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 """)
0040 
0041 def get_type(decl):
0042     typename = ' '.join(decl[0:-1])
0043 
0044     if typename == 'void':
0045         typename = ''
0046     elif typename == 'any':
0047         typename = '_mixed'
0048     elif typename == 'boolean' or typename == 'bool':
0049         typename = 'true'
0050     elif typename == 'DOMString':
0051         typename = "''"
0052     elif typename == 'DOMObject':
0053         typename = 'new Object()'
0054     elif typename == 'DOMTimeStamp':
0055         typename = 'new Date()'
0056     elif 'unsigned' in typename or ' short' in typename or ' int' in typename or ' long' in typename or typename in ['short', 'int', 'long']:
0057         typename = '1'
0058     elif typename == 'float' or typename == 'double':
0059         typename = '1.0'
0060     elif typename == 'Array':
0061         typename = '[]'
0062     elif 'Callback' in typename or 'Handler' in typename:
0063         typename = 'function(){}'
0064     elif 'Constructor' in typename:
0065         typename = typename.replace('Constructor', '')
0066     else:
0067         typename = 'new %s()' % typename
0068 
0069     return typename
0070 
0071 def get_name(decl):
0072     return decl[-1]
0073 
0074 member_decl = []
0075 param_decl = []
0076 params = []
0077 skip_end_of_line = False
0078 in_module = False
0079 in_interface = False
0080 in_inherit = False
0081 in_param = False
0082 cl = None
0083 
0084 def parse(token):
0085     global member_decl, param_decl, params, skip_end_of_line, in_module, in_interface, in_inherit, in_param, cl
0086 
0087     if token in ['in', 'readonly', 'optional', 'attribute', 'getter', 'setter', '{', '}']:
0088         pass
0089     elif token == 'raises':
0090         skip_end_of_line = True
0091     elif token == 'module':
0092         in_module = True
0093     elif token == 'interface':
0094         in_module = False
0095         in_interface = True
0096     elif in_module:
0097         # Skip the module declaration
0098         pass
0099     elif in_interface:
0100         # Interface name
0101         cl = Class(token)
0102         in_interface = False
0103 
0104         if token == 'DOMWindow':
0105             # Export window, the only thing that should be exposed to the outside world
0106             print('module.exports = DOMWindow;')
0107 
0108     elif token == ';':
0109         # End the current declaration
0110         if len(member_decl) == 0:
0111             # When the end of a class is reached, an empty declaration is produced
0112             cl.print()
0113             return
0114 
0115         if in_param:
0116             # Declare a method
0117             cl.member(F(get_type(member_decl), get_name(member_decl), \
0118                 *[(get_name(p), get_type(p)) for p in params]
0119             ))
0120         else:
0121             # Declare a member variable
0122             if get_type(member_decl) is not None and get_name(member_decl)[0].isalpha():
0123                 cl.member(Var(get_type(member_decl), get_name(member_decl)))
0124 
0125         member_decl.clear()
0126         params.clear()
0127         skip_end_of_line = False
0128         in_param = False
0129     elif skip_end_of_line:
0130         # Skip everything until the colon
0131         pass
0132     elif token == ':':
0133         in_inherit = True
0134     elif in_inherit:
0135         cl.prototype(token)
0136         in_inherit = False
0137     elif token == '(':
0138         # Begin the parameter list
0139         in_param = True
0140     elif token == ')' or token == ',':
0141         # End of a parameter
0142         if len(param_decl) != 0:
0143             params.append(param_decl[:])
0144             param_decl.clear()
0145 
0146         pass
0147     elif in_param:
0148         # Add a token to the parameter declaration
0149         param_decl.append(token)
0150     else:
0151         # Add a token to the member declaration
0152         member_decl.append(token)
0153 
0154 def tokenize(data):
0155     token = ''
0156     prev_c = ''
0157     c = ''
0158     next_c = ''
0159     in_comment = 'none'
0160     bracket_depth = 0
0161 
0162     for i in range(len(data) + 1):
0163         prev_c = c
0164         c = next_c
0165 
0166         if i < len(data):
0167             next_c = data[i]
0168 
0169         # Handle single-line and multi-line comments
0170         if in_comment == 'singleline':
0171             if c == '\n':
0172                 in_comment = 'none'
0173             continue
0174 
0175         if in_comment == 'multiline':
0176             if prev_c == '*' and c == '/':
0177                 in_comment = 'none'
0178             continue
0179 
0180         if c == '/' and next_c == '*':
0181             in_comment = 'multiline'
0182             continue
0183 
0184         if c == '/' and next_c == '/':
0185             in_comment = 'singleline'
0186             continue
0187 
0188         if c == '#':
0189             # Skip preprocessor macros: consider them as comments
0190             in_comment = 'singleline'
0191             continue
0192 
0193         # Skip hints between brackets
0194         if c == '[':
0195             bracket_depth += 1
0196             continue
0197         elif c == ']':
0198             bracket_depth -= 1
0199             continue
0200 
0201         if bracket_depth > 0:
0202             continue
0203 
0204         # Spaces are used to separate tokens
0205         if not c.isalnum() or not token.isalnum():
0206             if token != '':
0207                 parse(token)
0208                 token = ''
0209 
0210             if c.isspace():
0211                 continue
0212 
0213         token += c
0214 
0215 def main():
0216     license()
0217 
0218     for fl in sys.argv[1:]:
0219         f = open(fl, 'r')
0220         tokenize(f.read())
0221         f.close()
0222 
0223 if __name__ == '__main__':
0224     if len(sys.argv) < 2:
0225         print('Usage: idltojs.py <idl...>')
0226     else:
0227         main()