Fix visibility bugs

This commit is contained in:
Shunsuke Shibayama 2022-09-10 01:42:23 +09:00
parent c96fe956a5
commit 3895d29669
12 changed files with 372 additions and 488 deletions

View file

@ -18,7 +18,7 @@ use erg_parser::ast::DefId;
use erg_type::codeobj::{CodeObj, CodeObjFlags};
use Opcode::*;
use erg_parser::ast::{Identifier, ParamPattern, ParamSignature, Params, VarName};
use erg_parser::ast::{ParamPattern, ParamSignature, Params, VarName};
use erg_parser::token::{Token, TokenKind};
use erg_type::free::fresh_varname;
@ -32,11 +32,18 @@ use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::hir::AttrDef;
use crate::hir::Attribute;
use crate::hir::{
Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Literal, Local, PosArg, Signature,
SubrSignature, Tuple, VarSignature, HIR,
Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Identifier, Literal, PosArg,
Signature, SubrSignature, Tuple, VarSignature, HIR,
};
use AccessKind::*;
fn is_python_special(name: &str) -> bool {
match name {
"__call__" | "__init__" => true,
_ => false,
}
}
fn is_python_global(name: &str) -> bool {
match name {
"ArithmeticError"
@ -214,11 +221,17 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
}
}
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str {
let mut name = convert_to_python_attr(class, uniq_obj_name, name).to_string();
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, ident: Identifier) -> Str {
let vis = ident.vis();
let mut name =
convert_to_python_attr(class, uniq_obj_name, ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__");
Str::rc(&name)
if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name)
} else {
Str::from("::".to_string() + &name)
}
}
fn convert_to_python_name(name: Str) -> Str {
@ -254,7 +267,7 @@ fn escape_name(ident: Identifier) -> Str {
let mut name = convert_to_python_name(ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__");
if vis.is_public() || is_python_global(&name) {
if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name)
} else {
Str::from("::".to_string() + &name)
@ -500,9 +513,8 @@ impl CodeGenerator {
Some(StoreLoadKind::Global)
}
fn register_name(&mut self, ident: Identifier) -> Name {
fn register_name(&mut self, name: Str) -> Name {
let current_is_toplevel = self.cur_block() == self.toplevel_block();
let name = escape_name(ident);
match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
let st = if current_is_toplevel {
@ -533,25 +545,22 @@ impl CodeGenerator {
}
}
fn register_attr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_attr(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn register_method(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_method(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -566,9 +575,10 @@ impl CodeGenerator {
fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_NAME);
self.write_arg(name.idx as u8);
self.stack_dec(); // (level + from_list) -> module object
@ -577,9 +587,10 @@ impl CodeGenerator {
fn emit_import_from_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_FROM);
self.write_arg(name.idx as u8);
// self.stack_inc(); (module object) -> attribute
@ -590,12 +601,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}.{name})", fn_name!());
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Attr)
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
.local_search(&escaped, Attr)
.unwrap_or_else(|| self.register_attr(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -611,12 +623,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}.{name})", fn_name!());
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Method)
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
.local_search(&escaped, Method)
.unwrap_or_else(|| self.register_method(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -630,15 +643,14 @@ impl CodeGenerator {
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
log!(info "entered {} ({ident})", fn_name!());
let name = self
.local_search(ident.inspect(), acc_kind)
.unwrap_or_else(|| {
if acc_kind.is_local() {
self.register_name(ident)
} else {
self.register_attr("", None, ident.inspect().clone())
}
});
let escaped = escape_name(ident);
let name = self.local_search(&escaped, acc_kind).unwrap_or_else(|| {
if acc_kind.is_local() {
self.register_name(escaped)
} else {
self.register_attr(escaped)
}
});
let instr = match name.kind {
StoreLoadKind::Fast => Opcode::STORE_FAST,
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
@ -668,18 +680,12 @@ impl CodeGenerator {
fn store_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Local(local) => {
self.emit_store_instr(Identifier::new(None, VarName::new(local.name)), Name);
}
Accessor::Public(public) => {
self.emit_store_instr(
Identifier::new(Some(public.dot), VarName::new(public.name)),
Name,
);
Accessor::Ident(ident) => {
self.emit_store_instr(ident, Name);
}
Accessor::Attr(attr) => {
self.codegen_expr(*attr.obj);
self.emit_store_instr(Identifier::new(None, VarName::new(attr.name)), Attr);
self.emit_store_instr(attr.ident, Attr);
}
acc => todo!("store: {acc}"),
}
@ -728,7 +734,8 @@ impl CodeGenerator {
.iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")),
)
.map(|s| self.get_cached(s))
.map(|s| format!("::{s}"))
.map(|s| self.get_cached(&s))
.collect()
}
@ -938,7 +945,7 @@ impl CodeGenerator {
let mut pop_jump_points = vec![];
match pat {
ParamPattern::VarName(name) => {
let ident = Identifier::new(None, name);
let ident = Identifier::bare(None, name);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
@ -993,8 +1000,8 @@ impl CodeGenerator {
self.emit_call_method(*call.obj, method_name, call.args);
} else {
match *call.obj {
Expr::Accessor(Accessor::Local(local)) => {
self.emit_call_local(local, call.args).unwrap()
Expr::Accessor(Accessor::Ident(ident)) if ident.vis().is_private() => {
self.emit_call_local(ident, call.args).unwrap()
}
other => {
self.codegen_expr(other);
@ -1004,7 +1011,7 @@ impl CodeGenerator {
}
}
fn emit_call_local(&mut self, local: Local, args: Args) -> CompileResult<()> {
fn emit_call_local(&mut self, local: Identifier, args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
match &local.inspect()[..] {
"assert" => self.emit_assert_instr(args),
@ -1013,9 +1020,7 @@ impl CodeGenerator {
"if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true),
_ => {
let name = VarName::new(local.name);
let ident = Identifier::new(None, name);
self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.emit_load_name_instr(local).unwrap_or_else(|e| {
self.errs.push(e);
});
self.emit_args(args, Name);
@ -1032,14 +1037,10 @@ impl CodeGenerator {
let class = obj.ref_t().name(); // これは必ずmethodのあるクラスになっている
let uniq_obj_name = obj.__name__().map(Str::rc);
self.codegen_expr(obj);
self.emit_load_method_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
method_name.name.into_token().content,
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), method_name)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_args(args, Method);
}
@ -1361,14 +1362,7 @@ impl CodeGenerator {
fn codegen_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Local(local) => {
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::Public(public) => {
let ident = Identifier::new(Some(public.dot), VarName::new(public.name));
Accessor::Ident(ident) => {
self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err);
});
@ -1377,14 +1371,10 @@ impl CodeGenerator {
let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_load_attr_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), a.ident)
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::TupleAttr(t_attr) => {
self.codegen_expr(*t_attr.obj);
@ -1516,26 +1506,32 @@ impl CodeGenerator {
let subr_sig = SubrSignature::new(ident, params.clone(), __new__.clone());
let mut attrs = vec![];
match __new__.non_default_params().unwrap()[0].typ() {
// namedtupleは仕様上::xなどの名前を使えない
// {x = Int; y = Int}
// self.x = %x.x; self.y = %x.y
// => self::x = %x.x; self::y = %x.y
// {.x = Int; .y = Int}
// => self.x = %x.x; self.y = %x.y
Type::Record(rec) => {
for field in rec.keys() {
let obj = Expr::Accessor(Accessor::local(
Token::symbol_with_line(&param_name[..], line),
Type::Failure,
));
let obj =
Expr::Accessor(Accessor::private_with_line(Str::from(&param_name), line));
let expr = Expr::Accessor(Accessor::Attr(Attribute::new(
obj,
Token::symbol(&field.symbol[..]),
Identifier::bare(
Some(Token::dummy()),
VarName::from_str(field.symbol.clone()),
),
Type::Failure,
)));
let obj = Expr::Accessor(Accessor::local(
Token::symbol_with_line("self", line),
Type::Failure,
));
let obj = Expr::Accessor(Accessor::private_with_line(Str::ever("self"), line));
let dot = if field.vis.is_private() {
None
} else {
Some(Token::dummy())
};
let attr = Accessor::Attr(Attribute::new(
obj,
Token::symbol(&field.symbol[..]),
Identifier::bare(dot, VarName::from_str(field.symbol.clone())),
Type::Failure,
));
let attr_def = AttrDef::new(attr, Block::new(vec![expr]));
@ -1569,17 +1565,14 @@ impl CodeGenerator {
Params::new(vec![param], None, vec![], None),
__new__.clone(),
);
let arg = PosArg::new(Expr::Accessor(Accessor::local(
Token::symbol_with_line(&param_name[..], line),
Type::Failure,
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name),
line,
)));
let class = Expr::Accessor(Accessor::local(
Token::symbol_with_line(class_name, line),
Type::Failure,
));
let class = Expr::Accessor(Accessor::private_with_line(class_name.clone(), line));
let class_new = Expr::Accessor(Accessor::attr(
class,
Token::symbol_with_line("__new__", line),
Identifier::bare(None, VarName::from_str_and_line(Str::ever("__new__"), line)),
Type::Failure,
));
let call = Expr::Call(Call::new(

View file

@ -166,17 +166,17 @@ impl SubstContext {
impl Context {
fn eval_const_acc(&self, acc: &Accessor) -> EvalResult<ValueObj> {
match acc {
Accessor::Local(local) => {
if let Some(val) = self.rec_get_const_obj(local.inspect()) {
Accessor::Ident(ident) => {
if let Some(val) = self.rec_get_const_obj(ident.inspect()) {
Ok(val.clone())
} else {
if local.is_const() {
if ident.is_const() {
Err(EvalError::no_var_error(
line!() as usize,
local.loc(),
ident.loc(),
self.caused_by(),
local.inspect(),
self.get_similar_name(local.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
} else {
Err(EvalError::not_const_expr(
@ -232,22 +232,22 @@ impl Context {
fn eval_const_call(&self, call: &Call, __name__: Option<&Str>) -> EvalResult<ValueObj> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Local(name) => {
Accessor::Ident(ident) => {
let obj =
self.rec_get_const_obj(&name.inspect())
self.rec_get_const_obj(&ident.inspect())
.ok_or(EvalError::no_var_error(
line!() as usize,
name.loc(),
ident.loc(),
self.caused_by(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))?;
let subr = option_enum_unwrap!(obj, ValueObj::Subr)
.ok_or(EvalError::type_mismatch_error(
line!() as usize,
name.loc(),
ident.loc(),
self.caused_by(),
name.inspect(),
ident.inspect(),
&mono("Subroutine"),
&obj.t(),
None,
@ -258,7 +258,6 @@ impl Context {
}
Accessor::Attr(_attr) => todo!(),
Accessor::TupleAttr(_attr) => todo!(),
Accessor::Public(_name) => todo!(),
Accessor::Subscr(_subscr) => todo!(),
}
} else {

View file

@ -91,17 +91,17 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<&Context> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(name)) => {
hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
if kind == Some(ContextKind::Module) {
if let Some(ctx) = self.rec_get_mod(name.inspect()) {
if let Some(ctx) = self.rec_get_mod(ident.inspect()) {
Ok(ctx)
} else {
Err(TyCheckError::no_var_error(
line!() as usize,
obj.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
} else {
@ -197,34 +197,20 @@ impl Context {
None
}
pub(crate) fn rec_get_var_t(
&self,
name: &Token,
vis: Visibility,
namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&name.inspect()[..]) {
if vi.vis == vis {
Ok(vi.t())
} else {
Err(TyCheckError::visibility_error(
line!() as usize,
name.loc(),
namespace.clone(),
name.inspect(),
vi.vis,
))
}
pub(crate) fn rec_get_var_t(&self, ident: &Identifier, namespace: &Str) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&ident.inspect()[..]) {
// self.validate_visibility(ident, vi, self)?;
Ok(vi.t())
} else {
if let Some(parent) = self.outer.as_ref() {
return parent.rec_get_var_t(name, vis, namespace);
return parent.rec_get_var_t(ident, namespace);
}
Err(TyCheckError::no_var_error(
line!() as usize,
name.loc(),
ident.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
}
@ -232,11 +218,12 @@ impl Context {
pub(crate) fn rec_get_attr_t(
&self,
obj: &hir::Expr,
name: &Token,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
let self_t = obj.t();
match self.get_attr_t_from_attributive_t(obj, &self_t, name, namespace) {
let name = ident.name.token();
match self.get_attr_t_from_attributive_t(obj, &self_t, ident, namespace) {
Ok(t) => {
return Ok(t);
}
@ -245,17 +232,22 @@ impl Context {
return Err(e);
}
}
if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
if let Ok(t) = singular_ctx.rec_get_var_t(ident, namespace) {
return Ok(t);
}
}
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(&self_t)
.ok_or_else(|| todo!())?
{
if let Ok(t) = ctx.rec_get_var_t(name, Public, namespace) {
if let Ok(t) = ctx.rec_get_var_t(ident, namespace) {
return Ok(t);
}
}
// TODO: dependent type widening
if let Some(parent) = self.outer.as_ref() {
parent.rec_get_attr_t(obj, name, namespace)
parent.rec_get_attr_t(obj, ident, namespace)
} else {
Err(TyCheckError::no_attr_error(
line!() as usize,
@ -272,53 +264,56 @@ impl Context {
&self,
obj: &hir::Expr,
t: &Type,
name: &Token,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
match t {
Type::FreeVar(fv) if fv.is_linked() => {
self.get_attr_t_from_attributive_t(obj, &fv.crack(), name, namespace)
self.get_attr_t_from_attributive_t(obj, &fv.crack(), ident, namespace)
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
self.get_attr_t_from_attributive_t(obj, &sup, name, namespace)
self.get_attr_t_from_attributive_t(obj, &sup, ident, namespace)
}
Type::Ref(t) => self.get_attr_t_from_attributive_t(obj, t, name, namespace),
Type::Ref(t) => self.get_attr_t_from_attributive_t(obj, t, ident, namespace),
Type::RefMut { before, .. } => {
self.get_attr_t_from_attributive_t(obj, before, name, namespace)
self.get_attr_t_from_attributive_t(obj, before, ident, namespace)
}
Type::Refinement(refine) => {
self.get_attr_t_from_attributive_t(obj, &refine.t, name, namespace)
self.get_attr_t_from_attributive_t(obj, &refine.t, ident, namespace)
}
Type::Record(record) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr) = record.get(&Field::new(Public, name.inspect().clone())) {
if let Some(attr) = record.get(&Field::new(Public, ident.inspect().clone())) {
Ok(attr.clone())
} else {
let t = Type::Record(record.clone());
Err(TyCheckError::no_attr_error(
line!() as usize,
name.loc(),
ident.loc(),
namespace.clone(),
&t,
name.inspect(),
self.get_similar_attr(&t, name.inspect()),
ident.inspect(),
self.get_similar_attr(&t, ident.inspect()),
))
}
}
Module => {
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
let t = mod_ctx.rec_get_var_t(name, Public, namespace)?;
let t = mod_ctx.rec_get_var_t(ident, namespace)?;
Ok(t)
}
other => {
if let Some(v) = self.rec_get_const_obj(&other.name()) {
match v {
ValueObj::Type(TypeObj::Generated(gen)) => self
.get_gen_t_require_attr_t(gen, &name.inspect()[..])
.get_gen_t_require_attr_t(gen, &ident.inspect()[..])
.map(|t| t.clone())
.ok_or(TyCheckError::dummy(line!() as usize)),
ValueObj::Type(TypeObj::Builtin(t)) => todo!("{t}"),
ValueObj::Type(TypeObj::Builtin(_t)) => {
// FIXME:
Err(TyCheckError::dummy(line!() as usize))
}
other => todo!("{other}"),
}
} else {
@ -421,8 +416,9 @@ impl Context {
&& self
.outer
.as_ref()
.map(|outer| outer.name.split("::").last().unwrap_or(&outer.name))
.map(|name| name != &ctx.name[..])
// TODO: also split with `.`
.map(|outer| outer.name.split("::"))
.map(|mut names| names.all(|name| name != &ctx.name[..]))
.unwrap_or(true)
{
Err(TyCheckError::visibility_error(
@ -446,14 +442,17 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 2);
let cont = binop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_t(
&Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let lhs = args[0].expr.clone();
let rhs = args[1].expr.clone();
let bin = hir::BinOp::new(op.name, lhs, rhs, op.t);
let bin = hir::BinOp::new(op.name.into_token(), lhs, rhs, op.t.clone());
// HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする
let core = ErrorCore::new(
e.core.errno,
@ -475,13 +474,16 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 1);
let cont = unaryop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_t(
&Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let expr = args[0].expr.clone();
let unary = hir::UnaryOp::new(op.name, expr, op.t);
let unary = hir::UnaryOp::new(op.name.into_token(), expr, op.t.clone());
let core = ErrorCore::new(
e.core.errno,
e.core.kind,
@ -655,7 +657,7 @@ impl Context {
let callee = if let Some(ident) = method_name {
let attr = hir::Attribute::new(
obj.clone(),
ident.name.clone().into_token(),
hir::Identifier::bare(ident.dot.clone(), ident.name.clone()),
Type::Uninited,
);
let acc = hir::Expr::Accessor(hir::Accessor::Attr(attr));
@ -886,7 +888,9 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<Type> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => {
hir::Expr::Accessor(hir::Accessor::Ident(local))
if local.vis().is_private() && &local.inspect()[..] == "match" =>
{
return self.get_match_call_t(pos_args, kw_args);
}
_ => {}

View file

@ -109,7 +109,7 @@ impl Context {
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Local(local)) if local.is_const() => {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
@ -428,7 +428,7 @@ impl Context {
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Local(local)) if local.is_const() => {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,

View file

@ -371,7 +371,7 @@ impl Context {
self.deref_expr_t(&mut subscr.obj)?;
self.deref_expr_t(&mut subscr.index)?;
}
hir::Accessor::Local(_) | hir::Accessor::Public(_) => {}
hir::Accessor::Ident(_) => {}
}
Ok(())
}

View file

@ -259,10 +259,10 @@ impl SideEffectChecker {
Expr::Lambda(lambda) => lambda.is_procedural(),
// 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => self.is_procedural(&call.obj),
Expr::Accessor(Accessor::Local(local)) => local.name.is_procedural(),
Expr::Accessor(Accessor::Ident(ident)) => ident.name.is_procedural(),
// procedural: x.y! (e.g. Array.sample!)
// !procedural: !x.y
Expr::Accessor(Accessor::Attr(attr)) => attr.name.is_procedural(),
Expr::Accessor(Accessor::Attr(attr)) => attr.ident.is_procedural(),
Expr::Accessor(_) => todo!(),
_ => false,
}

View file

@ -11,7 +11,7 @@ use erg_common::{
impl_stream_for_wrapper,
};
use erg_parser::ast::{fmt_lines, DefId, Identifier, Params, TypeSpec};
use erg_parser::ast::{fmt_lines, DefId, Params, TypeSpec, VarName};
use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{array, tuple};
@ -286,84 +286,55 @@ impl Args {
}
}
/// represents local variables
#[derive(Debug, Clone)]
pub struct Local {
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
pub(crate) t: Type,
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub dot: Option<Token>,
pub name: VarName,
pub __name__: Option<Str>,
pub t: Type,
}
impl NestedDisplay for Local {
impl NestedDisplay for Identifier {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
} else {
"".to_string()
};
write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
match &self.dot {
Some(_dot) => {
write!(f, ".{}", self.name)?;
}
None => {
write!(f, "::{}", self.name)?;
}
}
if let Some(__name__) = &self.__name__ {
write!(f, "(__name__: {})", __name__)?;
}
if self.t != Type::Uninited {
write!(f, "(: {})", self.t)?;
}
Ok(())
}
}
impl_display_from_nested!(Local);
impl_t!(Local);
impl_display_from_nested!(Identifier);
impl_t!(Identifier);
impl Locational for Local {
#[inline]
impl Locational for Identifier {
fn loc(&self) -> Location {
self.name.loc()
}
}
impl Local {
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self {
Self { name, __name__, t }
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&self.name.content
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct Public {
pub dot: Token,
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
t: Type,
}
impl NestedDisplay for Public {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
if let Some(dot) = &self.dot {
Location::concat(dot, &self.name)
} else {
"".to_string()
};
write!(f, ".{} (: {}){}", self.name.content, self.t, __name__)
self.name.loc()
}
}
}
impl_display_from_nested!(Public);
impl_t!(Public);
impl Locational for Public {
#[inline]
fn loc(&self) -> Location {
Location::concat(&self.dot, &self.name)
impl From<&Identifier> for Field {
fn from(ident: &Identifier) -> Self {
Self::new(ident.vis(), ident.inspect().clone())
}
}
impl Public {
pub const fn new(dot: Token, name: Token, __name__: Option<Str>, t: Type) -> Self {
impl Identifier {
pub const fn new(dot: Option<Token>, name: VarName, __name__: Option<Str>, t: Type) -> Self {
Self {
dot,
name,
@ -372,43 +343,75 @@ impl Public {
}
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&self.name.content
pub fn public(name: &'static str) -> Self {
Self::bare(
Some(Token::from_str(TokenKind::Dot, ".")),
VarName::from_static(name),
)
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
pub fn private(name: Str) -> Self {
Self::bare(None, VarName::from_str(name))
}
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::bare(None, VarName::from_str_and_line(name, line))
}
pub fn public_with_line(dot: Token, name: Str, line: usize) -> Self {
Self::bare(Some(dot), VarName::from_str_and_line(name, line))
}
pub const fn bare(dot: Option<Token>, name: VarName) -> Self {
Self::new(dot, name, None, Type::Uninited)
}
pub fn is_const(&self) -> bool {
self.name.is_const()
}
pub const fn vis(&self) -> Visibility {
match &self.dot {
Some(_) => Visibility::Public,
None => Visibility::Private,
}
}
pub const fn inspect(&self) -> &Str {
&self.name.inspect()
}
pub fn is_procedural(&self) -> bool {
self.name.is_procedural()
}
}
#[derive(Debug, Clone)]
pub struct Attribute {
pub obj: Box<Expr>,
pub name: Token,
pub ident: Identifier,
t: Type,
}
impl NestedDisplay for Attribute {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
if self.t != Type::Uninited {
write!(f, "({}).{}(: {})", self.obj, self.name.content, self.t)
write!(f, "({}){}(: {})", self.obj, self.ident, self.t)
} else {
write!(f, "({}).{}", self.obj, self.name.content)
write!(f, "({}){}", self.obj, self.ident)
}
}
}
impl_display_from_nested!(Attribute);
impl_locational!(Attribute, obj, name);
impl_locational!(Attribute, obj, ident);
impl_t!(Attribute);
impl Attribute {
pub fn new(obj: Expr, name: Token, t: Type) -> Self {
pub fn new(obj: Expr, ident: Identifier, t: Type) -> Self {
Self {
obj: Box::new(obj),
name,
ident,
t,
}
}
@ -471,29 +474,32 @@ impl Subscript {
#[derive(Debug, Clone)]
pub enum Accessor {
Local(Local),
Public(Public),
Ident(Identifier),
Attr(Attribute),
TupleAttr(TupleAttribute),
Subscr(Subscript),
}
impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_nested_display_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_display_from_nested!(Accessor);
impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_locational_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl Accessor {
pub const fn local(symbol: Token, t: Type) -> Self {
Self::Local(Local::new(symbol, None, t))
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::private_with_line(name, line))
}
pub const fn public(dot: Token, name: Token, t: Type) -> Self {
Self::Public(Public::new(dot, name, None, t))
pub fn public_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::public_with_line(Token::dummy(), name, line))
}
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
Self::Attr(Attribute::new(obj, name, t))
pub const fn private(name: Token, t: Type) -> Self {
Self::Ident(Identifier::new(None, VarName::new(name), None, t))
}
pub fn attr(obj: Expr, ident: Identifier, t: Type) -> Self {
Self::Attr(Attribute::new(obj, ident, t))
}
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
@ -502,14 +508,13 @@ impl Accessor {
pub fn show(&self) -> String {
match self {
Self::Local(local) => readable_name(local.inspect()).to_string(),
Self::Public(public) => readable_name(public.inspect()).to_string(),
Self::Ident(ident) => readable_name(ident.inspect()).to_string(),
Self::Attr(attr) => {
attr.obj
.show_acc()
.unwrap_or_else(|| attr.obj.ref_t().to_string())
+ "."
+ readable_name(attr.name.inspect())
+ "." // TODO: visibility
+ readable_name(attr.ident.inspect())
}
Self::TupleAttr(t_attr) => {
t_attr
@ -526,8 +531,7 @@ impl Accessor {
// 参照するオブジェクト自体が持っている固有の名前
pub fn __name__(&self) -> Option<&str> {
match self {
Self::Local(local) => local.__name__().map(|s| &s[..]),
Self::Public(public) => public.__name__().map(|s| &s[..]),
Self::Ident(ident) => ident.__name__.as_ref().map(|s| &s[..]),
_ => None,
}
}
@ -1260,19 +1264,6 @@ impl DefBody {
pub const fn new(op: Token, block: Block, id: DefId) -> Self {
Self { op, block, id }
}
pub fn is_type(&self) -> bool {
match self.block.first().unwrap() {
Expr::Call(call) => {
if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() {
&local.inspect()[..] == "Type"
} else {
false
}
}
_ => false,
}
}
}
#[derive(Debug, Clone)]

View file

@ -271,7 +271,7 @@ impl ASTLowerer {
fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
log!(info "entered {}({acc})", fn_name!());
match acc {
ast::Accessor::Local(local) => {
/*ast::Accessor::Local(local) => {
// `match` is an untypable special form
// `match`は型付け不可能な特殊形式
let (t, __name__) = if &local.inspect()[..] == "match" {
@ -279,29 +279,23 @@ impl ASTLowerer {
} else {
(
self.ctx
.rec_get_var_t(&local.symbol, Private, &self.ctx.name)?,
.rec_get_var_t(&local.symbol, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&local.symbol),
)
};
let acc = hir::Accessor::Local(hir::Local::new(local.symbol, __name__, t));
Ok(acc)
}
ast::Accessor::Public(public) => {
let (t, __name__) = (
self.ctx
.rec_get_var_t(&public.symbol, Public, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&public.symbol),
);
let public = hir::Public::new(public.dot, public.symbol, __name__, t);
let acc = hir::Accessor::Public(public);
}*/
ast::Accessor::Ident(ident) => {
let ident = self.lower_ident(ident)?;
let acc = hir::Accessor::Ident(ident);
Ok(acc)
}
ast::Accessor::Attr(attr) => {
let obj = self.lower_expr(*attr.obj)?;
let t = self
.ctx
.rec_get_attr_t(&obj, &attr.name.symbol, &self.ctx.name)?;
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, attr.name.symbol, t));
let t = self.ctx.rec_get_attr_t(&obj, &attr.ident, &self.ctx.name)?;
let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, ident, t));
Ok(acc)
}
ast::Accessor::TupleAttr(t_attr) => {
@ -329,6 +323,19 @@ impl ASTLowerer {
}
}
fn lower_ident(&self, ident: ast::Identifier) -> LowerResult<hir::Identifier> {
let (t, __name__) = if ident.vis().is_private() && &ident.inspect()[..] == "match" {
(Type::Failure, None)
} else {
(
self.ctx.rec_get_var_t(&ident, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(ident.name.token()),
)
};
let ident = hir::Identifier::new(ident.dot, ident.name, __name__, t);
Ok(ident)
}
fn lower_bin(&mut self, bin: ast::BinOp) -> LowerResult<hir::BinOp> {
log!(info "entered {}({bin})", fn_name!());
let mut args = bin.args.into_iter();
@ -376,7 +383,17 @@ impl ASTLowerer {
&hir_args.kw_args,
&self.ctx.name,
)?;
Ok(hir::Call::new(obj, call.method_name, hir_args, sig_t))
let method_name = if let Some(method_name) = call.method_name {
Some(hir::Identifier::new(
method_name.dot,
method_name.name,
None,
Type::Uninited,
))
} else {
None
};
Ok(hir::Call::new(obj, method_name, hir_args, sig_t))
}
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
@ -406,6 +423,7 @@ impl ASTLowerer {
&self.ctx.name,
)?;
let args = hir::Args::new(args, None, vec![], None);
let method_name = hir::Identifier::bare(method_name.dot, method_name.name);
Ok(hir::Call::new(class, Some(method_name), args, sig_t))
}
@ -540,7 +558,8 @@ impl ASTLowerer {
}
_other => {}
}
let sig = hir::VarSignature::new(ident.clone(), found_body_t.clone());
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
let sig = hir::VarSignature::new(ident, found_body_t.clone());
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Var(sig), body))
}
@ -579,7 +598,8 @@ impl ASTLowerer {
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let sig = hir::SubrSignature::new(sig.ident, sig.params, t);
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}

View file

@ -186,26 +186,15 @@ impl OwnershipChecker {
fn check_acc(&mut self, acc: &Accessor, ownership: Ownership) {
match acc {
Accessor::Local(local) => {
self.check_if_dropped(local.inspect(), local.loc());
Accessor::Ident(ident) => {
self.check_if_dropped(ident.inspect(), ident.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
local.inspect(),
local.ln_begin().unwrap_or(0)
ident.inspect(),
ident.ln_begin().unwrap_or(0)
);
self.drop(local.inspect(), acc.loc());
}
}
Accessor::Public(public) => {
self.check_if_dropped(public.inspect(), public.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
public.inspect(),
public.ln_begin().unwrap_or(0)
);
self.drop(public.inspect(), acc.loc());
self.drop(ident.inspect(), acc.loc());
}
}
Accessor::Attr(attr) => {

View file

@ -226,107 +226,26 @@ impl Args {
}
}
/// represents a local (private) variable
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Local {
pub symbol: Token,
}
impl NestedDisplay for Local {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{}", self.symbol.content)
}
}
impl_display_from_nested!(Local);
impl_locational!(Local, symbol);
impl Local {
pub const fn new(symbol: Token) -> Self {
Self { symbol }
}
pub fn static_dummy(name: &'static str) -> Self {
Self::new(Token::static_symbol(name))
}
pub fn dummy(name: &str) -> Self {
Self::new(Token::symbol(name))
}
pub fn dummy_with_line(name: &str, line: usize) -> Self {
Self::new(Token::new(TokenKind::Symbol, Str::rc(name), line, 0))
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
pub const fn inspect(&self) -> &Str {
&self.symbol.content
}
pub fn is_const(&self) -> bool {
self.symbol.inspect().chars().next().unwrap().is_uppercase()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Public {
pub dot: Token,
pub symbol: Token,
}
impl NestedDisplay for Public {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, ".{}", self.symbol.content)
}
}
impl_display_from_nested!(Public);
impl_locational!(Public, dot, symbol);
impl Public {
pub const fn new(dot: Token, symbol: Token) -> Self {
Self { dot, symbol }
}
pub fn dummy(name: &'static str) -> Self {
Self::new(
Token::from_str(TokenKind::Dot, "."),
Token::from_str(TokenKind::Symbol, name),
)
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
pub const fn inspect(&self) -> &Str {
&self.symbol.content
}
pub fn is_const(&self) -> bool {
self.symbol.inspect().chars().next().unwrap().is_uppercase()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attribute {
pub obj: Box<Expr>,
pub vis: Token,
pub name: Local,
pub ident: Identifier,
}
impl NestedDisplay for Attribute {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "({}){}{}", self.obj, self.vis.inspect(), self.name)
write!(f, "({}){}", self.obj, self.ident)
}
}
impl_display_from_nested!(Attribute);
impl_locational!(Attribute, obj, name);
impl_locational!(Attribute, obj, ident);
impl Attribute {
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
pub fn new(obj: Expr, ident: Identifier) -> Self {
Self {
obj: Box::new(obj),
vis,
name,
ident,
}
}
}
@ -382,28 +301,27 @@ impl Subscript {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Accessor {
Local(Local),
Public(Public),
Ident(Identifier),
Attr(Attribute),
TupleAttr(TupleAttribute),
Subscr(Subscript),
}
impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_nested_display_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_display_from_nested!(Accessor);
impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_locational_for_enum!(Accessor; Ident Attr, TupleAttr, Subscr);
impl Accessor {
pub const fn local(symbol: Token) -> Self {
Self::Local(Local::new(symbol))
Self::Ident(Identifier::new(None, VarName::new(symbol)))
}
pub const fn public(dot: Token, symbol: Token) -> Self {
Self::Public(Public::new(dot, symbol))
Self::Ident(Identifier::new(Some(dot), VarName::new(symbol)))
}
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self {
Self::Attr(Attribute::new(obj, vis, name))
pub fn attr(obj: Expr, ident: Identifier) -> Self {
Self::Attr(Attribute::new(obj, ident))
}
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
@ -416,19 +334,17 @@ impl Accessor {
pub const fn name(&self) -> Option<&Str> {
match self {
Self::Local(local) => Some(local.inspect()),
Self::Public(local) => Some(local.inspect()),
Self::Ident(ident) => Some(ident.inspect()),
_ => None,
}
}
pub fn is_const(&self) -> bool {
match self {
Self::Local(local) => local.is_const(),
Self::Public(public) => public.is_const(),
Self::Ident(ident) => ident.is_const(),
Self::Subscr(subscr) => subscr.obj.is_const_acc(),
Self::TupleAttr(attr) => attr.obj.is_const_acc(),
Self::Attr(attr) => attr.obj.is_const_acc() && attr.name.is_const(),
Self::Attr(attr) => attr.obj.is_const_acc() && attr.ident.is_const(),
}
}
}
@ -494,7 +410,7 @@ pub struct ArrayComprehension {
pub l_sqbr: Token,
pub r_sqbr: Token,
pub elem: Box<Expr>,
pub generators: Vec<(Local, Expr)>,
pub generators: Vec<(Identifier, Expr)>,
pub guards: Vec<Expr>,
}
@ -522,7 +438,7 @@ impl ArrayComprehension {
l_sqbr: Token,
r_sqbr: Token,
elem: Expr,
generators: Vec<(Local, Expr)>,
generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>,
) -> Self {
Self {
@ -1773,8 +1689,8 @@ pub struct Identifier {
pub name: VarName,
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl NestedDisplay for Identifier {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match &self.dot {
Some(_dot) => write!(f, ".{}", self.name),
None => write!(f, "::{}", self.name),
@ -1782,6 +1698,8 @@ impl fmt::Display for Identifier {
}
}
impl_display_from_nested!(Identifier);
impl Locational for Identifier {
fn loc(&self) -> Location {
if let Some(dot) = &self.dot {

View file

@ -12,7 +12,7 @@ use erg_common::{enum_unwrap, get_hash, set};
use crate::ast::{
Accessor, Args, Array, BinOp, Block, Call, DataPack, Def, DefBody, DefId, Expr, Identifier,
KwArg, Lambda, LambdaSignature, Literal, Local, Methods, Module, NormalArray, NormalRecord,
KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NormalArray, NormalRecord,
NormalTuple, ParamPattern, ParamSignature, Params, PosArg, Record, RecordAttrs,
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
@ -79,7 +79,7 @@ impl Desugarer {
} else {
self.gen_match_call(previous, def)
};
let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Local:(_))).inspect();
let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Ident:(_))).inspect();
// FIXME: multiple params
let param = VarName::new(Token::new(
TokenKind::Symbol,
@ -279,12 +279,12 @@ impl Desugarer {
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
}
BufIndex::Record(attr) => {
let ident = Identifier::new(
Some(Token::from_str(TokenKind::Dot, ".")),
VarName::new(Token::symbol_with_line(attr, sig.ln_begin().unwrap())),
);
// TODO: visibility
Accessor::attr(
obj,
Token::from_str(TokenKind::Dot, "."),
Local::dummy_with_line(attr, sig.ln_begin().unwrap()),
)
Accessor::attr(obj, ident)
}
};
let id = DefId(get_hash(&(&acc, buf_name)));

View file

@ -56,7 +56,7 @@ pub enum ArrayInner {
WithLength(PosArg, Expr),
Comprehension {
elem: PosArg,
generators: Vec<(Local, Expr)>,
generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>,
},
}
@ -408,8 +408,8 @@ impl Parser {
let token = self.lpop();
match token.kind {
Symbol => {
let attr = Local::new(token);
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
let ident = Identifier::new(Some(vis), VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), ident);
}
NatLit => {
let attr = Literal::from(token);
@ -434,8 +434,8 @@ impl Parser {
let token = self.lpop();
match token.kind {
Symbol => {
let attr = Local::new(token);
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
let ident = Identifier::new(None, VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), ident);
}
// DataPack
LBrace => {
@ -492,8 +492,8 @@ impl Parser {
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Local(local)) => {
let local = ConstLocal::new(local.symbol);
Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
}
// TODO: App, Array, Record, BinOp, UnaryOp,
@ -744,8 +744,8 @@ impl Parser {
// TODO: type specification
debug_power_assert!(self.cur_is(Walrus));
self.skip();
let kw = if let Accessor::Local(n) = acc {
n.symbol
let kw = if let Accessor::Ident(n) = acc {
n.name.into_token()
} else {
self.next_expr();
self.level -= 1;
@ -789,8 +789,8 @@ impl Parser {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
debug_power_assert!(self.cur_is(Walrus));
self.skip();
let keyword = if let Accessor::Local(n) = acc {
n.symbol
let keyword = if let Accessor::Ident(n) = acc {
n.name.into_token()
} else {
self.next_expr();
self.level -= 1;
@ -984,7 +984,8 @@ impl Parser {
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else {
let acc = Accessor::attr(obj, vis, Local::new(symbol));
let ident = Identifier::new(None, VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
}
}
@ -1043,7 +1044,8 @@ impl Parser {
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else {
let acc = Accessor::attr(obj, vis, Local::new(symbol));
let ident = Identifier::new(Some(vis), VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
}
}
@ -1198,7 +1200,8 @@ impl Parser {
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else {
let acc = Accessor::attr(obj, vis, Local::new(symbol));
let ident = Identifier::new(Some(vis), VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
}
}
@ -1385,23 +1388,8 @@ impl Parser {
if let Some(res) = self.opt_reduce_args() {
let args = res.map_err(|_| self.stack_dec())?;
let (obj, method_name) = match acc {
Accessor::Attr(attr) => {
if attr.vis.is(Dot) {
(
*attr.obj,
Some(Identifier::new(
Some(attr.vis),
VarName::new(attr.name.symbol),
)),
)
} else {
(
*attr.obj,
Some(Identifier::new(None, VarName::new(attr.name.symbol))),
)
}
}
Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None),
Accessor::Attr(attr) => (*attr.obj, Some(attr.ident)),
Accessor::Ident(ident) => (Expr::Accessor(Accessor::Ident(ident)), None),
_ => todo!(),
};
let call = Call::new(obj, method_name, args);
@ -1547,10 +1535,7 @@ impl Parser {
) -> ParseResult<ShortenedRecord> {
debug_call_info!(self);
let first = match first {
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
Accessor::Public(public) => {
Identifier::new(Some(public.dot), VarName::new(public.symbol))
}
Accessor::Ident(ident) => ident,
other => todo!("{other}"), // syntax error
};
let mut idents = vec![first];
@ -1577,10 +1562,7 @@ impl Parser {
Some(_) => {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
let acc = match acc {
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
Accessor::Public(public) => {
Identifier::new(Some(public.dot), VarName::new(public.symbol))
}
Accessor::Ident(ident) => ident,
other => todo!("{other}"), // syntax error
};
idents.push(acc);
@ -1716,16 +1698,8 @@ impl Parser {
fn convert_accessor_to_var_sig(&mut self, _accessor: Accessor) -> ParseResult<VarSignature> {
debug_call_info!(self);
match _accessor {
Accessor::Local(local) => {
let pat = VarPattern::Ident(Identifier::new(None, VarName::new(local.symbol)));
self.level -= 1;
Ok(VarSignature::new(pat, None))
}
Accessor::Public(public) => {
let pat = VarPattern::Ident(Identifier::new(
Some(public.dot),
VarName::new(public.symbol),
));
Accessor::Ident(ident) => {
let pat = VarPattern::Ident(ident);
self.level -= 1;
Ok(VarSignature::new(pat, None))
}
@ -1866,10 +1840,7 @@ impl Parser {
fn convert_accessor_to_ident(&mut self, _accessor: Accessor) -> ParseResult<Identifier> {
debug_call_info!(self);
let ident = match _accessor {
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
Accessor::Public(public) => {
Identifier::new(Some(public.dot), VarName::new(public.symbol))
}
Accessor::Ident(ident) => ident,
other => {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
@ -1922,15 +1893,15 @@ impl Parser {
) -> ParseResult<ParamSignature> {
debug_call_info!(self);
match expr {
Expr::Accessor(Accessor::Local(local)) => {
if &local.inspect()[..] == "self" && !allow_self {
Expr::Accessor(Accessor::Ident(ident)) => {
if &ident.inspect()[..] == "self" && !allow_self {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, local.loc());
let err = ParseError::simple_syntax_error(line!() as usize, ident.loc());
self.errs.push(err);
return Err(());
}
let name = VarName::new(local.symbol);
let pat = ParamPattern::VarName(name);
// FIXME deny: public
let pat = ParamPattern::VarName(ident.name);
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
@ -1978,18 +1949,18 @@ impl Parser {
Expr::UnaryOp(unary) => match unary.op.kind {
TokenKind::RefOp => {
let var = unary.args.into_iter().next().unwrap();
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Local:(_)))
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::Ref(VarName::new(var.symbol));
let pat = ParamPattern::Ref(var.name);
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
}
TokenKind::RefMutOp => {
let var = unary.args.into_iter().next().unwrap();
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Local:(_)))
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::RefMut(VarName::new(var.symbol));
let pat = ParamPattern::RefMut(var.name);
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
@ -2201,10 +2172,9 @@ impl Parser {
) -> ParseResult<PreDeclTypeSpec> {
debug_call_info!(self);
let t_spec = match accessor {
Accessor::Local(local) => PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
VarName::new(local.symbol),
ConstArgs::empty(),
)),
Accessor::Ident(ident) => {
PreDeclTypeSpec::Simple(SimpleTypeSpec::new(ident.name, ConstArgs::empty()))
}
other => todo!("{other}"),
};
self.level -= 1;