Skip to content

Commit 3c469ea

Browse files
committed
compiler/porcelain wrapper
1 parent 0c5bf8e commit 3c469ea

3 files changed

Lines changed: 148 additions & 1 deletion

File tree

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "rustpython-compiler"
2+
name = "rustpython-compiler-core"
33
version = "0.1.2"
44
description = "Compiler for python code into bytecode for the rustpython VM."
55
authors = ["RustPython Team"]

‎porcelain/Cargo.toml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "rustpython-compiler"
3+
version = "0.1.2"
4+
description = "A usability wrapper around rustpython-parser and rustpython-compiler-core"
5+
authors = ["RustPython Team"]
6+
edition = "2018"
7+
8+
[dependencies]
9+
thiserror = "1.0"
10+
rustpython-compiler-core = { path = ".." }
11+
rustpython-parser = { path = "../../parser" }
12+
rustpython-bytecode = { path = "../../bytecode" }

‎porcelain/src/lib.rs‎

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use rustpython_bytecode::bytecode::CodeObject;
2+
use rustpython_compiler_core::{compile, symboltable};
3+
use rustpython_parser::{ast::Location, parser};
4+
use std::fmt;
5+
6+
pub use compile::{CompileOpts, Mode};
7+
pub use symboltable::{Symbol, SymbolScope, SymbolTable, SymbolTableType};
8+
9+
#[derive(Debug, thiserror::Error)]
10+
pub enum CompileErrorType {
11+
#[error(transparent)]
12+
Compile(#[from] rustpython_compiler_core::error::CompileErrorType),
13+
#[error(transparent)]
14+
Parse(#[from] rustpython_parser::error::ParseErrorType),
15+
}
16+
17+
#[derive(Debug, thiserror::Error)]
18+
pub struct CompileError {
19+
pub error: CompileErrorType,
20+
pub statement: Option<String>,
21+
pub source_path: String,
22+
pub location: Location,
23+
}
24+
25+
impl fmt::Display for CompileError {
26+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27+
let loc = self.location;
28+
if let Some(ref stmt) = self.statement {
29+
// visualize the error when location and statement are provided
30+
write!(
31+
f,
32+
"{}",
33+
loc.visualize(stmt, &format_args!("{} at {}", self.error, loc))
34+
)
35+
} else {
36+
write!(f, "{} at {}", self.error, loc)
37+
}
38+
}
39+
}
40+
41+
impl CompileError {
42+
fn from_compile(error: rustpython_compiler_core::error::CompileError, source: &str) -> Self {
43+
CompileError {
44+
error: error.error.into(),
45+
location: error.location,
46+
source_path: error.source_path,
47+
statement: get_statement(source, error.location),
48+
}
49+
}
50+
fn from_parse(
51+
error: rustpython_parser::error::ParseError,
52+
source: &str,
53+
source_path: String,
54+
) -> Self {
55+
CompileError {
56+
error: error.error.into(),
57+
location: error.location,
58+
source_path,
59+
statement: get_statement(source, error.location),
60+
}
61+
}
62+
fn from_symtable(
63+
error: symboltable::SymbolTableError,
64+
source: &str,
65+
source_path: String,
66+
) -> Self {
67+
Self::from_compile(error.into_compile_error(source_path), source)
68+
}
69+
}
70+
71+
/// Compile a given sourcecode into a bytecode object.
72+
pub fn compile(
73+
source: &str,
74+
mode: compile::Mode,
75+
source_path: String,
76+
opts: CompileOpts,
77+
) -> Result<CodeObject, CompileError> {
78+
macro_rules! try_parse {
79+
($x:expr) => {
80+
match $x {
81+
Ok(x) => x,
82+
Err(e) => return Err(CompileError::from_parse(e, source, source_path)),
83+
}
84+
};
85+
}
86+
let res = match mode {
87+
compile::Mode::Exec => {
88+
let ast = try_parse!(parser::parse_program(source));
89+
compile::compile_program(ast, source_path, opts)
90+
}
91+
compile::Mode::Eval => {
92+
let statement = try_parse!(parser::parse_statement(source));
93+
compile::compile_statement_eval(statement, source_path, opts)
94+
}
95+
compile::Mode::Single => {
96+
let ast = try_parse!(parser::parse_program(source));
97+
compile::compile_program_single(ast, source_path, opts)
98+
}
99+
};
100+
res.map_err(|e| CompileError::from_compile(e, source))
101+
}
102+
103+
pub fn compile_symtable(
104+
source: &str,
105+
mode: compile::Mode,
106+
source_path: &str,
107+
) -> Result<symboltable::SymbolTable, CompileError> {
108+
macro_rules! try_parse {
109+
($x:expr) => {
110+
match $x {
111+
Ok(x) => x,
112+
Err(e) => return Err(CompileError::from_parse(e, source, source_path.to_owned())),
113+
}
114+
};
115+
}
116+
let res = match mode {
117+
compile::Mode::Exec | compile::Mode::Single => {
118+
let ast = try_parse!(parser::parse_program(source));
119+
symboltable::make_symbol_table(&ast)
120+
}
121+
compile::Mode::Eval => {
122+
let statement = try_parse!(parser::parse_statement(source));
123+
symboltable::statements_to_symbol_table(&statement)
124+
}
125+
};
126+
res.map_err(|e| CompileError::from_symtable(e, source, source_path.to_owned()))
127+
}
128+
129+
fn get_statement(source: &str, loc: Location) -> Option<String> {
130+
if loc.column() == 0 || loc.row() == 0 {
131+
return None;
132+
}
133+
let line = source.split('\n').nth(loc.row() - 1)?.to_owned();
134+
Some(line + "\n")
135+
}

0 commit comments

Comments
 (0)