| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -19,15 +19,17 @@ use proc_macro2::{Span, TokenStream as TokenStream2}; | |
| use quote::quote; | ||
| use rustpython_bytecode::bytecode::CodeObject; | ||
| use rustpython_compiler::compile; | ||
| use std::collections::HashMap; | ||
| use std::env; | ||
| use std::fs; | ||
| use std::path::PathBuf; | ||
| use syn::parse::{Parse, ParseStream, Result as ParseResult}; | ||
| use syn::{self, parse2, Lit, LitByteStr, Meta, Token}; | ||
| use syn::{self, parse2, Lit, LitByteStr, LitStr, Meta, Token}; | ||
|
|
||
| enum CompilationSourceKind { | ||
| File(PathBuf), | ||
| SourceCode(String), | ||
| Dir(PathBuf), | ||
| } | ||
|
|
||
| struct CompilationSource { | ||
| Expand All | @@ -36,14 +38,22 @@ struct CompilationSource { | |
| } | ||
|
|
||
| impl CompilationSource { | ||
| fn compile(self, mode: &compile::Mode, module_name: String) -> Result<CodeObject, Diagnostic> { | ||
| let compile = |source| { | ||
| compile::compile(source, mode, module_name, 0).map_err(|err| { | ||
| Diagnostic::spans_error(self.span, format!("Compile error: {}", err)) | ||
| }) | ||
| }; | ||
|
|
||
| match &self.kind { | ||
| fn compile_string( | ||
| &self, | ||
| source: &str, | ||
| mode: &compile::Mode, | ||
| module_name: String, | ||
| ) -> Result<CodeObject, Diagnostic> { | ||
| compile::compile(source, mode, module_name, 0) | ||
| .map_err(|err| Diagnostic::spans_error(self.span, format!("Compile error: {}", err))) | ||
| } | ||
|
|
||
| fn compile( | ||
| &self, | ||
| mode: &compile::Mode, | ||
| module_name: String, | ||
| ) -> Result<HashMap<String, CodeObject>, Diagnostic> { | ||
| Ok(match &self.kind { | ||
| CompilationSourceKind::File(rel_path) => { | ||
| let mut path = PathBuf::from( | ||
| env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"), | ||
| Expand All | @@ -55,10 +65,59 @@ impl CompilationSource { | |
| format!("Error reading file {:?}: {}", path, err), | ||
| ) | ||
| })?; | ||
| compile(&source) | ||
| hashmap! {module_name.clone() => self.compile_string(&source, mode, module_name.clone())?} | ||
| } | ||
| CompilationSourceKind::SourceCode(code) => { | ||
| hashmap! {module_name.clone() => self.compile_string(code, mode, module_name.clone())?} | ||
| } | ||
| CompilationSourceKind::Dir(rel_path) => { | ||
| let mut path = PathBuf::from( | ||
| env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"), | ||
| ); | ||
| path.push(rel_path); | ||
| self.compile_dir(&path, String::new(), mode)? | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| fn compile_dir( | ||
| &self, | ||
| path: &PathBuf, | ||
| parent: String, | ||
| mode: &compile::Mode, | ||
| ) -> Result<HashMap<String, CodeObject>, Diagnostic> { | ||
| let mut code_map = HashMap::new(); | ||
| let paths = fs::read_dir(&path).map_err(|err| { | ||
| Diagnostic::spans_error(self.span, format!("Error listing dir {:?}: {}", path, err)) | ||
| })?; | ||
| for path in paths { | ||
| let path = path.map_err(|err| { | ||
| Diagnostic::spans_error(self.span, format!("Failed to list file: {}", err)) | ||
| })?; | ||
| let path = path.path(); | ||
| let file_name = path.file_name().unwrap().to_str().unwrap(); | ||
| if path.is_dir() { | ||
| code_map.extend(self.compile_dir( | ||
| &path, | ||
| format!("{}{}.", parent, file_name), | ||
| mode, | ||
| )?); | ||
| } else if file_name.ends_with(".py") { | ||
| let source = fs::read_to_string(&path).map_err(|err| { | ||
| Diagnostic::spans_error( | ||
| self.span, | ||
| format!("Error reading file {:?}: {}", path, err), | ||
| ) | ||
| })?; | ||
| let file_name_splitte: Vec<&str> = file_name.splitn(2, ".").collect(); | ||
| let module_name = format!("{}{}", parent, file_name_splitte[0]); | ||
| code_map.insert( | ||
| module_name.clone(), | ||
| self.compile_string(&source, mode, module_name)?, | ||
| ); | ||
| } | ||
| CompilationSourceKind::SourceCode(code) => compile(code), | ||
| } | ||
| Ok(code_map) | ||
| } | ||
| } | ||
|
|
||
| Expand All | @@ -69,7 +128,7 @@ struct PyCompileInput { | |
| } | ||
|
|
||
| impl PyCompileInput { | ||
| fn compile(&self) -> Result<CodeObject, Diagnostic> { | ||
| fn compile(&self) -> Result<HashMap<String, CodeObject>, Diagnostic> { | ||
| let mut module_name = None; | ||
| let mut mode = None; | ||
| let mut source: Option<CompilationSource> = None; | ||
| Expand Down Expand Up | @@ -122,6 +181,16 @@ impl PyCompileInput { | |
| kind: CompilationSourceKind::File(path), | ||
| span: extract_spans(&name_value).unwrap(), | ||
| }); | ||
| } else if name_value.ident == "dir" { | ||
| assert_source_empty(&source)?; | ||
| let path = match &name_value.lit { | ||
| Lit::Str(s) => PathBuf::from(s.value()), | ||
| _ => bail_span!(name_value.lit, "source must be a string"), | ||
| }; | ||
| source = Some(CompilationSource { | ||
| kind: CompilationSourceKind::Dir(path), | ||
| span: extract_spans(&name_value).unwrap(), | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| Expand Down Expand Up | @@ -154,16 +223,23 @@ impl Parse for PyCompileInput { | |
| pub fn impl_py_compile_bytecode(input: TokenStream2) -> Result<TokenStream2, Diagnostic> { | ||
| let input: PyCompileInput = parse2(input)?; | ||
|
|
||
| let code_obj = input.compile()?; | ||
| let code_map = input.compile()?; | ||
|
|
||
| let bytes = bincode::serialize(&code_obj).expect("Failed to serialize"); | ||
| let bytes = LitByteStr::new(&bytes, Span::call_site()); | ||
| let modules = code_map.iter().map(|(module_name, code_obj)| { | ||
| let module_name = LitStr::new(&module_name, Span::call_site()); | ||
| let bytes = bincode::serialize(&code_obj).expect("Failed to serialize"); | ||
| let bytes = LitByteStr::new(&bytes, Span::call_site()); | ||
| quote! { #module_name.into() => bincode::deserialize::<::rustpython_vm::bytecode::CodeObject>(#bytes) | ||
| .expect("Deserializing CodeObject failed") } | ||
| }); | ||
|
|
||
| let output = quote! { | ||
| ({ | ||
| use ::rustpython_vm::__exports::bincode; | ||
| bincode::deserialize::<::rustpython_vm::bytecode::CodeObject>(#bytes) | ||
| .expect("Deserializing CodeObject failed") | ||
| use ::rustpython_vm::__exports::hashmap; | ||
| hashmap! { | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityYou should probably add hashmap to __exports and use it here.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWhat is the purpose of the __exports? This is my first time using procedural macro
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI think I understand what __exports do. Added hashmap
Sorry, something went wrong.
All reactions
|
||
| #(#modules),* | ||
| } | ||
| }) | ||
| }; | ||
|
|
||
| Expand Down | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -79,4 +79,5 @@ pub use rustpython_bytecode::*; | |
| #[doc(hidden)] | ||
| pub mod __exports { | ||
| pub use bincode; | ||
| pub use maplit::hashmap; | ||
| } | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualitySorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWhy is this better?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityPathBuf vs Path is akin to String vs str - an owned, allocated buffer vs a slice. Like you should (almost) always prefer &str over &String, so should you for &Path over &PathBuf.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.