Add with statement conversion

This commit is contained in:
Shunsuke Shibayama 2022-12-31 02:45:44 +09:00
parent 04ea96bebf
commit b8fc7b9778
6 changed files with 217 additions and 67 deletions

112
Cargo.lock generated
View file

@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.20"
@ -58,6 +73,32 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "backtrace-on-stack-overflow"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51cef6be4d7cb70701727ca9662b5b428833918c13c4095220763ba385ac9bd"
dependencies = [
"backtrace",
"libc",
"nix",
]
[[package]]
name = "base64"
version = "0.13.1"
@ -129,6 +170,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -206,8 +253,7 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "els"
version = "0.1.13-nightly.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d1a798dd47241b5ea7b11e84d49dfd13eafe3332a6d435b3023021fb8ebe60"
source = "git+https://github.com/erg-lang/erg-language-server?branch=main#e92f3aa0bae74b9b4d7c1d4335e1a776edf307e9"
dependencies = [
"erg_common",
"erg_compiler",
@ -228,9 +274,9 @@ dependencies = [
[[package]]
name = "erg_common"
version = "0.6.1-nightly.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "710e477633ea57d0a9d435f2d9377aa0c14a327451288d63cfd655e0d57f07d0"
source = "git+https://github.com/erg-lang/erg?branch=main#8353e811ed20ba55a87d05e91c1a2456b03928b0"
dependencies = [
"backtrace-on-stack-overflow",
"hermit-abi",
"libc",
"winapi",
@ -239,8 +285,7 @@ dependencies = [
[[package]]
name = "erg_compiler"
version = "0.6.1-nightly.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7f577c97c5d5cd6eac03f1e0eee27c47819ca6b6bfc9f65bcffa68eac50d49"
source = "git+https://github.com/erg-lang/erg?branch=main#8353e811ed20ba55a87d05e91c1a2456b03928b0"
dependencies = [
"erg_common",
"erg_parser",
@ -249,8 +294,7 @@ dependencies = [
[[package]]
name = "erg_parser"
version = "0.6.1-nightly.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3a335596f8aa1fd268f451999bf39e73039f54806dec6780ad33c54bb5141e"
source = "git+https://github.com/erg-lang/erg?branch=main#8353e811ed20ba55a87d05e91c1a2456b03928b0"
dependencies = [
"erg_common",
"unicode-xid 0.2.4",
@ -303,6 +347,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -408,12 +458,43 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
"memoffset",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
@ -444,6 +525,15 @@ dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "object"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
dependencies = [
"memchr",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
@ -696,6 +786,12 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustpython-parser"
version = "0.1.2"

View file

@ -22,13 +22,13 @@ edition = "2021"
repository = "https://github.com/mtshiba/pylyzer"
[workspace.dependencies]
erg_common = "0.6.1-nightly.1"
erg_compiler = "0.6.1-nightly.1"
els = "0.1.13-nightly.1"
# erg_common = "0.6.1-nightly.1"
# erg_compiler = "0.6.1-nightly.1"
# els = "0.1.13-nightly.1"
rustpython-parser = "0.1.2"
# erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main" }
# erg_common = { git = "https://github.com/erg-lang/erg", branch = "main" }
# els = { git = "https://github.com/erg-lang/erg-language-server", branch = "main" }
erg_compiler = { git = "https://github.com/erg-lang/erg", branch = "main", features = ["py_compatible"] }
erg_common = { git = "https://github.com/erg-lang/erg", branch = "main" }
els = { git = "https://github.com/erg-lang/erg-language-server", branch = "main", features = ["py_compatible"] }
[features]
debug = ["erg_compiler/debug", "erg_common/debug", "py2erg/debug"]

View file

@ -1,16 +1,10 @@
use erg_common::config::ErgConfig;
use erg_common::fresh::fresh_varname;
use erg_common::traits::{Locational, Stream};
use erg_compiler::artifact::IncompleteArtifact;
use rustpython_parser::ast::Location as PyLocation;
use rustpython_parser::ast::{
BooleanOperator, Comparison, ExpressionType, Located, Number, Operator, Parameter, Parameters,
Program, StatementType, StringGroup, Suite, UnaryOperator,
};
use erg_common::dict::Dict as HashMap;
use erg_common::set;
use erg_common::fresh::fresh_varname;
use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, Stream};
use erg_common::{log, set};
use erg_compiler::artifact::IncompleteArtifact;
use erg_compiler::erg_parser::ast::{
Accessor, Args, Array, BinOp, Block, ClassAttr, ClassAttrs, ClassDef, ConstArgs, Decorator,
Def, DefBody, DefId, DefaultParamSignature, Dict, Dummy, Expr, Identifier, KeyValue, Lambda,
@ -21,6 +15,11 @@ use erg_compiler::erg_parser::ast::{
};
use erg_compiler::erg_parser::token::{Token, TokenKind, COLON, DOT, EQUAL};
use erg_compiler::error::CompileErrors;
use rustpython_parser::ast::Location as PyLocation;
use rustpython_parser::ast::{
BooleanOperator, Comparison, ExpressionType, Located, Number, Operator, Parameter, Parameters,
Program, StatementType, StringGroup, Suite, UnaryOperator,
};
use crate::error::*;
@ -126,10 +125,40 @@ pub fn pyloc_to_ergloc(loc: PyLocation, cont_len: usize) -> erg_common::error::L
erg_common::error::Location::range(loc.row(), loc.column(), loc.row(), loc.column() + cont_len)
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DefinedPlace {
Known(String),
Unknown,
}
impl PartialEq<str> for DefinedPlace {
fn eq(&self, other: &str) -> bool {
match self {
Self::Known(s) => s == other,
Self::Unknown => false,
}
}
}
impl PartialEq<String> for DefinedPlace {
fn eq(&self, other: &String) -> bool {
match self {
Self::Known(s) => s == other,
Self::Unknown => false,
}
}
}
impl DefinedPlace {
pub const fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NameInfo {
rename: Option<String>,
defined_in: String,
defined_in: DefinedPlace,
defined_block_id: usize,
defined_times: usize,
referenced: HashSet<String>,
@ -138,7 +167,7 @@ pub struct NameInfo {
impl NameInfo {
pub fn new(
rename: Option<String>,
defined_in: String,
defined_in: DefinedPlace,
defined_block_id: usize,
defined_times: usize,
) -> Self {
@ -230,6 +259,29 @@ impl ASTConverter {
self.namespace.last().unwrap().clone()
}
fn register_name_info(&mut self, name: &str, kind: NameKind) {
let cur_namespace = self.cur_namespace();
if let Some(name_info) = self.names.get_mut(name) {
if name_info.defined_in == cur_namespace {
name_info.defined_times += 1;
} else if name_info.defined_in.is_unknown() {
name_info.defined_in = DefinedPlace::Known(cur_namespace);
name_info.defined_times += 1;
}
} else {
// In Erg, classes can only be defined in uppercase
// So if not, prefix it with `Type_`
let rename = if kind.is_class() && !name.starts_with(char::is_uppercase) {
Some(format!("Type_{name}"))
} else {
None
};
let defined_in = DefinedPlace::Known(self.cur_namespace());
let info = NameInfo::new(rename, defined_in, self.cur_block_id(), 1);
self.names.insert(String::from(name), info);
}
}
fn convert_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
let shadowing = self.shadowing;
let name = escape_name(name);
@ -260,7 +312,12 @@ impl ASTConverter {
}
}
} else {
let mut info = NameInfo::new(None, cur_namespace.clone(), cur_block_id, 0);
let defined_in = if self.cur_namespace() == "<module>" {
DefinedPlace::Known(self.cur_namespace())
} else {
DefinedPlace::Unknown
};
let mut info = NameInfo::new(None, defined_in, cur_block_id, 0);
info.add_referrer(cur_namespace);
self.names.insert(name.clone(), info);
name
@ -279,14 +336,14 @@ impl ASTConverter {
Identifier::new(Some(dot), name)
}
fn convert_param_pattern(arg: String, loc: PyLocation) -> ParamPattern {
let token = Token::new(TokenKind::Symbol, arg, loc.row(), loc.column() - 1);
let name = VarName::new(token);
ParamPattern::VarName(name)
fn convert_param_pattern(&mut self, arg: String, loc: PyLocation) -> ParamPattern {
self.register_name_info(&arg, NameKind::Variable);
let ident = self.convert_ident(arg, loc);
ParamPattern::VarName(ident.name)
}
fn convert_nd_param(&mut self, param: Parameter) -> NonDefaultParamSignature {
let pat = Self::convert_param_pattern(param.arg, param.location);
let pat = self.convert_param_pattern(param.arg, param.location);
let t_spec = param
.annotation
.map(|anot| self.convert_type_spec(*anot))
@ -309,8 +366,8 @@ impl ASTConverter {
Params::new(non_defaults, None, vec![], None)
}
fn convert_for_param(name: String, loc: PyLocation) -> NonDefaultParamSignature {
let pat = Self::convert_param_pattern(name, loc);
fn convert_for_param(&mut self, name: String, loc: PyLocation) -> NonDefaultParamSignature {
let pat = self.convert_param_pattern(name, loc);
let t_spec = None;
NonDefaultParamSignature::new(pat, t_spec)
}
@ -330,7 +387,7 @@ impl ASTConverter {
) -> (NonDefaultParamSignature, Vec<Expr>) {
match expr.node {
ExpressionType::Identifier { name } => {
(Self::convert_for_param(name, expr.location), vec![])
(self.convert_for_param(name, expr.location), vec![])
}
ExpressionType::Tuple { elements } => {
let tmp = fresh_varname();
@ -590,8 +647,10 @@ impl ASTConverter {
obj.attr_expr(name)
}
ExpressionType::Lambda { args, body } => {
self.namespace.push("<lambda>".to_string());
let params = self.convert_params(args);
let body = vec![self.convert_expr(*body)];
self.namespace.pop();
let sig = LambdaSignature::new(params, None, TypeBoundSpecs::empty());
let op = Token::from_str(TokenKind::ProcArrow, "=>");
Expr::Lambda(Lambda::new(sig, op, Block::new(body), DefId(0)))
@ -653,7 +712,7 @@ impl ASTConverter {
method.call_expr(args)
}
_other => {
erg_common::log!(err "unimplemented: {:?}", _other);
log!(err "unimplemented: {:?}", _other);
Expr::Dummy(Dummy::empty())
}
}
@ -905,22 +964,6 @@ impl ASTConverter {
Expr::ClassDef(classdef)
}
fn register_name_info(&mut self, name: &str, kind: NameKind) {
if let Some(name_info) = self.names.get_mut(name) {
name_info.defined_times += 1;
} else {
// In Erg, classes can only be defined in uppercase
// So if not, prefix it with `Type_`
let rename = if kind.is_class() && !name.starts_with(char::is_uppercase) {
Some(format!("Type_{name}"))
} else {
None
};
let info = NameInfo::new(rename, self.cur_namespace(), self.cur_block_id(), 1);
self.names.insert(String::from(name), info);
}
}
fn convert_statement(&mut self, stmt: Located<StatementType>, dont_call_return: bool) -> Expr {
match stmt.node {
StatementType::Expression { expression } => self.convert_expr(expression),
@ -1240,7 +1283,6 @@ impl ASTConverter {
));
let return_acc = self.convert_ident("return".to_string(), stmt.location);
let return_acc = Expr::Accessor(Accessor::attr(func_acc, return_acc));
erg_common::log!(err "{return_acc}");
return_acc.call_expr(Args::new(vec![PosArg::new(value)], vec![], None))
}
}
@ -1377,8 +1419,24 @@ impl ASTConverter {
};
Expr::Dummy(Dummy::new(dummy))
}
StatementType::With {
is_async: _,
mut items,
body,
} => {
let item = items.remove(0);
let context_expr = self.convert_expr(item.context_expr);
let body = self.convert_for_body(item.optional_vars.unwrap(), body);
let with_ident = self.convert_ident("with".to_string(), stmt.location);
let with_acc = Expr::Accessor(Accessor::Ident(with_ident));
with_acc.call_expr(Args::new(
vec![PosArg::new(context_expr), PosArg::new(Expr::Lambda(body))],
vec![],
None,
))
}
_other => {
erg_common::log!(err "unimplemented: {:?}", _other);
log!(err "unimplemented: {:?}", _other);
Expr::Dummy(Dummy::empty())
}
}

View file

@ -13,10 +13,7 @@ use erg_common::spawn::exec_new_thread;
pub fn parse_args() -> ErgConfig {
let mut args = env::args();
args.next(); // "pylyzer"
let mut cfg = ErgConfig {
python_compatible_mode: true,
..ErgConfig::default()
};
let mut cfg = ErgConfig::default();
while let Some(arg) = args.next() {
match &arg[..] {
"--" => {

View file

@ -15,14 +15,14 @@ for i in [1, 2, 3]:
j = i + "aa"
print(j)
i: int # OK
i = 1
i: str # ERR
i = "aa" if True else "bb"
i: str # OK
a: int # OK
a = 1
a: str # ERR
a = "aa" if True else "bb"
a: str # OK
while "aaa": # ERR
i += 1 # ERR
a += 1 # ERR
break
class C:
@ -31,5 +31,5 @@ class C:
dic = {"a": 1, "b": 2}
print(dic["c"]) # ERR
a = [1, 2, 3]
print(a[4]) # ERR
arr = [1, 2, 3]
print(arr[4]) # ERR

View file

@ -7,7 +7,6 @@ use pylyzer::PythonAnalyzer;
pub fn exec_analyzer(file_path: &'static str) -> Result<CompleteArtifact, IncompleteArtifact> {
let cfg = ErgConfig {
python_compatible_mode: true,
input: Input::File(PathBuf::from(file_path)),
..Default::default()
};