Impl: variable visibility

This commit is contained in:
Shunsuke Shibayama 2022-08-22 23:15:07 +09:00
parent a6f9e89ffc
commit 20aaf6a53e
14 changed files with 620 additions and 309 deletions

View file

@ -18,6 +18,45 @@ use crate::ty::{fresh_varname, ConstSubr, Predicate, TyParam, Type};
use crate::{fmt_iter, impl_display_from_debug, switch_lang}; use crate::{fmt_iter, impl_display_from_debug, switch_lang};
use crate::{RcArray, Str}; use crate::{RcArray, Str};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
Private,
Public,
}
impl Visibility {
pub const fn is_public(&self) -> bool {
matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
}
/// same structure as `Identifier`, but only for Record fields.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field {
vis: Visibility,
symbol: Str,
}
impl fmt::Display for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.vis == Visibility::Public {
write!(f, ".{}", self.symbol)
} else {
write!(f, "{}", self.symbol)
}
}
}
impl Field {
pub const fn new(vis: Visibility, symbol: Str) -> Self {
Field { vis, symbol }
}
}
/// 値オブジェクト /// 値オブジェクト
/// コンパイル時評価ができ、シリアライズも可能 /// コンパイル時評価ができ、シリアライズも可能
#[derive(Clone, PartialEq, Default)] #[derive(Clone, PartialEq, Default)]
@ -29,7 +68,7 @@ pub enum ValueObj {
Bool(bool), Bool(bool),
Array(Rc<[ValueObj]>), Array(Rc<[ValueObj]>),
Dict(Rc<[(ValueObj, ValueObj)]>), Dict(Rc<[(ValueObj, ValueObj)]>),
Record(Dict<Str, ValueObj>), Record(Dict<Field, ValueObj>),
Code(Box<CodeObj>), Code(Box<CodeObj>),
Subr(ConstSubr), Subr(ConstSubr),
Type(Box<Type>), Type(Box<Type>),

View file

@ -19,7 +19,7 @@ use erg_common::{
}; };
use Opcode::*; use Opcode::*;
use erg_parser::ast::{ParamPattern, Params, VarPattern}; use erg_parser::ast::{Identifier, ParamPattern, Params, VarName, VarPattern};
use erg_parser::token::{Token, TokenCategory, TokenKind}; use erg_parser::token::{Token, TokenCategory, TokenKind};
use crate::compile::{AccessKind, Name, StoreLoadKind}; use crate::compile::{AccessKind, Name, StoreLoadKind};
@ -29,12 +29,162 @@ use crate::hir::{
}; };
use AccessKind::*; use AccessKind::*;
fn obj_name(obj: &Expr) -> Option<String> { fn is_python_global(name: &str) -> bool {
match obj { match name {
Expr::Accessor(Accessor::Local(n)) => Some(n.inspect().to_string()), "ArithmeticError"
Expr::Accessor(Accessor::Attr(a)) => Some(obj_name(&a.obj)? + "." + a.name.inspect()), | "AssertionError"
Expr::Accessor(Accessor::SelfDot(n)) => Some(format!(".{}", n.inspect())), | "AttributeError"
_ => None, | "BaseException"
| "BlockingIOError"
| "BrokenPipeError"
| "BufferError"
| "BytesWarning"
| "ChildProcessError"
| "ConnectionAbortedError"
| "ConnectionError"
| "ConnectionRefusedError"
| "ConnectionResetError"
| "DeprecationWarning"
| "EOFError"
| "Ellipsis"
| "EncodingWarning"
| "EnvironmentError"
| "Exception"
| "False"
| "FileExistsError"
| "FileNotFoundError"
| "FloatingPointError"
| "FutureWarning"
| "GeneratorExit"
| "IOError"
| "ImportError"
| "ImportWarning"
| "IndentationError"
| "IndexError"
| "InterruptedError"
| "IsADirectoryError"
| "KeyError"
| "KeyboardInterrupt"
| "LookupError"
| "MemoryError"
| "ModuleNotFoundError"
| "NameError"
| "None"
| "NotADirectoryError"
| "NotImplemented"
| "NotImplementedError"
| "OSError"
| "OverflowError"
| "PendingDeprecationWarning"
| "PermissionError"
| "ProcessLookupError"
| "RecursionError"
| "ReferenceError"
| "ResourceWarning"
| "RuntimeError"
| "RuntimeWarning"
| "StopAsyncIteration"
| "StopIteration"
| "SyntaxError"
| "SyntaxWarning"
| "SystemError"
| "SystemExit"
| "TabError"
| "TimeoutError"
| "True"
| "TypeError"
| "UnboundLocalError"
| "UnicodeDecodeError"
| "UnicodeEncodeError"
| "UnicodeError"
| "UnicodeTranslateError"
| "UnicodeWarning"
| "UserWarning"
| "ValueError"
| "Warning"
| "WindowsError"
| "ZeroDivisionError"
| "__build__class__"
| "__debug__"
| "__doc__"
| "__import__"
| "__loader__"
| "__name__"
| "__package__"
| "__spec__"
| "__annotations__"
| "__builtins__"
| "abs"
| "aiter"
| "all"
| "any"
| "anext"
| "ascii"
| "bin"
| "bool"
| "breakpoint"
| "bytearray"
| "bytes"
| "callable"
| "chr"
| "classmethod"
| "compile"
| "complex"
| "delattr"
| "dict"
| "dir"
| "divmod"
| "enumerate"
| "eval"
| "exec"
| "filter"
| "float"
| "format"
| "frozenset"
| "getattr"
| "globals"
| "hasattr"
| "hash"
| "help"
| "hex"
| "id"
| "input"
| "int"
| "isinstance"
| "issubclass"
| "iter"
| "len"
| "list"
| "locals"
| "map"
| "max"
| "memoryview"
| "min"
| "next"
| "object"
| "oct"
| "open"
| "ord"
| "pow"
| "print"
| "property"
| "range"
| "repr"
| "reversed"
| "round"
| "set"
| "setattr"
| "slice"
| "sorted"
| "staticmethod"
| "str"
| "sum"
| "super"
| "tuple"
| "type"
| "vars"
| "zip" => true,
_ => false,
} }
} }
@ -76,11 +226,16 @@ fn convert_to_python_name(name: Str) -> Str {
} }
} }
fn escape_name(name: Str) -> Str { fn escape_name(ident: Identifier) -> Str {
let mut name = convert_to_python_name(name).to_string(); let vis = ident.vis();
name = name.replace('!', "__erg_proc__"); let mut name = convert_to_python_name(ident.name.into_token().content).to_string();
name = name.replace('$', "__erg_shared__"); name = name.replace('!', "__erg_proc");
Str::rc(&name) name = name.replace('$', "__erg_shared");
if vis.is_public() || is_python_global(&name) {
Str::rc(&name)
} else {
Str::from("__".to_string() + &name)
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -324,9 +479,9 @@ impl CodeGenerator {
Some(StoreLoadKind::Global) Some(StoreLoadKind::Global)
} }
fn register_name(&mut self, name: Str) -> Name { fn register_name(&mut self, ident: Identifier) -> Name {
let current_is_toplevel = self.cur_block() == self.toplevel_block(); let current_is_toplevel = self.cur_block() == self.toplevel_block();
let name = escape_name(name); let name = escape_name(ident);
match self.rec_search(&name) { match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => { Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
let st = if current_is_toplevel { let st = if current_is_toplevel {
@ -371,10 +526,10 @@ impl CodeGenerator {
Name::local(self.cur_block_codeobj().names.len() - 1) Name::local(self.cur_block_codeobj().names.len() - 1)
} }
fn emit_load_name_instr(&mut self, name: Str) -> CompileResult<()> { fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
let name = self let name = self
.local_search(&name, Name) .local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(name)); .unwrap_or_else(|| self.register_name(ident));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -427,10 +582,10 @@ impl CodeGenerator {
Ok(()) Ok(())
} }
fn emit_store_instr(&mut self, name: Str, acc_kind: AccessKind) { fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
let name = self let name = self
.local_search(&name, acc_kind) .local_search(ident.inspect(), acc_kind)
.unwrap_or_else(|| self.register_name(name)); .unwrap_or_else(|| self.register_name(ident));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast => Opcode::STORE_FAST, StoreLoadKind::Fast => Opcode::STORE_FAST,
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT, StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
@ -492,11 +647,11 @@ impl CodeGenerator {
.collect() .collect()
} }
fn emit_var_pat(&mut self, pat: &VarPattern, op: &Token) { fn emit_var_pat(&mut self, pat: VarPattern, op: &Token) {
match pat { match pat {
VarPattern::Local(var) => { VarPattern::Ident(ident) => {
if op.category_is(TokenCategory::DefOp) { if op.category_is(TokenCategory::DefOp) {
self.emit_store_instr(var.inspect().clone(), Name); self.emit_store_instr(ident, Name);
} else { } else {
todo!() todo!()
} }
@ -507,8 +662,8 @@ impl CodeGenerator {
self.write_instr(UNPACK_SEQUENCE); self.write_instr(UNPACK_SEQUENCE);
self.write_arg(a.len() as u8); self.write_arg(a.len() as u8);
self.stack_inc_n(a.len() - 1); self.stack_inc_n(a.len() - 1);
for sig in a.iter() { for sig in a.into_iter() {
self.emit_var_pat(&sig.pat, op); self.emit_var_pat(sig.pat, op);
} }
} else { } else {
switch_unreachable!() switch_unreachable!()
@ -522,17 +677,20 @@ impl CodeGenerator {
self.write_instr(Opcode::LOAD_BUILD_CLASS); self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0); self.write_arg(0);
self.stack_inc(); self.stack_inc();
let name = sig.inspect().unwrap(); let ident = match sig.pat {
let code = self.codegen_typedef_block(name.clone(), body.block); VarPattern::Ident(ident) => ident,
_ => todo!(),
};
let code = self.codegen_typedef_block(ident.inspect().clone(), body.block);
self.emit_load_const(code); self.emit_load_const(code);
self.emit_load_const(name.clone()); self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION); self.write_instr(Opcode::MAKE_FUNCTION);
self.write_arg(0); self.write_arg(0);
self.emit_load_const(name.clone()); self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::CALL_FUNCTION); self.write_instr(Opcode::CALL_FUNCTION);
self.write_arg(2); self.write_arg(2);
self.stack_dec_n((1 + 2) - 1); self.stack_dec_n((1 + 2) - 1);
self.emit_store_instr(name.clone(), Name); self.emit_store_instr(ident, Name);
} }
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) { fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
@ -544,11 +702,11 @@ impl CodeGenerator {
} else { } else {
self.codegen_frameless_block(body.block, vec![]); self.codegen_frameless_block(body.block, vec![]);
} }
self.emit_var_pat(&sig.pat, &body.op); self.emit_var_pat(sig.pat, &body.op);
} }
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) { fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) {
let name = sig.name.inspect().clone(); let name = sig.ident.inspect().clone();
let mut opcode_flag = 0u8; let mut opcode_flag = 0u8;
let params = self.gen_param_names(&sig.params); let params = self.gen_param_names(&sig.params);
let code = self.codegen_block(body.block, Some(name.clone()), params); let code = self.codegen_block(body.block, Some(name.clone()), params);
@ -568,7 +726,7 @@ impl CodeGenerator {
self.write_arg(opcode_flag); self.write_arg(opcode_flag);
// stack_dec: <code obj> + <name> -> <function> // stack_dec: <code obj> + <name> -> <function>
self.stack_dec(); self.stack_dec();
self.emit_store_instr(name, Name); self.emit_store_instr(sig.ident, Name);
} }
fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> { fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> {
@ -687,7 +845,8 @@ impl CodeGenerator {
let mut pop_jump_points = vec![]; let mut pop_jump_points = vec![];
match pat { match pat {
ParamPattern::VarName(name) => { ParamPattern::VarName(name) => {
self.emit_store_instr(name.inspect().clone(), AccessKind::Name); let ident = Identifier::new(None, name);
self.emit_store_instr(ident, AccessKind::Name);
} }
ParamPattern::Lit(lit) => { ParamPattern::Lit(lit) => {
self.emit_load_const(ValueObj::from(&lit)); self.emit_load_const(ValueObj::from(&lit));
@ -735,15 +894,16 @@ impl CodeGenerator {
Ok(pop_jump_points) Ok(pop_jump_points)
} }
fn emit_call_name(&mut self, name: Str, mut args: Args) -> CompileResult<()> { fn emit_call_special(&mut self, name: VarName, mut args: Args) -> CompileResult<()> {
match &name[..] { match &name.inspect()[..] {
"assert" => self.emit_assert_instr(args), "assert" => self.emit_assert_instr(args),
"discard" => self.emit_discard_instr(args), "discard" => self.emit_discard_instr(args),
"for" | "for!" => self.emit_for_instr(args), "for" | "for!" => self.emit_for_instr(args),
"if" | "if!" => self.emit_if_instr(args), "if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true), "match" | "match!" => self.emit_match_instr(args, true),
_ => { _ => {
self.emit_load_name_instr(name).unwrap_or_else(|e| { let ident = Identifier::new(None, name);
self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.errs.push(e); self.errs.push(e);
}); });
let argc = args.len(); let argc = args.len();
@ -772,66 +932,20 @@ impl CodeGenerator {
} }
} }
fn emit_call_method(&mut self, obj: Expr, name: Str, mut args: Args, is_static: bool) { fn emit_call(&mut self, obj: Expr, method_name: Option<Token>, mut args: Args) {
if is_static { let class = Str::rc(obj.ref_t().name()); // これは必ずmethodのあるクラスになっている
self.emit_load_name_instr(name).unwrap_or_else(|err| { let uniq_obj_name = obj.__name__().map(Str::rc);
self.codegen_expr(obj);
if let Some(method_name) = method_name {
self.emit_load_method_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
method_name.content,
)
.unwrap_or_else(|err| {
self.errs.push(err); self.errs.push(err);
}); });
let argc = args.len();
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
1
} else {
self.write_instr(CALL_FUNCTION);
0
};
self.write_arg(1 + argc as u8);
// (1 (method as subroutine) + 1 (obj) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + 1 + argc + kwsc) - 1);
} else {
let class = Str::rc(obj.ref_t().name());
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[..]), name)
.unwrap_or_else(|err| {
self.errs.push(err);
});
let argc = args.len();
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
1
} else {
self.write_instr(CALL_METHOD);
0
};
self.write_arg(argc as u8);
// (1 (method) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1);
} }
}
fn emit_call_callable_obj(&mut self, obj: Expr, mut args: Args) {
self.codegen_expr(obj);
let argc = args.len(); let argc = args.len();
let mut kws = Vec::with_capacity(args.kw_len()); let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) { while let Some(arg) = args.try_remove_pos(0) {
@ -847,11 +961,11 @@ impl CodeGenerator {
self.write_instr(CALL_FUNCTION_KW); self.write_instr(CALL_FUNCTION_KW);
1 1
} else { } else {
self.write_instr(CALL_FUNCTION); self.write_instr(CALL_METHOD);
0 0
}; };
self.write_arg(argc as u8); self.write_arg(argc as u8);
// (1 (name) + argc + kwsc) objects -> 1 return object // (1 (method) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1); self.stack_dec_n((1 + argc + kwsc) - 1);
} }
@ -912,7 +1026,7 @@ impl CodeGenerator {
self.emit_load_const(lit.data); self.emit_load_const(lit.data);
} }
Expr::Accessor(Accessor::Local(l)) => { Expr::Accessor(Accessor::Local(l)) => {
self.emit_load_name_instr(l.inspect().clone()) self.emit_load_name_instr(Identifier::new(None, VarName::new(l.name)))
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.errs.push(err); self.errs.push(err);
}); });
@ -971,7 +1085,8 @@ impl CodeGenerator {
match &bin.op.kind { match &bin.op.kind {
// l..<r == range(l, r) // l..<r == range(l, r)
TokenKind::RightOpen => { TokenKind::RightOpen => {
self.emit_load_name_instr(Str::ever("range")).unwrap(); self.emit_load_name_instr(Identifier::public("range"))
.unwrap();
} }
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(), TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
_ => {} _ => {}
@ -1034,22 +1149,15 @@ impl CodeGenerator {
_ => {} _ => {}
} }
} }
Expr::Call(call) => { Expr::Call(call) => match *call.obj {
// TODO: unwrap Expr::Accessor(Accessor::Local(local)) => {
let name = Str::from(obj_name(&call.obj).unwrap()); let name = VarName::new(local.name);
match *call.obj { self.emit_call_special(name, call.args).unwrap();
Expr::Accessor(Accessor::Local(_)) => {
self.emit_call_name(name, call.args).unwrap();
}
Expr::Accessor(Accessor::Attr(a)) => {
// TODO: impl static dispatch mode
self.emit_call_method(*a.obj, name, call.args, false);
}
obj => {
self.emit_call_callable_obj(obj, call.args);
}
} }
} obj => {
self.emit_call(obj, call.method_name, call.args);
}
},
// TODO: list comprehension // TODO: list comprehension
Expr::Array(arr) => match arr { Expr::Array(arr) => match arr {
Array::Normal(mut arr) => { Array::Normal(mut arr) => {
@ -1082,7 +1190,7 @@ impl CodeGenerator {
/// forブロックなどで使う /// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) { fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
for param in params { for param in params {
self.emit_store_instr(param, Name); self.emit_store_instr(Identifier::private(param), Name);
} }
for expr in block.into_iter() { for expr in block.into_iter() {
self.codegen_expr(expr); self.codegen_expr(expr);
@ -1106,9 +1214,9 @@ impl CodeGenerator {
)); ));
let mod_name = self.toplevel_block_codeobj().name.clone(); let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name); self.emit_load_const(mod_name);
self.emit_store_instr(Str::from("__module__"), Attr); self.emit_store_instr(Identifier::public("__module__"), Attr);
self.emit_load_const(name); self.emit_load_const(name);
self.emit_store_instr(Str::from("__qualname__"), Attr); self.emit_store_instr(Identifier::public("__qualname__"), Attr);
// TODO: サブルーチンはT.subという書式でSTORE // TODO: サブルーチンはT.subという書式でSTORE
for expr in block.into_iter() { for expr in block.into_iter() {
self.codegen_expr(expr); self.codegen_expr(expr);
@ -1222,7 +1330,8 @@ impl CodeGenerator {
let mut print_point = 0; let mut print_point = 0;
if self.input().is_repl() { if self.input().is_repl() {
print_point = self.cur_block().lasti; print_point = self.cur_block().lasti;
self.emit_load_name_instr(Str::ever("print")).unwrap(); self.emit_load_name_instr(Identifier::public("print"))
.unwrap();
} }
for expr in hir.module.into_iter() { for expr in hir.module.into_iter() {
self.codegen_expr(expr); self.codegen_expr(expr);

View file

@ -15,10 +15,10 @@ use erg_common::ty::{
Constraint, FreeKind, HasLevel, IntervalOp, ParamTy, Predicate, RefinementType, SubrKind, Constraint, FreeKind, HasLevel, IntervalOp, ParamTy, Predicate, RefinementType, SubrKind,
SubrType, TyBound, TyParam, TyParamOrdering, Type, SubrType, TyBound, TyParam, TyParamOrdering, Type,
}; };
use erg_common::value::ValueObj; use erg_common::value::{ValueObj, Visibility};
use erg_common::Str; use erg_common::Str;
use erg_common::{ use erg_common::{
assume_unreachable, enum_unwrap, fmt_slice, fn_name, get_hash, log, set, try_map, assume_unreachable, enum_unwrap, fmt_option, fmt_slice, fn_name, get_hash, log, set, try_map,
}; };
use Predicate as Pred; use Predicate as Pred;
use TyParamOrdering::*; use TyParamOrdering::*;
@ -36,7 +36,7 @@ use crate::error::readable_name;
use crate::error::{binop_to_dname, unaryop_to_dname, TyCheckError, TyCheckErrors, TyCheckResult}; use crate::error::{binop_to_dname, unaryop_to_dname, TyCheckError, TyCheckErrors, TyCheckResult};
use crate::eval::Evaluator; use crate::eval::Evaluator;
use crate::hir; use crate::hir;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind, Visibility}; use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
use Mutability::*; use Mutability::*;
use Visibility::*; use Visibility::*;
@ -777,30 +777,30 @@ impl Context {
opt_t: Option<Type>, opt_t: Option<Type>,
id: Option<DefId>, id: Option<DefId>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
let vis = Private; // TODO:
let muty = Mutability::from(&sig.inspect().unwrap()[..]); let muty = Mutability::from(&sig.inspect().unwrap()[..]);
match &sig.pat { match &sig.pat {
ast::VarPattern::Local(v) => { ast::VarPattern::Ident(ident) => {
if sig.t_spec.is_none() && opt_t.is_none() { if sig.t_spec.is_none() && opt_t.is_none() {
Err(TyCheckError::no_type_spec_error( Err(TyCheckError::no_type_spec_error(
line!() as usize, line!() as usize,
sig.loc(), sig.loc(),
self.caused_by(), self.caused_by(),
v.inspect(), ident.inspect(),
)) ))
} else { } else {
if self.registered(v.inspect(), v.inspect().is_uppercase()) { if self.registered(ident.inspect(), ident.is_const()) {
return Err(TyCheckError::duplicate_decl_error( return Err(TyCheckError::duplicate_decl_error(
line!() as usize, line!() as usize,
sig.loc(), sig.loc(),
self.caused_by(), self.caused_by(),
v.inspect(), ident.inspect(),
)); ));
} }
let vis = ident.vis();
let kind = id.map_or(VarKind::Declared, VarKind::Defined); let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let sig_t = self.instantiate_var_sig_t(sig, opt_t, PreRegister)?; let sig_t = self.instantiate_var_sig_t(sig, opt_t, PreRegister)?;
self.decls self.decls
.insert(v.clone(), VarInfo::new(sig_t, muty, vis, kind)); .insert(ident.name.clone(), VarInfo::new(sig_t, muty, vis, kind));
Ok(()) Ok(())
} }
} }
@ -826,7 +826,8 @@ impl Context {
opt_ret_t: Option<Type>, opt_ret_t: Option<Type>,
id: Option<DefId>, id: Option<DefId>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
let name = sig.name.inspect(); let name = sig.ident.inspect();
let vis = sig.ident.vis();
let muty = Mutability::from(&name[..]); let muty = Mutability::from(&name[..]);
let kind = id.map_or(VarKind::Declared, VarKind::Defined); let kind = id.map_or(VarKind::Declared, VarKind::Defined);
if self.registered(name, name.is_uppercase()) { if self.registered(name, name.is_uppercase()) {
@ -838,7 +839,7 @@ impl Context {
)); ));
} }
let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?; let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?;
let vi = VarInfo::new(t, muty, Private, kind); let vi = VarInfo::new(t, muty, vis, kind);
if let Some(_decl) = self.decls.remove(name) { if let Some(_decl) = self.decls.remove(name) {
return Err(TyCheckError::duplicate_decl_error( return Err(TyCheckError::duplicate_decl_error(
line!() as usize, line!() as usize,
@ -847,7 +848,7 @@ impl Context {
name, name,
)); ));
} else { } else {
self.decls.insert(sig.name.clone(), vi); self.decls.insert(sig.ident.name.clone(), vi);
} }
Ok(()) Ok(())
} }
@ -868,7 +869,6 @@ impl Context {
id: DefId, id: DefId,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
self.validate_var_sig_t(sig, body_t, Normal)?; self.validate_var_sig_t(sig, body_t, Normal)?;
let vis = Private; // TODO:
let muty = Mutability::from(&sig.inspect().unwrap()[..]); let muty = Mutability::from(&sig.inspect().unwrap()[..]);
let (generalized, bounds) = self.generalize_t(body_t.clone()); let (generalized, bounds) = self.generalize_t(body_t.clone());
let generalized = if !bounds.is_empty() { let generalized = if !bounds.is_empty() {
@ -882,24 +882,24 @@ impl Context {
}; };
match &sig.pat { match &sig.pat {
ast::VarPattern::Discard(_token) => Ok(()), ast::VarPattern::Discard(_token) => Ok(()),
ast::VarPattern::Local(v) => { ast::VarPattern::Ident(ident) => {
if self.registered(v.inspect(), v.inspect().is_uppercase()) { if self.registered(ident.inspect(), ident.is_const()) {
Err(TyCheckError::reassign_error( Err(TyCheckError::reassign_error(
line!() as usize, line!() as usize,
v.loc(), ident.loc(),
self.caused_by(), self.caused_by(),
v.inspect(), ident.inspect(),
)) ))
} else { } else {
if self.decls.remove(v.inspect()).is_some() { if self.decls.remove(ident.inspect()).is_some() {
// something to do? // something to do?
} }
let vis = ident.vis();
let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id)); let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id));
self.params.push((Some(v.clone()), vi)); self.params.push((Some(ident.name.clone()), vi));
Ok(()) Ok(())
} }
} }
ast::VarPattern::Public(_) => todo!(),
ast::VarPattern::Array(arr) => { ast::VarPattern::Array(arr) => {
for (elem, inf) in arr.iter().zip(generalized.inner_ts().iter()) { for (elem, inf) in arr.iter().zip(generalized.inner_ts().iter()) {
let id = DefId(get_hash(&(&self.name, elem))); let id = DefId(get_hash(&(&self.name, elem)));
@ -1036,12 +1036,12 @@ impl Context {
id: DefId, id: DefId,
body_t: &Type, body_t: &Type,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
let muty = if sig.name.is_const() { let muty = if sig.ident.is_const() {
Mutability::Const Mutability::Const
} else { } else {
Mutability::Immutable Mutability::Immutable
}; };
let name = &sig.name; let name = &sig.ident.name;
// FIXME: constでない関数 // FIXME: constでない関数
let t = self let t = self
.get_current_scope_var(name.inspect()) .get_current_scope_var(name.inspect())
@ -1070,7 +1070,7 @@ impl Context {
name.inspect(), name.inspect(),
)) ))
} else { } else {
let sub_t = if sig.name.is_procedural() { let sub_t = if sig.ident.is_procedural() {
Type::proc( Type::proc(
non_default_params.clone(), non_default_params.clone(),
default_params.clone(), default_params.clone(),
@ -2617,13 +2617,13 @@ impl Context {
)); ));
} }
} }
ast::VarPattern::Local(n) => { ast::VarPattern::Ident(ident) => {
if self.unify(&spec_t, body_t, None, Some(sig.loc())).is_err() { if self.unify(&spec_t, body_t, None, Some(sig.loc())).is_err() {
return Err(TyCheckError::type_mismatch_error( return Err(TyCheckError::type_mismatch_error(
line!() as usize, line!() as usize,
n.loc(), ident.loc(),
self.caused_by(), self.caused_by(),
n.inspect(), ident.inspect(),
&spec_t, &spec_t,
body_t, body_t,
)); ));
@ -2703,7 +2703,7 @@ impl Context {
None, None,
)?; )?;
} }
Ok(if sig.name.is_procedural() { Ok(if sig.ident.is_procedural() {
Type::proc(non_defaults, defaults, return_t) Type::proc(non_defaults, defaults, return_t)
} else { } else {
Type::func(non_defaults, defaults, return_t) Type::func(non_defaults, defaults, return_t)
@ -3104,17 +3104,35 @@ impl Context {
} }
/// 戻り値ではなく、call全体の型を返す /// 戻り値ではなく、call全体の型を返す
/// objは現時点ではAccessorのみ対応 fn search_callee_t(
/// 受け入れるobj(Accessor)はcheckしてないハリボテ &self,
fn search_call_t(&self, callee: &hir::Expr, namespace: &Str) -> TyCheckResult<Type> { obj: &hir::Expr,
match callee { method_name: &Option<Token>,
hir::Expr::Accessor(hir::Accessor::Local(local)) => { namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() {
for ctx in self.rec_sorted_sup_type_ctxs(obj.ref_t()) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t());
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) {
return Ok(vi.t());
}
}
Err(TyCheckError::no_attr_error(
line!() as usize,
method_name.loc(),
namespace.clone(),
obj.ref_t(),
method_name.inspect(),
self.get_similar_attr(obj.ref_t(), method_name.inspect()),
))
} else {
if obj.ref_t().rec_eq(&ASTOmitted) {
let local = enum_unwrap!(obj, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
self.get_var_t(&local.name, namespace) self.get_var_t(&local.name, namespace)
} else {
Ok(obj.t())
} }
hir::Expr::Accessor(hir::Accessor::Attr(attr)) => {
self.get_attr_t(&attr.obj, &attr.name, namespace)
}
_ => todo!(),
} }
} }
@ -3127,17 +3145,18 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 2); erg_common::debug_power_assert!(args.len() == 2);
let symbol = Token::symbol(binop_to_dname(op.inspect())); let symbol = Token::symbol(binop_to_dname(op.inspect()));
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, Type::ASTOmitted)); let op = hir::Expr::Accessor(hir::Accessor::local(symbol, Type::ASTOmitted));
self.get_call_t(&op, args, &[], namespace).map_err(|e| { self.get_call_t(&op, &None, args, &[], namespace)
// HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする .map_err(|e| {
let core = ErrorCore::new( // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする
e.core.errno, let core = ErrorCore::new(
e.core.kind, e.core.errno,
op.loc(), e.core.kind,
e.core.desc, op.loc(),
e.core.hint, e.core.desc,
); e.core.hint,
TyCheckError::new(core, e.caused_by) );
}) TyCheckError::new(core, e.caused_by)
})
} }
pub(crate) fn get_unaryop_t( pub(crate) fn get_unaryop_t(
@ -3149,40 +3168,45 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 1); erg_common::debug_power_assert!(args.len() == 1);
let symbol = Token::symbol(unaryop_to_dname(op.inspect())); let symbol = Token::symbol(unaryop_to_dname(op.inspect()));
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, Type::ASTOmitted)); let op = hir::Expr::Accessor(hir::Accessor::local(symbol, Type::ASTOmitted));
self.get_call_t(&op, args, &[], namespace).map_err(|e| { self.get_call_t(&op, &None, args, &[], namespace)
let core = ErrorCore::new( .map_err(|e| {
e.core.errno, let core = ErrorCore::new(
e.core.kind, e.core.errno,
op.loc(), e.core.kind,
e.core.desc, op.loc(),
e.core.hint, e.core.desc,
); e.core.hint,
TyCheckError::new(core, e.caused_by) );
}) TyCheckError::new(core, e.caused_by)
})
} }
pub(crate) fn get_call_t( pub(crate) fn get_call_t(
&self, &self,
callee: &hir::Expr, obj: &hir::Expr,
method_name: &Option<Token>,
pos_args: &[hir::PosArg], pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg], kw_args: &[hir::KwArg],
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
match callee { match obj {
hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => { hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => {
return self.get_match_call_t(pos_args, kw_args) return self.get_match_call_t(pos_args, kw_args)
} }
_ => {} _ => {}
} }
let found = self.search_call_t(callee, namespace)?; let found = self.search_callee_t(obj, method_name, namespace)?;
log!("Found:\ncallee: {callee}\nfound: {found}"); log!(
let instance = self.instantiate(found, callee)?; "Found:\ncallee: {obj}{}\nfound: {found}",
fmt_option!(pre ".", method_name.as_ref().map(|t| &t.content))
);
let instance = self.instantiate(found, obj)?;
log!( log!(
"Instantiated:\ninstance: {instance}\npos_args: ({})\nkw_args: ({})", "Instantiated:\ninstance: {instance}\npos_args: ({})\nkw_args: ({})",
fmt_slice(pos_args), fmt_slice(pos_args),
fmt_slice(kw_args) fmt_slice(kw_args)
); );
self.substitute_call(callee, &instance, pos_args, kw_args)?; self.substitute_call(obj, &instance, pos_args, kw_args)?;
log!("Substituted:\ninstance: {instance}"); log!("Substituted:\ninstance: {instance}");
let res = self.deref_tyvar(instance)?; let res = self.deref_tyvar(instance)?;
log!("Derefed:\nres: {res}\n"); log!("Derefed:\nres: {res}\n");
@ -3195,7 +3219,7 @@ impl Context {
log!("Params Evaluated:\nres: {res}\n"); log!("Params Evaluated:\nres: {res}\n");
let res = self.deref_tyvar(res)?; let res = self.deref_tyvar(res)?;
log!("Derefed (2):\nres: {res}\n"); log!("Derefed (2):\nres: {res}\n");
self.propagate(&res, callee)?; self.propagate(&res, obj)?;
log!("Propagated:\nres: {res}\n"); log!("Propagated:\nres: {res}\n");
Ok(res) Ok(res)
} }
@ -4150,6 +4174,7 @@ impl Context {
if name.len() <= 1 { if name.len() <= 1 {
return None; return None;
} }
// TODO: add `.decls`
let most_similar_name = self let most_similar_name = self
.params .params
.iter() .iter()

View file

@ -5,11 +5,12 @@
use erg_common::color::{GREEN, RESET}; use erg_common::color::{GREEN, RESET};
use erg_common::log; use erg_common::log;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_common::value::Visibility;
use erg_common::Str; use erg_common::Str;
use crate::error::{EffectError, EffectErrors, EffectResult}; use crate::error::{EffectError, EffectErrors, EffectResult};
use crate::hir::{Accessor, Def, Expr, Signature, HIR}; use crate::hir::{Accessor, Def, Expr, Signature, HIR};
use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
#[derive(Debug)] #[derive(Debug)]
@ -85,7 +86,7 @@ impl SideEffectChecker {
(Str::ever("::<instant>"), Private) (Str::ever("::<instant>"), Private)
} }
} }
Signature::Subr(subr) => (subr.name.inspect().clone(), Private), Signature::Subr(subr) => (subr.ident.inspect().clone(), Private),
}; };
self.path_stack.push(name_and_vis); self.path_stack.push(name_and_vis);
// TODO: support raw identifier (``) // TODO: support raw identifier (``)

