aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/py/genlast.py
blob: ad44745d973ae1fa4b84b0ea2ecfaf028294c963 (plain)
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
#!/usr/bin/env python3

import sys
import re
import os
import itertools
from concurrent.futures import ProcessPoolExecutor
import multiprocessing
import threading
import subprocess

from makeqstrdefs import qstr_unescape, QSTRING_BLOCK_LIST

re_line = re.compile(r"#[line]*\s(\d+)\s\"([^\"]+)\"", re.DOTALL)
re_qstr = re.compile(r"MP_QSTR_[_a-zA-Z0-9]+", re.DOTALL)
re_translate = re.compile(r"translate\(\"((?:(?=(\\?))\2.)*?)\"\)", re.DOTALL)


def write_out(fname, output_dir, output):
    if output:
        for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
            fname = fname.replace(m, r)
        with open(output_dir + "/" + fname + ".qstr", "w") as f:
            f.write("\n".join(output) + "\n")


def process_file(fname, output_dir, content):
    content = content.decode("utf-8", errors="ignore")
    output = []
    for match in re_qstr.findall(content):
        name = match.replace("MP_QSTR_", "")
        if name not in QSTRING_BLOCK_LIST:
            output.append("Q(" + qstr_unescape(name) + ")")
    for match in re_translate.findall(content):
        output.append('TRANSLATE("' + match[0] + '")')

    write_out(fname, output_dir, output)


def checkoutput1(args):
    info = subprocess.run(args, check=True, stdout=subprocess.PIPE, input="")
    return info.stdout


def preprocess(command, output_dir, fn):
    try:
        output = checkoutput1(command + [fn])
        process_file(fn, output_dir, output)
    except Exception as e:
        print(e, file=sys.stderr)
        raise


def maybe_preprocess(command, output_dir, fn):
    # Preprocess the source file if it contains "MP_QSTR", "translate",
    # or if it uses enum.h (which generates "MP_QSTR" strings.
    if subprocess.call(["grep", "-lqE", r"(MP_QSTR|translate|enum\.h)", fn]) == 0:
        preprocess(command, output_dir, fn)


if __name__ == "__main__":

    idx1 = sys.argv.index("--")
    idx2 = sys.argv.index("--", idx1 + 1)
    output_dir = sys.argv[1]
    check = sys.argv[2:idx1]
    always = sys.argv[idx1 + 1 : idx2]
    command = sys.argv[idx2 + 1 :]

    if not os.path.isdir(output_dir):
        os.makedirs(output_dir)

    # Mac and Windows use 'spawn'.  Uncomment this during testing to catch spawn-specific problems on Linux.
    # multiprocessing.set_start_method("spawn")
    executor = ProcessPoolExecutor(max_workers=multiprocessing.cpu_count() + 1)
    results = []
    try:
        results.extend(
            executor.map(
                maybe_preprocess, itertools.repeat(command), itertools.repeat(output_dir), check
            )
        )
        results.extend(
            executor.map(
                preprocess, itertools.repeat(command), itertools.repeat(output_dir), always
            )
        )
    except subprocess.CalledProcessError:
        raise SystemExit(1)
    executor.shutdown()