Merge branch 'main' of https://github.com/GreasySlug/erg into split-err-msg

This commit is contained in:
GreasySlug 2022-11-20 10:41:10 +09:00
commit ff24c62de1
31 changed files with 878 additions and 412 deletions

View file

@ -16,7 +16,7 @@ use crate::mod_cache::SharedModuleCache;
use crate::ownercheck::OwnershipChecker;
/// Summarize lowering, side-effect checking, and ownership checking
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct HIRBuilder {
lowerer: ASTLowerer,
ownership_checker: OwnershipChecker,

View file

@ -7,7 +7,6 @@ use std::process;
use crate::ty::codeobj::MakeFunctionFlags;
use crate::ty::codeobj::{CodeObj, CodeObjFlags};
use crate::ty::value::GenTypeObj;
use erg_common::astr::AtomicStr;
use erg_common::cache::CacheSet;
use erg_common::config::{ErgConfig, Input};
use erg_common::env::erg_std_path;
@ -131,7 +130,7 @@ pub struct PyCodeGenStack(Vec<PyCodeGenUnit>);
impl_stream_for_wrapper!(PyCodeGenStack, PyCodeGenUnit);
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct PyCodeGenerator {
cfg: ErgConfig,
pub(crate) py_version: PythonVersion,
@ -1265,7 +1264,7 @@ impl PyCodeGenerator {
self.cfg.input.clone(),
unary.op.loc(),
&unary.op.inspect().clone(),
AtomicStr::from(unary.op.content),
String::from(unary.op.content),
)
.write_to_stderr();
NOT_IMPLEMENTED
@ -1348,7 +1347,7 @@ impl PyCodeGenerator {
self.cfg.input.clone(),
binop.loc(),
&binop.inspect().clone(),
AtomicStr::from(binop.content),
String::from(binop.content),
)
.write_to_stderr();
Opcode310::NOT_IMPLEMENTED
@ -1416,7 +1415,7 @@ impl PyCodeGenerator {
self.cfg.input.clone(),
binop.loc(),
&binop.inspect().clone(),
AtomicStr::from(binop.content),
String::from(binop.content),
)
.write_to_stderr();
Opcode311::NOT_IMPLEMENTED

View file

@ -91,7 +91,7 @@ impl AccessKind {
}
/// Generates a `CodeObj` from an String or other File inputs.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct Compiler {
pub cfg: ErgConfig,
builder: HIRBuilder,

View file

@ -1,4 +1,3 @@
use erg_common::astr::AtomicStr;
use erg_common::enum_unwrap;
use crate::ty::typaram::TyParam;
@ -26,11 +25,7 @@ impl Context {
}
}
pub(crate) fn get_type_mismatch_hint(
&self,
expected: &Type,
found: &Type,
) -> Option<AtomicStr> {
pub(crate) fn get_type_mismatch_hint(&self, expected: &Type, found: &Type) -> Option<String> {
let expected = if let Type::FreeVar(fv) = expected {
if fv.is_linked() {
fv.crack().clone()
@ -42,12 +37,12 @@ impl Context {
expected.clone()
};
match (&expected.qual_name()[..], &found.qual_name()[..]) {
("Eq", "Float") => Some(AtomicStr::ever("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")),
("Eq", "Float") => Some(String::from("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")),
_ => None,
}
}
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<AtomicStr> {
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<String> {
match proj {
Type::Proj { lhs, rhs: _ } => {
if let Type::FreeVar(fv) = lhs.as_ref() {
@ -69,9 +64,7 @@ impl Context {
} else {
(sup, sub)
};
Some(AtomicStr::from(format!(
"cannot {verb} {l} {preposition} {r}"
)))
Some(format!("cannot {verb} {l} {preposition} {r}"))
} else {
None
}

View file

@ -6,7 +6,6 @@ use crate::context::Context;
use crate::ty::constructors::{and, mono};
use crate::ty::value::{EvalValueResult, GenTypeObj, TypeObj, ValueObj};
use crate::ty::ValueArgs;
use erg_common::astr::AtomicStr;
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
use erg_common::style::{Color, StyledStr, StyledString, THEME};
@ -24,7 +23,7 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{REQ_ERR} is not passed")),
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -34,9 +33,9 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = StyledString::new(&format!("{}", require), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-type object {require} is passed to {REQ_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -54,7 +53,7 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = StyledStr::new("Super", Some(ERR), None);
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{sup} is not passed")),
format!("{sup} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -64,9 +63,9 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup_ty = StyledString::new(&format!("{}", sup), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-class object {sup_ty} is passed to {SUP_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -88,7 +87,7 @@ pub fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<
let class = args.remove_left_or_key("Class").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{CLASS_ERR} is not passed")),
format!("{CLASS_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -120,7 +119,7 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{REQ_ERR} is not passed")),
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -130,9 +129,9 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
let require = StyledString::new(&format!("{}", require), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-type object {require} is passed to {REQ_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -149,7 +148,7 @@ pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{SUP_ERR} is not passed")),
format!("{SUP_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
@ -159,9 +158,9 @@ pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
let sup = StyledString::new(&format!("{}", sup), Some(ERR), None);
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"non-trait object {sup} is passed to {SUP_WARN}",
)),
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
@ -187,12 +186,12 @@ pub fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!(
format!(
"[{}] has {} elements, but accessed {}th element",
erg_common::fmt_vec(&slf),
slf.len(),
index
)),
),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
@ -226,7 +225,7 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<V
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("{slf} has no key {index}",)),
format!("{slf} has no key {index}"),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
@ -251,7 +250,7 @@ pub fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
AtomicStr::from(format!("Index out of range: {}", index)),
format!("Index out of range: {}", index),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,

View file

@ -921,6 +921,12 @@ impl Context {
Immutable,
Public,
);
str_.register_builtin_impl(
"format",
fn_met(Str, vec![], Some(kw("args", Obj)), vec![], Str),
Immutable,
Public,
);
let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2);
str_eq.register_builtin_impl("__eq__", fn1_met(Str, Str, Bool), Const, Public);
str_.register_trait(Str, str_eq);

View file

@ -18,7 +18,6 @@ use std::mem;
use std::option::Option; // conflicting to Type::Option
use std::path::Path;
use erg_common::astr::AtomicStr;
use erg_common::config::ErgConfig;
use erg_common::dict::Dict;
use erg_common::error::Location;
@ -792,8 +791,8 @@ impl Context {
}
#[inline]
pub fn caused_by(&self) -> AtomicStr {
AtomicStr::arc(&self.name[..])
pub fn caused_by(&self) -> String {
String::from(&self.name[..])
}
pub(crate) fn get_outer(&self) -> Option<&Context> {

View file

@ -1,12 +1,12 @@
use std::fmt;
use std::fmt::Display;
use erg_common::astr::AtomicStr;
use erg_common::config::Input;
use erg_common::error::{
ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage,
};
use erg_common::set::Set;
use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, THEME};
use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, Theme, THEME};
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::{
@ -113,7 +113,8 @@ pub fn readable_name(name: &str) -> &str {
pub struct CompileError {
pub core: Box<ErrorCore>, // ErrorCore is large, so box it
pub input: Input,
pub caused_by: AtomicStr,
pub caused_by: String,
pub theme: Theme,
}
impl_display_and_error!(CompileError);
@ -123,7 +124,8 @@ impl From<ParserRunnerError> for CompileError {
Self {
core: Box::new(err.core),
input: err.input,
caused_by: "".into(),
caused_by: "".to_owned(),
theme: THEME,
}
}
}
@ -151,11 +153,12 @@ const URL: StyledStr = StyledStr::new(
);
impl CompileError {
pub fn new(core: ErrorCore, input: Input, caused_by: AtomicStr) -> Self {
pub fn new(core: ErrorCore, input: Input, caused_by: String) -> Self {
Self {
core: Box::new(core),
input,
caused_by,
theme: THEME,
}
}
@ -217,7 +220,7 @@ impl CompileError {
)
}
pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: AtomicStr) -> Self {
pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: String) -> Self {
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
@ -300,7 +303,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
) -> Self {
let name = readable_name(name);
@ -327,7 +330,7 @@ impl TyCheckError {
errno: usize,
callee: &C,
param_ts: impl Iterator<Item = &'a Type>,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let param_ts = fmt_iter(param_ts);
Self::new(
@ -357,13 +360,13 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
nth_param: Option<usize>,
expect: &Type,
found: &Type,
candidates: Option<Set<Type>>,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let ord = match nth_param {
Some(pos) => switch_lang!(
@ -422,7 +425,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
expect: &Type,
found: &Type,
@ -471,7 +474,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
t: &Type,
) -> Self {
@ -497,7 +500,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
expect: usize,
found: usize,
) -> Self {
@ -541,7 +544,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
expr_t: &Type,
) -> Self {
Self::new(
@ -566,7 +569,7 @@ impl TyCheckError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
expr: &str,
) -> Self {
Self::new(
@ -601,7 +604,7 @@ impl TyCheckError {
errno: usize,
loc: Location,
callee_name: &str,
caused_by: AtomicStr,
caused_by: String,
params_len: usize,
pos_args_len: usize,
kw_args_len: usize,
@ -667,7 +670,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
loc: Location,
callee_name: &str,
caused_by: AtomicStr,
caused_by: String,
missing_len: usize,
missing_params: Vec<Str>,
) -> Self {
@ -697,7 +700,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
loc: Location,
callee_name: &str,
caused_by: AtomicStr,
caused_by: String,
arg_name: &str,
) -> Self {
let name = readable_name(callee_name);
@ -725,7 +728,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
loc: Location,
callee_name: &str,
caused_by: AtomicStr,
caused_by: String,
param_name: &str,
) -> Self {
let name = readable_name(callee_name);
@ -754,7 +757,7 @@ passed keyword args: {kw_args_len}"
lhs_t: &Type,
rhs_t: &Type,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let mut lhs_typ = StyledStrings::default();
switch_lang!(
@ -800,7 +803,7 @@ passed keyword args: {kw_args_len}"
lhs_t: &Type,
rhs_t: &Type,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARN), Some(Attribute::Bold));
let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARN), Some(Attribute::Bold));
@ -828,7 +831,7 @@ passed keyword args: {kw_args_len}"
sub_t: &Type,
sup_t: &Type,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let mut sub_type = StyledStrings::default();
switch_lang!(
@ -875,7 +878,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
lhs: &Predicate,
rhs: &Predicate,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let mut lhs_uni = StyledStrings::default();
switch_lang!(
@ -920,8 +923,8 @@ passed keyword args: {kw_args_len}"
errno: usize,
proj: &Type,
loc: Location,
caused_by: AtomicStr,
hint: Option<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> Self {
Self::new(
ErrorCore::new(
@ -947,8 +950,8 @@ passed keyword args: {kw_args_len}"
class: &Type,
trait_: &Type,
loc: Location,
caused_by: AtomicStr,
hint: Option<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> Self {
Self::new(
ErrorCore::new(
@ -972,9 +975,9 @@ passed keyword args: {kw_args_len}"
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold));
Self::new(
@ -1008,12 +1011,12 @@ passed keyword args: {kw_args_len}"
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
member_name: &str,
trait_type: &Type,
expect: &Type,
found: &Type,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let mut expct = StyledStrings::default();
expct.push_str_with_color_and_attribute(&format!("{}", trait_type), WARN, Attribute::Bold);
@ -1059,11 +1062,11 @@ passed keyword args: {kw_args_len}"
pub fn trait_member_not_defined_error(
input: Input,
errno: usize,
caused_by: AtomicStr,
caused_by: String,
member_name: &str,
trait_type: &Type,
class_type: &Type,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold));
Self::new(
@ -1088,11 +1091,11 @@ passed keyword args: {kw_args_len}"
pub fn not_in_trait_error(
input: Input,
errno: usize,
caused_by: AtomicStr,
caused_by: String,
member_name: &str,
trait_type: &Type,
class_type: &Type,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold));
Self::new(
@ -1118,7 +1121,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
name: &str,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold));
Self::new(
@ -1144,7 +1147,7 @@ passed keyword args: {kw_args_len}"
errno: usize,
expr: &(impl Locational + Display),
candidates: &[Type],
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let hint = Some(
switch_lang!(
@ -1197,7 +1200,7 @@ pub type EvalResult<T> = TyCheckResult<T>;
pub type SingleEvalResult<T> = SingleTyCheckResult<T>;
impl EvalError {
pub fn not_const_expr(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self {
pub fn not_const_expr(input: Input, errno: usize, loc: Location, caused_by: String) -> Self {
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
@ -1216,12 +1219,7 @@ impl EvalError {
)
}
pub fn invalid_literal(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
) -> Self {
pub fn invalid_literal(input: Input, errno: usize, loc: Location, caused_by: String) -> Self {
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
@ -1245,7 +1243,7 @@ pub type EffectError = TyCheckError;
pub type EffectErrors = TyCheckErrors;
impl EffectError {
pub fn has_effect<S: Into<AtomicStr>>(
pub fn has_effect<S: Into<String>>(
input: Input,
errno: usize,
expr: &Expr,
@ -1269,7 +1267,7 @@ impl EffectError {
)
}
pub fn proc_assign_error<S: Into<AtomicStr>>(
pub fn proc_assign_error<S: Into<String>>(
input: Input,
errno: usize,
sig: &Signature,
@ -1307,7 +1305,7 @@ pub type OwnershipError = TyCheckError;
pub type OwnershipErrors = TyCheckErrors;
impl OwnershipError {
pub fn move_error<S: Into<AtomicStr>>(
pub fn move_error<S: Into<String>>(
input: Input,
errno: usize,
name: &str,
@ -1355,13 +1353,13 @@ pub type LowerResult<T> = TyCheckResult<T>;
pub type SingleLowerResult<T> = SingleTyCheckResult<T>;
impl LowerError {
pub fn syntax_error<S: Into<AtomicStr>>(
pub fn syntax_error<S: Into<String>>(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
desc: S,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
Self::new(
ErrorCore::new(
@ -1380,7 +1378,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
) -> Self {
let name = readable_name(name);
@ -1406,7 +1404,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
) -> Self {
let name = readable_name(name);
@ -1432,7 +1430,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
spec_t: &Type,
found_t: &Type,
@ -1462,7 +1460,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
similar_name: Option<&str>,
) -> Self {
@ -1475,7 +1473,6 @@ impl LowerError {
"traditional_chinese" => format!("存在相同名稱變量: {n}"),
"english" => format!("exists a similar name variable: {n}"),
)
.into()
});
let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold));
Self::new(
@ -1500,7 +1497,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
typ: &Type,
) -> Self {
let typ = StyledString::new(&typ.to_string(), Some(ERR), Some(Attribute::Bold));
@ -1533,7 +1530,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
obj_t: &Type,
name: &str,
similar_name: Option<&str>,
@ -1545,7 +1542,6 @@ impl LowerError {
"traditional_chinese" => format!("具有相同名稱的屬性: {n}"),
"english" => format!("has a similar name attribute: {n}"),
)
.into()
});
let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold));
Self::new(
@ -1571,7 +1567,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
obj_name: &str,
obj_t: &Type,
name: &str,
@ -1585,7 +1581,6 @@ impl LowerError {
"traditional_chinese" => format!("具有相同名稱的屬性: {n}"),
"english" => format!("has a similar name attribute: {n}"),
)
.into()
});
let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold));
Self::new(
@ -1610,7 +1605,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
) -> Self {
let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold));
@ -1637,7 +1632,7 @@ impl LowerError {
errno: usize,
loc: Location,
name: &str,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold));
Self::new(
@ -1658,7 +1653,7 @@ impl LowerError {
)
}
pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self {
pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: String) -> Self {
let name = StyledString::new(
readable_name(ident.inspect()),
Some(WARN),
@ -1686,7 +1681,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
vis: Visibility,
) -> Self {
@ -1725,7 +1720,7 @@ impl LowerError {
)
}
pub fn override_error<S: Into<AtomicStr>>(
pub fn override_error<S: Into<String>>(
input: Input,
errno: usize,
name: &str,
@ -1789,7 +1784,7 @@ impl LowerError {
errno: usize,
class: String,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
Self::new(
ErrorCore::new(
@ -1814,8 +1809,8 @@ impl LowerError {
errno: usize,
desc: String,
loc: Location,
caused_by: AtomicStr,
hint: Option<AtomicStr>,
caused_by: String,
hint: Option<String>,
) -> Self {
Self::new(
ErrorCore::new(
@ -1835,7 +1830,7 @@ impl LowerError {
errno: usize,
mod_name: &str,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
let desc = switch_lang!(
"japanese" => format!("{mod_name}モジュールはお使いの環境をサポートしていません"),
@ -1851,7 +1846,7 @@ impl LowerError {
errno: usize,
desc: String,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
similar_erg_mod: Option<Str>,
similar_py_mod: Option<Str>,
) -> Self {
@ -1948,7 +1943,6 @@ impl LowerError {
}
},
);
let hint = hint.map(AtomicStr::from);
Self::new(
ErrorCore::new(
vec![SubMessage::ambiguous_new(
@ -1970,7 +1964,7 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
) -> Self {
Self::new(
ErrorCore::new(
@ -1990,7 +1984,7 @@ impl LowerError {
)
}
pub fn declare_error(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self {
pub fn declare_error(input: Input, errno: usize, loc: Location, caused_by: String) -> Self {
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
@ -2014,10 +2008,10 @@ impl LowerError {
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
caused_by: String,
name: &str,
cast_to: &Type,
hint: Option<AtomicStr>,
hint: Option<String>,
) -> Self {
let name = StyledString::new(name, Some(WARN), Some(Attribute::Bold));
let found = StyledString::new(&format!("{}", cast_to), Some(WARN), Some(Attribute::Bold));
@ -2065,6 +2059,12 @@ impl From<CompileError> for CompileErrors {
impl MultiErrorDisplay<CompileError> for CompileErrors {}
impl fmt::Display for CompileErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt_all(f)
}
}
impl CompileErrors {
pub fn flush(&mut self) -> Self {
Self(self.0.drain(..).collect())

View file

@ -21,5 +21,6 @@ pub mod mod_cache;
pub mod optimize;
pub mod ownercheck;
pub mod reorder;
pub mod transpile;
pub mod ty;
pub mod varinfo;

View file

@ -2,7 +2,6 @@
//!
//! ASTLowerer(ASTからHIRへの変換器)を実装
use erg_common::astr::AtomicStr;
use erg_common::config::ErgConfig;
use erg_common::dict;
use erg_common::error::{Location, MultiErrorDisplay};
@ -161,7 +160,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
expr.loc(),
AtomicStr::arc(&self.ctx.name[..]),
String::from(&self.ctx.name[..]),
switch_lang!(
"japanese" => format!("式の評価結果(: {})が使われていません", expr.ref_t()),
"simplified_chinese" => format!("表达式评估结果(: {})未使用", expr.ref_t()),
@ -226,7 +225,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
elem.loc(),
AtomicStr::arc(&self.ctx.name[..]),
String::from(&self.ctx.name[..]),
switch_lang!(
"japanese" => "配列の要素は全て同じ型である必要があります",
"simplified_chinese" => "数组元素必须全部是相同类型",
@ -372,7 +371,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
elem.loc(),
AtomicStr::arc(&self.ctx.name[..]),
String::from(&self.ctx.name[..]),
switch_lang!(
"japanese" => "集合の要素は全て同じ型である必要があります",
"simplified_chinese" => "集合元素必须全部是相同类型",
@ -404,7 +403,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
normal_set.loc(),
AtomicStr::arc(&self.ctx.name[..]),
String::arc(&self.ctx.name[..]),
switch_lang!(
"japanese" => "要素が重複しています",
"simplified_chinese" => "元素重复",
@ -498,7 +497,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
loc,
AtomicStr::arc(&self.ctx.name[..]),
String::from(&self.ctx.name[..]),
switch_lang!(
"japanese" => "Dictの値は全て同じ型である必要があります",
"simplified_chinese" => "Dict的值必须是同一类型",
@ -543,7 +542,7 @@ impl ASTLowerer {
self.cfg.input.clone(),
line!() as usize,
normal_set.loc(),
AtomicStr::arc(&self.ctx.name[..]),
String::arc(&self.ctx.name[..]),
switch_lang!(
"japanese" => "要素が重複しています",
"simplified_chinese" => "元素重复",

View file

@ -10,6 +10,7 @@ use erg_common::traits::Runnable;
use erg_compiler::build_hir::HIRBuilder;
use erg_compiler::lower::ASTLowerer;
use erg_compiler::transpile::Transpiler;
use erg_compiler::ty::deserialize::Deserializer;
use erg_compiler::Compiler;
@ -31,6 +32,9 @@ fn run() {
"check" => {
HIRBuilder::run(cfg);
}
"transpile" => {
Transpiler::run(cfg);
}
"compile" | "exec" => {
Compiler::run(cfg);
}

View file

@ -0,0 +1,429 @@
use std::fs::File;
use std::io::Write;
use erg_common::config::ErgConfig;
use erg_common::log;
use erg_common::traits::{Runnable, Stream};
use erg_common::Str;
use erg_parser::ast::ParamPattern;
use crate::build_hir::HIRBuilder;
use crate::desugar_hir::HIRDesugarer;
use crate::error::{CompileError, CompileErrors};
use crate::hir::{
Accessor, Array, Block, Call, ClassDef, Def, Dict, Expr, Identifier, Lambda, Params, Set,
Signature, Tuple, HIR,
};
use crate::link::Linker;
use crate::mod_cache::SharedModuleCache;
use crate::ty::Type;
#[derive(Debug, Clone)]
pub struct PyScript {
pub filename: Str,
pub code: String,
}
/// Generates a `PyScript` from an String or other File inputs.
#[derive(Debug, Default)]
pub struct Transpiler {
pub cfg: ErgConfig,
builder: HIRBuilder,
mod_cache: SharedModuleCache,
script_generator: ScriptGenerator,
}
impl Runnable for Transpiler {
type Err = CompileError;
type Errs = CompileErrors;
const NAME: &'static str = "Erg transpiler";
fn new(cfg: ErgConfig) -> Self {
let mod_cache = SharedModuleCache::new();
let py_mod_cache = SharedModuleCache::new();
Self {
builder: HIRBuilder::new_with_cache(
cfg.copy(),
"<module>",
mod_cache.clone(),
py_mod_cache,
),
script_generator: ScriptGenerator::new(),
mod_cache,
cfg,
}
}
#[inline]
fn cfg(&self) -> &ErgConfig {
&self.cfg
}
#[inline]
fn finish(&mut self) {}
fn clear(&mut self) {
// self.builder.clear();
}
fn exec(&mut self) -> Result<i32, Self::Errs> {
let path = self.input().filename().replace(".er", ".py");
let script = self.transpile(self.input().read(), "exec")?;
let mut f = File::create(&path).unwrap();
f.write_all(script.code.as_bytes()).unwrap();
Ok(0)
}
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
let script = self.transpile(src, "eval")?;
Ok(script.code)
}
}
impl Transpiler {
pub fn transpile(&mut self, src: String, mode: &str) -> Result<PyScript, CompileErrors> {
log!(info "the transpiling process has started.");
let hir = self.build_link_desugar(src, mode)?;
let script = self.script_generator.transpile(hir);
log!(info "code:\n{}", script.code);
log!(info "the transpiling process has completed");
Ok(script)
}
fn build_link_desugar(&mut self, src: String, mode: &str) -> Result<HIR, CompileErrors> {
let artifact = self
.builder
.build(src, mode)
.map_err(|artifact| artifact.errors)?;
let linker = Linker::new(&self.cfg, &self.mod_cache);
let hir = linker.link(artifact.hir);
Ok(HIRDesugarer::desugar(hir))
}
}
#[derive(Debug, Default)]
pub struct ScriptGenerator {
level: usize,
}
impl ScriptGenerator {
pub const fn new() -> Self {
Self { level: 0 }
}
pub fn transpile(&mut self, hir: HIR) -> PyScript {
let mut code = self.load_prelude();
for chunk in hir.module.into_iter() {
code += &self.transpile_expr(chunk);
code.push('\n');
}
PyScript {
filename: hir.name,
code,
}
}
fn load_prelude(&mut self) -> String {
"from collections import namedtuple as NamedTuple__\n".to_string()
}
fn transpile_expr(&mut self, expr: Expr) -> String {
match expr {
Expr::Lit(lit) => lit.token.content.to_string(),
Expr::Call(call) => self.transpile_call(call),
Expr::BinOp(bin) => {
let mut code = "(".to_string();
code += &self.transpile_expr(*bin.lhs);
code += &bin.op.content;
code += &self.transpile_expr(*bin.rhs);
code += ")";
code
}
Expr::UnaryOp(unary) => {
let mut code = "(".to_string();
code += &unary.op.content;
code += &self.transpile_expr(*unary.expr);
code += ")";
code
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let mut code = "[".to_string();
for elem in arr.elems.pos_args {
code += &format!("{},", self.transpile_expr(elem.expr));
}
code += "]";
code
}
other => todo!("transpiling {other}"),
},
Expr::Set(set) => match set {
Set::Normal(st) => {
let mut code = "{".to_string();
for elem in st.elems.pos_args {
code += &format!("{},", self.transpile_expr(elem.expr));
}
code += "}";
code
}
other => todo!("transpiling {other}"),
},
Expr::Record(rec) => {
let mut attrs = "[".to_string();
let mut values = "(".to_string();
for mut attr in rec.attrs.into_iter() {
attrs += &format!("'{}',", Self::transpile_ident(attr.sig.into_ident()));
if attr.body.block.len() > 1 {
todo!("transpile instant blocks")
}
values += &format!("{},", self.transpile_expr(attr.body.block.remove(0)));
}
attrs += "]";
values += ")";
format!("NamedTuple__('Record', {attrs}){values}")
}
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let mut code = "(".to_string();
for elem in tup.elems.pos_args {
code += &format!("{},", self.transpile_expr(elem.expr));
}
code += ")";
code
}
},
Expr::Dict(dict) => match dict {
Dict::Normal(dic) => {
let mut code = "{".to_string();
for kv in dic.kvs {
code += &format!(
"({}): ({}),",
self.transpile_expr(kv.key),
self.transpile_expr(kv.value)
);
}
code += "}";
code
}
other => todo!("transpiling {other}"),
},
Expr::Accessor(acc) => match acc {
Accessor::Ident(ident) => Self::transpile_ident(ident),
Accessor::Attr(attr) => {
format!(
"({}).{}",
self.transpile_expr(*attr.obj),
Self::transpile_ident(attr.ident)
)
}
},
Expr::Def(def) => self.transpile_def(def),
Expr::Lambda(lambda) => self.transpile_lambda(lambda),
Expr::ClassDef(classdef) => self.transpile_classdef(classdef),
Expr::AttrDef(mut adef) => {
let mut code = format!("{} = ", self.transpile_expr(Expr::Accessor(adef.attr)));
if adef.block.len() > 1 {
todo!("transpile instant blocks")
}
let expr = adef.block.remove(0);
code += &self.transpile_expr(expr);
code
}
// TODO:
Expr::Compound(comp) => {
let mut code = "".to_string();
for expr in comp.into_iter() {
code += &self.transpile_expr(expr);
code += &format!("\n{}", " ".repeat(self.level));
}
code
}
other => todo!("transpile {other}"),
}
}
fn transpile_call(&mut self, mut call: Call) -> String {
match call.obj.local_name() {
Some("assert") => {
let mut code = format!("assert {}", self.transpile_expr(call.args.remove(0)));
if let Some(msg) = call.args.try_remove(0) {
code += &format!(", {}", self.transpile_expr(msg));
}
code
}
Some("if" | "if!") => {
let cond = self.transpile_expr(call.args.remove(0));
let Expr::Lambda(mut block) = call.args.remove(0) else { todo!() };
let then = self.transpile_expr(block.body.remove(0));
if let Some(Expr::Lambda(mut block)) = call.args.try_remove(0) {
let els = self.transpile_expr(block.body.remove(0));
format!("{then} if {cond} else {els}")
} else {
format!("{then} if {cond} else None")
}
}
Some("for" | "for!") => {
let mut code = "for ".to_string();
let iter = call.args.remove(0);
let Expr::Lambda(block) = call.args.remove(0) else { todo!() };
let sig = block.params.non_defaults.get(0).unwrap();
let ParamPattern::VarName(param) = &sig.pat else { todo!() };
code += &format!("{}__ ", &param.token().content);
code += &format!("in {}:\n", self.transpile_expr(iter));
code += &self.transpile_block(block.body, false);
code
}
Some("while" | "while!") => {
let mut code = "while ".to_string();
let cond = call.args.remove(0);
let Expr::Lambda(block) = call.args.remove(0) else { todo!() };
code += &format!("{}:\n", self.transpile_expr(cond));
code += &self.transpile_block(block.body, false);
code
}
// TODO:
Some("match" | "match!") => {
let mut code = "match ".to_string();
let cond = call.args.remove(0);
code += &format!("{}:\n", self.transpile_expr(cond));
while let Some(Expr::Lambda(arm)) = call.args.try_remove(0) {
self.level += 1;
code += &" ".repeat(self.level);
let target = arm.params.non_defaults.get(0).unwrap();
let ParamPattern::VarName(param) = &target.pat else { todo!() };
code += &format!("case {}__:\n", &param.token().content);
code += &self.transpile_block(arm.body, false);
self.level -= 1;
}
code
}
_ => self.transpile_simple_call(call),
}
}
fn transpile_simple_call(&mut self, mut call: Call) -> String {
let mut code = format!("({})", self.transpile_expr(*call.obj));
if let Some(attr) = call.attr_name {
code += &format!(".{}", Self::transpile_ident(attr));
}
code.push('(');
while let Some(arg) = call.args.try_remove_pos(0) {
code += &self.transpile_expr(arg.expr);
code.push(',');
}
while let Some(arg) = call.args.try_remove_kw(0) {
code += &format!("{}={},", arg.keyword, self.transpile_expr(arg.expr));
}
code.push(')');
code
}
fn transpile_ident(ident: Identifier) -> String {
if let Some(py_name) = ident.vi.py_name {
py_name.to_string()
} else if ident.dot.is_some() {
ident.name.into_token().content.to_string()
} else {
let name = ident.name.into_token().content;
let name = name.replace('!', "__erg_proc__");
let name = name.replace('$', "erg_shared__");
format!("{name}__")
}
}
fn transpile_params(&mut self, params: Params) -> String {
let mut code = String::new();
for non_default in params.non_defaults {
let ParamPattern::VarName(param) = non_default.pat else { todo!() };
code += &format!("{}__,", param.into_token().content);
}
for default in params.defaults {
let ParamPattern::VarName(param) = default.sig.pat else { todo!() };
code += &format!(
"{}__ = {},",
param.into_token().content,
self.transpile_expr(default.default_val)
);
}
code
}
fn transpile_block(&mut self, block: Block, return_last: bool) -> String {
self.level += 1;
let mut code = String::new();
let last = block.len() - 1;
for (i, chunk) in block.into_iter().enumerate() {
code += &" ".repeat(self.level);
if i == last && return_last {
code += "return ";
}
code += &self.transpile_expr(chunk);
code.push('\n');
}
self.level -= 1;
code
}
fn transpile_lambda(&mut self, lambda: Lambda) -> String {
let mut code = format!("(lambda {}:", self.transpile_params(lambda.params));
if lambda.body.len() > 1 {
todo!("multi line lambda");
}
code += &self.transpile_block(lambda.body, false);
code.pop(); // \n
code.push(')');
code
}
fn transpile_def(&mut self, mut def: Def) -> String {
match def.sig {
Signature::Var(var) => {
let mut code = format!("{} = ", Self::transpile_ident(var.ident));
if def.body.block.len() > 1 {
todo!("transpile instant blocks")
}
let expr = def.body.block.remove(0);
code += &self.transpile_expr(expr);
code
}
Signature::Subr(subr) => {
let mut code = format!(
"def {}({}):\n",
Self::transpile_ident(subr.ident),
self.transpile_params(subr.params)
);
code += &self.transpile_block(def.body.block, true);
code
}
}
}
fn transpile_classdef(&mut self, classdef: ClassDef) -> String {
let class_name = Self::transpile_ident(classdef.sig.into_ident());
let mut code = format!("class {class_name}():\n");
let mut init_method = format!(
"{}def __init__(self, param__):\n",
" ".repeat(self.level + 1)
);
match classdef.__new__.non_default_params().unwrap()[0].typ() {
Type::Record(rec) => {
for field in rec.keys() {
init_method += &format!(
"{}self.{} = param__.{}\n",
" ".repeat(self.level + 2),
field.symbol,
field.symbol
);
}
}
other => todo!("{other}"),
}
code += &init_method;
if classdef.need_to_gen_new {
code += &format!("def new(x): return {class_name}.__call__(x)\n");
}
code += &self.transpile_block(classdef.methods, false);
code
}
}

View file

@ -2,7 +2,6 @@
use std::process;
use std::string::FromUtf8Error;
use erg_common::astr::AtomicStr;
use erg_common::cache::CacheSet;
use erg_common::config::{ErgConfig, Input};
use erg_common::dict::Dict;
@ -21,8 +20,8 @@ use super::{HasType, Type};
#[derive(Debug)]
pub struct DeserializeError {
pub errno: usize,
pub caused_by: AtomicStr,
pub desc: AtomicStr,
pub caused_by: String,
pub desc: String,
}
impl From<std::io::Error> for DeserializeError {
@ -50,11 +49,7 @@ impl From<DeserializeError> for ErrorCore {
}
impl DeserializeError {
pub fn new<S: Into<AtomicStr>, T: Into<AtomicStr>>(
errno: usize,
caused_by: S,
desc: T,
) -> Self {
pub fn new<S: Into<String>, T: Into<String>>(errno: usize, caused_by: S, desc: T) -> Self {
Self {
errno,
caused_by: caused_by.into(),