diff --git a/Cargo.lock b/Cargo.lock index 202874c..19b8ee4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index a121308..05c7ca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/crates/py2erg/convert.rs b/crates/py2erg/convert.rs index 496e99b..beaaff0 100644 --- a/crates/py2erg/convert.rs +++ b/crates/py2erg/convert.rs @@ -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 for DefinedPlace { + fn eq(&self, other: &str) -> bool { + match self { + Self::Known(s) => s == other, + Self::Unknown => false, + } + } +} + +impl PartialEq 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, - defined_in: String, + defined_in: DefinedPlace, defined_block_id: usize, defined_times: usize, referenced: HashSet, @@ -138,7 +167,7 @@ pub struct NameInfo { impl NameInfo { pub fn new( rename: Option, - 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() == "" { + 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) { 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("".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, 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()) } } diff --git a/src/main.rs b/src/main.rs index 4d70bcc..669d110 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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[..] { "--" => { diff --git a/tests/test.py b/tests/test.py index b07ea44..d8d3e24 100644 --- a/tests/test.py +++ b/tests/test.py @@ -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 diff --git a/tests/test.rs b/tests/test.rs index de1f733..68202bd 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -7,7 +7,6 @@ use pylyzer::PythonAnalyzer; pub fn exec_analyzer(file_path: &'static str) -> Result { let cfg = ErgConfig { - python_compatible_mode: true, input: Input::File(PathBuf::from(file_path)), ..Default::default() };