mirror of https://github.com/mtshiba/pylyzer
Enhance: `ASTConverter` can return errors
This commit is contained in:
parent
4a606c4646
commit
eb3fc9be8d
|
|
@ -1,5 +1,7 @@
|
|||
use erg_common::config::ErgConfig;
|
||||
use erg_common::fresh::fresh_varname;
|
||||
use erg_common::traits::{Locational};
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_compiler::artifact::CompleteArtifact;
|
||||
use rustpython_parser::ast::{StatementType, ExpressionType, Located, Program, Number, StringGroup, Operator, BooleanOperator, UnaryOperator, Suite, Parameters, Parameter, Comparison};
|
||||
use rustpython_parser::ast::Location as PyLocation;
|
||||
|
||||
|
|
@ -11,6 +13,9 @@ use erg_compiler::erg_parser::ast::{
|
|||
BinOp, Lambda, LambdaSignature, TypeBoundSpecs, TypeSpec, SubrSignature, Decorator, NonDefaultParamSignature, DefaultParamSignature, ParamPattern, TypeSpecWithOp,
|
||||
Tuple, NormalTuple, Array, NormalArray, Set, NormalSet, Dict, NormalDict, PreDeclTypeSpec, SimpleTypeSpec, ConstArgs, AttrDef, UnaryOp, KeyValue, Dummy, TypeAscription, ClassDef, Record, Methods, NormalRecord,
|
||||
};
|
||||
use erg_compiler::error::{CompileErrors};
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum BlockKind {
|
||||
|
|
@ -71,39 +76,47 @@ fn op_to_token(op: Operator) -> Token {
|
|||
Token::from_str(kind, cont)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub fn pyloc_to_ergloc(loc: PyLocation, cont_len: usize) -> erg_common::error::Location {
|
||||
erg_common::error::Location::range(loc.row(), loc.column(), loc.row(), loc.column()+cont_len)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct NameInfo {
|
||||
// last_defined_line: usize,
|
||||
defined_times: usize,
|
||||
referenced: HashSet<String>,
|
||||
}
|
||||
|
||||
impl NameInfo {
|
||||
pub const fn new(defined_times: usize) -> Self {
|
||||
pub fn new(defined_times: usize) -> Self {
|
||||
Self {
|
||||
// last_defined_line,
|
||||
defined_times,
|
||||
referenced: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_referrer(&mut self, referrer: String) {
|
||||
self.referenced.insert(referrer);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ASTConverter {
|
||||
cfg: ErgConfig,
|
||||
namespace: Vec<String>,
|
||||
/// Erg does not allow variables to be defined multiple times, so rename them using this
|
||||
names: Vec<HashMap<String, NameInfo>>,
|
||||
}
|
||||
|
||||
impl Default for ASTConverter {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
warns: CompileErrors,
|
||||
}
|
||||
|
||||
impl ASTConverter {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(cfg: ErgConfig) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
namespace: vec![String::from("<module>")],
|
||||
names: vec![HashMap::new()],
|
||||
warns: CompileErrors::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +129,7 @@ impl ASTConverter {
|
|||
None
|
||||
}
|
||||
|
||||
fn _get_mut_name_global(&mut self, name: &str) -> Option<&mut NameInfo> {
|
||||
fn get_mut_name_global(&mut self, name: &str) -> Option<&mut NameInfo> {
|
||||
for space in self.names.iter_mut().rev() {
|
||||
if let Some(name) = space.get_mut(name) {
|
||||
return Some(name);
|
||||
|
|
@ -125,9 +138,13 @@ impl ASTConverter {
|
|||
None
|
||||
}
|
||||
|
||||
fn convert_ident(&self, name: String, loc: PyLocation) -> Identifier {
|
||||
fn convert_ident(&mut self, name: String, loc: PyLocation) -> Identifier {
|
||||
let referrer = self.namespace.last().unwrap().clone();
|
||||
let name = escape_name(name);
|
||||
let cont = if let Some(name_info) = self.get_name_global(&name) {
|
||||
let cont = if let Some(name_info) = self.get_mut_name_global(&name) {
|
||||
if referrer != "<module>" {
|
||||
name_info.add_referrer(referrer);
|
||||
}
|
||||
if name_info.defined_times > 1 {
|
||||
// HACK: add zero-width characters as postfix
|
||||
format!("{name}{}", "\0".repeat(name_info.defined_times))
|
||||
|
|
@ -149,7 +166,7 @@ impl ASTConverter {
|
|||
ParamPattern::VarName(name)
|
||||
}
|
||||
|
||||
fn convert_nd_param(&self, param: Parameter) -> NonDefaultParamSignature {
|
||||
fn convert_nd_param(&mut self, param: Parameter) -> NonDefaultParamSignature {
|
||||
let pat = Self::convert_param_pattern(param.arg, param.location);
|
||||
let t_spec = param.annotation
|
||||
.map(|anot| self.convert_type_spec(*anot))
|
||||
|
|
@ -162,7 +179,7 @@ impl ASTConverter {
|
|||
}
|
||||
|
||||
// TODO: defaults
|
||||
fn convert_params(&self, args: Box<Parameters>) -> Params {
|
||||
fn convert_params(&mut self, args: Box<Parameters>) -> Params {
|
||||
let non_defaults = args.args.into_iter().map(|p| self.convert_nd_param(p)).collect();
|
||||
// let defaults = args. args.defaults.into_iter().map(convert_default_param).collect();
|
||||
Params::new(non_defaults, None, vec![], None)
|
||||
|
|
@ -182,7 +199,7 @@ impl ASTConverter {
|
|||
}
|
||||
|
||||
/// (i, j) => $1 (i = $1[0]; j = $1[1])
|
||||
fn convert_expr_to_param(&self, expr: Located<ExpressionType>) -> (NonDefaultParamSignature, Vec<Expr>) {
|
||||
fn convert_expr_to_param(&mut self, expr: Located<ExpressionType>) -> (NonDefaultParamSignature, Vec<Expr>) {
|
||||
match expr.node {
|
||||
ExpressionType::Identifier { name } => (Self::convert_for_param(name, expr.location), vec![]),
|
||||
ExpressionType::Tuple { elements } => {
|
||||
|
|
@ -222,7 +239,7 @@ impl ASTConverter {
|
|||
Lambda::new(sig, op, Block::new(body), DefId(0))
|
||||
}
|
||||
|
||||
fn convert_type_spec(&self, expr: Located<ExpressionType>) -> TypeSpec {
|
||||
fn convert_type_spec(&mut self, expr: Located<ExpressionType>) -> TypeSpec {
|
||||
match expr.node {
|
||||
ExpressionType::Identifier { name } =>
|
||||
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(SimpleTypeSpec::new(self.convert_ident(name, expr.location), ConstArgs::empty()))),
|
||||
|
|
@ -249,7 +266,7 @@ impl ASTConverter {
|
|||
(l_brace, r_brace)
|
||||
}
|
||||
|
||||
fn convert_expr(&self, expr: Located<ExpressionType>) -> Expr {
|
||||
fn convert_expr(&mut self, expr: Located<ExpressionType>) -> Expr {
|
||||
match expr.node {
|
||||
ExpressionType::Number { value } => {
|
||||
let (kind, cont) = match value {
|
||||
|
|
@ -668,19 +685,31 @@ impl ASTConverter {
|
|||
decorator_list,
|
||||
returns
|
||||
} => {
|
||||
// TODO: If a function can be defined multiple times, which function is called in a recursive function?
|
||||
self.namespace.push(name.clone());
|
||||
let decos = decorator_list.into_iter().map(|ex| Decorator(self.convert_expr(ex))).collect::<HashSet<_>>();
|
||||
self.register_name_info(&name);
|
||||
let ident = self.convert_ident(name, stmt.location);
|
||||
let params = self.convert_params(args);
|
||||
let return_t = returns.map(|ret| self.convert_type_spec(ret));
|
||||
let sig = Signature::Subr(SubrSignature::new(decos, ident, TypeBoundSpecs::empty(), params, return_t));
|
||||
let block = self.convert_block(body, BlockKind::Function);
|
||||
let body = DefBody::new(EQUAL, block, DefId(0));
|
||||
let def = Def::new(sig, body);
|
||||
self.namespace.pop();
|
||||
Expr::Def(def)
|
||||
// if reassigning of a function referenced by other functions is occurred, it is an error
|
||||
if self.get_name_global(&name).map(|info| !info.referenced.is_empty()).unwrap_or(false) {
|
||||
let warn = reassign_func_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
pyloc_to_ergloc(stmt.location, name.len()),
|
||||
self.namespace.join("."),
|
||||
&name
|
||||
);
|
||||
self.warns.push(warn);
|
||||
Expr::Dummy(Dummy::empty())
|
||||
} else {
|
||||
self.namespace.push(name.clone());
|
||||
let decos = decorator_list.into_iter().map(|ex| Decorator(self.convert_expr(ex))).collect::<HashSet<_>>();
|
||||
self.register_name_info(&name);
|
||||
let ident = self.convert_ident(name, stmt.location);
|
||||
let params = self.convert_params(args);
|
||||
let return_t = returns.map(|ret| self.convert_type_spec(ret));
|
||||
let sig = Signature::Subr(SubrSignature::new(decos, ident, TypeBoundSpecs::empty(), params, return_t));
|
||||
let block = self.convert_block(body, BlockKind::Function);
|
||||
let body = DefBody::new(EQUAL, block, DefId(0));
|
||||
let def = Def::new(sig, body);
|
||||
self.namespace.pop();
|
||||
Expr::Def(def)
|
||||
}
|
||||
}
|
||||
StatementType::ClassDef { name, body, bases, keywords: _, decorator_list } => {
|
||||
self.convert_classdef(name, body, bases, decorator_list, stmt.location)
|
||||
|
|
@ -818,10 +847,10 @@ impl ASTConverter {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn convert_program(mut self, program: Program) -> Module {
|
||||
pub fn convert_program(mut self, program: Program) -> CompleteArtifact<Module> {
|
||||
let program = program.statements.into_iter()
|
||||
.map(|stmt| self.convert_statement(stmt, true))
|
||||
.collect();
|
||||
Module::new(program)
|
||||
CompleteArtifact::new(Module::new(program), self.warns)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
use erg_common::switch_lang;
|
||||
use erg_common::config::Input;
|
||||
use erg_common::error::{Location, ErrorCore, ErrorKind, SubMessage};
|
||||
use erg_compiler::error::CompileError;
|
||||
|
||||
pub(crate) fn reassign_func_error(
|
||||
input: Input,
|
||||
errno: usize,
|
||||
loc: Location,
|
||||
caused_by: String,
|
||||
name: &str,
|
||||
) -> CompileError {
|
||||
CompileError::new(
|
||||
ErrorCore::new(
|
||||
vec![SubMessage::only_loc(loc)],
|
||||
switch_lang!(
|
||||
"japanese" => format!("{name}は既に宣言され、参照されています。このような関数に再代入するのは望ましくありません"),
|
||||
"simplified_chinese" => format!("{name}已声明,已被引用。不建议再次赋值"),
|
||||
"traditional_chinese" => format!("{name}已宣告,已被引用。不建議再次賦值"),
|
||||
"english" => format!("{name} has already been declared and referenced. It is not recommended to reassign such a function"),
|
||||
),
|
||||
errno,
|
||||
ErrorKind::AssignError,
|
||||
loc,
|
||||
),
|
||||
input,
|
||||
caused_by,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
mod convert;
|
||||
mod gen_decl;
|
||||
mod error;
|
||||
|
||||
pub use convert::*;
|
||||
pub use gen_decl::*;
|
||||
pub use gen_decl::*;
|
||||
|
|
|
|||
|
|
@ -81,13 +81,14 @@ impl PythonAnalyzer {
|
|||
let err = CompileError::new(core, self.cfg.input.clone(), "".into());
|
||||
IncompleteArtifact::new(None, CompileErrors::from(err), CompileErrors::empty())
|
||||
})?;
|
||||
let converter = py2erg::ASTConverter::new();
|
||||
let erg_module = converter.convert_program(py_program);
|
||||
let converter = py2erg::ASTConverter::new(self.cfg.copy());
|
||||
let CompleteArtifact{ object: erg_module, mut warns } = converter.convert_program(py_program);
|
||||
let erg_ast = AST::new(erg_common::Str::rc(filename), erg_module);
|
||||
erg_common::log!("AST: {erg_ast}");
|
||||
self.checker.lower(erg_ast, mode).map_err(|iart| {
|
||||
let errors = handle_err::filter_errors(self.checker.get_mod_ctx(), iart.errors);
|
||||
let warns = handle_err::filter_errors(self.checker.get_mod_ctx(), iart.warns);
|
||||
let ws = handle_err::filter_errors(self.checker.get_mod_ctx(), iart.warns);
|
||||
warns.extend(ws);
|
||||
IncompleteArtifact::new(iart.object, errors, warns)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue