Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/tools/self.js
1396 views
1
/*
2
* self.js
3
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
*
5
* Distributed under terms of the BSD license.
6
*/
7
"use strict"; /*jshint node:true */
8
9
var path = require("path");
10
var crypto = require("crypto");
11
var fs = require("fs");
12
var vm = require("vm");
13
var zlib = require("zlib");
14
15
function compile_baselib(PyLang, src_path) {
16
var items = fs
17
.readdirSync(path.join(src_path, "baselib"))
18
.filter(function (name) {
19
return name.endsWith(".py");
20
});
21
var ans = { pretty: "" };
22
23
items.sort().forEach(function (fname) {
24
var name = fname.slice(0, -3),
25
ast;
26
var raw = fs.readFileSync(path.join(src_path, "baselib", fname), "utf-8");
27
try {
28
ast = PyLang.parse(raw, {
29
filename: fname,
30
basedir: path.join(src_path, "baselib"),
31
});
32
} catch (e) {
33
if (!(e instanceof PyLang.SyntaxError)) throw e;
34
console.error(e.toString());
35
process.exit(1);
36
}
37
var output = new PyLang.OutputStream({
38
beautify: true,
39
write_name: false,
40
private_scope: false,
41
omit_baselib: true,
42
});
43
ast.print(output);
44
ans["pretty"] += output.get();
45
});
46
return ans;
47
}
48
49
function check_for_changes(base_path, src_path, signatures) {
50
// Check if any of the files involved in the build process have changed,
51
// as compared to the saved sha1 hashes from the last build
52
var saved_hashes = {},
53
hashes = {},
54
sources = {};
55
var compiler_changed = false,
56
compiler_hash,
57
source_hash;
58
try {
59
saved_hashes = JSON.parse(fs.readFileSync(signatures, "utf-8"));
60
} catch (e) {
61
if (e.code != "ENOENT") throw e;
62
}
63
64
var src_file_names = [];
65
66
function process_dir(p) {
67
fs.readdirSync(p).forEach(function (name) {
68
var fp = path.join(p, name);
69
if (name.endsWith(".py")) {
70
src_file_names.push(path.relative(src_path, fp));
71
} else if (name != "lib" && fs.statSync(fp).isDirectory()) {
72
process_dir(fp);
73
}
74
});
75
}
76
process_dir(src_path);
77
78
compiler_hash = crypto.createHash("sha1");
79
source_hash = crypto.createHash("sha1");
80
src_file_names.forEach(function (fname) {
81
var src = path.join(src_path, fname);
82
sources[src] = fs.readFileSync(src, "utf-8");
83
compiler_hash.update(sources[src]);
84
source_hash.update(sources[src]);
85
var h = crypto.createHash("sha1");
86
h.update(sources[src]);
87
hashes[fname.split(".")[0]] = h.digest("hex");
88
});
89
var compiler_files = [
90
module.filename,
91
path.join(base_path, "tools", "compiler.ts"),
92
];
93
compiler_files.forEach(function (fpath) {
94
compiler_hash.update(fs.readFileSync(fpath, "utf-8"));
95
});
96
hashes["#compiler#"] = compiler_hash.digest("hex");
97
hashes["#compiled_with#"] = saved_hashes["#compiler#"] || "unknown";
98
source_hash = source_hash.digest("hex");
99
if (hashes["#compiler#"] != saved_hashes["#compiler#"]) {
100
console.log(
101
"There are changes to the source files of the compiler, rebuilding"
102
);
103
compiler_changed = true;
104
} else if (hashes["#compiled_with#"] != saved_hashes["#compiled_with#"]) {
105
console.log("Re-building compiler with updated version of itself");
106
compiler_changed = true;
107
}
108
109
return [source_hash, compiler_changed, sources, hashes];
110
}
111
112
import createCompiler from "./compiler";
113
114
function compile(src_path, lib_path, sources, source_hash, profile) {
115
var file = path.join(src_path, "compiler.py");
116
var t1 = new Date().getTime();
117
var PyLang = createCompiler();
118
var output_options, profiler, cpu_profile;
119
var compiled_baselib = compile_baselib(PyLang, src_path);
120
var out_path = lib_path;
121
try {
122
fs.mkdirSync(out_path);
123
} catch (e) {
124
if (e.code != "EEXIST") throw e;
125
}
126
output_options = { beautify: true, baselib_plain: compiled_baselib.pretty };
127
128
var raw = sources[file],
129
toplevel;
130
131
function parse_file(code, file) {
132
return PyLang.parse(code, {
133
filename: file,
134
basedir: path.dirname(file),
135
libdir: path.join(src_path, "lib"),
136
});
137
}
138
139
try {
140
if (profile) {
141
profiler = require("v8-profiler");
142
profiler.startProfiling();
143
}
144
toplevel = parse_file(raw, file);
145
if (profile) {
146
cpu_profile = profiler.stopProfiling();
147
fs.writeFileSync("self.cpuprofile", JSON.stringify(cpu_profile), "utf-8");
148
}
149
} catch (e) {
150
if (!(e instanceof PyLang.SyntaxError)) throw e;
151
console.error(e.toString());
152
process.exit(1);
153
}
154
var output = new PyLang.OutputStream(output_options);
155
toplevel.print(output);
156
output = output.get().replace("__COMPILER_VERSION__", source_hash);
157
fs.writeFileSync(path.join(out_path, "compiler.js"), output, "utf8");
158
fs.writeFileSync(
159
path.join(out_path, "baselib-plain-pretty.js"),
160
compiled_baselib.pretty,
161
"utf-8"
162
);
163
console.log(
164
"Compiler built in",
165
(new Date().getTime() - t1) / 1000,
166
"seconds\n"
167
);
168
return output;
169
}
170
171
function run_single_compile(base_path, src_path, lib_path, profile) {
172
var out_path = lib_path;
173
var signatures = path.join(out_path, "signatures.json");
174
var temp = check_for_changes(base_path, src_path, signatures);
175
var source_hash = temp[0],
176
compiler_changed = temp[1],
177
sources = temp[2],
178
hashes = temp[3];
179
180
if (compiler_changed) {
181
compile(src_path, lib_path, sources, source_hash, profile);
182
fs.writeFileSync(signatures, JSON.stringify(hashes, null, 4));
183
} else console.log("Compiler is built with the up-to-date version of itself");
184
return compiler_changed;
185
}
186
187
module.exports = function compile_self(
188
base_path,
189
src_path,
190
lib_path,
191
complete,
192
profile
193
) {
194
var changed;
195
do {
196
changed = run_single_compile(base_path, src_path, lib_path, profile);
197
lib_path = lib_path;
198
} while (changed && complete);
199
};
200
201