File size: 6,151 Bytes
985c397
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#! python
# SPDX-License-Identifier: LGPL-2.1-or-later

# (c) 2007 Jürgen Riegel

import os


def ensureDir(path, mode=0o777):
    try:
        os.makedirs(path, mode)
    except OSError as err:
        # https://docs.python.org/3/tutorial/errors.html
        #  raise an error unless it's about an already existing directory
        print("Dir Exist")
        # if errno != 17 or not os.path.isdir(path):
        # 	raise


def convertMultilineString(str):
    str = str.replace("\n", "\\n")
    str = str.replace('"', '\\"')
    return str


"Yet Another Python Templating Utility, Version 1.2"

import sys


# utility stuff to avoid tests in the mainline code
class _nevermatch:
    "Polymorphic with a regex that never matches"

    def match(self, line):
        return None


_never = _nevermatch()  # one reusable instance of it suffices


def identity(string, why):
    "A do-nothing-special-to-the-input, just-return-it function"
    return string


def nohandle(string):
    "A do-nothing handler that just re-raises the exception"
    raise


# and now the real thing
class copier:
    "Smart-copier (YAPTU) class"

    def copyblock(self, cur_line=0, last=None):
        "Main copy method: process lines [i,last) of block"

        def repl(match, self=self):
            "return the eval of a found expression, for replacement"
            # uncomment for debug: print ('!!! replacing',match.group(1))
            expr = self.preproc(match.group(1), "eval")
            try:
                return str(eval(expr, self.globals, self.locals))
            except Exception:
                return str(self.handle(expr))

        block = self.locals["_bl"]
        if last is None:
            last = len(block)
        while cur_line < last:
            line = block[cur_line]
            match = self.restat.match(line)
            if match:  # a statement starts "here" (at line block[i])
                # i is the last line to _not_ process
                stat = match.string[match.end(0) :].strip()
                j = cur_line + 1  # look for 'finish' from here onwards
                nest = 1  # count nesting levels of statements
                while j < last:
                    line = block[j]
                    # first look for nested statements or 'finish' lines
                    if self.restend.match(line):  # found a statement-end
                        nest = nest - 1  # update (decrease) nesting
                        if nest == 0:
                            break  # j is first line to _not_ process
                    elif self.restat.match(line):  # found a nested statement
                        nest = nest + 1  # update (increase) nesting
                    elif nest == 1:  # look for continuation only at this nesting
                        match = self.recont.match(line)
                        if match:  # found a contin.-statement
                            nestat = match.string[match.end(0) :].strip()
                            stat = "%s _cb(%s,%s)\n%s" % (stat, cur_line + 1, j, nestat)
                            cur_line = j  # again, i is the last line to _not_ process
                    j = j + 1
                stat = self.preproc(stat, "exec")
                stat = "%s _cb(%s,%s)" % (stat, cur_line + 1, j)
                # for debugging, uncomment...: print(f"-> Executing on line {cur_line}: {stat}")
                exec(stat, self.globals, self.locals)
                cur_line = j + 1
            else:  # normal line, just copy with substitution
                try:
                    self.ouf.write(self.regex.sub(repl, line).encode("utf8"))
                except TypeError:
                    self.ouf.write(self.regex.sub(repl, line))
                cur_line = cur_line + 1

    def __init__(

        self,

        regex=_never,

        dict=None,

        restat=_never,

        restend=_never,

        recont=_never,

        preproc=identity,

        handle=nohandle,

        ouf=sys.stdout,

    ):
        "Initialize self's attributes"
        self.regex = regex
        if dict is not None:
            self.globals = dict
        else:
            self.globals = {}
        self.globals["sys"] = sys
        self.locals = {"_cb": self.copyblock}
        self.restat = restat
        self.restend = restend
        self.recont = recont
        self.preproc = preproc
        self.handle = handle
        self.ouf = ouf

    def copy(self, block=None, inf=sys.stdin):
        "Entry point: copy-with-processing a file, or a block of lines"
        if block is None:
            block = inf.readlines()
        self.locals["_bl"] = block
        self.copyblock()


def replace(template, dict, file):
    "Test: copy a block of lines, with full processing"
    import re

    rex = re.compile(r"@([^@]+)@")
    rbe = re.compile(r"\+")
    ren = re.compile(r"-")
    rco = re.compile(r"= ")
    x = 23  # just a variable to try substitution
    cop = copier(rex, dict, rbe, ren, rco)
    lines_block = [line + "\n" for line in template.split("\n")]
    cop.ouf = file
    cop.copy(lines_block)


if __name__ == "__main__":
    "Test: copy a block of lines, with full processing"
    import re

    rex = re.compile(r"@([^@]+)@")
    rbe = re.compile(r"\+")
    ren = re.compile(r"-")
    rco = re.compile(r"= ")
    x = 23  # just a variable to try substitution
    cop = copier(rex, globals(), rbe, ren, rco)
    lines_block = [
        line + "\n"
        for line in """

A first, plain line -- it just gets copied.

A second line, with @x@ substitutions.

+ x+=1   # non-block statements MUST end with comments

-

Now the substitutions are @x@.

+ if x>23:

After all, @x@ is rather large!

= else:

After all, @x@ is rather small!

-

+ for i in range(3):

  Also, @i@ times @x@ is @i*x@.

-

One last, plain line at the end.""".split(
            "\n"
        )
    ]
    print("*** input:")
    print("".join(lines_block))
    print("*** output:")
    cop.copy(lines_block)