Skip to content

Commit

Permalink
Merge pull request #467 from erg-lang/parser-pylib
Browse files Browse the repository at this point in the history
publish erg_compiler/erg_parser as Python libs
  • Loading branch information
mtshiba committed Nov 18, 2023
2 parents 0156606 + b838154 commit d1919af
Show file tree
Hide file tree
Showing 34 changed files with 1,602 additions and 98 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/.idea/
/timeit.dat
**/__pycache__/
**/.venv

# Nix
.direnv
Expand Down
100 changes: 99 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ erg_parser = { version = "0.6.25", path = "./crates/erg_parser" }
erg_compiler = { version = "0.6.25", path = "./crates/erg_compiler" }
els = { version = "0.1.37", path = "./crates/els" }
erg_proc_macros = { version = "0.6.25", path = "./crates/erg_proc_macros" }
pyo3 = { version = "0.20", features = ["extension-module"] }

[dependencies]
erg_common = { workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/erg_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ gal = []
no_std = []
full-repl = ["dep:crossterm"]
experimental = []
pylib = ["dep:pyo3"]

[target.'cfg(unix)'.dependencies]
backtrace-on-stack-overflow = { version = "0.3.0", optional = true }
Expand All @@ -32,6 +33,7 @@ backtrace-on-stack-overflow = { version = "0.3.0", optional = true }
crossterm = { optional = true, version = "0.25.0" }
parking_lot = "0.12"
thread_local = "1.1"
pyo3 = { workspace = true, optional = true }

[lib]
path = "lib.rs"
47 changes: 46 additions & 1 deletion crates/erg_common/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use crate::style::THEME;
use crate::traits::{Locational, Stream};
use crate::{impl_display_from_debug, switch_lang};

#[cfg(feature = "pylib")]
use pyo3::prelude::*;

/// This includes not only Error but also Warning, Exception
/// Numbering of this is not specifically related to ErrFmt.errno().
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -278,6 +281,48 @@ impl fmt::Display for Location {
}
}

#[cfg(feature = "pylib")]
impl FromPyObject<'_> for Location {
fn extract(ob: &'_ PyAny) -> PyResult<Self> {
if let Ok(s) = ob.extract::<String>() {
Ok(s.parse::<Location>().unwrap())
} else if let Ok(s) = ob.extract::<u32>() {
Ok(Location::Line(s))
} else if let Ok((l, r)) = ob.extract::<(u32, u32)>() {
Ok(Location::LineRange(l, r))
} else if let Ok((lb, cb, le, ce)) = ob.extract::<(u32, u32, u32, u32)>() {
Ok(Location::Range {
ln_begin: lb,
col_begin: cb,
ln_end: le,
col_end: ce,
})
} else {
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(format!(
"expected Into<Location>, but got {:?}",
ob.get_type().name()?
)))
}
}
}

#[cfg(feature = "pylib")]
impl IntoPy<PyObject> for Location {
fn into_py(self, py: Python<'_>) -> PyObject {
match self {
Self::Line(l) => (l, py.None(), l, py.None()).into_py(py),
Self::LineRange(lb, le) => (lb, py.None(), le, py.None()).into_py(py),
Self::Range {
ln_begin,
col_begin,
ln_end,
col_end,
} => (ln_begin, col_begin, ln_end, col_end).into_py(py),
Self::Unknown => (py.None(), py.None(), py.None(), py.None()).into_py(py),
}
}
}

impl std::str::FromStr for Location {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Expand Down Expand Up @@ -328,7 +373,7 @@ impl Ord for Location {
}

impl PartialOrd for Location {
#[allow(clippy::incorrect_partial_ord_impl_on_ord_type)]
#[allow(clippy::non_canonical_partial_ord_impl)]
fn partial_cmp(&self, other: &Location) -> Option<Ordering> {
if self.is_unknown() || other.is_unknown() {
None
Expand Down
22 changes: 22 additions & 0 deletions crates/erg_common/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use std::iter::FromIterator;
use crate::fxhash::FxHashSet;
use crate::{debug_fmt_iter, fmt_iter};

#[cfg(feature = "pylib")]
use pyo3::{FromPyObject, IntoPy, PyAny, PyObject, Python};

#[macro_export]
macro_rules! set {
() => { $crate::set::Set::new() };
Expand All @@ -22,6 +25,25 @@ pub struct Set<T> {
elems: FxHashSet<T>,
}

#[cfg(feature = "pylib")]
impl<T: Hash + Eq + IntoPy<PyObject>> IntoPy<PyObject> for Set<T> {
fn into_py(self, py: Python<'_>) -> PyObject {
self.elems.into_py(py)
}
}

#[cfg(feature = "pylib")]
impl<'source, T> FromPyObject<'source> for Set<T>
where
T: Hash + Eq + FromPyObject<'source>,
{
fn extract(ob: &'source PyAny) -> pyo3::PyResult<Self> {
Ok(Set {
elems: ob.extract::<FxHashSet<T>>()?,
})
}
}

// Use `fast_eq` for faster comparisons
impl<T: Hash + Eq> PartialEq for Set<T> {
fn eq(&self, other: &Set<T>) -> bool {
Expand Down
18 changes: 18 additions & 0 deletions crates/erg_common/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Add, Deref};

#[cfg(feature = "pylib")]
use pyo3::{FromPyObject, IntoPy, PyAny, PyObject, Python};

pub type ArcStr = std::sync::Arc<str>;

/// Used to hold an immutable string.
Expand All @@ -14,6 +17,21 @@ pub enum Str {
Static(&'static str),
}

#[cfg(feature = "pylib")]
impl FromPyObject<'_> for Str {
fn extract(ob: &PyAny) -> pyo3::PyResult<Self> {
let s = ob.extract::<String>()?;
Ok(Str::Rc(s.into()))
}
}

#[cfg(feature = "pylib")]
impl IntoPy<PyObject> for Str {
fn into_py(self, py: Python<'_>) -> PyObject {
(&self[..]).into_py(py)
}
}

impl PartialEq for Str {
#[inline]
fn eq(&self, other: &Str) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion crates/erg_common/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ pub trait Runnable: Sized + Default + New {
let indent = vm.indent();
if vm.now_block.len() > 1 {
output.write_all(instance.ps2().as_bytes()).unwrap();
output.write_all(indent.as_str().as_bytes()).unwrap();
output.write_all(indent.as_bytes()).unwrap();
output.flush().unwrap();
} else {
output.write_all(instance.ps1().as_bytes()).unwrap();
Expand Down
4 changes: 4 additions & 0 deletions crates/erg_compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,19 @@ els = ["erg_common/els"]
no_std = ["erg_common/no_std"]
full-repl = ["erg_common/full-repl"]
experimental = ["erg_common/experimental", "erg_parser/experimental"]
pylib = ["dep:pyo3", "erg_common/pylib", "erg_parser/pylib"]
pylib_compiler = ["pylib"]

[dependencies]
erg_common = { workspace = true }
erg_parser = { workspace = true }
pyo3 = { workspace = true, optional = true }

[build-dependencies]
erg_common = { workspace = true }

[lib]
crate-type = ["cdylib", "rlib"]
path = "lib.rs"

[[bin]]
Expand Down
Loading

0 comments on commit d1919af

Please sign in to comment.