diff options
author | László Németh <nemeth@numbertext.org> | 2018-11-05 22:50:40 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2018-11-06 08:32:56 +0100 |
commit | b274e879bdbed85c9373e90e6998cabe22b5bd3a (patch) | |
tree | 604efbe2d00dc6bd2729fe178e453db4d6e2eb7d /librelogo | |
parent | 97ebc98f0e956712d242e13f15531742f844a738 (diff) |
LibreLogo: function calls and definitions can be in any order
with Logo syntax, too.
Mutual recursion, for example drawing dragon curve (see in the
unit test of the commit) doesn't need Python syntax any more
to call the function before its definition.
Change-Id: I93426a8c5be394fb4f1203e0490f7fa8d8491597
Reviewed-on: https://gerrit.libreoffice.org/62926
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
Diffstat (limited to 'librelogo')
-rw-r--r-- | librelogo/source/LibreLogo/LibreLogo.py | 33 |
1 files changed, 21 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 |