Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ license = "MIT"
include = ["LICENSE", "Cargo.toml", "src/**/*.rs"]

[workspace]
members = [".", "derive", "vm", "wasm/lib", "parser", "compiler", "bytecode", "vm/pylib-crate", "common", "jit"]
members = [
".", "ast", "bytecode", "common", "compiler", "compiler/porcelain",
"derive", "jit", "parser", "vm", "vm/pylib-crate", "wasm/lib",
]

[[bench]]
name = "bench"
Expand All @@ -28,7 +31,7 @@ ssl = ["rustpython-vm/ssl"]
log = "0.4"
env_logger = "0.7"
clap = "2.33"
rustpython-compiler = { path = "compiler", version = "0.1.1" }
rustpython-compiler = { path = "compiler/porcelain", version = "0.1.1" }
rustpython-parser = { path = "parser", version = "0.1.1" }
rustpython-vm = { path = "vm", version = "0.1.1", default-features = false, features = ["compile-parse"] }
pylib = { package = "rustpython-pylib", path = "vm/pylib-crate", version = "0.1.0", default-features = false, optional = true }
Expand Down
8 changes: 8 additions & 0 deletions ast/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "rustpython-ast"
version = "0.1.0"
authors = ["RustPython Team"]
edition = "2018"

[dependencies]
num-bigint = "0.3"
File renamed without changes.
5 changes: 5 additions & 0 deletions ast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod ast;
mod location;

pub use ast::*;
pub use location::Location;
30 changes: 27 additions & 3 deletions parser/src/location.rs → ast/src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,33 @@ impl fmt::Display for Location {
}

impl Location {
pub fn visualize(&self, line: &str, desc: &str) -> String {
// desc.to_owned()
format!("{}\n{}\n{}↑", desc, line, " ".repeat(self.column - 1))
pub fn visualize<'a>(
&self,
line: &'a str,
desc: impl fmt::Display + 'a,
) -> impl fmt::Display + 'a {
struct Visualize<'a, D: fmt::Display> {
loc: Location,
line: &'a str,
desc: D,
}
impl<D: fmt::Display> fmt::Display for Visualize<'_, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}\n{}\n{arrow:>pad$}",
self.desc,
self.line,
pad = self.loc.column,
arrow = "↑",
)
}
}
Visualize {
loc: *self,
line,
desc,
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "rustpython-compiler"
name = "rustpython-compiler-core"
version = "0.1.2"
description = "Compiler for python code into bytecode for the rustpython VM."
authors = ["RustPython Team"]
Expand All @@ -11,10 +11,11 @@ edition = "2018"
indexmap = "1.0"
itertools = "0.9"
rustpython-bytecode = { path = "../bytecode", version = "0.1.1" }
rustpython-parser = { path = "../parser", version = "0.1.1" }
rustpython-ast = { path = "../ast" }
num-complex = { version = "0.3", features = ["serde"] }
log = "0.4"
arrayvec = "0.5"

[dev-dependencies]
rustpython-parser = { path = "../parser" }
insta = "1.1"
12 changes: 12 additions & 0 deletions compiler/porcelain/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "rustpython-compiler"
version = "0.1.2"
description = "A usability wrapper around rustpython-parser and rustpython-compiler-core"
authors = ["RustPython Team"]
edition = "2018"

[dependencies]
thiserror = "1.0"
rustpython-compiler-core = { path = ".." }
rustpython-parser = { path = "../../parser" }
rustpython-bytecode = { path = "../../bytecode" }
135 changes: 135 additions & 0 deletions compiler/porcelain/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
use rustpython_bytecode::bytecode::CodeObject;
use rustpython_compiler_core::{compile, symboltable};
use rustpython_parser::{ast::Location, parser};
use std::fmt;

pub use compile::{CompileOpts, Mode};
pub use symboltable::{Symbol, SymbolScope, SymbolTable, SymbolTableType};

#[derive(Debug, thiserror::Error)]
pub enum CompileErrorType {
#[error(transparent)]
Compile(#[from] rustpython_compiler_core::error::CompileErrorType),
#[error(transparent)]
Parse(#[from] rustpython_parser::error::ParseErrorType),
}

#[derive(Debug, thiserror::Error)]
pub struct CompileError {
pub error: CompileErrorType,
pub statement: Option<String>,
pub source_path: String,
pub location: Location,
}

impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let loc = self.location;
if let Some(ref stmt) = self.statement {
// visualize the error when location and statement are provided
write!(
f,
"{}",
loc.visualize(stmt, &format_args!("{} at {}", self.error, loc))
)
} else {
write!(f, "{} at {}", self.error, loc)
}
}
}

impl CompileError {
fn from_compile(error: rustpython_compiler_core::error::CompileError, source: &str) -> Self {
CompileError {
error: error.error.into(),
location: error.location,
source_path: error.source_path,
statement: get_statement(source, error.location),
}
}
fn from_parse(
error: rustpython_parser::error::ParseError,
source: &str,
source_path: String,
) -> Self {
CompileError {
error: error.error.into(),
location: error.location,
source_path,
statement: get_statement(source, error.location),
}
}
fn from_symtable(
error: symboltable::SymbolTableError,
source: &str,
source_path: String,
) -> Self {
Self::from_compile(error.into_compile_error(source_path), source)
}
}

/// Compile a given sourcecode into a bytecode object.
pub fn compile(
source: &str,
mode: compile::Mode,
source_path: String,
opts: CompileOpts,
) -> Result<CodeObject, CompileError> {
macro_rules! try_parse {
($x:expr) => {
match $x {
Ok(x) => x,
Err(e) => return Err(CompileError::from_parse(e, source, source_path)),
}
};
}
let res = match mode {
compile::Mode::Exec => {
let ast = try_parse!(parser::parse_program(source));
compile::compile_program(ast, source_path, opts)
}
compile::Mode::Eval => {
let statement = try_parse!(parser::parse_statement(source));
compile::compile_statement_eval(statement, source_path, opts)
}
compile::Mode::Single => {
let ast = try_parse!(parser::parse_program(source));
compile::compile_program_single(ast, source_path, opts)
}
};
res.map_err(|e| CompileError::from_compile(e, source))
}

pub fn compile_symtable(
source: &str,
mode: compile::Mode,
source_path: &str,
) -> Result<symboltable::SymbolTable, CompileError> {
macro_rules! try_parse {
($x:expr) => {
match $x {
Ok(x) => x,
Err(e) => return Err(CompileError::from_parse(e, source, source_path.to_owned())),
}
};
}
let res = match mode {
compile::Mode::Exec | compile::Mode::Single => {
let ast = try_parse!(parser::parse_program(source));
symboltable::make_symbol_table(&ast)
}
compile::Mode::Eval => {
let statement = try_parse!(parser::parse_statement(source));
symboltable::statements_to_symbol_table(&statement)
}
};
res.map_err(|e| CompileError::from_symtable(e, source, source_path.to_owned()))
}

fn get_statement(source: &str, loc: Location) -> Option<String> {
if loc.column() == 0 || loc.row() == 0 {
return None;
}
let line = source.split('\n').nth(loc.row() - 1)?.to_owned();
Some(line + "\n")
}
46 changes: 13 additions & 33 deletions compiler/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::symboltable::{
};
use itertools::Itertools;
use num_complex::Complex64;
use rustpython_ast as ast;
use rustpython_bytecode::bytecode::{self, CallType, CodeObject, Instruction, Label};
use rustpython_parser::{ast, parser};

type CompileResult<T> = Result<T, CompileError>;

Expand Down Expand Up @@ -61,31 +61,6 @@ impl CompileContext {
}
}

