Merge branch 'main' into dict

This commit is contained in:
Shunsuke Shibayama 2022-10-10 13:57:08 +09:00
commit c784ba261e
53 changed files with 1336 additions and 818 deletions

View file

@ -1,13 +1,13 @@
[package]
name = "erg_common"
version = "0.5.7"
description = "A common components library of Erg"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_common"
documentation = "https://docs.rs/erg_common"
homepage = "https://erg-lang.github.io/"
documentation = "http://docs.rs/erg_common"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -17,8 +17,13 @@ japanese = []
simplified_chinese = []
traditional_chinese = []
[dependencies]
atty = "0.2.14"
[target.'cfg(unix)'.dependencies]
libc = { version = "0.2", default-features = false }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = "0.1.6"
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["consoleapi"]
[lib]
path = "lib.rs"

View file

@ -211,48 +211,70 @@ impl ErgConfig {
let mut cfg = Self::default();
// ループ内でnextするのでforにしないこと
while let Some(arg) = args.next() {
let next_arg = args.next();
match &arg[..] {
"-c" if next_arg.is_some() => {
cfg.input = Input::Str(next_arg.unwrap());
"-c" | "--code" => {
cfg.input = Input::Str(args.next().expect("the value of `-c` is not passed"));
}
"--dump-as-pyc" => {
cfg.dump_as_pyc = true;
}
"-?" | "-h" | "--help" => {
// TODO:
println!("{}", command_message());
if let "--mode" = args.next().as_ref().map(|s| &s[..]).unwrap_or("") {
println!("{}", mode_message());
}
process::exit(0);
}
"-m" if next_arg.is_some() => {
cfg.module = Box::leak(next_arg.unwrap().into_boxed_str());
"-m" | "--module" => {
let module = args
.next()
.expect("the value of `-m` is not passed")
.into_boxed_str();
cfg.module = Box::leak(module);
}
"--mode" if next_arg.is_some() => {
let mode = next_arg.unwrap();
"--mode" => {
let mode = args.next().expect("the value of `--mode` is not passed");
if let "-?" | "-h" | "--help" = &mode[..] {
println!("{}", mode_message());
process::exit(0);
}
cfg.mode = Box::leak(mode.into_boxed_str());
}
"--ps1" if next_arg.is_some() => {
cfg.ps1 = Box::leak(next_arg.unwrap().into_boxed_str());
"--ps1" => {
let ps1 = args
.next()
.expect("the value of `--ps1` is not passed")
.into_boxed_str();
cfg.ps1 = Box::leak(ps1);
}
"--ps2" if next_arg.is_some() => {
cfg.ps2 = Box::leak(next_arg.unwrap().into_boxed_str());
"--ps2" => {
let ps2 = args
.next()
.expect("the value of `--ps2` is not passed")
.into_boxed_str();
cfg.ps2 = Box::leak(ps2);
}
"-o" | "--opt-level" | "--optimization-level" if next_arg.is_some() => {
cfg.opt_level = next_arg.unwrap().parse::<u8>().unwrap();
"-o" | "--opt-level" | "--optimization-level" => {
cfg.opt_level = args
.next()
.expect("the value of `-o` is not passed")
.parse::<u8>()
.expect("the value of `-o` is not a number");
}
"-p" | "--py-ver" | "--python-version" if next_arg.is_some() => {
if let Ok(ver) = next_arg.unwrap().parse::<u32>() {
cfg.python_ver = Some(ver)
}
"-p" | "--py-ver" | "--python-version" => {
let py_ver = args
.next()
.expect("the value of `-p` is not passed")
.parse::<u32>()
.expect("the value of `-p` is not a number");
cfg.python_ver = Some(py_ver);
}
"--py-server-timeout" if next_arg.is_some() => {
if let Ok(time) = next_arg.unwrap().parse::<u64>() {
cfg.py_server_timeout = time;
}
"--py-server-timeout" => {
cfg.py_server_timeout = args
.next()
.expect("the value of `--py-server-timeout` is not passed")
.parse::<u64>()
.expect("the value of `--py-server-timeout` is not a number");
}
"--quiet-startup" => {
cfg.quiet_startup = true;
@ -260,10 +282,12 @@ impl ErgConfig {
"-t" | "--show-type" => {
cfg.show_type = true;
}
"--verbose" if next_arg.is_some() => {
if let Ok(vr) = next_arg.unwrap().parse::<u8>() {
cfg.verbose = vr;
}
"--verbose" => {
cfg.verbose = args
.next()
.expect("the value of `--verbose` is not passed")
.parse::<u8>()
.expect("the value of `--verbose` is not a number");
}
"-V" | "--version" => {
println!("Erg {}", env!("CARGO_PKG_VERSION"));
@ -282,7 +306,8 @@ impl ErgConfig {
}
}
if cfg.input == Input::REPL {
let is_stdin_piped = atty::isnt(atty::Stream::Stdin);
use crate::tty::IsTty;
let is_stdin_piped = !stdin().is_tty();
let input = if is_stdin_piped {
let mut buffer = String::new();
stdin().read_to_string(&mut buffer).unwrap();

View file

@ -20,7 +20,7 @@ OPTIONS
--python-version/-p (uint 32 number) Pythonバージョンを指定
--py-server-timeout (uint 64 number) PythonのREPLサーバーのタイムアウト時間を指定
--dump-as-pyc .pycファイルにダンプ
--mode lex|parse|compile|exec
--mode lex|parse|compile|exec (--mode --helpを参照)
SUBCOMMAND
-c cmd :
@ -43,7 +43,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python
--py-server-timeout (uint 64 number) Python REPL
--dump-as-pyc .pyc
--mode lex|parse|compile|exec
--mode lex|parse|compile|exec (`--mode --help`)
SUBCOMMAND
-c cmd :
@ -66,7 +66,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python
--py-server-timeout (uint 64 number) Python REPL
--dump-as-pyc .pyc
--mode lex|parse|compile|exec
--mode lex|parse|compile|exec (`--mode --help`)
SUBCOMMAND
-c cmd :
@ -89,7 +89,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python version
--py-server-timeout (uint 64 number) timeout for the Python REPL server
--dump-as-pyc dump as .pyc file
--mode lex|parse|compile|exec execution mode
--mode lex|parse|compile|exec execution mode (See `--mode --help` for details)
SUBCOMMAND
-c cmd : program passed in as string

View file

@ -21,6 +21,7 @@ pub mod stdin;
pub mod str;
pub mod traits;
pub mod tsort;
pub mod tty;
pub mod vis;
use crate::set::Set;

View file

@ -0,0 +1,63 @@
//! Copied and modified from the [crossterm](https://github.com/crossterm-rs/crossterm).
//! Making it a little more convenient and safe to query whether
//! something is a terminal teletype or not.
//! This module defines the IsTty trait and the is_tty method to
//! return true if the item represents a terminal.
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawHandle;
#[cfg(windows)]
use winapi::um::consoleapi::GetConsoleMode;
/// Adds the `is_tty` method to types that might represent a terminal
///
/// ```rust
/// use std::io::stdout;
/// use erg_common::tty::IsTty;
///
/// let is_tty: bool = stdout().is_tty();
/// ```
pub trait IsTty {
/// Returns true when an instance is a terminal teletype, otherwise false.
fn is_tty(&self) -> bool;
}
/// On UNIX, the `isatty()` function returns true if a file
/// descriptor is a terminal.
#[cfg(unix)]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
let fd = self.as_raw_fd();
unsafe { libc::isatty(fd) == 1 }
}
}
#[cfg(target_os = "hermit")]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
let fd = self.as_raw_fd();
hermit_abi::isatty(fd)
}
}
/// returns true if this is a tty
#[cfg(any(target_arch = "wasm32", target_env = "sgx"))]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
false
}
}
/// On windows, `GetConsoleMode` will return true if we are in a terminal.
/// Otherwise false.
#[cfg(windows)]
impl<S: AsRawHandle> IsTty for S {
fn is_tty(&self) -> bool {
let mut mode = 0;
let ok = unsafe { GetConsoleMode(self.as_raw_handle() as *mut _, &mut mode) };
ok == 1
}
}

View file

@ -1,25 +1,34 @@
[package]
name = "erg_compiler"
version = "0.5.7"
description = "Centimetre: the Erg compiler"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler"
documentation = "https://docs.rs/erg_compiler"
homepage = "https://erg-lang.github.io/"
documentation = "http://docs.rs/erg_compiler"
build = "build.rs"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
[features]
# when "debug" feature is turned on, that of parser will also be turned on.
debug = [ "erg_common/debug", "erg_parser/debug", "erg_type/debug" ]
japanese = [ "erg_common/japanese", "erg_parser/japanese", "erg_type/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_chinese", "erg_type/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
debug = ["erg_common/debug", "erg_parser/debug", "erg_type/debug"]
japanese = ["erg_common/japanese", "erg_parser/japanese", "erg_type/japanese"]
simplified_chinese = [
"erg_common/simplified_chinese",
"erg_parser/simplified_chinese",
"erg_type/simplified_chinese",
]
traditional_chinese = [
"erg_common/traditional_chinese",
"erg_parser/traditional_chinese",
"erg_type/traditional_chinese",
]
[dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" }
erg_parser = { version = "0.5.7", path = "../erg_parser" }
erg_type = { version = "0.5.7", path = "../erg_type" }
erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
erg_parser = { version = "0.5.9-nightly.0", path = "../erg_parser" }
erg_type = { version = "0.5.9-nightly.0", path = "../erg_type" }
[lib]
path = "lib.rs"

View file

@ -0,0 +1,33 @@
#![allow(deprecated)]
use std::env;
use std::fs;
use std::path;
fn main() -> std::io::Result<()> {
// Create a ".erg" directory
let erg_path = env::home_dir()
.expect("failed to get the location of the home dir")
.to_str()
.expect("invalid encoding of the home dir name")
.to_string()
+ "/.erg";
if !path::Path::new(&erg_path).exists() {
fs::create_dir(&erg_path)?;
fs::create_dir(format!("{erg_path}/std"))?;
}
println!("cargo:rustc-env=ERG_PATH={erg_path}");
println!("cargo:rustc-env=ERG_STD_PATH={erg_path}/std");
// create a std library in ".erg"
for res in fs::read_dir("std")? {
let entry = res?;
let path = entry.path();
let filename = path
.file_name()
.expect("this is not a file")
.to_str()
.unwrap();
fs::copy(&path, format!("{erg_path}/std/{filename}"))?;
}
Ok(())
}

View file

@ -29,7 +29,7 @@ use erg_type::value::ValueObj;
use erg_type::{HasType, Type, TypeCode, TypePair};
use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::context::eval::eval_lit;
use crate::context::eval::type_from_token_kind;
use crate::error::CompileError;
use crate::hir::{
Accessor, Args, Array, AttrDef, Attribute, BinOp, Block, Call, ClassDef, Def, DefBody, Expr,
@ -867,7 +867,7 @@ impl CodeGenerator {
self.write_instr(MAKE_FUNCTION);
self.write_arg(0);
self.emit_load_const(def.sig.ident().inspect().clone());
self.emit_load_name_instr(Identifier::private(Str::ever("#ABCMeta")));
self.emit_load_name_instr(Identifier::private("#ABCMeta"));
self.emit_load_const(vec![ValueObj::from("metaclass")]);
let subclasses_len = 1;
self.write_instr(Opcode::CALL_FUNCTION_KW);
@ -917,7 +917,7 @@ impl CodeGenerator {
self.emit_empty_func(
Some(sig.ident().inspect()),
def.sig.into_ident(),
Some(Identifier::private(Str::ever("#abstractmethod"))),
Some(Identifier::private("#abstractmethod")),
);
}
self.emit_load_const(ValueObj::None);
@ -1129,7 +1129,7 @@ impl CodeGenerator {
CompileError::feature_error(
self.cfg.input.clone(),
unary.op.loc(),
"",
&unary.op.inspect().clone(),
AtomicStr::from(unary.op.content),
)
.write_to_stderr();
@ -1150,6 +1150,9 @@ impl CodeGenerator {
self.emit_load_name_instr(Identifier::public("range"));
}
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
TokenKind::InOp => {
self.emit_load_name_instr(Identifier::private("#in_operator"));
}
_ => {}
}
let type_pair = TypePair::new(bin.lhs_t(), bin.rhs_t());
@ -1170,14 +1173,16 @@ impl CodeGenerator {
| TokenKind::NotEq
| TokenKind::Gre
| TokenKind::GreEq => COMPARE_OP,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => {
CALL_FUNCTION
} // ERG_BINARY_RANGE,
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => CALL_FUNCTION, // ERG_BINARY_RANGE,
_ => {
CompileError::feature_error(
self.cfg.input.clone(),
bin.op.loc(),
"",
&bin.op.inspect().clone(),
AtomicStr::from(bin.op.content),
)
.write_to_stderr();
@ -1191,14 +1196,22 @@ impl CodeGenerator {
TokenKind::NotEq => 3,
TokenKind::Gre => 4,
TokenKind::GreEq => 5,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => 2,
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => 2,
_ => type_pair as u8,
};
self.write_instr(instr);
self.write_arg(arg);
self.stack_dec();
match &bin.op.kind {
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Open | TokenKind::Closed => {
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Open
| TokenKind::Closed
| TokenKind::InOp => {
self.stack_dec();
}
_ => {}
@ -1339,7 +1352,11 @@ impl CodeGenerator {
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
self.emit_load_const(eval_lit(&lit));
let value = {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content).unwrap()
};
self.emit_load_const(value);
self.write_instr(Opcode::COMPARE_OP);
self.write_arg(2); // ==
self.stack_dec();
@ -1597,7 +1614,7 @@ impl CodeGenerator {
log!(info "entered {} ({rec})", fn_name!());
let attrs_len = rec.attrs.len();
// making record type
let ident = Identifier::private(Str::ever("#NamedTuple"));
let ident = Identifier::private("#NamedTuple");
self.emit_load_name_instr(ident);
// record name, let it be anonymous
self.emit_load_const("Record");
@ -1615,10 +1632,10 @@ impl CodeGenerator {
self.write_arg(2);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + 2 + 0) - 1);
let ident = Identifier::private(Str::ever("#rec"));
let ident = Identifier::private("#rec");
self.emit_store_instr(ident, Name);
// making record instance
let ident = Identifier::private(Str::ever("#rec"));
let ident = Identifier::private("#rec");
self.emit_load_name_instr(ident);
for field in rec.attrs.into_iter() {
self.emit_frameless_block(field.body.block, vec![]);
@ -1687,6 +1704,15 @@ impl CodeGenerator {
self.stack_dec_n(len - 1);
}
}
Array::WithLength(arr) => {
self.emit_expr(*arr.elem);
self.write_instr(BUILD_LIST);
self.write_arg(1u8);
self.emit_expr(*arr.len);
self.write_instr(BINARY_MULTIPLY);
self.write_arg(0);
self.stack_dec();
}
other => todo!("{other}"),
},
// TODO: tuple comprehension
@ -1720,7 +1746,11 @@ impl CodeGenerator {
self.stack_dec_n(len - 1);
}
}
crate::hir::Set::WithLength(_) => todo!(),
crate::hir::Set::WithLength(st) => {
self.emit_expr(*st.elem);
self.write_instr(BUILD_SET);
self.write_arg(1u8);
}
},
Expr::Record(rec) => self.emit_record(rec),
Expr::Code(code) => {
@ -1739,7 +1769,7 @@ impl CodeGenerator {
}
// Dict,
other => {
CompileError::feature_error(self.cfg.input.clone(), other.loc(), "???", "".into())
CompileError::feature_error(self.cfg.input.clone(), other.loc(), "Dict", "".into())
.write_to_stderr();
self.crash("cannot compile this expression at this time");
}
@ -1894,7 +1924,7 @@ impl CodeGenerator {
attrs.push(Expr::AttrDef(attr_def));
}
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
attrs.push(Expr::Lit(Literal::from(none)));
attrs.push(Expr::Lit(Literal::try_from(none).unwrap()));
}
other => todo!("{other}"),
}
@ -2007,15 +2037,40 @@ impl CodeGenerator {
fn load_prelude(&mut self) {
self.load_record_type();
self.load_prelude_py();
self.record_type_loaded = true;
}
fn load_prelude_py(&mut self) {
self.emit_global_import_items(
Identifier::public("sys"),
vec![(
Identifier::public("path"),
Some(Identifier::private("#path")),
)],
);
self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr("Array!", None, Identifier::public("push!"));
self.emit_load_const(env!("ERG_STD_PATH"));
self.write_instr(CALL_METHOD);
self.write_arg(1u8);
self.stack_dec();
self.emit_pop_top();
self.emit_global_import_items(
Identifier::public("_erg_std_prelude"),
vec![(
Identifier::public("in_operator"),
Some(Identifier::private("#in_operator")),
)],
);
}
fn load_record_type(&mut self) {
self.emit_global_import_items(
Identifier::public("collections"),
vec![(
Identifier::public("namedtuple"),
Some(Identifier::private(Str::ever("#NamedTuple"))),
Some(Identifier::private("#NamedTuple")),
)],
);
}
@ -2026,11 +2081,11 @@ impl CodeGenerator {
vec![
(
Identifier::public("ABCMeta"),
Some(Identifier::private(Str::ever("#ABCMeta"))),
Some(Identifier::private("#ABCMeta")),
),
(
Identifier::public("abstractmethod"),
Some(Identifier::private(Str::ever("#abstractmethod"))),
Some(Identifier::private("#abstractmethod")),
),
],
);
@ -2041,7 +2096,7 @@ impl CodeGenerator {
Identifier::public("types"),
vec![(
Identifier::public("ModuleType"),
Some(Identifier::private(Str::ever("#ModuleType"))),
Some(Identifier::private("#ModuleType")),
)],
);
}

View file

@ -681,25 +681,26 @@ impl Context {
pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool {
let subst_ctx = SubstContext::new(rhs, self, Location::Unknown);
if let Some(super_traits) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_traits) {
for sup_trait in super_traits {
let sup_trait = if sup_trait.has_qvar() {
subst_ctx.substitute(sup_trait.clone()).unwrap()
for super_trait in super_traits {
let sup_trait = if super_trait.has_qvar() {
subst_ctx.substitute(super_trait.clone()).unwrap()
} else {
sup_trait.clone()
super_trait.clone()
};
if self.sup_conforms(lhs, rhs, &sup_trait) {
return true;
}
}
}
if let Some(sup_classes) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_classes) {
for sup_class in sup_classes {
let sup_class = if sup_class.has_qvar() {
subst_ctx.substitute(sup_class.clone()).unwrap()
if let Some(super_classes) = self.get_super_classes(rhs) {
for super_class in super_classes {
let sup_class = if super_class.has_qvar() {
subst_ctx.substitute(super_class).unwrap()
} else {
sup_class.clone()
super_class
};
if self.cyclic_supertype_of(lhs, &sup_class) {
log!(err "引っかかった: {lhs}, {sup_class}");
return true;
}
}
@ -849,6 +850,9 @@ impl Context {
/// returns union of two types (A or B)
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// `?T or ?U` will not be unified
// `Set!(?T, 3) or Set(?T, 3)` wii be unified to Set(?T, 3)
if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
@ -888,6 +892,9 @@ impl Context {
/// returns intersection of two types (A and B)
pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// ?T and ?U will not be unified
if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {

View file

@ -100,12 +100,6 @@ fn op_to_name(op: OpKind) -> &'static str {
}
}
#[inline]
pub(crate) fn eval_lit(lit: &Literal) -> ValueObj {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone())
}
/// Instantiate the polymorphic type from the quantified state.
///
/// e.g.
@ -577,13 +571,26 @@ impl Context {
Ok(ValueObj::Subr(subr))
}
pub(crate) fn eval_lit(&self, lit: &Literal) -> EvalResult<ValueObj> {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone()).ok_or_else(|| {
EvalError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
lit.token.loc(),
self.caused_by(),
)
.into()
})
}
pub(crate) fn eval_const_expr(
&self,
expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
@ -603,7 +610,7 @@ impl Context {
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),

View file

@ -109,9 +109,14 @@ impl Context {
panic!("{} has already been registered as const", t.name());
} else {
let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(meta_t, muty, Private, Builtin, None),
);
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -156,9 +161,14 @@ impl Context {
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
} else {
let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(meta_t, muty, Private, Builtin, None),
);
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -203,7 +213,7 @@ impl Context {
let name = VarName::from_static(name);
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(Patch, muty, Private, Builtin, None),
);
for method_name in ctx.locals.keys() {
if let Some(patches) = self.method_impl_patches.get_mut(method_name) {
@ -454,7 +464,7 @@ impl Context {
/* Obj */
let mut obj = Self::builtin_mono_class("Obj", 2);
let t = fn0_met(mono_q("Self"), mono_q("Self"));
let t = quant(t, set! {subtypeof(mono_q("Self"), builtin_mono("Obj"))});
let t = quant(t, set! {subtypeof(mono_q("Self"), Obj)});
obj.register_builtin_impl("clone", t, Const, Public);
obj.register_builtin_impl("__module__", Str, Const, Public);
obj.register_builtin_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public);
@ -469,10 +479,11 @@ impl Context {
);
let mut obj_in = Self::builtin_methods("In", 2);
obj_in.register_builtin_impl("__in__", fn1_met(Obj, Type, Bool), Const, Public);
obj.register_trait(Obj, builtin_poly("Eq", vec![ty_tp(Type)]), obj_in);
obj.register_trait(Obj, builtin_poly("In", vec![ty_tp(Type)]), obj_in);
let mut obj_mutizable = Self::builtin_methods("Mutizable", 1);
obj_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Obj!")));
obj.register_trait(Obj, builtin_mono("Mutizable"), obj_mutizable);
// Obj does not implement Eq
/* Float */
let mut float = Self::builtin_mono_class("Float", 2);
@ -760,6 +771,24 @@ impl Context {
let mut str_show = Self::builtin_methods("Show", 1);
str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public);
str_.register_trait(Str, builtin_mono("Show"), str_show);
/* NoneType */
let mut nonetype = Self::builtin_mono_class("NoneType", 10);
nonetype.register_superclass(Obj, &obj);
let mut nonetype_eq = Self::builtin_methods("Eq", 2);
nonetype_eq.register_builtin_impl(
"__eq__",
fn1_met(NoneType, NoneType, Bool),
Const,
Public,
);
nonetype.register_trait(
NoneType,
builtin_poly("Eq", vec![ty_tp(NoneType)]),
nonetype_eq,
);
let mut nonetype_show = Self::builtin_methods("Show", 1);
nonetype_show.register_builtin_impl("to_str", fn0_met(NoneType, Str), Immutable, Public);
nonetype.register_trait(NoneType, builtin_mono("Show"), nonetype_show);
/* Type */
let mut type_ = Self::builtin_mono_class("Type", 2);
type_.register_superclass(Obj, &obj);
@ -783,6 +812,21 @@ impl Context {
builtin_poly("Eq", vec![ty_tp(ClassType)]),
class_eq,
);
let mut trait_type = Self::builtin_mono_class("TraitType", 2);
trait_type.register_superclass(Type, &type_);
trait_type.register_marker_trait(builtin_mono("Named"));
let mut trait_eq = Self::builtin_methods("Eq", 2);
trait_eq.register_builtin_impl(
"__eq__",
fn1_met(TraitType, TraitType, Bool),
Const,
Public,
);
trait_type.register_trait(
TraitType,
builtin_poly("Eq", vec![ty_tp(TraitType)]),
trait_eq,
);
let g_module_t = builtin_mono("GenericModule");
let mut generic_module = Self::builtin_mono_class("GenericModule", 2);
generic_module.register_superclass(Obj, &obj);
@ -849,7 +893,15 @@ impl Context {
Immutable,
Public,
);
array_.register_trait(array_t, builtin_mono("Show"), array_show);
array_.register_trait(array_t.clone(), builtin_mono("Show"), array_show);
let array_type_t = builtin_poly("ArrayType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut array_type = Self::builtin_poly_class(
"ArrayType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
array_type.register_superclass(array_t.clone(), &array_);
array_type.register_superclass(Type, &type_);
/* Set */
let mut set_ =
Self::builtin_poly_class("Set", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], 10);
@ -892,6 +944,14 @@ impl Context {
let mut set_show = Self::builtin_methods("Show", 1);
set_show.register_builtin_impl("to_str", fn0_met(set_t.clone(), Str), Immutable, Public);
set_.register_trait(set_t.clone(), builtin_mono("Show"), set_show);
let set_type_t = builtin_poly("SetType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut set_type = Self::builtin_poly_class(
"SetType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
set_type.register_superclass(set_t.clone(), &set_);
set_type.register_superclass(Type, &type_);
/* Bytes */
let mut bytes = Self::builtin_mono_class("Bytes", 2);
bytes.register_superclass(Obj, &obj);
@ -1117,243 +1177,16 @@ impl Context {
),
tuple5_eq,
);
let mut tuple6 = Self::builtin_poly_class(
"Tuple6",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
],
2,
);
tuple6.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple6_eq = Self::builtin_methods("Eq", 2);
tuple6_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
Bool,
),
Const,
Public,
);
tuple6.register_trait(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
))],
),
tuple6_eq,
);
let mut tuple7 = Self::builtin_poly_class(
"Tuple7",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
],
2,
);
tuple7.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple7_eq = Self::builtin_methods("Eq", 2);
tuple7_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
Bool,
),
Const,
Public,
);
tuple7.register_trait(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
))],
),
tuple7_eq,
);
let mut tuple8 = Self::builtin_poly_class(
"Tuple8",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
PS::t_nd("H"),
],
2,
);
tuple8.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple8_eq = Self::builtin_methods("Eq", 2);
tuple8_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
Bool,
),
Const,
Public,
);
tuple8.register_trait(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
))],
),
tuple8_eq,
);
/* record */
let mut record = Self::builtin_mono_class("Record", 2);
record.register_superclass(Obj, &obj);
let mut record_type = Self::builtin_mono_class("RecordType", 2);
record_type.register_superclass(builtin_mono("Record"), &record);
record_type.register_superclass(builtin_mono("Type"), &type_);
record_type.register_superclass(Type, &type_);
/* Or (true or type) */
let or_t = builtin_poly("Or", vec![ty_tp(mono_q("L")), ty_tp(mono_q("R"))]);
let mut or = Self::builtin_poly_class("Or", vec![PS::t_nd("L"), PS::t_nd("R")], 2);
or.register_superclass(Obj, &obj);
/* Float_mut */
let mut float_mut = Self::builtin_mono_class("Float!", 2);
float_mut.register_superclass(Float, &float);
@ -1378,15 +1211,7 @@ impl Context {
ratio_mut.register_superclass(Ratio, &ratio);
let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2);
ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio));
let f_t = kw(
"f",
func(
vec![kw("old", builtin_mono("Ratio"))],
None,
vec![],
builtin_mono("Ratio"),
),
);
let f_t = kw("f", func(vec![kw("old", Ratio)], None, vec![], Ratio));
let t = pr_met(
ref_mut(builtin_mono("Ratio!"), None),
vec![f_t],
@ -1462,7 +1287,7 @@ impl Context {
);
/* Str_mut */
let mut str_mut = Self::builtin_mono_class("Str!", 2);
str_mut.register_superclass(Str, &str_);
str_mut.register_superclass(Str, &nonetype);
let mut str_mut_mutable = Self::builtin_methods("Mutable", 2);
str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str));
let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str));
@ -1500,7 +1325,6 @@ impl Context {
file_mut_readable,
);
/* Array_mut */
let array_t = builtin_poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let mut array_mut_ = Self::builtin_poly_class(
"Array!",
@ -1617,7 +1441,8 @@ impl Context {
/* Range */
let range_t = builtin_poly("Range", vec![TyParam::t(mono_q("T"))]);
let mut range = Self::builtin_poly_class("Range", vec![PS::t_nd("T")], 2);
range.register_superclass(Obj, &obj);
// range.register_superclass(Obj, &obj);
range.register_superclass(Type, &type_);
range.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("T"))]));
let mut range_eq = Self::builtin_methods("Eq", 2);
range_eq.register_builtin_impl(
@ -1653,12 +1478,16 @@ impl Context {
self.register_builtin_type(Ratio, ratio, Const);
self.register_builtin_type(Bool, bool_, Const);
self.register_builtin_type(Str, str_, Const);
self.register_builtin_type(NoneType, nonetype, Const);
self.register_builtin_type(Type, type_, Const);
self.register_builtin_type(ClassType, class_type, Const);
self.register_builtin_type(TraitType, trait_type, Const);
self.register_builtin_type(g_module_t, generic_module, Const);
self.register_builtin_type(module_t, module, Const);
self.register_builtin_type(array_t, array_, Const);
self.register_builtin_type(array_type_t, array_type, Const);
self.register_builtin_type(set_t, set_, Const);
self.register_builtin_type(set_type_t, set_type, Const);
self.register_builtin_type(builtin_mono("Bytes"), bytes, Const);
self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const);
self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const);
@ -1683,47 +1512,9 @@ impl Context {
tuple5,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
]),
tuple6,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
]),
tuple7,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
mono_q("H"),
]),
tuple8,
Const,
);
self.register_builtin_type(builtin_mono("Record"), record, Const);
self.register_builtin_type(builtin_mono("RecordType"), record_type, Const);
self.register_builtin_type(or_t, or, Const);
self.register_builtin_type(builtin_mono("Int!"), int_mut, Const);
self.register_builtin_type(builtin_mono("Nat!"), nat_mut, Const);
self.register_builtin_type(builtin_mono("Float!"), float_mut, Const);
@ -1744,12 +1535,19 @@ impl Context {
fn init_builtin_funcs(&mut self) {
let t_abs = nd_func(vec![kw("n", builtin_mono("Num"))], None, Nat);
let t_ascii = nd_func(vec![kw("object", Obj)], None, Str);
let t_assert = func(
vec![kw("condition", Bool)],
None,
vec![kw("err_message", Str)],
NoneType,
);
let t_bin = nd_func(vec![kw("n", Int)], None, Str);
let t_chr = nd_func(
vec![kw("i", Type::from(value(0usize)..=value(1_114_111usize)))],
None,
Str,
);
let t_classof = nd_func(vec![kw("old", Obj)], None, ClassType);
let t_compile = nd_func(vec![kw("src", Str)], None, Code);
let t_cond = nd_func(
@ -1786,6 +1584,27 @@ impl Context {
module(mono_q_tp("Path")),
);
let t_import = quant(t_import, set! {static_instance("Path", Str)});
let t_isinstance = nd_func(
vec![
kw("object", Obj),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_issubclass = nd_func(
vec![
kw("subclass", ClassType),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_len = nd_func(
vec![kw("s", builtin_poly("Seq", vec![TyParam::erased(Type)]))],
None,
Nat,
);
let t_log = func(
vec![],
Some(kw("objects", ref_(Obj))),
@ -1797,31 +1616,57 @@ impl Context {
],
NoneType,
);
let t_oct = nd_func(vec![kw("x", Int)], None, Str);
let t_ord = nd_func(vec![kw("c", Str)], None, Nat);
let t_panic = nd_func(vec![kw("err_message", Str)], None, Never);
let m = mono_q("M");
// TODO: mod
let t_pow = nd_func(
vec![kw("base", m.clone()), kw("exp", m.clone())],
None,
m.clone(),
);
let t_pow = quant(
t_pow,
set! {static_instance("M", builtin_poly("Mul", vec![ty_tp(m)]))},
);
let t_pyimport = nd_func(
vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))],
None,
module(mono_q_tp("Path")),
);
let t_panic = nd_func(vec![kw("err_message", Str)], None, NoneType);
let t_pyimport = quant(t_pyimport, set! {static_instance("Path", Str)});
let t_quit = func(vec![], None, vec![kw("code", Int)], NoneType);
let t_exit = t_quit.clone();
let t_repr = nd_func(vec![kw("object", Obj)], None, Str);
let t_round = nd_func(vec![kw("number", Float)], None, Int);
self.register_builtin_impl("abs", t_abs, Immutable, Private);
self.register_builtin_impl("ascii", t_ascii, Immutable, Private);
self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく
self.register_builtin_impl("bin", t_bin, Immutable, Private);
self.register_builtin_impl("chr", t_chr, Immutable, Private);
self.register_builtin_impl("classof", t_classof, Immutable, Private);
self.register_builtin_impl("compile", t_compile, Immutable, Private);
self.register_builtin_impl("cond", t_cond, Immutable, Private);
self.register_builtin_impl("discard", t_discard, Immutable, Private);
self.register_builtin_impl("exit", t_exit, Immutable, Private);
self.register_builtin_impl("if", t_if, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("import", t_import, Immutable, Private);
self.register_builtin_impl("isinstance", t_isinstance, Immutable, Private);
self.register_builtin_impl("issubclass", t_issubclass, Immutable, Private);
self.register_builtin_impl("len", t_len, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("oct", t_oct, Immutable, Private);
self.register_builtin_impl("ord", t_ord, Immutable, Private);
self.register_builtin_impl("panic", t_panic, Immutable, Private);
self.register_builtin_impl("pow", t_pow, Immutable, Private);
if cfg!(feature = "debug") {
self.register_builtin_impl("py", t_pyimport.clone(), Immutable, Private);
}
self.register_builtin_impl("pyimport", t_pyimport, Immutable, Private);
self.register_builtin_impl("quit", t_quit, Immutable, Private);
self.register_builtin_impl("repr", t_repr, Immutable, Private);
self.register_builtin_impl("round", t_round, Immutable, Private);
}
fn init_builtin_const_funcs(&mut self) {
@ -2051,7 +1896,7 @@ impl Context {
self.register_builtin_decl("__rorng__", op_t.clone(), Private);
self.register_builtin_decl("__orng__", op_t, Private);
// TODO: use existential type: |T: Type| (T, In(T)) -> Bool
let op_t = bin_op(mono_q("T"), mono_q("I"), Bool);
let op_t = bin_op(mono_q("I"), mono_q("T"), Bool);
let op_t = quant(
op_t,
set! { static_instance("T", Type), subtypeof(mono_q("I"), builtin_poly("In", vec![ty_tp(mono_q("T"))])) },

View file

@ -17,7 +17,7 @@ use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token;
use erg_type::constructors::{
anon, builtin_mono, free_var, func, module, mono_proj, subr_t, v_enum,
anon, builtin_mono, builtin_poly, free_var, func, module, mono_proj, subr_t, v_enum,
};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
@ -87,6 +87,31 @@ impl Context {
})
}
pub(crate) fn get_mut_current_scope_var(&mut self, name: &str) -> Option<&mut VarInfo> {
self.locals
.get_mut(name)
.or_else(|| self.decls.get_mut(name))
.or_else(|| {
self.params
.iter_mut()
.find(|(opt_name, _)| {
opt_name
.as_ref()
.map(|n| &n.inspect()[..] == name)
.unwrap_or(false)
})
.map(|(_, vi)| vi)
})
.or_else(|| {
for (_, methods) in self.methods_list.iter_mut() {
if let Some(vi) = methods.get_mut_current_scope_var(name) {
return Some(vi);
}
}
None
})
}
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.locals.get_key_value(name)
}
@ -1160,8 +1185,19 @@ impl Context {
}
pub(crate) fn get_similar_name(&self, name: &str) -> Option<&str> {
match name {
"true" => return Some("True"),
"false" => return Some("False"),
"Null" | "Nil" | "null" | "nil" | "none" => return Some("None"),
"del" => return Some("Del"),
"int" => return Some("Int"),
"nat" => return Some("Nat"),
"str" => return Some("Str"),
"bool" => return Some("Bool"),
_ => {}
}
let name = readable_name(name);
// TODO: add decls
// REVIEW: add decls?
get_similar_name(
self.params
.iter()
@ -1298,35 +1334,6 @@ impl Context {
concatenated
}
pub(crate) fn _get_nominal_super_trait_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
let ctx = self.get_nominal_type_ctx(t)?;
Some(ctx.super_traits.iter().map(|sup| {
let sup_ctx = self
.get_nominal_type_ctx(sup)
.unwrap_or_else(|| todo!("{} not found", sup));
sup_ctx
}))
}
pub(crate) fn _get_nominal_super_class_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
// if `t` is {S: Str | ...}, `ctx_t` will be Str
// else if `t` is Array(Int, 10), `ctx_t` will be Array(T, N) (if Array(Int, 10) is not specialized)
let ctx = self.get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
Some(
ctx.super_classes
.iter()
.map(|sup| self.get_nominal_type_ctx(sup).unwrap()),
)
}
pub(crate) fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a Context>> {
match t {
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()),
@ -1364,6 +1371,7 @@ impl Context {
}
}
/// include `t` itself
fn get_simple_nominal_super_type_ctxs<'a>(
&'a self,
t: &Type,
@ -1377,6 +1385,19 @@ impl Context {
Some(vec![ctx].into_iter().chain(sups))
}
/// if `typ` is a refinement type, include the base type (refine.t)
pub(crate) fn get_super_classes(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
self.get_nominal_type_ctx(typ).map(|ctx| {
let super_classes = ctx.super_classes.clone();
let derefined = typ.derefine();
if typ != &derefined {
vec![derefined].into_iter().chain(super_classes)
} else {
vec![].into_iter().chain(super_classes)
}
})
}
// TODO: Never
pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a Context> {
match typ {
@ -1433,7 +1454,7 @@ impl Context {
}
Type::Poly { path, name, .. } => {
if self.path() == path {
if let Some((_, ctx)) = self.rec_get_mono_type(name) {
if let Some((_, ctx)) = self.rec_get_poly_type(name) {
return Some(ctx);
}
}
@ -1448,7 +1469,7 @@ impl Context {
.and_then(|cache| cache.ref_ctx(path.as_path()))
})
{
if let Some((_, ctx)) = ctx.rec_get_mono_type(name) {
if let Some((_, ctx)) = ctx.rec_get_poly_type(name) {
return Some(ctx);
}
}
@ -1495,16 +1516,10 @@ impl Context {
return Some(res);
}
}
Type::Or(l, r) => {
let lctx = self.get_nominal_type_ctx(l)?;
let rctx = self.get_nominal_type_ctx(r)?;
// use smaller context
return match (self.supertype_of(l, r), self.supertype_of(r, l)) {
(true, true) => Some(lctx),
(true, false) => Some(rctx),
(false, true) => Some(lctx),
(false, false) => None,
};
Type::Or(_l, _r) => {
if let Some(ctx) = self.get_nominal_type_ctx(&builtin_poly("Or", vec![])) {
return Some(ctx);
}
}
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => {

View file

@ -26,7 +26,6 @@ use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type};
use TyParamOrdering::*;
use Type::*;
use crate::context::eval::eval_lit;
use crate::context::{Context, RegistrationMode};
use crate::error::{SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult};
use crate::hir;
@ -577,7 +576,7 @@ impl Context {
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_ctx, mode)?
} else {
match &sig.pat {
ast::ParamPattern::Lit(lit) => v_enum(set![eval_lit(lit)]),
ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]),
// TODO: Array<Lit>
_ => {
let level = if mode == PreRegister {
@ -613,7 +612,7 @@ impl Context {
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_ctx, mode)?;
match (sig.inspect(), &sig.opt_default_val) {
(Some(name), Some(default)) => {
let default = self.instantiate_const_expr(default);
let default = self.instantiate_const_expr(default)?;
Ok(ParamTy::kw_default(
name.clone(),
t,
@ -665,7 +664,7 @@ impl Context {
if let Some(first) = args.next() {
let t = self.instantiate_const_expr_as_type(&first.expr)?;
let len = args.next().unwrap();
let len = self.instantiate_const_expr(&len.expr);
let len = self.instantiate_const_expr(&len.expr)?;
Ok(array(t, len))
} else {
Ok(builtin_mono("GenericArray"))
@ -707,23 +706,28 @@ impl Context {
}
other => {
// FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)),
_ => {
todo!()
let mut new_params = vec![];
for arg in simple.args.pos_args() {
match &arg.expr {
ast::ConstExpr::Lit(lit) => {
new_params.push(TyParam::Value(self.eval_lit(lit)?));
}
_ => {
todo!()
}
}
});
}
// FIXME: non-builtin
Ok(builtin_poly(Str::rc(other), params.collect()))
Ok(builtin_poly(Str::rc(other), new_params))
}
}
}
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyParam {
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyCheckResult<TyParam> {
match expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)),
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
TyParam::Mono(name.inspect().clone())
Ok(TyParam::Mono(name.inspect().clone()))
}
_ => todo!(),
}
@ -780,13 +784,13 @@ impl Context {
)),
TypeSpec::Array(arr) => {
let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&arr.len);
Ok(array(elem_t, len))
let len = self.instantiate_const_expr(&arr.len)?;
Ok(builtin_poly("ArrayType", vec![ty_tp(elem_t), len]))
}
TypeSpec::Set(set) => {
let elem_t = self.instantiate_typespec(&set.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&set.len);
Ok(erg_type::constructors::set(elem_t, len))
let len = self.instantiate_const_expr(&set.len)?;
Ok(builtin_poly("SetType", vec![ty_tp(elem_t), len]))
}
// FIXME: unwrap
TypeSpec::Tuple(tys) => Ok(tuple(
@ -797,18 +801,18 @@ impl Context {
})
.collect(),
)),
// TODO: エラー処理(リテラルでない、ダブりがある)はパーサーにやらせる
TypeSpec::Enum(set) => Ok(v_enum(
set.pos_args()
.map(|arg| {
if let ast::ConstExpr::Lit(lit) = &arg.expr {
eval_lit(lit)
} else {
todo!()
}
})
.collect::<Set<_>>(),
)),
// TODO: エラー処理(リテラルでない)はパーサーにやらせる
TypeSpec::Enum(set) => {
let mut new_set = set! {};
for arg in set.pos_args() {
if let ast::ConstExpr::Lit(lit) = &arg.expr {
new_set.insert(self.eval_lit(lit)?);
} else {
todo!()
}
}
Ok(v_enum(new_set))
}
TypeSpec::Interval { op, lhs, rhs } => {
let op = match op.kind {
TokenKind::Closed => IntervalOp::Closed,
@ -817,9 +821,9 @@ impl Context {
TokenKind::Open => IntervalOp::Open,
_ => assume_unreachable!(),
};
let l = self.instantiate_const_expr(lhs);
let l = self.instantiate_const_expr(lhs)?;
let l = self.eval_tp(&l)?;
let r = self.instantiate_const_expr(rhs);
let r = self.instantiate_const_expr(rhs)?;
let r = self.eval_tp(&r)?;
if let Some(Greater) = self.try_cmp(&l, &r) {
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")

View file

@ -281,6 +281,7 @@ pub enum OperationKind {
Import,
PyImport,
Del,
AssertCast,
}
impl OperationKind {

View file

@ -14,8 +14,9 @@ use ast::{DefId, Identifier, VarName};
use erg_parser::ast;
use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum};
use erg_type::free::{Constraint, Cyclicity, FreeKind};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{ParamTy, SubrType, Type};
use erg_type::{HasType, ParamTy, SubrType, Type};
use crate::build_hir::HIRBuilder;
use crate::context::{
@ -1076,4 +1077,75 @@ impl Context {
)))
}
}
pub(crate) fn cast(
&mut self,
type_spec: ast::TypeSpec,
call: &mut hir::Call,
) -> TyCheckResult<()> {
let cast_to =
self.instantiate_typespec(&type_spec, None, None, RegistrationMode::Normal)?;
let lhs = enum_unwrap!(
call.args.get_mut_left_or_key("pred").unwrap(),
hir::Expr::BinOp
)
.lhs
.as_mut();
match (
self.supertype_of(lhs.ref_t(), &cast_to),
self.subtype_of(lhs.ref_t(), &cast_to),
) {
// assert 1 in {1}
(true, true) => Ok(()),
// assert x in Int (x: Nat)
(false, true) => Ok(()), // TODO: warn (needless)
// assert x in Nat (x: Int)
(true, false) => {
if let hir::Expr::Accessor(ref acc) = lhs {
self.change_var_type(acc, cast_to.clone())?;
}
match lhs.ref_t() {
Type::FreeVar(fv) if fv.is_linked() => {
let constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.replace(FreeKind::new_unbound(self.level, constraint));
}
Type::FreeVar(fv) => {
let new_constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.update_constraint(new_constraint);
}
_ => {
*lhs.ref_mut_t() = cast_to;
}
}
Ok(())
}
// assert x in Str (x: Int)
(false, false) => Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error(
self.cfg.input.clone(),
line!() as usize,
lhs.loc(),
self.caused_by(),
&lhs.to_string(),
&cast_to,
None,
))),
}
}
fn change_var_type(&mut self, acc: &hir::Accessor, t: Type) -> TyCheckResult<()> {
#[allow(clippy::single_match)]
match acc {
hir::Accessor::Ident(ident) => {
if let Some(vi) = self.get_mut_current_scope_var(ident.inspect()) {
vi.t = t;
} else {
todo!()
}
}
_ => {
// TODO: support other accessors
}
}
Ok(())
}
}

View file

@ -671,6 +671,13 @@ impl Context {
}
Ok(())
}
hir::Array::WithLength(arr) => {
let loc = arr.loc();
arr.t = self.deref_tyvar(mem::take(&mut arr.t), Covariant, loc)?;
self.resolve_expr_t(&mut arr.elem)?;
self.resolve_expr_t(&mut arr.len)?;
Ok(())
}
_ => todo!(),
},
hir::Expr::Tuple(tuple) => match tuple {
@ -683,12 +690,20 @@ impl Context {
},
hir::Expr::Set(set) => match set {
hir::Set::Normal(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
for elem in st.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?;
}
Ok(())
}
hir::Set::WithLength(_) => todo!(),
hir::Set::WithLength(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
self.resolve_expr_t(&mut st.elem)?;
self.resolve_expr_t(&mut st.len)?;
Ok(())
}
},
hir::Expr::Dict(_dict) => {
todo!()

View file

@ -990,6 +990,30 @@ impl EvalError {
caused_by,
)
}
pub fn invalid_literal(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
) -> Self {
Self::new(
ErrorCore::new(
errno,
SyntaxError,
loc,
switch_lang!(
"japanese" => "リテラルが不正です",
"simplified_chinese" => "字面量不合法",
"traditional_chinese" => "字面量不合法",
"english" => "invalid literal",
),
None,
),
input,
caused_by,
)
}
}
pub type EffectError = TyCheckError;
@ -1568,6 +1592,34 @@ impl LowerError {
caused_by,
)
}
#[allow(clippy::too_many_arguments)]
pub fn invalid_type_cast_error(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
name: &str,
cast_to: &Type,
hint: Option<AtomicStr>,
) -> Self {
Self::new(
ErrorCore::new(
errno,
TypeError,
loc,
switch_lang!(
"japanese" => format!("{YELLOW}{name}{RESET}の型を{RED}{cast_to}{RESET}にキャストすることはできません"),
"simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型无法转换为{RED}{cast_to}{RESET}"),
"traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型無法轉換為{RED}{cast_to}{RESET}"),
"english" => format!("the type of {YELLOW}{name}{RESET} cannot be cast to {RED}{cast_to}{RESET}"),
),
hint,
),
input,
caused_by,
)
}
}
#[derive(Debug)]

