diff --git a/src/Clochur/ClochurLexer.py b/src/Clochur/ClochurLexer.py index 4002ba2..3919873 100644 --- a/src/Clochur/ClochurLexer.py +++ b/src/Clochur/ClochurLexer.py @@ -160,7 +160,7 @@ def styleText(self, start, end): # pass '''comment''' - if item["str"] == "%": + if item["str"] == "%" and rainbow_state < 10: is_comment = True if is_comment == True: new_state = self.Comment # end of comment diff --git a/src/Clochur/Interpreter.py b/src/Clochur/Interpreter.py index 827b9ec..8dea1dc 100644 --- a/src/Clochur/Interpreter.py +++ b/src/Clochur/Interpreter.py @@ -288,10 +288,16 @@ def interprete_aux(self, sexp): elif sexp[0]["token"] == "str-append": if len(sexp) != 3: - raise Exception("Ln %d, Col %d: the argument number of str should be 2" % + raise Exception("Ln %d, Col %d: the argument number of str-append should be 2" % (sexp[0]["line"], sexp[0]["col"])) else: - return self.interprete_aux(sexp[1]) + self.interprete_aux(sexp[2]) + lhs = self.destring(self.interprete_aux(sexp[1])) + rhs = self.destring(self.interprete_aux(sexp[2])) + if isinstance(lhs, str) and isinstance(rhs, str): + return lhs + rhs + else: + raise Exception("Ln %d, Col %d: the argument of str-append should be string" % + (sexp[0]["line"], sexp[0]["col"])) elif sexp[0]["token"] == "print": if len(sexp) != 2: @@ -440,42 +446,54 @@ def interprete_aux(self, sexp): # (car List) elif sexp[0]["token"] == "car": + ls = self.interprete_aux(sexp[1]) if len(sexp) != 2: raise Exception("Line %d, Col. %d, the argument length should be 1" % (sexp[0]["line"], sexp[0]["col"])) - elif not isinstance(sexp[1], List): + elif not isinstance(ls, List): raise Exception("Line %d, Col. %d, the argument is not a list." % (sexp[1]["line"], sexp[1]["col"])) else: - ls = sexp[1].ls + ls = ls.ls return ls[0] # (cdr List) elif sexp[0]["token"] == "cdr": + ls = self.interprete_aux(sexp[1]) if len(sexp) != 2: raise Exception("Line %d, Col. %d, the argument length should be 1" % (sexp[0]["line"], sexp[0]["col"])) - elif not isinstance(sexp[1], List): + elif not isinstance(ls, List): raise Exception("Line %d, Col. %d, the argument is not a list." % (sexp[1]["line"], sexp[1]["col"])) else: - ls = sexp[1].ls - return ls[1:] + ls = ls.ls + return List(ls[1:]) # (cons any List) elif sexp[0]["token"] == "cons": + ls = self.interprete_aux(sexp[2]) if len(sexp) != 3: raise Exception("Line %d, Col. %d, the argument length should be 2" % (sexp[0]["line"], sexp[0]["col"])) - elif not isinstance(sexp[2], List): + elif not isinstance(ls, List): raise Exception("Line %d, Col. %d, the 2nd argument of cons is not a list." % (sexp[2]["line"], sexp[2]["col"])) else: car = sexp[1] - cdr = sexp[2].ls - result_ls = List([sexp[1]]+cdr) + cdr = ls.ls + result_ls = List([sexp[1]["token"]]+cdr) return result_ls elif sexp[0]["token"] == "ls-ref": + ls = self.interprete_aux(sexp[1]) + index = self.interprete_aux(sexp[2]) if len(sexp) != 3: raise Exception("Line %d, Col. %d, the argument length should be 1" % (sexp[0]["line"], sexp[0]["col"])) - elif not isinstance(sexp[1], List): - raise Exception("Line %d, Col. %d, the 2nd argument of cons is not a list." % (sexp[2]["line"], sexp[2]["col"])) + elif not isinstance(index, int): + raise Exception("Line %d, Col. %d, the 1st argument of cons is not a integer." % (sexp[2]["line"], sexp[2]["col"])) + elif not isinstance(ls, List): + raise Exception("Line %d, Col. %d, the 2nd argument of cons is not a List." % (ls, sexp[1]["col"])) + elif index >= len(ls.ls): + raise Exception("Line %d, Col. %d, List out of range") + else: + return ls.ls[index] + @@ -621,6 +639,8 @@ def __str__(self): class List: def __init__(self, ls): self.ls = ls + def __repr__(self): + return (f"<List object of Clochur. list={self.ls}>") # closure class Lambda: @@ -633,3 +653,15 @@ def __init__(self, vars, body, env): self.vars = [i["token"] for i in vars] self.body = body self.env = env + + def __str__(self): + parser = Parser() + body_sexp = parser.generate_printable_sexp(self.body) + return (f"<Clojure object of Clochur. vars={self.vars}, " + \ + "env=" + str(self.env) + f", body={body_sexp}>") + + def __repr__(self): + parser = Parser() + body_sexp = parser.generate_printable_sexp(self.body) + return (f"<Clojure object of Clochur. vars={self.vars}, " + \ + "env=" + str(self.env) + f", body={body_sexp}>") diff --git a/src/Clochur/__init__.py b/src/Clochur/__init__.py index 230735e..60c61ed 100755 --- a/src/Clochur/__init__.py +++ b/src/Clochur/__init__.py @@ -302,8 +302,12 @@ def convert_call(self): with open(sile_xml_path, "w") as xml: xml.write(result) xml.close() - - subprocess.run([sile_command, sile_xml_path]) + + try: + subprocess.run([sile_command, sile_xml_path]) + except FileNotFoundError as e: + raise Exception("the command \"sile\" is not found. Please check if it's installed.") + pdf_js_webviewer_list = self.findChildren(QtWebEngineWidgets.QWebEngineView) pdf_js_webviewer = pdf_js_webviewer_list[-1] pdf_js_webviewer.load_path(sile_pdf_path) @@ -325,6 +329,8 @@ def exit_call(self): if reply == QMessageBox.Yes: if self.filename != None: self.save_call() + self.remove_tmp_outputs() + app.exit() else: file_path = QFileDialog.getSaveFileName(self, 'Save file as...', self.opened_file_dirname, "CLC typesetting format (*.clc)") @@ -386,7 +392,7 @@ def underline_call(self): def add_font_call(self): selected_text = self.editor.selectedText() font_family = self.font_combo_box.currentText() - self.editor.replaceSelectedText(f'[font-family "{font_family}" {selected_text}]') + self.editor.replaceSelectedText(f'[font-family "{font_family}" "{selected_text}"]') def about_call(self): diff --git a/src/manual.pdf b/src/manual.pdf index 55decdc..eec8ba4 100644 Binary files a/src/manual.pdf and b/src/manual.pdf differ