1#!/usr/bin/env python
2# This file is part of python-ly, https://pypi.python.org/pypi/python-ly
3#
4# Copyright (c) 2008 - 2015 by Wilbert Berendsen
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19# See http://www.gnu.org/licenses/ for more information.
20
21"""
22generate all scheme words in the _scheme_data.py file
23"""
24from __future__ import unicode_literals
25
26import os
27import re
28try:
29    from urllib.request import urlopen
30except:
31    from urllib import urlopen
32
33
34VERSION = "2.18"
35GUILE_URL = "https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/Procedure-Index.html#Procedure-Index"
36LY_FUNCTION_URL = "http://lilypond.org/doc/v2.18/Documentation/internals/scheme-functions"
37SCM_PATH = os.path.join(os.environ['HOME'], 'lilypond_bin/2.18.2-1/lilypond/usr/share/lilypond/current/scm')
38
39GUILE_IGNONED_TYPE = (
40    'Apply Traps',
41    'Common Trap Options',
42    'Continuations',
43    'Debug on Error',
44    'Display Backtrace',
45    'Encryption',
46    'Entry Traps',
47    'Exit Traps',
48    'Garbage Collection Functions',
49    'getopt-long Reference',
50    'Internationalization',
51    'Location Traps',
52    'Network Databases',
53    'Network Socket Address',
54    'Network Sockets and Communication',
55    'Procedure Traps',
56    'Signals',
57    'Threads',
58    'Trap Utilities',
59    'Source Traps',
60    'Step Traps',
61    'SRFI-37',
62    'Stepping and Continuing',
63    'System asyncs',
64    'System Identification',
65    'User asyncs',
66    'User Information',
67    'User level options interfaces',
68)
69
70GUILE_OTHER_WORDS = ['else', 'set!']
71
72def writeList(file_, name, lst):
73    file_.write("{} = [\n".format(name))
74    for word in sorted(set(lst)):
75        file_.write("    '{0}',\n".format(word))
76    file_.write("]\n\n")
77
78def replace(word):
79    word = word.replace('&lt;', '<')
80    word = word.replace('&gt;', '>')
81    return word
82
83guilePage = urlopen(GUILE_URL).read()
84guilePat = re.compile(r"<code>([a-z\d\+\?\!\*&;/=:-]+)</code></a>: <a href=\".+\">(.+)</a>")
85
86lyFunctionPage = urlopen(LY_FUNCTION_URL).read()
87lyFunctionPat = re.compile(r'<u>Function:</u> <b>(ly:.+)</b>')
88
89
90defineFunc = re.compile(r'\((?:define\*?|define-safe)-public\s+\(([-><a-zA-Z:\?]+)[\s\)]')
91defineMacro = re.compile(r'\(defmacro\*?-public\s+([-><a-zA-Z:\?]+)[\s\)]')
92defineVar = re.compile(r'\((?:define\*?|define-safe)-public\s+([-><a-zA-Z:\?]+)[\s\)]')
93startWithLy = re.compile(r"(ly:[-><a-zA-Z:\?]+)[\s\)]")
94
95
96schemeDataPath = os.path.join(os.path.split(__file__)[0], '_scheme_data.py')
97
98def main():
99    with open(schemeDataPath, "w") as f:
100        f.write("#generated by makeschemedata.py\n\nversion=\"{}\"\n\n".format(VERSION))
101
102        guileWords = []
103        for m in guilePat.finditer(guilePage.decode('utf-8')):
104            if m.group(2) not in GUILE_IGNONED_TYPE:
105                proc = m.group(1)
106                if not proc.startswith('gds-'):
107                    guileWords.append(replace(proc))
108        guileWords += GUILE_OTHER_WORDS
109
110
111        lyFunctions = []
112        lyVars = []
113        lyCons = []
114        for word in lyFunctionPat.finditer(lyFunctionPage.decode('utf-8')):
115            lyFunctions.append(replace(word.group(1)))
116
117        for filename in os.listdir(SCM_PATH):
118            path = os.path.join(SCM_PATH, filename)
119            with open(path) as inp:
120                text = inp.read()
121                for m in defineFunc.finditer(text):
122                    lyFunctions.append(m.group(1))
123
124                for m in defineMacro.finditer(text):
125                    lyFunctions.append(m.group(1))
126
127                for m in startWithLy.finditer(text):
128                    lyFunctions.append(m.group(1))
129
130                for m in defineVar.finditer(text):
131                    word = m.group(1)
132                    if word.isupper():
133                        lyCons.append(word)
134                    else:
135                        lyVars.append(word)
136
137        for word in lyFunctions:
138            if word in lyVars:
139                lyVars.remove(word)
140
141        lyVars.remove('parser')
142
143        writeList(f, 'scheme_keywords', guileWords)
144        writeList(f, 'scheme_functions', lyFunctions)
145        writeList(f, 'scheme_variables', lyVars)
146        writeList(f, 'scheme_constants', lyCons)
147
148
149if __name__ == "__main__":
150    main()
151
152