/// Compile a given sourcecode into a bytecode object.
pub fn compile(
source: &str,
mode: Mode,
source_path: String,
opts: CompileOpts,
) -> CompileResult<CodeObject> {
let to_compile_error =
|parse_error| CompileError::from_parse_error(parse_error, source_path.clone());
match mode {
Mode::Exec => {
let ast = parser::parse_program(source).map_err(to_compile_error)?;
compile_program(ast, source_path, opts)
}
Mode::Eval => {
let statement = parser::parse_statement(source).map_err(to_compile_error)?;
compile_statement_eval(statement, source_path, opts)
}
Mode::Single => {
let ast = parser::parse_program(source).map_err(to_compile_error)?;
compile_program_single(ast, source_path, opts)
}
}
}

/// A helper function for the shared code of the different compile functions
fn with_compiler(
source_path: String,
Expand All @@ -106,8 +81,10 @@ pub fn compile_program(
source_path: String,
opts: CompileOpts,
) -> CompileResult<CodeObject> {
let symbol_table = make_symbol_table(&ast)
.map_err(|e| CompileError::from_symbol_table_error(e, source_path.clone()))?;
let symbol_table = match make_symbol_table(&ast) {
Ok(x) => x,
Err(e) => return Err(e.into_compile_error(source_path)),
};
with_compiler(source_path, opts, |compiler| {
compiler.compile_program(&ast, symbol_table)
})
Expand All @@ -119,8 +96,10 @@ pub fn compile_statement_eval(
source_path: String,
opts: CompileOpts,
) -> CompileResult<CodeObject> {
let symbol_table = statements_to_symbol_table(&statement)
.map_err(|e| CompileError::from_symbol_table_error(e, source_path.clone()))?;
let symbol_table = match statements_to_symbol_table(&statement) {
Ok(x) => x,
Err(e) => return Err(e.into_compile_error(source_path)),
};
with_compiler(source_path, opts, |compiler| {
compiler.compile_statement_eval(&statement, symbol_table)
})
Expand All @@ -132,8 +111,10 @@ pub fn compile_program_single(
source_path: String,
opts: CompileOpts,
) -> CompileResult<CodeObject> {
let symbol_table = make_symbol_table(&ast)
.map_err(|e| CompileError::from_symbol_table_error(e, source_path.clone()))?;
let symbol_table = match make_symbol_table(&ast) {
Ok(x) => x,
Err(e) => return Err(e.into_compile_error(source_path)),
};
with_compiler(source_path, opts, |compiler| {
compiler.compile_program_single(&ast, symbol_table)
})
Expand Down Expand Up @@ -165,7 +146,6 @@ impl Compiler {
error,
location,
source_path: self.source_path.clone(),
statement: None,
}
}

Expand Down
Loading