View file

@ -5,9 +5,9 @@ use erg_common::rccell::RcCell;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_common::ty::{OpKind, Predicate, SubrKind, TyBound, TyParam, Type}; use erg_common::ty::{OpKind, Predicate, SubrKind, TyBound, TyParam, Type};
use erg_common::value::ValueObj; use erg_common::value::{Field, ValueObj};
use erg_common::Str;
use erg_common::{fn_name, set}; use erg_common::{fn_name, set};
use erg_common::{RcArray, Str};
use OpKind::*; use OpKind::*;
use erg_parser::ast::*; use erg_parser::ast::*;
@ -181,6 +181,46 @@ impl Evaluator {
None None
} }
fn eval_const_array(&self, arr: &Array, ctx: &Context) -> Option<ValueObj> {
let mut elems = vec![];
match arr {
Array::Normal(arr) => {
for elem in arr.elems.pos_args().iter() {
if let Some(elem) = self.eval_const_expr(&elem.expr, ctx) {
elems.push(elem);
} else {
return None;
}
}
}
_ => {
return None;
}
}
Some(ValueObj::Array(RcArray::from(elems)))
}
fn eval_const_record(&self, _record: &Record, ctx: &Context) -> Option<ValueObj> {
let mut attrs = vec![];
for attr in _record.attrs.iter() {
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
let ident = match &attr.sig {
Signature::Var(var) => match &var.pat {
VarPattern::Ident(ident) => {
Field::new(ident.vis(), ident.inspect().clone())
}
_ => todo!(),
},
_ => todo!(),
};
attrs.push((ident, elem));
} else {
return None;
}
}
Some(ValueObj::Record(attrs.into_iter().collect()))
}
// ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する // ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する
// コンパイル時評価できないならNoneを返す // コンパイル時評価できないならNoneを返す
pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> { pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> {
@ -191,6 +231,8 @@ impl Evaluator {
Expr::UnaryOp(unary) => self.eval_const_unary(unary), Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call, ctx), Expr::Call(call) => self.eval_const_call(call, ctx),
Expr::Def(def) => self.eval_const_def(def), Expr::Def(def) => self.eval_const_def(def),
Expr::Array(arr) => self.eval_const_array(arr, ctx),
Expr::Record(rec) => self.eval_const_record(rec, ctx),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }

View file

@ -4,7 +4,7 @@ use std::fmt;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::traits::{HasType, Locational, NestedDisplay, Stream}; use erg_common::traits::{HasType, Locational, NestedDisplay, Stream};
use erg_common::ty::{Constraint, TyParam, Type}; use erg_common::ty::{Constraint, TyParam, Type};
use erg_common::value::ValueObj; use erg_common::value::{ValueObj, Visibility};
use erg_common::Str; use erg_common::Str;
use erg_common::{ use erg_common::{
impl_display_for_enum, impl_display_from_nested, impl_locational, impl_locational_for_enum, impl_display_for_enum, impl_display_from_nested, impl_locational, impl_locational_for_enum,
@ -12,7 +12,7 @@ use erg_common::{
impl_t, impl_t_for_enum, impl_t, impl_t_for_enum,
}; };
use erg_parser::ast::{fmt_lines, DefId, Params, VarName, VarPattern}; use erg_parser::ast::{fmt_lines, DefId, Identifier, Params, VarPattern};
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use crate::error::readable_name; use crate::error::readable_name;
@ -676,9 +676,9 @@ impl UnaryOp {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Call { pub struct Call {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub method_name: Option<Token>,
pub args: Args, pub args: Args,
/// 全体の型、e.g. `abs(-1)` -> `Neg -> Nat` /// 全体の型(引数自体の型は関係ない)、e.g. `abs(-1)` -> `Neg -> Nat`
/// necessary for mangling
pub sig_t: Type, pub sig_t: Type,
} }
@ -725,9 +725,10 @@ impl Locational for Call {
} }
impl Call { impl Call {
pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self { pub fn new(obj: Expr, method_name: Option<Token>, args: Args, sig_t: Type) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
method_name,
args, args,
sig_t, sig_t,
} }
@ -808,34 +809,38 @@ impl VarSignature {
pub fn inspect(&self) -> Option<&Str> { pub fn inspect(&self) -> Option<&Str> {
self.pat.inspect() self.pat.inspect()
} }
pub fn vis(&self) -> Visibility {
self.pat.vis()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SubrSignature { pub struct SubrSignature {
pub name: VarName, pub ident: Identifier,
pub params: Params, pub params: Params,
pub t: Type, pub t: Type,
} }
impl fmt::Display for SubrSignature { impl fmt::Display for SubrSignature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}{} (: {})", self.name, self.params, self.t) write!(f, "{}{} (: {})", self.ident, self.params, self.t)
} }
} }
impl Locational for SubrSignature { impl Locational for SubrSignature {
fn loc(&self) -> Location { fn loc(&self) -> Location {
Location::concat(&self.name, &self.params) Location::concat(&self.ident, &self.params)
} }
} }
impl SubrSignature { impl SubrSignature {
pub const fn new(name: VarName, params: Params, t: Type) -> Self { pub const fn new(ident: Identifier, params: Params, t: Type) -> Self {
Self { name, params, t } Self { ident, params, t }
} }
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
self.name.is_procedural() self.ident.is_procedural()
} }
} }
@ -892,14 +897,21 @@ impl Signature {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Var(v) => v.pat.is_const(), Self::Var(v) => v.pat.is_const(),
Self::Subr(s) => s.name.is_const(), Self::Subr(s) => s.ident.is_const(),
} }
} }
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
match self { match self {
Self::Var(v) => v.pat.is_procedural(), Self::Var(v) => v.pat.is_procedural(),
Self::Subr(s) => s.name.is_procedural(), Self::Subr(s) => s.ident.is_procedural(),
}
}
pub const fn vis(&self) -> Visibility {
match self {
Self::Var(v) => v.pat.vis(),
Self::Subr(s) => s.ident.vis(),
} }
} }
} }