View file

@ -47,14 +47,16 @@ impl Locational for Literal {
}
}
impl From<Token> for Literal {
fn from(token: Token) -> Self {
let data = ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone());
Self {
impl TryFrom<Token> for Literal {
type Error = ();
fn try_from(token: Token) -> Result<Self, ()> {
let data =
ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone()).ok_or(())?;
Ok(Self {
t: data.t(),
value: data,
token,
}
})
}
}
@ -282,6 +284,20 @@ impl Args {
}
}
pub fn get_mut_left_or_key(&mut self, key: &str) -> Option<&mut Expr> {
if !self.pos_args.is_empty() {
Some(&mut self.pos_args.get_mut(0)?.expr)
} else if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&mut self.kw_args.get_mut(pos)?.expr)
} else {
None
}
}
pub fn insert_pos(&mut self, idx: usize, pos: PosArg) {
self.pos_args.insert(idx, pos);
}
@ -351,8 +367,8 @@ impl Identifier {
)
}
pub fn private(name: Str) -> Self {
Self::bare(None, VarName::from_str(name))
pub fn private(name: &'static str) -> Self {
Self::bare(None, VarName::from_static(name))
}
pub fn private_with_line(name: Str, line: usize) -> Self {

View file

@ -59,6 +59,10 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr);
}
}
Array::WithLength(arr) => {
self.replace_import(&mut arr.elem);
self.replace_import(&mut arr.len);
}
_ => todo!(),
},
Expr::Tuple(tuple) => match tuple {
@ -74,9 +78,11 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr);
}
}
Set::WithLength(_) => todo!(),
Set::WithLength(st) => {
self.replace_import(&mut st.elem);
self.replace_import(&mut st.len);
}
},
Expr::Dict(_dict) => {
todo!()
}
@ -241,7 +247,7 @@ impl<'a> Linker<'a> {
mod_name_lit.ln_begin().unwrap(),
mod_name_lit.col_begin().unwrap(),
);
let mod_name = Expr::Lit(Literal::from(token));
let mod_name = Expr::Lit(Literal::try_from(token).unwrap());
args.insert_pos(0, PosArg::new(mod_name));
let line = expr.ln_begin().unwrap_or(0);
for attr in comps {

View file

@ -15,6 +15,7 @@ use erg_parser::ast;
use erg_parser::ast::AST;
use erg_parser::build_ast::ASTBuilder;
use erg_parser::token::{Token, TokenKind};
use erg_parser::Parser;
use erg_type::constructors::{
array, array_mut, builtin_mono, builtin_poly, free_var, func, mono, proc, quant, set, set_mut,
@ -182,6 +183,19 @@ impl ASTLowerer {
}
}
fn lower_literal(&self, lit: ast::Literal) -> LowerResult<hir::Literal> {
let loc = lit.loc();
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
LowerError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
loc,
self.ctx.caused_by(),
)
})?;
Ok(lit)
}
fn lower_array(&mut self, array: ast::Array) -> LowerResult<hir::Array> {
log!(info "entered {}({array})", fn_name!());
match array {
@ -260,6 +274,8 @@ impl ASTLowerer {
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("ArrayType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else {
array(elem.t(), TyParam::Value(v))
}
@ -429,6 +445,8 @@ impl ASTLowerer {
"SetWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("SetType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else {
set(elem.t(), TyParam::Value(v))
}
@ -489,7 +507,7 @@ impl ASTLowerer {
}
ast::Accessor::TupleAttr(t_attr) => {
let obj = self.lower_expr(*t_attr.obj)?;
let index = hir::Literal::from(t_attr.index.token);
let index = self.lower_literal(t_attr.index)?;
let n = enum_unwrap!(index.value, ValueObj::Nat);
let t = enum_unwrap!(
obj.ref_t().typarams().get(n as usize).unwrap().clone(),
@ -562,9 +580,27 @@ impl ASTLowerer {
Ok(hir::UnaryOp::new(unary.op, expr, t))
}
// TODO: single `import`
fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.method_name));
let opt_cast_to = if call.is_assert_cast() {
if let Some(typ) = call.assert_cast_target_type() {
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
let e = LowerError::new(e.into(), self.input().clone(), self.ctx.caused_by());
LowerErrors::from(e)
})?)
} else {
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
call.args.loc(),
self.ctx.caused_by(),
"invalid assert casting type",
None,
)));
}
} else {
None
};
let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
@ -597,7 +633,7 @@ impl ASTLowerer {
} else {
None
};
let call = hir::Call::new(obj, method_name, hir_args, sig_t);
let mut call = hir::Call::new(obj, method_name, hir_args, sig_t);
match call.additional_operation() {
Some(kind @ (OperationKind::Import | OperationKind::PyImport)) => {
let mod_name =
@ -621,7 +657,12 @@ impl ASTLowerer {
)))
}
},
_ => {}
_ => {
if let Some(type_spec) = opt_cast_to {
log!(err "cast({type_spec}): {call}");
self.ctx.cast(type_spec, &mut call)?;
}
}
}
Ok(call)
}
@ -1241,7 +1282,7 @@ impl ASTLowerer {
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!());
match expr {
ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(hir::Literal::from(lit.token))),
ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr)?)),
ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.lower_tuple(tup)?)),
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.lower_record(rec)?)),

