Skip to content

Commit 5c240d7

Browse files
committed
Support freezing of stdlib
1 parent f271a0e commit 5c240d7

File tree

5 files changed

+103
-18
lines changed

5 files changed

+103
-18
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

derive/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ rustpython-compiler = { path = "../compiler", version = "0.1.0" }
2121
rustpython-bytecode = { path = "../bytecode", version = "0.1.0" }
2222
bincode = "1.1"
2323
proc-macro-hack = { version = "0.5", optional = true }
24+
maplit = "1.0"

derive/src/compile_bytecode.rs

Lines changed: 93 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use proc_macro2::{Span, TokenStream as TokenStream2};
1919
use quote::quote;
2020
use rustpython_bytecode::bytecode::CodeObject;
2121
use rustpython_compiler::compile;
22+
use std::collections::HashMap;
2223
use std::env;
2324
use std::fs;
2425
use std::path::PathBuf;
@@ -28,6 +29,7 @@ use syn::{self, parse2, Lit, LitByteStr, LitStr, Meta, Token};
2829
enum CompilationSourceKind {
2930
File(PathBuf),
3031
SourceCode(String),
32+
Dir(PathBuf),
3133
}
3234

3335
struct CompilationSource {
@@ -36,14 +38,22 @@ struct CompilationSource {
3638
}
3739

3840
impl CompilationSource {
39-
fn compile(self, mode: &compile::Mode, module_name: String) -> Result<CodeObject, Diagnostic> {
40-
let compile = |source| {
41-
compile::compile(source, mode, module_name, 0).map_err(|err| {
42-
Diagnostic::spans_error(self.span, format!("Compile error: {}", err))
43-
})
44-
};
45-
46-
match &self.kind {
41+
fn compile_string(
42+
&self,
43+
source: &str,
44+
mode: &compile::Mode,
45+
module_name: String,
46+
) -> Result<CodeObject, Diagnostic> {
47+
compile::compile(source, mode, module_name, 0)
48+
.map_err(|err| Diagnostic::spans_error(self.span, format!("Compile error: {}", err)))
49+
}
50+
51+
fn compile(
52+
&self,
53+
mode: &compile::Mode,
54+
module_name: String,
55+
) -> Result<HashMap<String, CodeObject>, Diagnostic> {
56+
Ok(match &self.kind {
4757
CompilationSourceKind::File(rel_path) => {
4858
let mut path = PathBuf::from(
4959
env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"),
@@ -55,10 +65,61 @@ impl CompilationSource {
5565
format!("Error reading file {:?}: {}", path, err),
5666
)
5767
})?;
58-
compile(&source)
68+
hashmap! {module_name.clone() => self.compile_string(&source, mode, module_name.clone())?}
69+
}
70+
CompilationSourceKind::SourceCode(code) => {
71+
hashmap! {module_name.clone() => self.compile_string(code, mode, module_name.clone())?}
72+
}
73+
CompilationSourceKind::Dir(rel_path) => {
74+
let mut path = PathBuf::from(
75+
env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"),
76+
);
77+
path.push(rel_path);
78+
self.compile_dir(&path, "".to_string(), mode)?
79+
}
80+
})
81+
}
82+
83+
fn compile_dir(
84+
&self,
85+
path: &PathBuf,
86+
parent: String,
87+
mode: &compile::Mode,
88+
) -> Result<HashMap<String, CodeObject>, Diagnostic> {
89+
let mut code_map = HashMap::new();
90+
let paths = fs::read_dir(&path).map_err(|err| {
91+
Diagnostic::spans_error(self.span, format!("Error listing dir {:?}: {}", path, err))
92+
})?;
93+
for path in paths {
94+
let path = path.map_err(|err| {
95+
Diagnostic::spans_error(self.span, format!("Failed to list file: {}", err))
96+
})?;
97+
let path = path.path();
98+
let file_name = path.file_name().unwrap().to_str().unwrap();
99+
if path.is_dir() {
100+
code_map.extend(self.compile_dir(
101+
&path,
102+
format!("{}{}.", parent, file_name),
103+
mode,
104+
)?);
105+
} else {
106+
if file_name.ends_with(".py") {
107+
let source = fs::read_to_string(&path).map_err(|err| {
108+
Diagnostic::spans_error(
109+
self.span,
110+
format!("Error reading file {:?}: {}", path, err),
111+
)
112+
})?;
113+
let file_name_splitte: Vec<&str> = file_name.splitn(2, ".").collect();
114+
let module_name = format!("{}{}", parent, file_name_splitte[0]);
115+
code_map.insert(
116+
module_name.clone(),
117+
self.compile_string(&source, mode, module_name)?,
118+
);
119+
}
59120
}
60-
CompilationSourceKind::SourceCode(code) => compile(code),
61121
}
122+
Ok(code_map)
62123
}
63124
}
64125

@@ -69,7 +130,7 @@ struct PyCompileInput {
69130
}
70131

71132
impl PyCompileInput {
72-
fn compile(&self) -> Result<CodeObject, Diagnostic> {
133+
fn compile(&self) -> Result<HashMap<String, CodeObject>, Diagnostic> {
73134
let mut module_name = None;
74135
let mut mode = None;
75136
let mut source: Option<CompilationSource> = None;
@@ -122,6 +183,16 @@ impl PyCompileInput {
122183
kind: CompilationSourceKind::File(path),
123184
span: extract_spans(&name_value).unwrap(),
124185
});
186+
} else if name_value.ident == "dir" {
187+
assert_source_empty(&source)?;
188+
let path = match &name_value.lit {
189+
Lit::Str(s) => PathBuf::from(s.value()),
190+
_ => bail_span!(name_value.lit, "source must be a string"),
191+
};
192+
source = Some(CompilationSource {
193+
kind: CompilationSourceKind::Dir(path),
194+
span: extract_spans(&name_value).unwrap(),
195+
});
125196
}
126197
}
127198
}
@@ -154,18 +225,22 @@ impl Parse for PyCompileInput {
154225
pub fn impl_py_compile_bytecode(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
155226
let input: PyCompileInput = parse2(input)?;
156227

157-
let code_obj = input.compile()?;
158-
159-
let module_name = LitStr::new(&code_obj.source_path, Span::call_site());
228+
let code_map = input.compile()?;
160229

161-
let bytes = bincode::serialize(&code_obj).expect("Failed to serialize");
162-
let bytes = LitByteStr::new(&bytes, Span::call_site());
230+
let modules = code_map.iter().map(|(module_name, code_obj)| {
231+
let module_name = LitStr::new(&module_name, Span::call_site());
232+
let bytes = bincode::serialize(&code_obj).expect("Failed to serialize");
233+
let bytes = LitByteStr::new(&bytes, Span::call_site());
234+
quote! { #module_name.into() => bincode::deserialize::<::rustpython_vm::bytecode::CodeObject>(#bytes)
235+
.expect("Deserializing CodeObject failed") }
236+
});
163237

164238
let output = quote! {
165239
({
166240
use ::rustpython_vm::__exports::bincode;
167-
hashmap! { #module_name.into() => bincode::deserialize::<::rustpython_vm::bytecode::CodeObject>(#bytes)
168-
.expect("Deserializing CodeObject failed")}
241+
hashmap! {
242+
#(#modules),*
243+
}
169244
})
170245
};
171246

derive/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
extern crate proc_macro;
66

7+
#[macro_use]
8+
extern crate maplit;
9+
710
#[macro_use]
811
mod error;
912
mod compile_bytecode;

vm/src/frozen.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@ pub fn get_module_inits() -> HashMap<String, CodeObject> {
1616
module_name = "_frozen_importlib_external",
1717
));
1818

19+
#[cfg(feature = "freeze-stdlib")]
20+
{
21+
modules.extend(py_compile_bytecode!(dir = "../Lib/",));
22+
}
23+
1924
modules
2025
}

0 commit comments

Comments
 (0)