diff options
-rw-r--r-- | librelogo/source/LibreLogo/LibreLogo.py | 33 | ||||
-rw-r--r-- | sw/qa/uitest/librelogo/compile.py | 4 | ||||
-rw-r--r-- | sw/qa/uitest/librelogo/run.py | 29 |
3 files changed, 54 insertions, 12 deletions
diff --git a/librelogo/source/LibreLogo/LibreLogo.py b/librelogo/source/LibreLogo/LibreLogo.py index 93c51d636312..06ccca3a6377 100644 --- a/librelogo/source/LibreLogo/LibreLogo.py +++ b/librelogo/source/LibreLogo/LibreLogo.py @@ -1874,9 +1874,6 @@ def __compil__(s): globs = "" functions = ["range", "__int__", "__float__", "Random", "Input", "__string__", "len", "round", "abs", "sin", "cos", "sqrt", "log10", "set", "list", "tuple", "re.sub", "re.search", "re.findall", "sorted", "min", "max"] defaultfunc = ["Print"] # TODO handle all default procedures - names ={key: 1 for key in functions + defaultfunc} - names["range"] = names["re.sub"] = 3 - names["re.search"] = names["re.findall"] = 2 if len(subnames) > 0: globs = "global %s" % ", ".join(subnames) @@ -1909,17 +1906,29 @@ def __compil__(s): operators = re.compile(r"(?iu)(%s)" % "(?:[ ]*([+*/<>]|//|==|<=|>=|<>|!=)[ ]*|[ ]*-[ ]+|(?<! )-[ ]*|[ ]*[*][*][ ]*)") # operators, eg. " - ", "-", "- " atoms = re.compile(r"(?iu)(%s)" % "[0-9]+([.,][0-9]+)?|\w+([.]\w)?") + # store argument numbers of all subroutines in dictionary "names" + names = {key: 1 for key in functions + defaultfunc} + names["range"] = names["re.sub"] = 3 + names["re.search"] = names["re.findall"] = 2 + + # match a function header + search_funcdef = re.compile(r"(^|\n) *(def (\w+))(\([^\n]*\):) *(?=\n)") + + # "multiline" lambda function to process function headers: add commas to argument list and + # add {"subroutine_name": argument_count} into names using a temporary array + # (instead of using global variable "names" and a new global function to process the matching patterns) + # for example: "def f(x y z):" -> "def f(x,y,z):" and names = {"f": 3} + process_funcdef = lambda r: r.group(1) + r.group(2) + \ + [chsp.sub(", ", r.group(4)), names.update({r.group(3): len(re.findall(r"\w+", r.group(4)))})][0] + # process all function headers calling process_funcdef for every matching + # (before parsing Logo expressions line by line, we need to know about all functions, + # because functions can be defined in any order, ie. their calls can be before + # their definitions) + s = search_funcdef.sub(process_funcdef, s) + + # process line by line for i in s.split("\n"): i = i.strip() - # store argument numbers of subroutines in names - if i[0:4] == 'def ': - s = func.search(i) - if s.group(3) == '():': - names[s.group(2)] = 0 - else: - s2 = len(chsp.findall(s.group(3))) + 1 - i = s.group(1) + chsp.sub(", ", s.group(3)) - names[s.group(2)] = s2 # convert Logo expressions to Python ones using regex based tokenization # tokens: {startpos: endpos} dictionaries for subroutine names, operators and other tokens diff --git a/sw/qa/uitest/librelogo/compile.py b/sw/qa/uitest/librelogo/compile.py index 73c2e8fbaaa6..79a297ef1593 100644 --- a/sw/qa/uitest/librelogo/compile.py +++ b/sw/qa/uitest/librelogo/compile.py @@ -98,6 +98,8 @@ class LibreLogoCompileTest(UITestCase): ("a=(SIN 102) + (COS 102)", "a=(sin(102)) + (cos(102))"), ("a=SIN 103 + COS 103 - SQRT 103", "a=sin(103 + cos(103 - sqrt(103)))"), ("a=(SIN 104 + COS 104) - SQRT 104", "a=(sin(104 + cos(104))) - sqrt(104)"), + # SIN(x) is Python-like, SIN (x) is Logo-like syntax + ("a=SIN(105) + COS (105) - SQRT 105", "a=sin(105) + cos((105) - sqrt(105))"), ("a=COUNT [1, 2, 3]", "a=len([1, 2, 3])"), ("PRINT COUNT [1, 2, 3]", "Print(len([1, 2, 3]))"), ("PRINT 'TEXT: ' + 'CHAR'[0] + ' TEXT2: ' + variable[-1]", "Print(u'TEXT: ' + u'CHAR'[0] + u' TEXT2: ' + variable[-1])"), @@ -119,6 +121,8 @@ class LibreLogoCompileTest(UITestCase): ("TO f x y z\nLABEL x+y+z\nEND\nf len [1, cos 2, [65]] sqrt len [1, 2, 3, 4] sin 90 * cos 270", "global f\ndef f(x, y, z):\n __checkhalt__()\n %s\n label(x+y+z)\n %s\n%s\nf(len([1, cos(2), [65]]), sqrt(len([1, 2, 3, 4])), sin(90 * cos(270)))" % (((self.LS),)*3)), ("TO f x y z\nLABEL x+y+z\nEND\nf len([1, cos 2, [65]]) sqrt(len [1, 2, 3, 4]) sin(90) * cos 270", "global f\ndef f(x, y, z):\n __checkhalt__()\n %s\n label(x+y+z)\n %s\n%s\nf(len([1, cos(2), [65]]), sqrt(len([1, 2, 3, 4])), sin(90) * cos(270))" % (((self.LS),)*3)), ("TO f x y z\nLABEL x+y+z\nEND\nf (len [1, cos 2, [65]]) (sqrt len [1, 2, 3, 4]) (sin 90) * (cos 270)", "global f\ndef f(x, y, z):\n __checkhalt__()\n %s\n label(x+y+z)\n %s\n%s\nf((len([1, cos(2), [65]])), (sqrt(len([1, 2, 3, 4]))), (sin(90)) * (cos(270)))" % (((self.LS),)*3)), + # arbitrary order of function definitions and calls + ("f 1 1 f 2 2\nTO f x y\nPRINT x + y\nEND", "global f\nf(1, 1)\nf(2, 2)\n%s\ndef f(x, y):\n __checkhalt__()\n %s\n Print(x + y)\n %s" % (((self.LS),)*3)), ): compiled = xCompile.invoke((test[0],), (), ())[0] self.assertEqual(test[1], re.sub(r'(\n| +\n)+', '\n', re.sub(r'\( ', '(', compiled)).strip()) diff --git a/sw/qa/uitest/librelogo/run.py b/sw/qa/uitest/librelogo/run.py index 5d36c5d14e7b..5d64e1bea152 100644 --- a/sw/qa/uitest/librelogo/run.py +++ b/sw/qa/uitest/librelogo/run.py @@ -69,6 +69,35 @@ class LibreLogoTest(UITestCase): # first paragraph is empty (for working page break) self.assertEqual(document.Text.createEnumeration().nextElement().String, "") + # function definitions and calls can be in arbitrary order + document.Text.String = """ +; dragon curve +TO x n +IF n = 0 [ STOP ] +x n-1 +RIGHT 90 +y n-1 ; it worked only as "y(n-1)" +FORWARD 10 +END + +TO y n +IF n = 0 [ STOP ] +FORWARD 10 +x n-1 +LEFT 90 +y n-1 +END + +PICTURE ; start new line draw +x 3 ; draw only a few levels +""" + self.logo("run") + # wait for LibreLogo program termination + while xIsAlive.invoke((), (), ())[0]: + pass + # new shape + previous two ones = 3 + self.assertEqual(document.DrawPage.getCount(), 3) + self.ui_test.close_doc() # vim: set shiftwidth=4 softtabstop=4 expandtab: |