View file

@ -156,6 +156,10 @@ impl OwnershipChecker {
self.check_expr(&a.expr, ownership, false);
}
}
Array::WithLength(arr) => {
self.check_expr(&arr.elem, ownership, false);
self.check_expr(&arr.len, ownership, false);
}
_ => todo!(),
},
Expr::Tuple(tuple) => match tuple {
@ -182,12 +186,15 @@ impl OwnershipChecker {
}
}
Expr::Set(set) => match set {
hir::Set::Normal(set) => {
for a in set.elems.pos_args.iter() {
hir::Set::Normal(st) => {
for a in st.elems.pos_args.iter() {
self.check_expr(&a.expr, ownership, false);
}
}
hir::Set::WithLength(_) => todo!(),
hir::Set::WithLength(st) => {
self.check_expr(&st.elem, ownership, false);
self.check_expr(&st.len, ownership, false);
}
},
// TODO: capturing
Expr::Lambda(lambda) => {

View file

@ -0,0 +1,107 @@
from collections.abc import Iterable, Sequence, Iterator, Container
def in_operator(x, y):
if type(y) == type:
if isinstance(x, y):
return True
# TODO: trait check
return False
elif (type(y) == list or type(y) == set) and type(y[0]) == type:
# FIXME:
type_check = in_operator(x[0], y[0])
len_check = len(x) == len(y)
return type_check and len_check
elif type(y) == dict and type(y[0]) == type:
NotImplemented
else:
return x in y
class Range:
def __init__(self, start, end):
self.start = start
self.end = end
def __contains__(self, item):
pass
def __getitem__(self, item):
pass
def __len__(self):
pass
def __iter__(self):
return RangeIterator(rng=self)
Sequence.register(Range)
Container.register(Range)
Iterable.register(Range)
# represents `start<..end`
class LeftOpenRange(Range):
def __contains__(self, item):
return self.start < item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..<end`
class RightOpenRange(Range):
def __contains__(self, item):
return self.start <= item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start<..<end`
class OpenRange(Range):
def __contains__(self, item):
return self.start < item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..end`
class ClosedRange(Range):
def __contains__(self, item):
return self.start <= item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
class RangeIterator:
def __init__(self, rng):
self.rng = rng
self.needle = self.rng.start
if type(self.rng.start) == int:
if not(self.needle in self.rng):
self.needle += 1
elif type(self.rng.start) == str:
if not(self.needle in self.rng):
self.needle = chr(ord(self.needle) + 1)
else:
if not(self.needle in self.rng):
self.needle = self.needle.incremented()
def __iter__(self):
return self
def __next__(self):
if type(self.rng.start) == int:
if self.needle in self.rng:
result = self.needle
self.needle += 1
return result
elif type(self.rng.start) == str:
if self.needle in self.rng:
result = self.needle
self.needle = chr(ord(self.needle) + 1)
return result
else:
if self.needle in self.rng:
result = self.needle
self.needle = self.needle.incremented()
return result
raise StopIteration
Iterator.register(RangeIterator)

View file

@ -0,0 +1,82 @@
@Attach NeImpl
Eq(R := Self) = Trait {
.`==` = (self: Self, R) -> Bool
}
NeImpl R = Patch Eq R
NeImpl(R).
`!=`(self, other: R): Bool = not(self == other)
@Attach EqImpl, LeImpl, LtImpl, GeImpl, GtImpl
PartialOrd(R := Self) = Trait {
.cmp = (self: Self, R) -> Option Ordering
}
Ord = Subsume PartialOrd()
EqForOrd R = Patch Ord, Impl := Eq()
EqForOrd(R).
`==`(self, other: R): Bool = self.cmp(other) == Ordering.Equal
LeForOrd = Patch Ord
LeForOrd.
`<=`(self, other: Self): Bool = self.cmp(other) == Ordering.Less or self == other
LtForOrd = Patch Ord
LtForOrd.
`<`(self, other: Self): Bool = self.cmp(other) == Ordering.Less
GeForOrd = Patch Ord
GeForOrd.
`>=`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater or self == other
GtForOrd = Patch Ord
GtForOrd.
`>`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater
Add(R := Self) = Trait {
.Output = Type
.`_+_` = (self: Self, R) -> Self.Output
}
Sub(R := Self) = Trait {
.Output = Type
.`_-_` = (self: Self, R) -> Self.Output
}
Mul(R := Self()) = Trait {
.Output = Type
.`*` = (self: Self, R) -> Self.Output
}
Div(R := Self) = Trait {
.Output = Type
.`/` = (self: Self, R) -> Self.Output or Panic
}
Num: (R := Type) -> Type
Num = Add and Sub and Mul
Seq T = Trait {
.__len__ = (self: Ref(Self)) -> Nat
.get = (self: Ref(Self), Nat) -> T
}
`_+_`: |R: Type, A <: Add(R)| (A, R) -> A.AddO
`_-_`: |R: Type, S <: Add(R)| (S, R) -> S.SubO
`*`: |R, O: Type, M <: Add(R)| (M, R) -> M.MulO
`/`: |R, O: Type, D <: Add(R)| (D, R) -> D.DivO
AddForInt = Patch Int, Impl := Add()
AddForInt.AddO = Int
AddForInt.
`_+_`: (self: Self, other: Int) -> Int = magic("Add.`_+_`")
# TODO: Mul and Div
NumForInterval M, N, O, P: Int =
Patch M..N, Impl := Add(R := O..P) and Sub(R := O..P)
NumForInterval(M, N, O, P).
`_+_`: (self: Self, other: O..P) -> M+O..N+P = magic("NumForInterval.`_+_`")
`_-_`: (self: Self, other: O..P) -> M-P..N-O = magic("NumForInterval.`_-_`")
Read = Trait {
.read = (self: Ref(Self)) -> Str
}
Read! = Trait {
.read! = (self: Ref!(Self)) => Str
}
Write! = Trait {
.write! = (self: Ref!(Self), Str) => ()
}

View file

@ -0,0 +1,13 @@
discard _x = None
discard 1
# if: |T, U|(Bool, T, U) -> T or U
cond|T: Type|(c: Bool, then: T, else: T): T =
if c:
do then
do else
assert cond(False, 1, 2) == 2
# assert cond(True, 1, 3) == "a"
# assert "a" == cond(True, 1, 3)

View file

@ -1,22 +1,22 @@
[package]
name = "erg_parser"
version = "0.5.7"
description = "The Erg parser"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler/erg_parser"
documentation = "https://docs.rs/erg_parser"
homepage = "https://erg-lang.github.io/"
documentation = "http://docs.rs/erg_parser"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
[features]
debug = [ "erg_common/debug" ]
japanese = [ "erg_common/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ]
debug = ["erg_common/debug"]
japanese = ["erg_common/japanese"]
simplified_chinese = ["erg_common/simplified_chinese"]
traditional_chinese = ["erg_common/traditional_chinese"]
[dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" }
erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
[lib]
path = "lib.rs"

View file

@ -11,7 +11,7 @@ use erg_common::{
fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct,
impl_display_from_nested, impl_displayable_stream_for_wrapper, impl_locational,
impl_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
impl_stream, impl_stream_for_wrapper,
impl_stream, impl_stream_for_wrapper, option_enum_unwrap,
};
use erg_common::{fmt_vec_split_with, Str};
@ -960,6 +960,32 @@ impl Call {
args,
}
}
pub fn is_match(&self) -> bool {
self.obj
.get_name()
.map(|s| &s[..] == "match")
.unwrap_or(false)
}
pub fn is_assert_cast(&self) -> bool {
self.obj
.get_name()
.map(|s| &s[..] == "assert")
.unwrap_or(false)
&& self
.args
.get_left_or_key("pred")
.map(|pred| pred.is_bin_in())
.unwrap_or(false)
}
pub fn assert_cast_target_type(&self) -> Option<&Expr> {
self.args
.get_left_or_key("pred")
.and_then(|pred| option_enum_unwrap!(pred, Expr::BinOp))
.map(|bin| bin.args[1].as_ref())
}
}
/// e.g. `Data::{x = 1; y = 2}`
@ -3132,7 +3158,11 @@ impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record,
impl Expr {
pub fn is_match_call(&self) -> bool {
matches!(self, Expr::Call(Call{ obj, .. }) if obj.get_name().map(|s| &s[..] == "match").unwrap_or(false))
matches!(self, Expr::Call(call) if call.is_match())
}
pub fn is_bin_in(&self) -> bool {
matches!(self, Expr::BinOp(bin) if bin.op.is(TokenKind::InOp))
}
pub fn is_const_acc(&self) -> bool {

View file

@ -11,6 +11,18 @@ use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang};
#[derive(Debug)]
pub struct LexError(ErrorCore);
impl From<ErrorCore> for LexError {
fn from(core: ErrorCore) -> Self {
Self(core)
}
}
impl From<LexError> for ErrorCore {
fn from(err: LexError) -> Self {
err.0
}
}
#[derive(Debug)]
pub struct LexErrors(Vec<LexError>);

View file

@ -461,15 +461,30 @@ impl Lexer /*<'a>*/ {
let mut num = mantissa;
debug_power_assert!(self.peek_cur_ch(), ==, Some('e'));
num.push(self.consume().unwrap()); // e
num.push(self.consume().unwrap()); // + | -
while let Some(cur) = self.peek_cur_ch() {
if cur.is_ascii_digit() || cur == '_' {
num.push(self.consume().unwrap());
} else {
break;
if self.peek_cur_ch().is_some() {
num.push(self.consume().unwrap()); // + | -
while let Some(cur) = self.peek_cur_ch() {
if cur.is_ascii_digit() || cur == '_' {
num.push(self.consume().unwrap());
} else {
break;
}
}
Ok(self.emit_token(RatioLit, &num))
} else {
let token = self.emit_token(RatioLit, &num);
Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
"japanese" => format!("`{}`は無効な十進数リテラルです", &token.content),
"simplified_chinese" => format!("`{}`是无效的十进制字词", &token.content),
"traditional_chinese" => format!("`{}`是無效的十進製文字", &token.content),
"english" => format!("`{}` is invalid decimal literal", &token.content),
),
None,
))
}
Ok(self.emit_token(RatioLit, &num))
}
/// `_` will be removed at compiletime
@ -851,6 +866,10 @@ impl Iterator for Lexer /*<'a>*/ {
)))
}
}
Some('-') => {
self.consume();
self.accept(Inclusion, "<-")
}
Some('=') => {
self.consume();
self.accept(LessEq, "<=")

View file

@ -471,7 +471,8 @@ impl Parser {
}
}
}
Some(t) if t.is(LSqBr) => {
// x[...] (`x [...]` will interpreted as `x([...])`)
Some(t) if t.is(LSqBr) && acc.col_end().unwrap() == t.col_begin().unwrap() => {
self.skip();
let index = self
.try_reduce_expr(false, false, false)
@ -510,52 +511,6 @@ impl Parser {
Ok(acc)
}
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = self.validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::new(const_elems, vec![], None);
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
Ok(ConstExpr::Array(const_arr))
}
other => {
self.errs.push(ParseError::feature_error(
line!() as usize,
other.loc(),
"???",
));
Err(())
}
},
// TODO: App, Record, BinOp, UnaryOp,
other => {
self.errs.push(ParseError::syntax_error(
0,
other.loc(),
switch_lang!(
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
"traditional_chinese" => "此表達式在編譯時不可計算,因此不能用作類型參數",
"english" => "this expression is not computable at the compile-time, so cannot used as a type-argument",
),
None,
));
Err(())
}
}
}
/// For parsing elements of arrays and tuples
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
debug_call_info!(self);
@ -950,9 +905,7 @@ impl Parser {
}
}
let defs = RecordAttrs::from(defs);
let class = self
.convert_rhs_to_type_spec(class)
.map_err(|_| self.stack_dec())?;
let class = Self::expr_to_type_spec(class).map_err(|e| self.errs.push(e))?;
self.level -= 1;
Ok(Methods::new(class, vis, defs))
}
@ -1036,9 +989,7 @@ impl Parser {
let t_spec = self
.try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?;
let t_spec = self
.convert_rhs_to_type_spec(t_spec)
.map_err(|_| self.stack_dec())?;
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
stack.push(ExprOrOp::Expr(expr));
}
@ -1280,9 +1231,7 @@ impl Parser {
let t_spec = self
.try_reduce_expr(false, in_type_args, in_brace)
.map_err(|_| self.stack_dec())?;
let t_spec = self
.convert_rhs_to_type_spec(t_spec)
.map_err(|_| self.stack_dec())?;
let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
stack.push(ExprOrOp::Expr(expr));
}
@ -2173,9 +2122,7 @@ impl Parser {
pack: DataPack,
) -> ParseResult<VarDataPackPattern> {
debug_call_info!(self);
let class = self
.convert_rhs_to_type_spec(*pack.class)
.map_err(|_| self.stack_dec())?;
let class = Self::expr_to_type_spec(*pack.class).map_err(|e| self.errs.push(e))?;
let args = self
.convert_record_to_record_pat(pack.args)
.map_err(|_| self.stack_dec())?;
@ -2463,7 +2410,7 @@ impl Parser {
fn convert_kw_arg_to_default_param(&mut self, arg: KwArg) -> ParseResult<ParamSignature> {
debug_call_info!(self);
let pat = ParamPattern::VarName(VarName::new(arg.keyword));
let expr = self.validate_const_expr(arg.expr)?;
let expr = Self::validate_const_expr(arg.expr).map_err(|e| self.errs.push(e))?;
let param = ParamSignature::new(pat, arg.t_spec, Some(expr));
self.level -= 1;
Ok(param)
@ -2672,95 +2619,51 @@ impl Parser {
TypeBoundSpecs::empty(),
))
}
}
fn convert_rhs_to_type_spec(&mut self, rhs: Expr) -> ParseResult<TypeSpec> {
debug_call_info!(self);
match rhs {
Expr::Accessor(acc) => {
let t_spec = self
.convert_accessor_to_type_spec(acc)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(t_spec)
// The APIs defined below are also used by `ASTLowerer` to interpret expressions as types.
impl Parser {
fn validate_const_expr(expr: Expr) -> Result<ConstExpr, ParseError> {
match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
}
Expr::Call(call) => {
let predecl = self
.convert_call_to_predecl_type_spec(call)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::PreDeclTy(predecl))
}
Expr::Lambda(lambda) => {
let lambda = self
.convert_lambda_to_subr_type_spec(lambda)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Subr(lambda))
}
Expr::Array(array) => {
let array = self
.convert_array_to_array_type_spec(array)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Array(array))
}
Expr::Set(set) => {
let set = self
.convert_set_to_set_type_spec(set)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Set(set))
}
Expr::BinOp(bin) => {
if bin.op.kind.is_range_op() {
let op = bin.op;
let mut args = bin.args.into_iter();
let lhs = self
.validate_const_expr(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.validate_const_expr(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Interval { op, lhs, rhs })
} else if bin.op.kind == TokenKind::AndOp {
let mut args = bin.args.into_iter();
let lhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::and(lhs, rhs))
} else if bin.op.kind == TokenKind::OrOp {
let mut args = bin.args.into_iter();
let lhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::or(lhs, rhs))
} else {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, bin.loc());
self.errs.push(err);
Err(())
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = Self::validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::new(const_elems, vec![], None);
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
Ok(ConstExpr::Array(const_arr))
}
}
other => {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err);
Err(())
}
other => Err(ParseError::feature_error(
line!() as usize,
other.loc(),
"???",
)),
},
// TODO: App, Record, BinOp, UnaryOp,
other => Err(ParseError::syntax_error(
line!() as usize,
other.loc(),
switch_lang!(
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
"traditional_chinese" => "此表達式在編譯時不可計算,因此不能用作類型參數",
"english" => "this expression is not computable at the compile-time, so cannot used as a type-argument",
),
None,
)),
}
}
fn convert_accessor_to_type_spec(&mut self, accessor: Accessor) -> ParseResult<TypeSpec> {
debug_call_info!(self);
fn accessor_to_type_spec(accessor: Accessor) -> Result<TypeSpec, ParseError> {
let t_spec = match accessor {
Accessor::Ident(ident) => {
let predecl =
@ -2768,32 +2671,22 @@ impl Parser {
TypeSpec::PreDeclTy(predecl)
}
Accessor::TypeApp(tapp) => {
let spec = self
.convert_rhs_to_type_spec(*tapp.obj)
.map_err(|_| self.stack_dec())?;
let spec = Self::expr_to_type_spec(*tapp.obj)?;
TypeSpec::type_app(spec, tapp.type_args)
}
other => {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err);
return Err(());
return Err(err);
}
};
self.level -= 1;
Ok(t_spec)
}
fn convert_call_to_predecl_type_spec(&mut self, _call: Call) -> ParseResult<PreDeclTypeSpec> {
debug_call_info!(self);
fn call_to_predecl_type_spec(_call: Call) -> Result<PreDeclTypeSpec, ParseError> {
todo!()
}
fn convert_lambda_to_subr_type_spec(
&mut self,
mut lambda: Lambda,
) -> ParseResult<SubrTypeSpec> {
debug_call_info!(self);
fn lambda_to_subr_type_spec(mut lambda: Lambda) -> Result<SubrTypeSpec, ParseError> {
let bounds = lambda.sig.bounds;
let lparen = lambda.sig.params.parens.map(|(l, _)| l);
let mut non_defaults = vec![];
@ -2838,8 +2731,7 @@ impl Parser {
};
defaults.push(param);
}
let return_t = self.convert_rhs_to_type_spec(lambda.body.remove(0))?;
self.level -= 1;
let return_t = Self::expr_to_type_spec(lambda.body.remove(0))?;
Ok(SubrTypeSpec::new(
bounds,
lparen,
@ -2851,45 +2743,86 @@ impl Parser {
))
}
fn convert_array_to_array_type_spec(&mut self, array: Array) -> ParseResult<ArrayTypeSpec> {
debug_call_info!(self);
fn array_to_array_type_spec(array: Array) -> Result<ArrayTypeSpec, ParseError> {
match array {
Array::Normal(arr) => {
// TODO: add hint
self.errs
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc()));
Err(())
let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
Err(err)
}
Array::WithLength(arr) => {
let t_spec = self.convert_rhs_to_type_spec(arr.elem.expr)?;
let len = self.validate_const_expr(*arr.len)?;
self.level -= 1;
let t_spec = Self::expr_to_type_spec(arr.elem.expr)?;
let len = Self::validate_const_expr(*arr.len)?;
Ok(ArrayTypeSpec::new(t_spec, len))
}
Array::Comprehension(arr) => {
// TODO: add hint
self.errs
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc()));
Err(())
let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
Err(err)
}
}
}
fn convert_set_to_set_type_spec(&mut self, set: Set) -> ParseResult<SetTypeSpec> {
debug_call_info!(self);
fn set_to_set_type_spec(set: Set) -> Result<SetTypeSpec, ParseError> {
match set {
Set::Normal(arr) => {
// TODO: add hint
self.errs
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc()));
Err(())
let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
Err(err)
}
Set::WithLength(set) => {
let t_spec = self.convert_rhs_to_type_spec(set.elem.expr)?;
let len = self.validate_const_expr(*set.len)?;
self.level -= 1;
let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
let len = Self::validate_const_expr(*set.len)?;
Ok(SetTypeSpec::new(t_spec, len))
}
}
}
pub fn expr_to_type_spec(rhs: Expr) -> Result<TypeSpec, ParseError> {
match rhs {
Expr::Accessor(acc) => Self::accessor_to_type_spec(acc),
Expr::Call(call) => {
let predecl = Self::call_to_predecl_type_spec(call)?;
Ok(TypeSpec::PreDeclTy(predecl))
}
Expr::Lambda(lambda) => {
let lambda = Self::lambda_to_subr_type_spec(lambda)?;
Ok(TypeSpec::Subr(lambda))
}
Expr::Array(array) => {
let array = Self::array_to_array_type_spec(array)?;
Ok(TypeSpec::Array(array))
}
Expr::Set(set) => {
let set = Self::set_to_set_type_spec(set)?;
Ok(TypeSpec::Set(set))
}
Expr::BinOp(bin) => {
if bin.op.kind.is_range_op() {
let op = bin.op;
let mut args = bin.args.into_iter();
let lhs = Self::validate_const_expr(*args.next().unwrap())?;
let rhs = Self::validate_const_expr(*args.next().unwrap())?;
Ok(TypeSpec::Interval { op, lhs, rhs })
} else if bin.op.kind == TokenKind::AndOp {
let mut args = bin.args.into_iter();
let lhs = Self::expr_to_type_spec(*args.next().unwrap())?;
let rhs = Self::expr_to_type_spec(*args.next().unwrap())?;
Ok(TypeSpec::and(lhs, rhs))
} else if bin.op.kind == TokenKind::OrOp {
let mut args = bin.args.into_iter();
let lhs = Self::expr_to_type_spec(*args.next().unwrap())?;
let rhs = Self::expr_to_type_spec(*args.next().unwrap())?;
Ok(TypeSpec::or(lhs, rhs))
} else {
let err = ParseError::simple_syntax_error(line!() as usize, bin.loc());
Err(err)
}
}
other => {
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
Err(err)
}
}
}
}

View file

@ -109,6 +109,8 @@ pub enum TokenKind {
RefMutOp,
/// =
Equal,
/// <-
Inclusion,
/// :=
Walrus,
/// ->
@ -214,9 +216,8 @@ impl TokenKind {
| InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp,
Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => {
TokenCategory::SpecialBinOp
}
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
| Inclusion => TokenCategory::SpecialBinOp,
Equal => TokenCategory::DefOp,
FuncArrow | ProcArrow => TokenCategory::LambdaOp,
Semi | Newline => TokenCategory::Separator,
@ -246,14 +247,14 @@ impl TokenKind {
BitOr => 120, // ||
Closed | LeftOpen | RightOpen | Open => 100, // range operators
Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
AndOp => 80, // and
OrOp => 70, // or
FuncArrow | ProcArrow => 60, // -> =>
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
Comma => 40, // ,
Equal | Walrus => 20, // = :=
Newline | Semi => 10, // \n ;
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
AndOp => 80, // and
OrOp => 70, // or
FuncArrow | ProcArrow | Inclusion => 60, // -> => <-
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
Comma => 40, // ,
Equal | Walrus => 20, // = :=
Newline | Semi => 10, // \n ;
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
_ => return None,
};
Some(prec)

View file

@ -1,25 +1,25 @@
[package]
name = "erg_type"
version = "0.5.7"
description = "APIs for Erg types"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/compiler/erg_type"
documentation = "https://docs.rs/erg_type"
homepage = "https://erg-lang.github.io/"
documentation = "http://docs.rs/erg_type"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
debug = [ "erg_common/debug" ]
japanese = [ "erg_common/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ]
debug = ["erg_common/debug"]
japanese = ["erg_common/japanese"]
simplified_chinese = ["erg_common/simplified_chinese"]
traditional_chinese = ["erg_common/traditional_chinese"]
[dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" }
erg_parser = { version = "0.5.7", path = "../erg_parser" }
erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
erg_parser = { version = "0.5.9-nightly.0", path = "../erg_parser" }
[lib]
path = "lib.rs"

View file

@ -330,7 +330,17 @@ pub fn callable(param_ts: Vec<Type>, return_t: Type) -> Type {
#[inline]
pub fn builtin_mono<S: Into<Str>>(name: S) -> Type {
Type::BuiltinMono(name.into())
let name = name.into();
if cfg!(feature = "debug") {
// do not use for: `Int`, `Nat`, ...
match &name[..] {
"Obj" | "Int" | "Nat" | "Ratio" | "Float" | "Bool" | "Str" | "NoneType" | "Code"
| "Frame" | "Error" | "Inf" | "NegInf" | "Type" | "ClassType" | "TraitType"
| "Patch" | "NotImplemented" | "Ellipsis" | "Never" => todo!("{name}"),
_ => {}
}
}
Type::BuiltinMono(name)
}
#[inline]

View file

@ -325,6 +325,17 @@ impl<T> FreeKind<T> {
}
}
pub fn new_unbound(lev: Level, constraint: Constraint) -> Self {
UNBOUND_ID.with(|id| {
*id.borrow_mut() += 1;
Self::Unbound {
id: *id.borrow(),
lev,
constraint,
}
})
}
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self {
Self::NamedUnbound {
name,
@ -440,6 +451,14 @@ impl<T: Clone + HasLevel> Free<T> {
*self.borrow_mut() = FreeKind::Linked(to.clone());
}
pub fn replace(&self, to: FreeKind<T>) {
// prevent linking to self
if self.is_linked() && addr_eq!(*self.borrow(), to) {
return;
}
*self.borrow_mut() = to;
}
/// NOTE: Do not use this except to rewrite circular references.
/// No reference to any type variable may be left behind when rewriting.
/// However, `get_bound_types` is safe because it does not return references.

View file

@ -1284,15 +1284,9 @@ impl PartialEq for Type {
rhs: rrhs,
},
) => lhs == rlhs && rhs == rrhs,
(Self::FreeVar(fv), other) if fv.is_linked() => &*fv.crack() == other,
(_self, Self::FreeVar(fv)) if fv.is_linked() => _self == &*fv.crack(),
(Self::FreeVar(l), Self::FreeVar(r)) => l == r,
(Self::FreeVar(fv), other) => match &*fv.borrow() {
FreeKind::Linked(t) => t == other,
_ => false,
},
(self_, Self::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) => t == self_,
_ => false,
},
(Self::Failure, Self::Failure) | (Self::Uninited, Self::Uninited) => true,
_ => false,
}
@ -1922,11 +1916,6 @@ impl Type {
matches!(self, Self::FreeVar(_))
}
/// FIXME: `Int or Str` should be monomorphic
pub fn is_monomorphic(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
}
pub const fn is_callable(&self) -> bool {
matches!(self, Self::Subr { .. } | Self::Callable { .. })
}
@ -1935,6 +1924,18 @@ impl Type {
matches!(self, Self::FreeVar(fv) if fv.is_unbound() || fv.crack().is_unbound_var())
}
/// See also: `is_monomorphized`
pub fn is_monomorphic(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
}
/// `Set(Int, 3)` is not monomorphic but monomorphized
pub fn is_monomorphized(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
|| (self.has_no_qvar() && self.has_no_unbound_var())
}
/// if the type is polymorphic
pub fn has_qvar(&self) -> bool {
match self {
Self::MonoQVar(_) | Self::PolyQVar { .. } => true,
@ -1972,6 +1973,10 @@ impl Type {
}
}
pub fn has_no_qvar(&self) -> bool {
!self.has_qvar()
}
pub fn is_cachable(&self) -> bool {
match self {
Self::FreeVar(_) => false,

View file

@ -406,27 +406,35 @@ impl ValueObj {
matches!(self, Self::Mut(_))
}
pub fn from_str(t: Type, content: Str) -> Self {
pub fn from_str(t: Type, content: Str) -> Option<Self> {
match t {
Type::Int => Self::Int(content.replace('_', "").parse::<i32>().unwrap()),
Type::Nat => Self::Nat(content.replace('_', "").parse::<u64>().unwrap()),
Type::Float => Self::Float(content.replace('_', "").parse::<f64>().unwrap()),
Type::Int => content.replace('_', "").parse::<i32>().ok().map(Self::Int),
Type::Nat => content.replace('_', "").parse::<u64>().ok().map(Self::Nat),
Type::Float => content
.replace('_', "")
.parse::<f64>()
.ok()
.map(Self::Float),
// TODO:
Type::Ratio => Self::Float(content.replace('_', "").parse::<f64>().unwrap()),
Type::Ratio => content
.replace('_', "")
.parse::<f64>()
.ok()
.map(Self::Float),
Type::Str => {
if &content[..] == "\"\"" {
Self::Str(Str::from(""))
Some(Self::Str(Str::from("")))
} else {
let replaced = content.trim_start_matches('\"').trim_end_matches('\"');
Self::Str(Str::rc(replaced))
Some(Self::Str(Str::rc(replaced)))
}
}
Type::Bool => Self::Bool(&content[..] == "True"),
Type::NoneType => Self::None,
Type::Ellipsis => Self::Ellipsis,
Type::NotImplemented => Self::NotImplemented,
Type::Inf => Self::Inf,
Type::NegInf => Self::NegInf,
Type::Bool => Some(Self::Bool(&content[..] == "True")),
Type::NoneType => Some(Self::None),
Type::Ellipsis => Some(Self::Ellipsis),
Type::NotImplemented => Some(Self::NotImplemented),
Type::Inf => Some(Self::Inf),
Type::NegInf => Some(Self::NegInf),
_ => todo!("{t} {content}"),
}
}
@ -534,7 +542,7 @@ impl ValueObj {
Self::None => Type::NoneType,
other => panic!("{other} object cannot be mutated"),
},
Self::Illegal => todo!(),
Self::Illegal => Type::Failure,
}
}