View file

@ -3,7 +3,7 @@
//! 組み込みオブジェクトの型情報を(Contextに)定義 //! 組み込みオブジェクトの型情報を(Contextに)定義
use erg_common::ty::type_constrs::*; use erg_common::ty::type_constrs::*;
use erg_common::ty::{TyParam, Type}; use erg_common::ty::{TyParam, Type};
use erg_common::value::ValueObj; use erg_common::value::{ValueObj, Visibility};
use erg_common::Str; use erg_common::Str;
use erg_common::{debug_power_assert, set}; use erg_common::{debug_power_assert, set};
use ParamSpec as PS; use ParamSpec as PS;
@ -12,7 +12,7 @@ use Type::*;
use erg_parser::ast::VarName; use erg_parser::ast::VarName;
use crate::context::{ConstTemplate, Context, ContextKind, DefaultInfo, ParamSpec}; use crate::context::{ConstTemplate, Context, ContextKind, DefaultInfo, ParamSpec};
use crate::varinfo::{Mutability, VarInfo, VarKind, Visibility}; use crate::varinfo::{Mutability, VarInfo, VarKind};
use DefaultInfo::*; use DefaultInfo::*;
use Mutability::*; use Mutability::*;
use VarKind::*; use VarKind::*;

View file

@ -6,7 +6,7 @@ use erg_common::error::Location;
use erg_common::get_hash; use erg_common::get_hash;
use erg_common::traits::{HasType, Locational, Stream}; use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ParamTy, TyParam, Type}; use erg_common::ty::{ParamTy, TyParam, Type};
use erg_common::value::ValueObj; use erg_common::value::{ValueObj, Visibility};
use erg_common::{fn_name, log, switch_lang}; use erg_common::{fn_name, log, switch_lang};
use erg_parser::ast; use erg_parser::ast;
@ -16,7 +16,6 @@ use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings}; use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir; use crate::hir;
use crate::hir::HIR; use crate::hir::HIR;
use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
/// Singleton that checks types of an AST, and convert (lower) it into a HIR /// Singleton that checks types of an AST, and convert (lower) it into a HIR
@ -245,10 +244,14 @@ impl ASTLowerer {
)); ));
} }
let obj = self.lower_expr(*call.obj, false)?; let obj = self.lower_expr(*call.obj, false)?;
let t = self let t = self.ctx.get_call_t(
.ctx &obj,
.get_call_t(&obj, &hir_args.pos_args, &hir_args.kw_args, &self.ctx.name)?; &call.method_name,
Ok(hir::Call::new(obj, hir_args, t)) &hir_args.pos_args,
&hir_args.kw_args,
&self.ctx.name,
)?;
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
} }
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> { fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
@ -361,13 +364,13 @@ impl ASTLowerer {
.assign_var(&sig, id, found_body_t)?; .assign_var(&sig, id, found_body_t)?;
match block.first().unwrap() { match block.first().unwrap() {
hir::Expr::Call(call) => { hir::Expr::Call(call) => {
if let ast::VarPattern::Local(name) = &sig.pat { if let ast::VarPattern::Ident(ident) = &sig.pat {
if call.is_import_call() { if call.is_import_call() {
self.ctx self.ctx
.outer .outer
.as_mut() .as_mut()
.unwrap() .unwrap()
.import_mod(name, &call.args.pos_args.first().unwrap().expr)?; .import_mod(&ident.name, &call.args.pos_args.first().unwrap().expr)?;
} }
} else { } else {
todo!() todo!()
@ -392,9 +395,9 @@ impl ASTLowerer {
.outer .outer
.as_ref() .as_ref()
.unwrap() .unwrap()
.get_current_scope_var(sig.name.inspect()) .get_current_scope_var(sig.ident.inspect())
.unwrap_or_else(|| { .unwrap_or_else(|| {
log!("{}\n", sig.name.inspect()); log!("{}\n", sig.ident.inspect());
log!("{}\n", self.ctx.outer.as_ref().unwrap()); log!("{}\n", self.ctx.outer.as_ref().unwrap());
panic!() panic!()
}) // FIXME: or instantiate }) // FIXME: or instantiate
@ -406,7 +409,7 @@ impl ASTLowerer {
let found_body_t = block.ref_t(); let found_body_t = block.ref_t();
let expect_body_t = t.return_t().unwrap(); let expect_body_t = t.return_t().unwrap();
if let Err(e) = if let Err(e) =
self.return_t_check(sig.loc(), sig.name.inspect(), expect_body_t, found_body_t) self.return_t_check(sig.loc(), sig.ident.inspect(), expect_body_t, found_body_t)
{ {
self.errs.push(e); self.errs.push(e);
} }
@ -416,7 +419,7 @@ impl ASTLowerer {
.as_mut() .as_mut()
.unwrap() .unwrap()
.assign_subr(&sig, id, found_body_t)?; .assign_subr(&sig, id, found_body_t)?;
let sig = hir::SubrSignature::new(sig.name, sig.params, t); let sig = hir::SubrSignature::new(sig.ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
} }

View file

@ -5,11 +5,11 @@ use erg_common::log;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{HasType, Locational, Stream}; use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ArgsOwnership, Ownership}; use erg_common::ty::{ArgsOwnership, Ownership};
use erg_common::value::Visibility;
use erg_common::Str; use erg_common::Str;
use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult}; use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult};
use crate::hir::{self, Accessor, Array, Block, Def, Expr, Signature, HIR}; use crate::hir::{self, Accessor, Array, Block, Def, Expr, Signature, HIR};
use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -84,19 +84,17 @@ impl OwnershipChecker {
match expr { match expr {
Expr::Def(def) => { Expr::Def(def) => {
self.define(def); self.define(def);
let name_and_vis = match &def.sig { let name = match &def.sig {
Signature::Var(var) => Signature::Var(var) => {
// TODO: visibility
{
if let Some(name) = var.inspect() { if let Some(name) = var.inspect() {
(name.clone(), Private) name.clone()
} else { } else {
(Str::ever("::<instant>"), Private) Str::ever("::<instant>")
} }
} }
Signature::Subr(subr) => (subr.name.inspect().clone(), Private), Signature::Subr(subr) => subr.ident.inspect().clone(),
}; };
self.path_stack.push(name_and_vis); self.path_stack.push((name, def.sig.vis()));
self.dict self.dict
.insert(Str::from(self.full_path()), LocalVars::default()); .insert(Str::from(self.full_path()), LocalVars::default());
self.check_block(&def.body.block); self.check_block(&def.body.block);
@ -239,7 +237,7 @@ impl OwnershipChecker {
Signature::Subr(sig) => { Signature::Subr(sig) => {
self.current_scope() self.current_scope()
.alive_vars .alive_vars
.insert(sig.name.inspect().clone()); .insert(sig.ident.inspect().clone());
} }
} }
} }

View file

@ -2,6 +2,8 @@ use std::fmt;
use erg_common::traits::HasType; use erg_common::traits::HasType;
use erg_common::ty::Type; use erg_common::ty::Type;
use erg_common::value::Visibility;
use Visibility::*;
use erg_parser::ast::DefId; use erg_parser::ast::DefId;
@ -32,24 +34,6 @@ impl Mutability {
use Mutability::*; use Mutability::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
Private,
Public,
}
impl Visibility {
pub const fn is_public(&self) -> bool {
matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
}
use Visibility::*;
/// e.g. /// e.g.
/// ```erg /// ```erg
/// K(T, [U, V]) = ... /// K(T, [U, V]) = ...

View file

@ -6,7 +6,7 @@ use erg_common::error::Location;
use erg_common::set::Set as HashSet; use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, NestedDisplay, Stream}; use erg_common::traits::{Locational, NestedDisplay, Stream};
use erg_common::ty::SubrKind; use erg_common::ty::SubrKind;
use erg_common::value::ValueObj; use erg_common::value::{ValueObj, Visibility};
use erg_common::Str; use erg_common::Str;
use erg_common::{ use erg_common::{
fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct, fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct,
@ -603,6 +603,12 @@ impl From<Vec<Def>> for RecordAttrs {
} }
} }
impl RecordAttrs {
pub fn iter(&self) -> impl Iterator<Item = &Def> {
self.0.iter()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Record { pub struct Record {
l_brace: Token, l_brace: Token,
@ -732,12 +738,15 @@ impl UnaryOp {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Call { pub struct Call {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub method_name: Option<Token>,
pub args: Args, pub args: Args,
} }
impl NestedDisplay for Call { impl NestedDisplay for Call {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
writeln!(f, "({}):", self.obj)?; write!(f, "({})", self.obj)?;
write!(f, "{}", fmt_option!(pre ".", self.method_name))?;
writeln!(f, ":")?;
self.args.fmt_nest(f, level + 1) self.args.fmt_nest(f, level + 1)
} }
} }
@ -755,9 +764,10 @@ impl Locational for Call {
} }
impl Call { impl Call {
pub fn new(obj: Expr, args: Args) -> Self { pub fn new(obj: Expr, method_name: Option<Token>, args: Args) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
method_name,
args, args,
} }
} }
@ -1597,6 +1607,67 @@ impl VarName {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub dot: Option<Token>,
pub name: VarName,
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.dot {
Some(_dot) => write!(f, ".{}", self.name),
None => write!(f, "{}", self.name),
}
}
}
impl Locational for Identifier {
fn loc(&self) -> Location {
if let Some(dot) = &self.dot {
Location::concat(dot, &self.name)
} else {
self.name.loc()
}
}
}
impl Identifier {
pub const fn new(dot: Option<Token>, name: VarName) -> Self {
Self { dot, name }
}
pub fn public(name: &'static str) -> Self {
Self::new(
Some(Token::from_str(TokenKind::Dot, ".")),
VarName::from_static(name),
)
}
pub fn private(name: Str) -> Self {
Self::new(None, VarName::from_str(name))
}
pub fn is_const(&self) -> bool {
self.name.is_const()
}
pub const fn vis(&self) -> Visibility {
match &self.dot {
Some(_dot) => 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(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VarArrayPattern { pub struct VarArrayPattern {
l_sqbr: Token, l_sqbr: Token,
@ -1708,8 +1779,7 @@ impl VarRecordPattern {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum VarPattern { pub enum VarPattern {
Discard(Token), Discard(Token),
Local(VarName), // x Ident(Identifier),
Public(VarName), // .x
/// e.g. `[x, y, z]` of `[x, y, z] = [1, 2, 3]` /// e.g. `[x, y, z]` of `[x, y, z] = [1, 2, 3]`
Array(VarArrayPattern), Array(VarArrayPattern),
/// e.g. `(x, y, z)` of `(x, y, z) = (1, 2, 3)` /// e.g. `(x, y, z)` of `(x, y, z) = (1, 2, 3)`
@ -1722,8 +1792,7 @@ impl NestedDisplay for VarPattern {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match self { match self {
Self::Discard(_) => write!(f, "_"), Self::Discard(_) => write!(f, "_"),
Self::Local(n) => write!(f, "{}", n), Self::Ident(ident) => write!(f, "{}", ident),
Self::Public(n) => write!(f, ".{}", n),
Self::Array(a) => write!(f, "{}", a), Self::Array(a) => write!(f, "{}", a),
Self::Tuple(t) => write!(f, "{}", t), Self::Tuple(t) => write!(f, "{}", t),
Self::Record(r) => write!(f, "{}", r), Self::Record(r) => write!(f, "{}", r),
@ -1732,19 +1801,19 @@ impl NestedDisplay for VarPattern {
} }
impl_display_from_nested!(VarPattern); impl_display_from_nested!(VarPattern);
impl_locational_for_enum!(VarPattern; Discard, Local, Public, Array, Tuple, Record); impl_locational_for_enum!(VarPattern; Discard, Ident, Array, Tuple, Record);
impl VarPattern { impl VarPattern {
pub const fn inspect(&self) -> Option<&Str> { pub const fn inspect(&self) -> Option<&Str> {
match self { match self {
Self::Local(n) | Self::Public(n) => Some(n.inspect()), Self::Ident(ident) => Some(ident.inspect()),
_ => None, _ => None,
} }
} }
pub fn inspects(&self) -> Vec<&Str> { pub fn inspects(&self) -> Vec<&Str> {
match self { match self {
Self::Local(n) | Self::Public(n) => vec![n.inspect()], Self::Ident(ident) => vec![ident.inspect()],
Self::Array(VarArrayPattern { elems, .. }) Self::Array(VarArrayPattern { elems, .. })
| Self::Tuple(VarTuplePattern { elems, .. }) | Self::Tuple(VarTuplePattern { elems, .. })
| Self::Record(VarRecordPattern { elems, .. }) => { | Self::Record(VarRecordPattern { elems, .. }) => {
@ -1757,7 +1826,7 @@ impl VarPattern {
// _!(...) = ... is invalid // _!(...) = ... is invalid
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
match self { match self {
Self::Local(n) | Self::Public(n) => n.is_procedural(), Self::Ident(ident) => ident.is_procedural(),
_ => false, _ => false,
} }
} }
@ -1765,10 +1834,18 @@ impl VarPattern {
// _ = (type block) is invalid // _ = (type block) is invalid
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Local(n) | Self::Public(n) => n.is_const(), Self::Ident(ident) => ident.is_const(),
_ => false, _ => false,
} }
} }
pub const fn vis(&self) -> Visibility {
match self {
Self::Ident(ident) => ident.vis(),
// TODO: `[.x, .y]`?
_ => Visibility::Private,
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -1807,6 +1884,10 @@ impl VarSignature {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
self.pat.is_const() self.pat.is_const()
} }
pub const fn vis(&self) -> Visibility {
self.pat.vis()
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -2066,7 +2147,7 @@ impl Params {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SubrSignature { pub struct SubrSignature {
pub decorators: HashSet<Decorator>, pub decorators: HashSet<Decorator>,
pub name: VarName, pub ident: Identifier,
pub params: Params, pub params: Params,
pub return_t_spec: Option<TypeSpec>, pub return_t_spec: Option<TypeSpec>,
pub bounds: TypeBoundSpecs, pub bounds: TypeBoundSpecs,
@ -2078,7 +2159,7 @@ impl NestedDisplay for SubrSignature {
write!( write!(
f, f,
"{}{}{}", "{}{}{}",
self.name, self.ident,
self.params, self.params,
fmt_option!(pre ": ", self.return_t_spec) fmt_option!(pre ": ", self.return_t_spec)
) )
@ -2086,7 +2167,7 @@ impl NestedDisplay for SubrSignature {
write!( write!(
f, f,
"{}|{}|{}{}", "{}|{}|{}{}",
self.name, self.ident,
self.bounds, self.bounds,
self.params, self.params,
fmt_option!(pre ": ", self.return_t_spec) fmt_option!(pre ": ", self.return_t_spec)
@ -2100,11 +2181,11 @@ impl_display_from_nested!(SubrSignature);
impl Locational for SubrSignature { impl Locational for SubrSignature {
fn loc(&self) -> Location { fn loc(&self) -> Location {
if !self.bounds.is_empty() { if !self.bounds.is_empty() {
Location::concat(&self.name, &self.bounds) Location::concat(&self.ident, &self.bounds)
} else if let Some(return_t) = &self.return_t_spec { } else if let Some(return_t) = &self.return_t_spec {
Location::concat(&self.name, return_t) Location::concat(&self.ident, return_t)
} else { } else {
Location::concat(&self.name, &self.params) Location::concat(&self.ident, &self.params)
} }
} }
} }
@ -2112,14 +2193,14 @@ impl Locational for SubrSignature {
impl SubrSignature { impl SubrSignature {
pub const fn new( pub const fn new(
decorators: HashSet<Decorator>, decorators: HashSet<Decorator>,
name: VarName, ident: Identifier,
params: Params, params: Params,
return_t: Option<TypeSpec>, return_t: Option<TypeSpec>,
bounds: TypeBoundSpecs, bounds: TypeBoundSpecs,
) -> Self { ) -> Self {
Self { Self {
decorators, decorators,
name, ident,
params, params,
return_t_spec: return_t, return_t_spec: return_t,
bounds, bounds,
@ -2127,7 +2208,11 @@ impl SubrSignature {
} }
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
self.name.is_const() self.ident.is_const()
}
pub const fn vis(&self) -> Visibility {
self.ident.vis()
} }
} }
@ -2236,21 +2321,21 @@ impl_locational_for_enum!(Signature; Var, Subr);
impl Signature { impl Signature {
pub fn name_as_str(&self) -> &Str { pub fn name_as_str(&self) -> &Str {
match self { match self {
Self::Var(v) => v.pat.inspect().unwrap(), Self::Var(var) => var.pat.inspect().unwrap(),
Self::Subr(s) => s.name.inspect(), Self::Subr(subr) => subr.ident.inspect(),
} }
} }
pub fn name(&self) -> Option<&VarName> { pub fn ident(&self) -> Option<&Identifier> {
match self { match self {
Self::Var(v) => { Self::Var(var) => {
if let VarPattern::Local(v) = &v.pat { if let VarPattern::Ident(ident) = &var.pat {
Some(v) Some(ident)
} else { } else {
None None
} }
} }
Self::Subr(s) => Some(&s.name), Self::Subr(subr) => Some(&subr.ident),
} }
} }
@ -2263,8 +2348,15 @@ impl Signature {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Var(v) => v.is_const(), Self::Var(var) => var.is_const(),
Self::Subr(s) => s.is_const(), Self::Subr(subr) => subr.is_const(),
}
}
pub const fn vis(&self) -> Visibility {
match self {
Self::Var(var) => var.vis(),
Self::Subr(subr) => subr.vis(),
} }
} }
} }

View file

@ -47,7 +47,7 @@ impl Desugarer {
if previous.is_subr() && previous.sig.name_as_str() == def.sig.name_as_str() if previous.is_subr() && previous.sig.name_as_str() == def.sig.name_as_str()
{ {
let mut previous = enum_unwrap!(new.pop().unwrap(), Expr::Def); let mut previous = enum_unwrap!(new.pop().unwrap(), Expr::Def);
let name = def.sig.name().unwrap().clone(); let name = def.sig.ident().unwrap().clone();
let op = Token::from_str(TokenKind::FuncArrow, "->"); let op = Token::from_str(TokenKind::FuncArrow, "->");
let (call, return_t_spec) = if previous.body.block.len() == 1 let (call, return_t_spec) = if previous.body.block.len() == 1
&& previous.body.block.first().unwrap().is_match_call() && previous.body.block.first().unwrap().is_match_call()
@ -104,7 +104,7 @@ impl Desugarer {
vec![], vec![],
None, None,
); );
let call = Call::new(match_symbol, args); let call = Call::new(match_symbol, None, args);
(call, return_t_spec) (call, return_t_spec)
}; };
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::Local:(_))).inspect();

View file

@ -515,7 +515,7 @@ impl Parser {
return Ok(Signature::Var(var)); return Ok(Signature::Var(var));
} }
let decorators = self.opt_reduce_decorators().map_err(|_| self.stack_dec())?; let decorators = self.opt_reduce_decorators().map_err(|_| self.stack_dec())?;
let (opt_dot, name) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
// TODO: parse bounds |...| // TODO: parse bounds |...|
let bounds = TypeBoundSpecs::empty(); let bounds = TypeBoundSpecs::empty();
if self.cur_is(VBar) { if self.cur_is(VBar) {
@ -534,7 +534,7 @@ impl Parser {
}; };
self.level -= 1; self.level -= 1;
Ok(Signature::Subr(SubrSignature::new( Ok(Signature::Subr(SubrSignature::new(
decorators, name, params, t_spec, bounds, decorators, ident, params, t_spec, bounds,
))) )))
} else { } else {
if !bounds.is_empty() { if !bounds.is_empty() {
@ -554,7 +554,7 @@ impl Parser {
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
} }
let t_spec = if name.is_const() { let t_spec = if ident.is_const() {
if self.cur_is(SubtypeOf) { if self.cur_is(SubtypeOf) {
self.skip(); self.skip();
Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?) Some(self.try_reduce_type_spec().map_err(|_| self.stack_dec())?)
@ -568,12 +568,10 @@ impl Parser {
None None
}; };
self.level -= 1; self.level -= 1;
let var_pat = if opt_dot.is_some() { Ok(Signature::Var(VarSignature::new(
VarPattern::Public(name) VarPattern::Ident(ident),
} else { t_spec,
VarPattern::Local(name) )))
};
Ok(Signature::Var(VarSignature::new(var_pat, t_spec)))
} }
} }
@ -906,14 +904,9 @@ impl Parser {
debug_call_info!(self); debug_call_info!(self);
match self.peek() { match self.peek() {
Some(t) if t.is(Symbol) => { Some(t) if t.is(Symbol) => {
let (opt_dot, varname) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
let var_pat = if let Some(_dot) = opt_dot {
VarPattern::Public(varname)
} else {
VarPattern::Local(varname)
};
self.level -= 1; self.level -= 1;
Ok(var_pat) Ok(VarPattern::Ident(ident))
} }
Some(t) if t.is(UBar) => { Some(t) if t.is(UBar) => {
self.level -= 1; self.level -= 1;
@ -968,8 +961,8 @@ impl Parser {
debug_call_info!(self); debug_call_info!(self);
match self.peek() { match self.peek() {
Some(t) if t.is(Symbol) => { Some(t) if t.is(Symbol) => {
let (opt_dot, varname) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
if let Some(dot) = opt_dot { if let Some(dot) = &ident.dot {
let loc = dot.loc(); let loc = dot.loc();
self.level -= 1; self.level -= 1;
self.errs.push(ParseError::syntax_error( self.errs.push(ParseError::syntax_error(
@ -986,7 +979,7 @@ impl Parser {
return Err(()); return Err(());
} }
self.level -= 1; self.level -= 1;
Ok(ParamPattern::VarName(varname)) Ok(ParamPattern::VarName(ident.name))
} }
Some(t) if t.is(UBar) => { Some(t) if t.is(UBar) => {
self.level -= 1; self.level -= 1;
@ -1000,8 +993,8 @@ impl Parser {
} }
Some(t) if t.is(Spread) => { Some(t) if t.is(Spread) => {
self.skip(); self.skip();
let (opt_dot, varname) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
if let Some(dot) = opt_dot { if let Some(dot) = &ident.dot {
let loc = dot.loc(); let loc = dot.loc();
self.level -= 1; self.level -= 1;
self.errs.push(ParseError::syntax_error( self.errs.push(ParseError::syntax_error(
@ -1018,7 +1011,7 @@ impl Parser {
return Err(()); return Err(());
} }
self.level -= 1; self.level -= 1;
Ok(ParamPattern::VarArgsName(varname)) Ok(ParamPattern::VarArgsName(ident.name))
} }
Some(t) if t.is(LSqBr) => { Some(t) if t.is(LSqBr) => {
let l_sqbr = self.lpop(); let l_sqbr = self.lpop();
@ -1162,11 +1155,11 @@ impl Parser {
debug_call_info!(self); debug_call_info!(self);
if self.cur_is(Symbol) && self.nth_is(1, Colon) { if self.cur_is(Symbol) && self.nth_is(1, Colon) {
// TODO: handle `.` // TODO: handle `.`
let (_opt_dot, name) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
self.skip(); self.skip();
let typ = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; let typ = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?;
self.level -= 1; self.level -= 1;
Ok(ParamTySpec::new(Some(name.into_token()), typ)) Ok(ParamTySpec::new(Some(ident.name.into_token()), typ))
} else { } else {
let ty_spec = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?; let ty_spec = self.try_reduce_type_spec().map_err(|_| self.stack_dec())?;
self.level -= 1; self.level -= 1;
@ -1228,15 +1221,15 @@ impl Parser {
debug_call_info!(self); debug_call_info!(self);
match self.peek() { match self.peek() {
Some(t) if t.is(Symbol) => { Some(t) if t.is(Symbol) => {
// TODO: handle dot // TODO: handle dot (`.`)
let (_opt_dot, name) = self.try_reduce_name().map_err(|_| self.stack_dec())?; let ident = self.try_reduce_ident().map_err(|_| self.stack_dec())?;
if let Some(res) = self.opt_reduce_args() { if let Some(res) = self.opt_reduce_args() {
let args = self.validate_const_args(res?)?; let args = self.validate_const_args(res?)?;
self.level -= 1; self.level -= 1;
Ok(SimpleTypeSpec::new(name, args)) Ok(SimpleTypeSpec::new(ident.name, args))
} else { } else {
self.level -= 1; self.level -= 1;
Ok(SimpleTypeSpec::new(name, ConstArgs::empty())) Ok(SimpleTypeSpec::new(ident.name, ConstArgs::empty()))
} }
} }
_ => { _ => {
@ -1714,11 +1707,15 @@ impl Parser {
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
}; };
let acc = Accessor::attr(obj, Local::new(symbol)); if let Some(args) = self
if let Ok(args) = self.try_reduce_args() { .opt_reduce_args()
let call = Call::new(Expr::Accessor(acc), args); .transpose()
.map_err(|_| self.stack_dec())?
{
let call = Call::new(obj, Some(symbol), args);
stack.push(ExprOrOp::Expr(Expr::Call(call))); stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else { } else {
let acc = Accessor::attr(obj, Local::new(symbol));
stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
} }
} }
@ -1864,7 +1861,12 @@ impl Parser {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
if let Some(res) = self.opt_reduce_args() { if let Some(res) = self.opt_reduce_args() {
let args = res.map_err(|_| self.stack_dec())?; let args = res.map_err(|_| self.stack_dec())?;
let call = Call::new(Expr::Accessor(acc), args); let (obj, method_name) = match acc {
Accessor::Attr(attr) => (*attr.obj, Some(attr.name.symbol)),
Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None),
_ => todo!(),
};
let call = Call::new(obj, method_name, args);
self.level -= 1; self.level -= 1;
Ok(Expr::Call(call)) Ok(Expr::Call(call))
} else { } else {
@ -1978,9 +1980,8 @@ impl Parser {
todo!() todo!()
} }
/// option: Dot(`.`)
#[inline] #[inline]
fn try_reduce_name(&mut self) -> ParseResult<(Option<Token>, VarName)> { fn try_reduce_ident(&mut self) -> ParseResult<Identifier> {
debug_call_info!(self); debug_call_info!(self);
self.level -= 1; self.level -= 1;
match self.peek() { match self.peek() {
@ -1988,9 +1989,13 @@ impl Parser {
let dot = self.lpop(); let dot = self.lpop();
// TODO: // TODO:
assert!(self.cur_category_is(TC::Symbol)); assert!(self.cur_category_is(TC::Symbol));
Ok((Some(dot), VarName::new(self.lpop()))) let ident = Identifier::new(Some(dot), VarName::new(self.lpop()));
Ok(ident)
}
Some(t) if t.is(Symbol) => {
let ident = Identifier::new(None, VarName::new(self.lpop()));
Ok(ident)
} }
Some(t) if t.is(Symbol) => Ok((None, VarName::new(self.lpop()))),
_ => { _ => {
let err = self.skip_and_throw_syntax_err(caused_by!()); let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err); self.errs.push(err);

View file

@ -4,3 +4,4 @@ fib 1 = 1
fib(n: Nat): Nat = fib(n-1) + fib(n-2) fib(n: Nat): Nat = fib(n-1) + fib(n-2)
assert fib(10) == 55 assert fib(10) == 55
print! fib 10