diff --git a/README.rst b/README.rst index 1bd8e753..f499bbe5 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -``SMOP`` is Small Matlab and Octave to Python compiler. +``SMOP`` is Small Matlab and Octave to Python compiler. ``SMOP`` translates matlab to python. Despite obvious similarities between matlab and numeric python, there are enough differences to make manual translation infeasible in real life. ``SMOP`` generates @@ -11,15 +11,15 @@ performance, and my interpretation is that scalar computations are of less interest to the octave team. -======================================== ================== - octave-3.8.1 190 ms +======================================== ================== + octave-3.8.1 190 ms ---------------------------------------- ------------------ - smop+python-2.7 80 ms + smop+python-2.7 80 ms ---------------------------------------- ------------------ - smop+python-2.7+cython-0.20.1 40 ms + smop+python-2.7+cython-0.20.1 40 ms ---------------------------------------- ------------------ Table 1. ``SMOP`` performance -======================================== ================== +======================================== ================== News ==== @@ -38,7 +38,7 @@ News 2 randn 2.26 1.04 0.46 3 primes 0.35 0.17 0.49 4 fft2 2.75 1.13 0.41 - 5 square 4.24 0 + 5 square 4.24 0 6 inv 4.38 2.26 0.53 7 eig 17.95 9.09 0.51 8 qr 3.06 1.83 0.60 @@ -79,6 +79,11 @@ Installation $ python main.py solver.m $ python solver.py ++ You can launch the GUI the following way:: + + $ cd smop/smop/GUI + $ python smop_GUI.py + Working example =============== @@ -91,8 +96,8 @@ to python. .. code:: matlab - 01 function mv = solver(ai,af,w) 01 def solver_(ai,af,w,nargout=1): - 02 nBlocks = max(ai(:)); 02 nBlocks=max_(ai[:]) + 01 function mv = solver(ai,af,w) 01 def solver_(ai,af,w,nargout=1): + 02 nBlocks = max(ai(:)); 02 nBlocks=max_(ai[:]) 03 [m,n] = size(ai); 03 m,n=size_(ai,nargout=2) ==== ========================================================================= @@ -110,7 +115,7 @@ to python. ==== ========================================================================= .. code:: matlab - + 04 I = [0 1 0 -1]; 04 I=matlabarray([0,1,0,- 1]) 05 J = [1 0 -1 0]; 05 J=matlabarray([1,0,- 1,0]) 06 a = ai; 06 a=copy_(ai) @@ -137,7 +142,7 @@ to python. ==== ========================================================================= .. code:: matlab - + 08 while ~isequal(af,a) 08 while not isequal_(af,a): 09 bid = ceil(rand*nBlocks); 09 bid=ceil_(rand_() * nBlocks) 10 [i,j] = find(a==bid); 10 i,j=find_(a == bid,nargout=2) @@ -185,7 +190,7 @@ Implementation status .. Table 3. Not compiled -.. =========================== ===================================== +.. =========================== ===================================== stft.m missing semicolon datenum.m missing semicolon orderfields.m @@ -195,7 +200,7 @@ Implementation status __unimplemented__.m premature EOF assert.m optimset.m - =========================== ===================================== + =========================== ===================================== Random remarks @@ -213,9 +218,9 @@ There is a price, too. The generated sources are `matlabic`, rather than `pythonic`, which means that library maintainers must be fluent in both languages, - and the old development environment must be kept around. + and the old development environment must be kept around. -Should the generated program be `pythonic` or `matlabic`? +Should the generated program be `pythonic` or `matlabic`? For example should array indexing start with zero (`pythonic`) or with one (`matlabic`)? @@ -241,7 +246,7 @@ Should the generated program be `pythonic` or `matlabic`? .. missing standard library and toolboxes .. missing grapphics library -Which one is faster --- python or octave? I don't know. +Which one is faster --- python or octave? I don't know. Doing reliable performance measurements is notoriously hard, and is of low priority for me now. Instead, I wrote a simple driver ``go.m`` and ``go.py`` and rewrote `rand` @@ -292,7 +297,7 @@ Command-line options information in "dot" format (see www.graphviz.org). You need an installation of graphviz to use --dot option. Use "dot" utility to create a pdf file. - For example: + For example: $ python main.py fastsolver.m -d "solver|cbest" $ dot -Tpdf -o resolve_solver.pdf resolve_solver.dot -h --help diff --git a/smop/GUI/Launch.bat b/smop/GUI/Launch.bat new file mode 100644 index 00000000..77002d87 --- /dev/null +++ b/smop/GUI/Launch.bat @@ -0,0 +1 @@ +python smop_GUI.py \ No newline at end of file diff --git a/smop/GUI/smop_GUI.py b/smop/GUI/smop_GUI.py new file mode 100644 index 00000000..75722df4 --- /dev/null +++ b/smop/GUI/smop_GUI.py @@ -0,0 +1,253 @@ +# @Author: Samuel Radat +# @Date: 2017-09-18T17:27:53+02:00 +# @Filename: smop_GUI.py +# @Last modified by: Samuel Radat +# @Last modified time: 2017-09-27T16:43:13+02:00 + + +from sys import argv, exit +from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox, QMenu, QHBoxLayout, QVBoxLayout, QLabel +from PyQt5.QtWidgets import QCheckBox, QDialog +from PyQt5.QtWidgets import QDesktopWidget, QMainWindow, QAction, qApp, QLineEdit, QInputDialog, QGridLayout, QFileDialog +from PyQt5.QtCore import QCoreApplication +from functools import partial +from smop_backend_ import Matlab_converter +import os + + +class MainApp(QMainWindow): + """Main application class""" + def __init__(self, width, height): + super().__init__(None) + self.username = "samuel_r" + self.initUi(width, height) + + + def initUi(self, width, height): + self.resize(width, height) + self.center_ui() + self.quit_ui() + self.setWindowTitle('SMOP') + self.centralWidget = GUI_smop(username=self.username) + self.setCentralWidget(self.centralWidget) + self.menu_Bar() + self.show() + + + def menu_Bar(self): + menubar = self.menuBar() + fileMenu = menubar.addMenu('Menu') + + settings = QAction('Settings', self) + fileMenu.addAction(settings) + settings.triggered.connect(self.settingsMenu) + + quitmenu = QAction('Quit', self) + fileMenu.addAction(quitmenu) + quitmenu.triggered.connect(qApp.quit) + + def settingsMenu(self): + settings_menu = GUI_settings(self.centralWidget) + settings_menu.exec_() + + def center_ui(self): + qr = self.frameGeometry() + cp = QDesktopWidget().availableGeometry().center() + qr.moveCenter(cp) + self.move(qr.topLeft()) + + + def quit_ui(self): + quit_btn = QAction('Exit', self) + quit_btn.setToolTip('Exit program') + quit_btn.triggered.connect(qApp.quit) + + + def closeEvent(self, event): + reply = QMessageBox.question(self, 'Warning', 'Are you sure to quit ?', + QMessageBox.Yes | QMessageBox.No, QMessageBox.No) + if reply == QMessageBox.Yes: + event.accept() + else: + event.ignore() + + +class GUI_smop(QWidget): + + + def __init__(self, parent=None, username='samuel_r'): + super().__init__(parent) + self.username = username + self.replace_by_self = False + self.script = "plot_Ar_fft" + self.plot_type = "Mechanics\\" + self.full_new_path = self.get_path() + self.python_executable = "C:\\Python27_64\\python.exe" + self.older_folder = None + self.init_UI() + + + def get_path(self): + if os.path.exists(os.path.join(os.path.curdir, "config.txt")): + with open('config.txt', 'r') as f: + s = f.read() + f.close() + return s + return '' + + + def init_UI(self): + self.core() + + + def set_new_script(self, script): + self.script = script + + + def set_python_executable(self, python_executable): + self.python_executable = python_executable + + + def set_output_path(self, path): + self.full_new_path = path + + + def core(self): + + self.grid = QGridLayout() + self.grid.setSpacing(40) + + # SCRIPT FILE SET + self.script_btn = QPushButton('Set script file', self) + self.grid.addWidget(self.script_btn, 1, 0) + self.script_btn.move(20, 20) + self.script_btn.clicked.connect(partial(self.show_Dialog,selector=1)) + + self.le = QLineEdit(self) + self.grid.addWidget(self.le, 1, 1) + self.le.setReadOnly(True) + self.le.setPlaceholderText('plot_Ar_fft') + # !SCRIPT FILE SET + + # python_executable SET + self.plot_type_btn = QPushButton('Set python 2 executable path', self) + self.grid.addWidget(self.plot_type_btn, 2, 0) + self.plot_type_btn.clicked.connect(partial(self.show_Dialog,selector=2)) + + self.plotle = QLineEdit(self) + self.grid.addWidget(self.plotle, 2, 1) + self.plotle.setReadOnly(True) + self.plotle.setPlaceholderText(self.python_executable) + # !python_executable SET + + # new_path SET + self.new_path_btn = QPushButton('Set output path', self) + self.grid.addWidget(self.new_path_btn, 3, 0) + self.new_path_btn.clicked.connect(partial(self.show_Dialog,selector=3)) + + self.new_pathle = QLineEdit(self) + self.grid.addWidget(self.new_pathle, 3, 1) + self.new_pathle.setReadOnly(True) + self.new_pathle.setPlaceholderText(self.full_new_path) + # !new_path SET + + # replace parameter by self check + self.self_chk = QLabel('working on a plot_ script', self) + self.grid.addWidget(self.self_chk, 4, 0) + + self.chk_widget = QCheckBox() + self.grid.addWidget(self.chk_widget, 4, 1) + # !replace parameter by self check + + # BUTTON TO CONVERT + self.convert_btn = QPushButton('Convert to python', self) + self.grid.addWidget(self.convert_btn, 5, 1, 2, 1) + self.convert_btn.clicked.connect(self.convert_file) + # !BUTTON TO CONVERT + + self.setLayout(self.grid) + + self.dictionary = {1: self.le, 2: self.plotle, 3: self.new_pathle} + + + def show_Dialog(self, selector): + fct_dict = {1: self.set_new_script, 2: self.set_python_executable, 3: self.set_output_path} + other_dict = {1: 'Enter script file:', 2: 'Enter python executable:', 3: 'Enter output path'} + + if selector == 1 or selector == 2: + dirname = QFileDialog.getOpenFileName(self, 'Select file')[0] + else: + if os.path.exists(os.path.join(os.path.curdir, "config.txt")): + with open("config.txt", 'r') as f: + self.older_folder = f.read() + f.close() + if self.older_folder != None: + dirname = QFileDialog.getExistingDirectory(self, 'Select folder', self.older_folder) + self.older_folder = dirname + with open("config.txt", 'w') as f: + f.write(self.older_folder) + f.close() + else: + dirname = QFileDialog.getExistingDirectory(self, 'Select folder') + self.older_folder = dirname + with open("config.txt", 'w') as f: + f.write(self.older_folder) + f.close() + self.dictionary[selector].setText(str(dirname)) + fct_dict[selector](str(dirname)) + if selector != 2: + if not self.full_new_path.endswith('\\'): + self.set_output_path(self.full_new_path + '\\') + + def self_replacement(self, sate): + if state == Qt.Checked: + self.replace_by_self = True + else: + self.replace_by_self = False + + def convert_file(self): + temporary_file = self.script.split('/')[-1].split('.')[0] + '.py' + print(self.python_executable + " " + os.path.abspath('../main.py') + " " + self.script + " -o " + temporary_file) + os.system(self.python_executable + " \"" + os.path.abspath('../main.py') + "\" \"" + self.script + "\" -o \"" + temporary_file + '"') + matlab_file = Matlab_converter(temporary_file, self.username) + noerror = matlab_file.rewrite_file(temporary_file, temporary_file.split('/')[-1], self.full_new_path, self.replace_by_self, self) + if noerror: + os.remove(os.path.join(os.path.curdir, temporary_file)) + +class GUI_settings(QDialog): + + def __init__(self, Main_window): + super().__init__() + Main_window.username = 'samuel_r' + self.smop_window = Main_window + self.init_gui() + + def init_gui(self): + self.resize(200, 150) + + + # SCRIPT FILE SET + self.script_btn = QPushButton('Set username', self) + self.script_btn.move(20, 20) + self.script_btn.clicked.connect(self.show_dial) + + self.le = QLineEdit(self) + self.le.move(20, 50) + self.le.setReadOnly(True) + self.le.setPlaceholderText('login_r') + # !SCRIPT FILE SET + + self.setWindowTitle('Header file settings') + + def show_dial(self): + + text, ok = QInputDialog.getText(self, 'username setting', 'enter username: ') + + if ok: + self.le.setText(str(text)) + self.smop_window.username = str(text) + + +app = QApplication(argv) +smop = MainApp(1280, 720) +exit(app.exec_()) diff --git a/smop/GUI/smop_GUI.spec b/smop/GUI/smop_GUI.spec new file mode 100644 index 00000000..c6aa8669 --- /dev/null +++ b/smop/GUI/smop_GUI.spec @@ -0,0 +1,33 @@ +# -*- mode: python -*- + +block_cipher = None + + +a = Analysis(['smop_GUI.py'], + pathex=['C:\\Users\\quentin\\Documents\\My Data Files\\smop\\smop\\Kazuhiro'], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher) +pyz = PYZ(a.pure, a.zipped_data, + cipher=block_cipher) +exe = EXE(pyz, + a.scripts, + exclude_binaries=True, + name='smop_GUI', + debug=False, + strip=False, + upx=True, + console=True ) +coll = COLLECT(exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + name='smop_GUI') diff --git a/smop/GUI/smop_backend_.py b/smop/GUI/smop_backend_.py new file mode 100644 index 00000000..77b57583 --- /dev/null +++ b/smop/GUI/smop_backend_.py @@ -0,0 +1,257 @@ +# @Author: Samuel Radat +# @Date: 2017-09-13T11:14:55+02:00 +# @Filename: smop_backend_.py +# @Last modified by: Samuel Radat +# @Last modified time: 2017-09-27T16:43:00+02:00 + + + +import os +from subprocess import call +from sys import stdout +from datetime import datetime +from PyQt5.QtWidgets import QMessageBox + + +class Matlab_converter: + + + def __init__(self, script, username): + self.script = script + self.header = "# -*- coding: utf-8 -*-\n\"\"\"@package plot_bemf\n@date Created on " + str(datetime.now()) +"\n@author " + username + "\n\"\"\"\n\n\n" + self.plot = False + + + def add_to_header(self, s): + self.header += s + '\n' + + + def normalise_header(self): + h = self.header.splitlines() + for l in h: + if h.count(l) > 1 and l != '': + h.pop(h.index(l)) + self.header = "\n".join(h) + pass #TODO: instead of several lines of imports, do it on one line (not sure if good idea though) + + + def set_new_script(self, script, plot_type): + self.script = script + self.plot_type = plot_type + + + def put_parameter_in_parenthesis(self, filename, s, bracket_content): + i = s.find('def ' + filename + '(') + i += 3 + 1 + len(filename) + 1 + parenthesis_content = [] + while s[i] != ')': + parenthesis_content.append(s[i]) + i += 1 + parenthesis_content = "".join(parenthesis_content) + s = s.replace(parenthesis_content, bracket_content) + return s + + + def get_parenthesis_content(self, s, filename): + i = s.find('def ' + filename + '(') + i += 3 + 1 + len(filename) + 1 + parenthesis_content = [] + while s[i] != ')': + parenthesis_content.append(s[i]) + i += 1 + return "".join(parenthesis_content) + + + def put_as_parameter(self, line, s, filename): + filename = filename.split('.')[0] + var_objs = {'Electrical': 'elec'} + try: + line_decomposition = [line.split('=')[0], [line.split('.')[0].split('=')[1], line.split('.')[1], line.split('.')[2]]] + except IndexError: + return [line, ""] + parameter_to_put = line_decomposition[0].strip() + bracket_content = self.get_parenthesis_content(s, filename) + s = self.put_parameter_in_parenthesis(filename, s, (self.get_parenthesis_content(s, filename) + ', ' + parameter_to_put)) + return ["", s] + + + def get_spaces(self, line_tab): + i = 0 + while line_tab[i] == '': + i += 1 + space_string = "" + for j in range(i): + space_string += ' ' + return space_string + + + def handle_plot_var(self, line, s): + if not self.plot: + self.add_to_header('from GUI import GUI_Option') + i = s.find(line) + line = self.get_spaces(line.split(' ')) + 'Input = GUI_Option()\n' + line.split('=')[0] + ' = Input.plot.' + line.split('.')[-1] + self.plot = True + else: + line = line.split('=')[0] + ' = Input.plot.' + line.split('.')[-1] + return [line, ""] + + + def get_bracket_content(self, s, name_f): + content = [] + i = s.find(name_f + '(') + len(name_f) + 1 + k = 1 + while s[i] != ')' or k > 1: + if s[i] == '(': + k += 1 + content.append(s[i]) + if s[i] == ')': + k -= 1 + i += 1 + return "".join(content) + + + def get_args_nb(self, s): + return len(s.split(',')) + + + def function_is(self, s, fct_name): + if s.find(fct_name + '(') != -1 and s.find(')') != -1: + return True + return False + + + def check_fct(self, line): + pyplot_fcts = [ + 'plot', 'legend', 'xlabel', 'ylabel', 'title', 'grid', 'hold', + 'bar', 'subplot', 'axis', 'polar' + ] + numpy_fcts = [ + 'diag', 'ravel', 'arange', 'dot', 'log10', 'sqrt', 'logical_not', + 'all', 'zeros', 'squeeze', 'shape', 'size', 'absolute', 'copy', + 'sign', 'transpose', 'ones' + ] + for fct_n in pyplot_fcts: + if self.function_is(line, fct_n) and fct_n not in self.header.split(): + self.add_to_header('from matplotlib.pyplot import ' + fct_n) + if self.function_is(line, 'Logger.warning'): + self.add_to_header('from logging import Logger') + for fct_n in numpy_fcts: + if self.function_is(line, fct_n) and fct_n not in self.header.split(): + self.add_to_header('from numpy import ' + fct_n) + + + def in_square_brackets(self, line, string): + i = line.find(string) + i_save = i + begin = False + end = False + while i > 0: + if line[i] == '[': + begin = True + break + i -= 1 + if not begin: + return False + while i_save < len(line): + if line[i_save] == ']': + end = True + break + i_save += 1 + if begin and end: + return True + return False + + + def evaluate_line(self, line, s, filename): + + # if line starts with these strings, delete the line + if line.startswith('# C:') or line.startswith('# Autogenerated with SMOP') or line.startswith('from smop.core import *') or line.find('varargin') != -1 or line.find('nargin') != -1: + return False + + # for zeros() function, adds surrounds the brackets_content with parenthesis to fit the right way to write this function + if line.find('zeros(') != -1 and line.find(')') != -1: + parenthesis_content = self.get_bracket_content(line, "zeros") + if parenthesis_content == None: + print('LINE=',line) + if not parenthesis_content.startswith('(') or not parenthesis_content.endswith(')'): + parenthesis_content = '(' + parenthesis_content + ')' + line = line.split('(')[0] + '(' + parenthesis_content + ')\n' + self.add_to_header('from numpy import zeros') + + # if it's the function figure(), removes the first parameter and adds some useful properties + if self.function_is(line, 'figure'): + line = (line.split('(')[0] + '(' + line.split(',')[1])[0:-2] + ", figsize=(12, 10), facecolor='w')\n" + self.add_to_header('from matplotlib.pyplot import figure') + return [line, ""] + + # replace dlmread() function by numpy.load() + if self.function_is(line, 'dlmread') and self.get_args_nb(line) == 1: + line = line.replace('dlmread(', 'load(') + self.add_to_header("from numpy import load") + + # this part is specific to the internship project, it puts the output and input variables as parameter + if (line.find('Input.') != -1 or line.find('Output.') != -1) and line.find("'") == -1: + if line.find('Input.Plot.') != -1: + return (self.handle_plot_var(line, s)) + return self.put_as_parameter(line, s, filename) + + # several correlations between matlab and python languages. Keywords are replaced + replace_str = {'size(': 'shape(', 'grid(\'on\')': 'grid(True)', + 'grid(\'off\')': 'grid(False)','disp(': 'print(', + 'num2str': 'str', 'hold(\'on\')': 'hold(True)', + 'hold(\'off\')': 'hold(False)', 'abs(': 'absolute(', + 'floor(': 'np_floor(', 'isempty(': 'all(', + 'length(': 'size(', 'matlabarray(': 'array('} + + if line.find('disp_com') != -1: + line = line.replace('disp_com', 'Logger.warning') + line = line.replace(',Input.Simu.is_warning,1)', ')') + + for replacement_s in replace_str.keys(): + line = line.replace(replacement_s, replace_str[replacement_s]) + + self.check_fct(line) + + if line.find('end()') != -1 and self.in_square_brackets(line, 'end()'): + line = line.replace('end()', '-1') + + return [line, ""] + + + def delete_file_begin(self, s, filename): + i = s.find('def ' + filename + '(') + return s[i:] + + + def rewrite_file(self, filename, filename_short, full_new_path, replace_by_self, Qobj): + s = "" + try: + f = open(filename, 'r') + except FileNotFoundError: + buttonReply = QMessageBox.critical(Qobj, 'File not found', 'The input script file was not found.', QMessageBox.Ok) + return False + lines = f.readlines() + f.close() + for line in lines: + # this will automatically replace any new function's parameters by "self" + if replace_by_self and line.find('def ' + filename_short.split('.')[0]) != -1: + print(line.split('(')[0] + '(self):\n') + line = line.split('(')[0].split(' ')[0] + ' ' + line.split('(')[0].split(' ')[1] + '(self):\n' + var = self.evaluate_line(line, s, filename_short) + if not var: + continue + if var[0] == "": + s = var[1] + continue + s += var[0] + s = self.delete_file_begin(s, filename_short.split('.')[0]) + if replace_by_self: + name_file = full_new_path + '_' + filename_short + else: + name_file = full_new_path + filename_short + new_f = open(name_file, 'w') + self.add_to_header('\n\n') + self.normalise_header() + new_f.write(self.header + s) + new_f.close() + return True diff --git a/smop/backend.py b/smop/backend.py index 513684c7..ee219743 100644 --- a/smop/backend.py +++ b/smop/backend.py @@ -34,6 +34,77 @@ "./=" : "/", } + +def is_tab_empty(tab): + for elem in tab: + if elem != "": + return False + return True + + +def compute_indexing(s): + """ + This function makes the correlation between matlab indexing and python indexing + Which specifications are listed below : + - Python is zero-indexed + - MATLAB is 1-indexed + + - MATLAB slice notation includes the endpoint + - Python slice notation excludes the endpoint + + - MATLAB start:step:stop + - Python start:stop:step + + :param s: string containing the content between squared brackets + :return: returns the string being parsed and analysed + """ + print 'computing : %s' % (s) + decomposition = s.split(",") + k = 0 + for element in decomposition: + try: + check = unicode(element, 'utf-8') + except TypeError: + check = element + if check.isnumeric(): + decomposition[k] = str(int(element) - 1) + if element.find(':') != -1: + tab = element.split(':') + if is_tab_empty(tab): + k += 1 + continue + start = 0 + if len(tab) == 2: + step = 1 + stop = 2 + if len(tab) == 3: + step = 2 + stop = 3 + try: + if unicode(tab[start], 'utf-8').isnumeric(): + tab[start] = str(int(tab[start]) - 1) + if unicode(tab[1], 'utf-8').isnumeric(): + tab[1] = str(int(tab[1]) + 1) + except TypeError: + if tab[start].isnumeric(): + tab[start] = str(int(tab[start]) - 1) + if tab[stop - 1].isnumeric(): + tab[stop - 1] = str(int(tab[stop - 1]) + 1) + for i in range(start, stop, step): + if tab[i].find("end") != -1: + tab[i] = tab[i].replace('end()', "-1") + tab[i] = tab[i].replace('end', "-1") + if len(tab) == 3: + tmp = tab[1] + tab[1] = tab[2] + tab[2] = tmp + decomposition[k] = ":".join(tab) + print tab + k += 1 + print decomposition + return ",".join(decomposition) + + def backend(t,*args,**kwargs): return t._backend(level=1,*args,**kwargs) @@ -78,9 +149,8 @@ def _backend(self,level=0): @extend(node.arrayref) def _backend(self,level=0): - fmt = "%s[%s]" - return fmt % (self.func_expr._backend(), - self.args._backend()) + fmt = "%s[%s]" % (self.func_expr._backend(), compute_indexing(self.args._backend())) + return fmt @extend(node.break_stmt) def _backend(self,level=0): @@ -207,10 +277,8 @@ def _backend(self,level=0): @extend(node.for_stmt) def _backend(self,level=0): - fmt = "for %s in %s.reshape(-1):%s" - return fmt % (self.ident._backend(), - self.expr._backend(), - self.stmt_list._backend(level+1)) + fmt = "for %s in %s.reshape(-1):%s" % (self.ident._backend(), self.expr._backend(), self.stmt_list._backend(level+1)) + return fmt @extend(node.func_stmt) @@ -275,12 +343,7 @@ def _backend(self,level=0): @extend(node.let) def _backend(self,level=0): - if not options.no_numbers: - t = "\n# %s:%s" % (options.filename, - self.lineno) - # level*indent) - else: - t = '' + t = '' s = '' #if self.args.__class__ is node.funcall: @@ -353,6 +416,7 @@ def _backend(self,level=0): @extend(node.stmt_list) def _backend(self,level=0): + # for each line parsed by the lexer parser for t in self: if not isinstance(t,(node.null_stmt, node.comment_stmt)): diff --git a/smop/main.py b/smop/main.py index 99327fda..b619dfdb 100644 --- a/smop/main.py +++ b/smop/main.py @@ -8,7 +8,9 @@ import sys import os import traceback +import getpass from os.path import basename, splitext +from datetime import datetime import lexer import options @@ -21,12 +23,14 @@ def print_header(fp): if options.no_header: return - print >> fp, "# Autogenerated with SMOP " + version.__version__ - # print >> fp, "from __future__ import division" - print >> fp, "from smop.core import *" - # if options.link: - # print >> fp, "from %s import *" % options.link - print >> fp, "#", options.filename + print >> fp, "# -*- coding: utf-8 -*-" + if options.filename == "": + print >> fp, "\"\"\"@package " + options.output + else: + print >> fp, "\"\"\"@package " + options.filename + print >> fp, "@date Created on " + str(datetime.now()) + print >> fp, "@author " + getpass.getuser() + print >> fp, '"""' def main(): diff --git a/smop/version.py b/smop/version.py new file mode 100644 index 00000000..31e08075 --- /dev/null +++ b/smop/version.py @@ -0,0 +1 @@ +__version__=''