mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-01 05:11:09 +00:00
Merge branch 'erg-lang:main' into fix/test
This commit is contained in:
commit
02d43dd7af
36 changed files with 802 additions and 340 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -15,7 +15,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg"
|
name = "erg"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_compiler",
|
"erg_compiler",
|
||||||
|
@ -25,14 +25,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_common"
|
name = "erg_common"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_compiler"
|
name = "erg_compiler"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
"erg_parser",
|
"erg_parser",
|
||||||
|
@ -41,14 +41,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_parser"
|
name = "erg_parser"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erg_type"
|
name = "erg_type"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"erg_common",
|
"erg_common",
|
||||||
]
|
]
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "erg"
|
name = "erg"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
description = "The Erg programming language"
|
description = "The Erg programming language"
|
||||||
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -46,10 +46,10 @@ traditional_chinese = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { version = "0.4.1", path = "./compiler/erg_common" }
|
erg_common = { version = "0.4.6", path = "./compiler/erg_common" }
|
||||||
erg_parser = { version = "0.4.1", path = "./compiler/erg_parser" }
|
erg_parser = { version = "0.4.6", path = "./compiler/erg_parser" }
|
||||||
erg_compiler = { version = "0.4.1", path = "./compiler/erg_compiler" }
|
erg_compiler = { version = "0.4.6", path = "./compiler/erg_compiler" }
|
||||||
erg_type = { version = "0.4.1", path = "./compiler/erg_type" }
|
erg_type = { version = "0.4.6", path = "./compiler/erg_type" }
|
||||||
|
|
||||||
# [workspace]
|
# [workspace]
|
||||||
# member = ["cm", "dyne"]
|
# member = ["cm", "dyne"]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "erg_common"
|
name = "erg_common"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
description = "A common components library of Erg"
|
description = "A common components library of Erg"
|
||||||
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_common"
|
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_common"
|
||||||
|
|
166
compiler/erg_common/astr.rs
Normal file
166
compiler/erg_common/astr.rs
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::ops::{Add, Deref};
|
||||||
|
|
||||||
|
use crate::Str;
|
||||||
|
|
||||||
|
pub type ArcStr = std::sync::Arc<str>;
|
||||||
|
|
||||||
|
/// Used to hold an immutable string.
|
||||||
|
///
|
||||||
|
/// It can construct as a const (by AtomicStr::ever).
|
||||||
|
#[derive(Debug, Clone, Eq)]
|
||||||
|
pub enum AtomicStr {
|
||||||
|
Arc(ArcStr),
|
||||||
|
Static(&'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsafe impl Sync for AtomicStr {}
|
||||||
|
|
||||||
|
impl PartialEq for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &AtomicStr) -> bool {
|
||||||
|
self[..] == other[..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<&str> for AtomicStr {
|
||||||
|
type Output = AtomicStr;
|
||||||
|
#[inline]
|
||||||
|
fn add(self, other: &str) -> AtomicStr {
|
||||||
|
AtomicStr::from(&format!("{self}{other}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for AtomicStr {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
match self {
|
||||||
|
AtomicStr::Arc(s) => (s[..]).hash(state),
|
||||||
|
AtomicStr::Static(s) => s.hash(state),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AtomicStr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
AtomicStr::Arc(s) => write!(f, "{s}"),
|
||||||
|
AtomicStr::Static(s) => write!(f, "{s}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// &'static str -> &strになってしまわないように
|
||||||
|
// あえて`impl<S: Into<Str>> From<S> for AtomicStr { ... }`はしない
|
||||||
|
impl From<&'static str> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: &'static str) -> Self {
|
||||||
|
AtomicStr::ever(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&String> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: &String) -> Self {
|
||||||
|
AtomicStr::Arc((s[..]).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
AtomicStr::Arc((s[..]).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ArcStr> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: &ArcStr) -> Self {
|
||||||
|
AtomicStr::Arc(s.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ArcStr> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: ArcStr) -> Self {
|
||||||
|
AtomicStr::Arc(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&AtomicStr> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: &AtomicStr) -> Self {
|
||||||
|
match s {
|
||||||
|
AtomicStr::Arc(s) => AtomicStr::Arc(s.clone()),
|
||||||
|
AtomicStr::Static(s) => AtomicStr::Static(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Str> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: Str) -> Self {
|
||||||
|
match s {
|
||||||
|
Str::Rc(s) => AtomicStr::Arc((&s[..]).into()),
|
||||||
|
Str::Static(s) => AtomicStr::Static(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Str> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: &Str) -> Self {
|
||||||
|
match s {
|
||||||
|
Str::Rc(s) => AtomicStr::Arc((&s[..]).into()),
|
||||||
|
Str::Static(s) => AtomicStr::Static(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for AtomicStr {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Borrow<str> for AtomicStr {
|
||||||
|
#[inline]
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
AtomicStr::Arc(s) => s.borrow(),
|
||||||
|
AtomicStr::Static(s) => s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for AtomicStr {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
self.borrow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtomicStr {
|
||||||
|
pub const fn ever(s: &'static str) -> Self {
|
||||||
|
AtomicStr::Static(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arc(s: &str) -> Self {
|
||||||
|
AtomicStr::Arc(s.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_rc(self) -> ArcStr {
|
||||||
|
match self {
|
||||||
|
AtomicStr::Arc(s) => s,
|
||||||
|
AtomicStr::Static(s) => ArcStr::from(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_uppercase(&self) -> bool {
|
||||||
|
self.chars()
|
||||||
|
.next()
|
||||||
|
.map(|c| c.is_uppercase())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use crate::stdin::GLOBAL_STDIN;
|
use crate::stdin::GLOBAL_STDIN;
|
||||||
use crate::Str;
|
|
||||||
use crate::{power_assert, read_file};
|
use crate::{power_assert, read_file};
|
||||||
|
|
||||||
pub const SEMVER: &str = env!("CARGO_PKG_VERSION");
|
pub const SEMVER: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
@ -19,12 +18,12 @@ pub const BUILD_DATE: &str = env!("BUILD_DATE");
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
/// filename
|
/// filename
|
||||||
File(Str),
|
File(String),
|
||||||
REPL,
|
REPL,
|
||||||
/// same content as cfg.command
|
/// same content as cfg.command
|
||||||
Pipe(Str),
|
Pipe(String),
|
||||||
/// from command option | eval
|
/// from command option | eval
|
||||||
Str(Str),
|
Str(String),
|
||||||
Dummy,
|
Dummy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self) -> Str {
|
pub fn read(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => {
|
Self::File(filename) => {
|
||||||
let file = match File::open(&filename[..]) {
|
let file = match File::open(&filename[..]) {
|
||||||
|
@ -63,15 +62,14 @@ impl Input {
|
||||||
process::exit(code);
|
process::exit(code);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let src = match read_file(file) {
|
match read_file(file) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let code = e.raw_os_error().unwrap_or(1);
|
let code = e.raw_os_error().unwrap_or(1);
|
||||||
println!("cannot read '{filename}': [Errno {code}] {e}");
|
println!("cannot read '{filename}': [Errno {code}] {e}");
|
||||||
process::exit(code);
|
process::exit(code);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Str::from(src)
|
|
||||||
}
|
}
|
||||||
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
||||||
Self::REPL => GLOBAL_STDIN.read(),
|
Self::REPL => GLOBAL_STDIN.read(),
|
||||||
|
@ -79,7 +77,7 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<Str> {
|
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> {
|
||||||
power_assert!(ln_begin, >=, 1);
|
power_assert!(ln_begin, >=, 1);
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => match File::open(&filename[..]) {
|
Self::File(filename) => match File::open(&filename[..]) {
|
||||||
|
@ -87,7 +85,7 @@ impl Input {
|
||||||
let mut codes = vec![];
|
let mut codes = vec![];
|
||||||
let mut lines = BufReader::new(file).lines().skip(ln_begin - 1);
|
let mut lines = BufReader::new(file).lines().skip(ln_begin - 1);
|
||||||
for _ in ln_begin..=ln_end {
|
for _ in ln_begin..=ln_end {
|
||||||
codes.push(Str::from(lines.next().unwrap().unwrap()));
|
codes.push(lines.next().unwrap().unwrap());
|
||||||
}
|
}
|
||||||
codes
|
codes
|
||||||
}
|
}
|
||||||
|
@ -96,18 +94,18 @@ impl Input {
|
||||||
Self::Pipe(s) | Self::Str(s) => s.split('\n').collect::<Vec<_>>()
|
Self::Pipe(s) | Self::Str(s) => s.split('\n').collect::<Vec<_>>()
|
||||||
[ln_begin - 1..=ln_end - 1]
|
[ln_begin - 1..=ln_end - 1]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Str::rc(*s))
|
.map(|s| s.to_string())
|
||||||
.collect(),
|
.collect(),
|
||||||
Self::REPL => GLOBAL_STDIN.reread_lines(ln_begin, ln_end),
|
Self::REPL => GLOBAL_STDIN.reread_lines(ln_begin, ln_end),
|
||||||
Self::Dummy => panic!("cannot read lines from a dummy file"),
|
Self::Dummy => panic!("cannot read lines from a dummy file"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread(&self) -> Str {
|
pub fn reread(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::File(_filename) => todo!(),
|
Self::File(_filename) => todo!(),
|
||||||
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
||||||
Self::REPL => Str::from(GLOBAL_STDIN.reread().trim_end().to_owned()),
|
Self::REPL => GLOBAL_STDIN.reread().trim_end().to_owned(),
|
||||||
Self::Dummy => panic!("cannot read from a dummy file"),
|
Self::Dummy => panic!("cannot read from a dummy file"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,6 +124,7 @@ pub struct ErgConfig {
|
||||||
pub dump_as_pyc: bool,
|
pub dump_as_pyc: bool,
|
||||||
pub python_ver: Option<u32>,
|
pub python_ver: Option<u32>,
|
||||||
pub py_server_timeout: u64,
|
pub py_server_timeout: u64,
|
||||||
|
pub quiet_startup: bool,
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub module: &'static str,
|
pub module: &'static str,
|
||||||
/// verbosity level for system messages.
|
/// verbosity level for system messages.
|
||||||
|
@ -142,7 +141,7 @@ impl Default for ErgConfig {
|
||||||
let input = if is_stdin_piped {
|
let input = if is_stdin_piped {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
stdin().read_to_string(&mut buffer).unwrap();
|
stdin().read_to_string(&mut buffer).unwrap();
|
||||||
Input::Pipe(Str::from(buffer))
|
Input::Pipe(buffer)
|
||||||
} else {
|
} else {
|
||||||
Input::REPL
|
Input::REPL
|
||||||
};
|
};
|
||||||
|
@ -152,6 +151,7 @@ impl Default for ErgConfig {
|
||||||
dump_as_pyc: false,
|
dump_as_pyc: false,
|
||||||
python_ver: None,
|
python_ver: None,
|
||||||
py_server_timeout: 10,
|
py_server_timeout: 10,
|
||||||
|
quiet_startup: false,
|
||||||
input,
|
input,
|
||||||
module: "<module>",
|
module: "<module>",
|
||||||
verbose: 2,
|
verbose: 2,
|
||||||
|
@ -174,7 +174,7 @@ impl ErgConfig {
|
||||||
while let Some(arg) = args.next() {
|
while let Some(arg) = args.next() {
|
||||||
match &arg[..] {
|
match &arg[..] {
|
||||||
"-c" => {
|
"-c" => {
|
||||||
cfg.input = Input::Str(Str::from(args.next().unwrap()));
|
cfg.input = Input::Str(args.next().unwrap());
|
||||||
}
|
}
|
||||||
"--dump-as-pyc" => {
|
"--dump-as-pyc" => {
|
||||||
cfg.dump_as_pyc = true;
|
cfg.dump_as_pyc = true;
|
||||||
|
@ -212,6 +212,9 @@ impl ErgConfig {
|
||||||
"--py-server-timeout" => {
|
"--py-server-timeout" => {
|
||||||
cfg.py_server_timeout = args.next().unwrap().parse::<u64>().unwrap();
|
cfg.py_server_timeout = args.next().unwrap().parse::<u64>().unwrap();
|
||||||
}
|
}
|
||||||
|
"--quiet-startup" => {
|
||||||
|
cfg.quiet_startup = true;
|
||||||
|
}
|
||||||
"--verbose" => {
|
"--verbose" => {
|
||||||
cfg.verbose = args.next().unwrap().parse::<u8>().unwrap();
|
cfg.verbose = args.next().unwrap().parse::<u8>().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -223,7 +226,7 @@ impl ErgConfig {
|
||||||
panic!("invalid option: {other}");
|
panic!("invalid option: {other}");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cfg.input = Input::File(Str::from(arg));
|
cfg.input = Input::File(arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ use std::fmt;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::io::{stderr, BufWriter, Write as _};
|
use std::io::{stderr, BufWriter, Write as _};
|
||||||
|
|
||||||
|
use crate::astr::AtomicStr;
|
||||||
use crate::color::*;
|
use crate::color::*;
|
||||||
use crate::config::Input;
|
use crate::config::Input;
|
||||||
use crate::traits::{Locational, Stream};
|
use crate::traits::{Locational, Stream};
|
||||||
use crate::Str;
|
|
||||||
use crate::{fmt_option, impl_display_from_debug, switch_lang};
|
use crate::{fmt_option, impl_display_from_debug, switch_lang};
|
||||||
|
|
||||||
/// ErrorKindと言っているが、ErrorだけでなくWarning, Exceptionも含まれる
|
/// ErrorKindと言っているが、ErrorだけでなくWarning, Exceptionも含まれる
|
||||||
|
@ -306,17 +306,17 @@ pub struct ErrorCore {
|
||||||
pub errno: usize,
|
pub errno: usize,
|
||||||
pub kind: ErrorKind,
|
pub kind: ErrorKind,
|
||||||
pub loc: Location,
|
pub loc: Location,
|
||||||
pub desc: Str,
|
pub desc: AtomicStr,
|
||||||
pub hint: Option<Str>,
|
pub hint: Option<AtomicStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorCore {
|
impl ErrorCore {
|
||||||
pub fn new<S: Into<Str>>(
|
pub fn new<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
kind: ErrorKind,
|
kind: ErrorKind,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
desc: S,
|
desc: S,
|
||||||
hint: Option<Str>,
|
hint: Option<AtomicStr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
errno,
|
errno,
|
||||||
|
@ -423,27 +423,31 @@ pub trait ErrorDisplay {
|
||||||
fn ref_inner(&self) -> Option<&Self>;
|
fn ref_inner(&self) -> Option<&Self>;
|
||||||
|
|
||||||
fn write_to_stderr(&self) {
|
fn write_to_stderr(&self) {
|
||||||
let mut writer = BufWriter::new(stderr());
|
let mut stderr = stderr();
|
||||||
writer
|
self.write_to(&mut stderr)
|
||||||
.write_all(
|
}
|
||||||
format!(
|
|
||||||
"{}{}{}: {}{}\n",
|
fn write_to<W: std::io::Write>(&self, w: &mut W) {
|
||||||
self.format_header(),
|
let mut writer = BufWriter::new(w);
|
||||||
self.format_code_and_pointer(),
|
writer.write_all(self.show().as_bytes()).unwrap();
|
||||||
self.core().kind,
|
|
||||||
self.core().desc,
|
|
||||||
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint),
|
|
||||||
)
|
|
||||||
.as_bytes(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
writer.flush().unwrap();
|
writer.flush().unwrap();
|
||||||
if let Some(inner) = self.ref_inner() {
|
if let Some(inner) = self.ref_inner() {
|
||||||
inner.write_to_stderr()
|
inner.write_to_stderr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// fmt::Display実装用
|
fn show(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"{}{}{}: {}{}\n",
|
||||||
|
self.format_header(),
|
||||||
|
self.format_code_and_pointer(),
|
||||||
|
self.core().kind,
|
||||||
|
self.core().desc,
|
||||||
|
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// for fmt::Display
|
||||||
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! provides utilities for parser, compiler, and vm crate.
|
//! provides utilities for parser, compiler, and vm crate.
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
pub mod astr;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
|
@ -2,29 +2,27 @@ use std::cell::RefCell;
|
||||||
use std::io::{stdin, BufRead, BufReader};
|
use std::io::{stdin, BufRead, BufReader};
|
||||||
use std::thread::LocalKey;
|
use std::thread::LocalKey;
|
||||||
|
|
||||||
use crate::Str;
|
|
||||||
|
|
||||||
pub struct StdinReader {
|
pub struct StdinReader {
|
||||||
pub lineno: usize,
|
pub lineno: usize,
|
||||||
buf: Vec<Str>,
|
buf: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StdinReader {
|
impl StdinReader {
|
||||||
pub fn read(&mut self) -> Str {
|
pub fn read(&mut self) -> String {
|
||||||
let mut buf = "".to_string();
|
let mut buf = "".to_string();
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
let mut reader = BufReader::new(stdin.lock());
|
let mut reader = BufReader::new(stdin.lock());
|
||||||
reader.read_line(&mut buf).unwrap();
|
reader.read_line(&mut buf).unwrap();
|
||||||
self.lineno += 1;
|
self.lineno += 1;
|
||||||
self.buf.push(buf.into());
|
self.buf.push(buf);
|
||||||
self.buf.last().unwrap().clone()
|
self.buf.last().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread(&self) -> Str {
|
pub fn reread(&self) -> String {
|
||||||
self.buf.last().unwrap().clone()
|
self.buf.last().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<Str> {
|
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> {
|
||||||
self.buf[ln_begin - 1..=ln_end - 1].to_vec()
|
self.buf[ln_begin - 1..=ln_end - 1].to_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,15 +37,15 @@ pub struct GlobalStdin(LocalKey<RefCell<StdinReader>>);
|
||||||
pub static GLOBAL_STDIN: GlobalStdin = GlobalStdin(READER);
|
pub static GLOBAL_STDIN: GlobalStdin = GlobalStdin(READER);
|
||||||
|
|
||||||
impl GlobalStdin {
|
impl GlobalStdin {
|
||||||
pub fn read(&'static self) -> Str {
|
pub fn read(&'static self) -> String {
|
||||||
self.0.with(|s| s.borrow_mut().read())
|
self.0.with(|s| s.borrow_mut().read())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread(&'static self) -> Str {
|
pub fn reread(&'static self) -> String {
|
||||||
self.0.with(|s| s.borrow().reread())
|
self.0.with(|s| s.borrow().reread())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reread_lines(&'static self, ln_begin: usize, ln_end: usize) -> Vec<Str> {
|
pub fn reread_lines(&'static self, ln_begin: usize, ln_end: usize) -> Vec<String> {
|
||||||
self.0
|
self.0
|
||||||
.with(|s| s.borrow_mut().reread_lines(ln_begin, ln_end))
|
.with(|s| s.borrow_mut().reread_lines(ln_begin, ln_end))
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ use std::vec::IntoIter;
|
||||||
|
|
||||||
use crate::config::{ErgConfig, Input, BUILD_DATE, GIT_HASH_SHORT, SEMVER};
|
use crate::config::{ErgConfig, Input, BUILD_DATE, GIT_HASH_SHORT, SEMVER};
|
||||||
use crate::error::{ErrorDisplay, ErrorKind, Location, MultiErrorDisplay};
|
use crate::error::{ErrorDisplay, ErrorKind, Location, MultiErrorDisplay};
|
||||||
use crate::Str;
|
|
||||||
use crate::{addr_eq, chomp, log, switch_unreachable};
|
use crate::{addr_eq, chomp, log, switch_unreachable};
|
||||||
|
|
||||||
pub trait Stream<T>: Sized {
|
pub trait Stream<T>: Sized {
|
||||||
|
@ -312,6 +311,12 @@ fn expect_block(src: &str) -> bool {
|
||||||
src.ends_with(&['.', '=', ':']) || src.ends_with("->") || src.ends_with("=>")
|
src.ends_with(&['.', '=', ':']) || src.ends_with("->") || src.ends_with("=>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In the REPL, it is invalid for these symbols to be at the beginning of a line
|
||||||
|
fn expect_invalid_block(src: &str) -> bool {
|
||||||
|
let src = src.trim_start();
|
||||||
|
src.starts_with(&['.', '=', ':']) || src.starts_with("->")
|
||||||
|
}
|
||||||
|
|
||||||
/// This trait implements REPL (Read-Eval-Print-Loop) automatically
|
/// This trait implements REPL (Read-Eval-Print-Loop) automatically
|
||||||
/// The `exec` method is called for file input, etc.
|
/// The `exec` method is called for file input, etc.
|
||||||
pub trait Runnable: Sized {
|
pub trait Runnable: Sized {
|
||||||
|
@ -328,7 +333,7 @@ pub trait Runnable: Sized {
|
||||||
}
|
}
|
||||||
fn finish(&mut self); // called when the :exit command is received.
|
fn finish(&mut self); // called when the :exit command is received.
|
||||||
fn clear(&mut self);
|
fn clear(&mut self);
|
||||||
fn eval(&mut self, src: Str) -> Result<String, Self::Errs>;
|
fn eval(&mut self, src: String) -> Result<String, Self::Errs>;
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs>;
|
fn exec(&mut self) -> Result<(), Self::Errs>;
|
||||||
|
|
||||||
fn ps1(&self) -> String {
|
fn ps1(&self) -> String {
|
||||||
|
@ -344,16 +349,19 @@ pub trait Runnable: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(cfg: ErgConfig) {
|
fn run(cfg: ErgConfig) {
|
||||||
|
let quiet_startup = cfg.quiet_startup;
|
||||||
let mut instance = Self::new(cfg);
|
let mut instance = Self::new(cfg);
|
||||||
let res = match instance.input() {
|
let res = match instance.input() {
|
||||||
Input::File(_) | Input::Pipe(_) | Input::Str(_) => instance.exec(),
|
Input::File(_) | Input::Pipe(_) | Input::Str(_) => instance.exec(),
|
||||||
Input::REPL => {
|
Input::REPL => {
|
||||||
let output = stdout();
|
let output = stdout();
|
||||||
let mut output = BufWriter::new(output.lock());
|
let mut output = BufWriter::new(output.lock());
|
||||||
log!(info_f output, "The REPL has started.\n");
|
if !quiet_startup {
|
||||||
output
|
log!(info_f output, "The REPL has started.\n");
|
||||||
.write_all(instance.start_message().as_bytes())
|
output
|
||||||
.unwrap();
|
.write_all(instance.start_message().as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
output.write_all(instance.ps1().as_bytes()).unwrap();
|
output.write_all(instance.ps1().as_bytes()).unwrap();
|
||||||
output.flush().unwrap();
|
output.flush().unwrap();
|
||||||
let mut lines = String::new();
|
let mut lines = String::new();
|
||||||
|
@ -381,13 +389,15 @@ pub trait Runnable: Sized {
|
||||||
&line[..]
|
&line[..]
|
||||||
};
|
};
|
||||||
lines.push_str(line);
|
lines.push_str(line);
|
||||||
if expect_block(line) || line.starts_with(' ') {
|
if expect_block(line) && !expect_invalid_block(line)
|
||||||
|
|| line.starts_with(' ') && lines.contains('\n')
|
||||||
|
{
|
||||||
lines += "\n";
|
lines += "\n";
|
||||||
output.write_all(instance.ps2().as_bytes()).unwrap();
|
output.write_all(instance.ps2().as_bytes()).unwrap();
|
||||||
output.flush().unwrap();
|
output.flush().unwrap();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match instance.eval(mem::take(&mut lines).into()) {
|
match instance.eval(mem::take(&mut lines)) {
|
||||||
Ok(out) => {
|
Ok(out) => {
|
||||||
output.write_all((out + "\n").as_bytes()).unwrap();
|
output.write_all((out + "\n").as_bytes()).unwrap();
|
||||||
output.flush().unwrap();
|
output.flush().unwrap();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "erg_compiler"
|
name = "erg_compiler"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
description = "Centimetre: the Erg compiler"
|
description = "Centimetre: the Erg compiler"
|
||||||
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler"
|
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler"
|
||||||
|
@ -17,9 +17,9 @@ simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_c
|
||||||
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
|
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { version = "0.4.1", path = "../erg_common" }
|
erg_common = { version = "0.4.6", path = "../erg_common" }
|
||||||
erg_parser = { version = "0.4.1", path = "../erg_parser" }
|
erg_parser = { version = "0.4.6", path = "../erg_parser" }
|
||||||
erg_type = { version = "0.4.1", path = "../erg_type" }
|
erg_type = { version = "0.4.6", path = "../erg_type" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::cache::CacheSet;
|
use erg_common::cache::CacheSet;
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::{Location, MultiErrorDisplay};
|
use erg_common::error::{Location, MultiErrorDisplay};
|
||||||
|
@ -1220,7 +1221,7 @@ impl CodeGenerator {
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
unary.op.loc(),
|
unary.op.loc(),
|
||||||
"",
|
"",
|
||||||
unary.op.content.clone(),
|
AtomicStr::from(unary.op.content),
|
||||||
));
|
));
|
||||||
NOT_IMPLEMENTED
|
NOT_IMPLEMENTED
|
||||||
}
|
}
|
||||||
|
@ -1267,7 +1268,7 @@ impl CodeGenerator {
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
bin.op.loc(),
|
bin.op.loc(),
|
||||||
"",
|
"",
|
||||||
bin.op.content.clone(),
|
AtomicStr::from(bin.op.content),
|
||||||
));
|
));
|
||||||
NOT_IMPLEMENTED
|
NOT_IMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::MultiErrorDisplay;
|
use erg_common::error::MultiErrorDisplay;
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::traits::{Runnable, Stream};
|
use erg_common::traits::{Runnable, Stream};
|
||||||
use erg_common::Str;
|
|
||||||
use erg_type::codeobj::CodeObj;
|
use erg_type::codeobj::CodeObj;
|
||||||
|
|
||||||
use erg_parser::ParserRunner;
|
use erg_parser::ParserRunner;
|
||||||
|
@ -134,7 +133,7 @@ impl Runnable for Compiler {
|
||||||
self.compile_and_dump_as_pyc(src, path, "exec")
|
self.compile_and_dump_as_pyc(src, path, "exec")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||||
let codeobj = self.compile(src, "eval")?;
|
let codeobj = self.compile(src, "eval")?;
|
||||||
Ok(codeobj.code_info())
|
Ok(codeobj.code_info())
|
||||||
}
|
}
|
||||||
|
@ -150,7 +149,7 @@ impl Compiler {
|
||||||
|
|
||||||
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(
|
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
src: Str,
|
src: String,
|
||||||
path: P,
|
path: P,
|
||||||
mode: &str,
|
mode: &str,
|
||||||
) -> Result<(), CompileErrors> {
|
) -> Result<(), CompileErrors> {
|
||||||
|
@ -160,7 +159,7 @@ impl Compiler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&mut self, src: Str, mode: &str) -> Result<CodeObj, CompileErrors> {
|
pub fn compile(&mut self, src: String, mode: &str) -> Result<CodeObj, CompileErrors> {
|
||||||
log!(info "the compiling process has started.");
|
log!(info "the compiling process has started.");
|
||||||
let mut cfg = self.cfg.copy();
|
let mut cfg = self.cfg.copy();
|
||||||
cfg.input = Input::Str(src);
|
cfg.input = Input::Str(src);
|
||||||
|
|
|
@ -780,23 +780,16 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn union_refinement(&self, lhs: &RefinementType, rhs: &RefinementType) -> RefinementType {
|
fn union_refinement(&self, lhs: &RefinementType, rhs: &RefinementType) -> RefinementType {
|
||||||
if let Some(max) = self.max(&lhs.t, &rhs.t) {
|
// TODO: warn if lhs.t !:> rhs.t && rhs.t !:> lhs.t
|
||||||
let name = lhs.var.clone();
|
let union = self.union(&lhs.t, &rhs.t);
|
||||||
let rhs_preds = rhs
|
let name = lhs.var.clone();
|
||||||
.preds
|
let rhs_preds = rhs
|
||||||
.iter()
|
.preds
|
||||||
.map(|p| p.clone().change_subject_name(name.clone()))
|
.iter()
|
||||||
.collect();
|
.map(|p| p.clone().change_subject_name(name.clone()))
|
||||||
// FIXME: predの包含関係も考慮する
|
.collect();
|
||||||
RefinementType::new(
|
// FIXME: predの包含関係も考慮する
|
||||||
lhs.var.clone(),
|
RefinementType::new(lhs.var.clone(), union, lhs.preds.clone().concat(rhs_preds))
|
||||||
max.clone(),
|
|
||||||
lhs.preds.clone().concat(rhs_preds),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log!(info "{lhs}\n{rhs}");
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// returns intersection of two types (A and B)
|
/// returns intersection of two types (A and B)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
|
use erg_common::error::Location;
|
||||||
use erg_common::rccell::RcCell;
|
use erg_common::rccell::RcCell;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
|
@ -496,21 +497,28 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn eval_t_params(&self, substituted: Type, level: usize) -> EvalResult<Type> {
|
pub(crate) fn eval_t_params(
|
||||||
|
&self,
|
||||||
|
substituted: Type,
|
||||||
|
level: usize,
|
||||||
|
t_loc: Location,
|
||||||
|
) -> EvalResult<Type> {
|
||||||
match substituted {
|
match substituted {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => self.eval_t_params(fv.crack().clone(), level),
|
Type::FreeVar(fv) if fv.is_linked() => {
|
||||||
|
self.eval_t_params(fv.crack().clone(), level, t_loc)
|
||||||
|
}
|
||||||
Type::Subr(mut subr) => {
|
Type::Subr(mut subr) => {
|
||||||
for pt in subr.non_default_params.iter_mut() {
|
for pt in subr.non_default_params.iter_mut() {
|
||||||
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
|
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)?;
|
||||||
}
|
}
|
||||||
if let Some(var_args) = subr.var_params.as_mut() {
|
if let Some(var_args) = subr.var_params.as_mut() {
|
||||||
*var_args.typ_mut() =
|
*var_args.typ_mut() =
|
||||||
self.eval_t_params(mem::take(var_args.typ_mut()), level)?;
|
self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc)?;
|
||||||
}
|
}
|
||||||
for pt in subr.default_params.iter_mut() {
|
for pt in subr.default_params.iter_mut() {
|
||||||
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
|
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)?;
|
||||||
}
|
}
|
||||||
let return_t = self.eval_t_params(*subr.return_t, level)?;
|
let return_t = self.eval_t_params(*subr.return_t, level, t_loc)?;
|
||||||
Ok(subr_t(
|
Ok(subr_t(
|
||||||
subr.kind,
|
subr.kind,
|
||||||
subr.non_default_params,
|
subr.non_default_params,
|
||||||
|
@ -533,7 +541,7 @@ impl Context {
|
||||||
// All type variables will be dereferenced or fail.
|
// All type variables will be dereferenced or fail.
|
||||||
let (sub, opt_sup) = match *lhs.clone() {
|
let (sub, opt_sup) = match *lhs.clone() {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => {
|
Type::FreeVar(fv) if fv.is_linked() => {
|
||||||
return self.eval_t_params(mono_proj(fv.crack().clone(), rhs), level)
|
return self.eval_t_params(mono_proj(fv.crack().clone(), rhs), level, t_loc)
|
||||||
}
|
}
|
||||||
Type::FreeVar(fv) if fv.is_unbound() => {
|
Type::FreeVar(fv) if fv.is_unbound() => {
|
||||||
let (sub, sup) = fv.get_bound_types().unwrap();
|
let (sub, sup) = fv.get_bound_types().unwrap();
|
||||||
|
@ -553,7 +561,7 @@ impl Context {
|
||||||
if let ValueObj::Type(quant_t) = obj {
|
if let ValueObj::Type(quant_t) = obj {
|
||||||
let subst_ctx = SubstContext::new(&sub, ty_ctx);
|
let subst_ctx = SubstContext::new(&sub, ty_ctx);
|
||||||
let t = subst_ctx.substitute(quant_t.typ().clone(), self)?;
|
let t = subst_ctx.substitute(quant_t.typ().clone(), self)?;
|
||||||
let t = self.eval_t_params(t, level)?;
|
let t = self.eval_t_params(t, level, t_loc)?;
|
||||||
return Ok(t);
|
return Ok(t);
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -577,7 +585,7 @@ impl Context {
|
||||||
if let ValueObj::Type(quant_t) = obj {
|
if let ValueObj::Type(quant_t) = obj {
|
||||||
let subst_ctx = SubstContext::new(&lhs, ty_ctx);
|
let subst_ctx = SubstContext::new(&lhs, ty_ctx);
|
||||||
let t = subst_ctx.substitute(quant_t.typ().clone(), self)?;
|
let t = subst_ctx.substitute(quant_t.typ().clone(), self)?;
|
||||||
let t = self.eval_t_params(t, level)?;
|
let t = self.eval_t_params(t, level, t_loc)?;
|
||||||
return Ok(t);
|
return Ok(t);
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -585,20 +593,20 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
todo!(
|
let proj = mono_proj(*lhs, rhs);
|
||||||
"{lhs}.{rhs} not found in [{}]",
|
Err(EvalError::no_candidate_error(
|
||||||
erg_common::fmt_iter(
|
line!() as usize,
|
||||||
self.get_nominal_super_type_ctxs(&lhs)
|
&proj,
|
||||||
.unwrap()
|
t_loc,
|
||||||
.map(|(_, ctx)| &ctx.name)
|
self.caused_by(),
|
||||||
)
|
self.get_no_candidate_hint(&proj),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level)?)),
|
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level, t_loc)?)),
|
||||||
Type::RefMut { before, after } => {
|
Type::RefMut { before, after } => {
|
||||||
let before = self.eval_t_params(*before, level)?;
|
let before = self.eval_t_params(*before, level, t_loc)?;
|
||||||
let after = if let Some(after) = after {
|
let after = if let Some(after) = after {
|
||||||
Some(self.eval_t_params(*after, level)?)
|
Some(self.eval_t_params(*after, level, t_loc)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -615,17 +623,23 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _eval_bound(&self, bound: TyBound, level: usize) -> EvalResult<TyBound> {
|
pub(crate) fn _eval_bound(
|
||||||
|
&self,
|
||||||
|
bound: TyBound,
|
||||||
|
level: usize,
|
||||||
|
t_loc: Location,
|
||||||
|
) -> EvalResult<TyBound> {
|
||||||
match bound {
|
match bound {
|
||||||
TyBound::Sandwiched { sub, mid, sup } => {
|
TyBound::Sandwiched { sub, mid, sup } => {
|
||||||
let sub = self.eval_t_params(sub, level)?;
|
let sub = self.eval_t_params(sub, level, t_loc)?;
|
||||||
let mid = self.eval_t_params(mid, level)?;
|
let mid = self.eval_t_params(mid, level, t_loc)?;
|
||||||
let sup = self.eval_t_params(sup, level)?;
|
let sup = self.eval_t_params(sup, level, t_loc)?;
|
||||||
Ok(TyBound::sandwiched(sub, mid, sup))
|
Ok(TyBound::sandwiched(sub, mid, sup))
|
||||||
}
|
}
|
||||||
TyBound::Instance { name: inst, t } => {
|
TyBound::Instance { name: inst, t } => Ok(TyBound::instance(
|
||||||
Ok(TyBound::instance(inst, self.eval_t_params(t, level)?))
|
inst,
|
||||||
}
|
self.eval_t_params(t, level, t_loc)?,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,36 @@
|
||||||
use erg_common::Str;
|
use erg_common::astr::AtomicStr;
|
||||||
|
use erg_common::enum_unwrap;
|
||||||
|
|
||||||
|
use erg_type::typaram::TyParam;
|
||||||
use erg_type::Type;
|
use erg_type::Type;
|
||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
enum Sequence {
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub(crate) fn get_type_mismatch_hint(&self, expected: &Type, found: &Type) -> Option<Str> {
|
fn readable_type(&self, typ: &Type) -> Type {
|
||||||
|
match typ {
|
||||||
|
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
||||||
|
let (sub, sup) = fv.get_bound_types().unwrap();
|
||||||
|
if sup == Type::Obj {
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
Type::FreeVar(fv.clone())
|
||||||
|
}
|
||||||
|
other => other.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_type_mismatch_hint(
|
||||||
|
&self,
|
||||||
|
expected: &Type,
|
||||||
|
found: &Type,
|
||||||
|
) -> Option<AtomicStr> {
|
||||||
let expected = if let Type::FreeVar(fv) = expected {
|
let expected = if let Type::FreeVar(fv) = expected {
|
||||||
if fv.is_linked() {
|
if fv.is_linked() {
|
||||||
fv.crack().clone()
|
fv.crack().clone()
|
||||||
|
@ -17,7 +42,38 @@ impl Context {
|
||||||
expected.clone()
|
expected.clone()
|
||||||
};
|
};
|
||||||
match (&expected.name()[..], &found.name()[..]) {
|
match (&expected.name()[..], &found.name()[..]) {
|
||||||
("Eq", "Float") => Some(Str::ever("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")),
|
("Eq", "Float") => Some(AtomicStr::ever("Float has no equivalence relation defined. you should use `l - r <= Float.EPSILON` instead of `l == r`.")),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<AtomicStr> {
|
||||||
|
match proj {
|
||||||
|
Type::MonoProj { lhs, rhs: _ } => {
|
||||||
|
if let Type::FreeVar(fv) = lhs.as_ref() {
|
||||||
|
let (sub, sup) = fv.get_bound_types()?;
|
||||||
|
// TODO: automating
|
||||||
|
let (verb, preposition, sequence) = match &sup.name()[..] {
|
||||||
|
"Add" => Some(("add", "and", Sequence::Forward)),
|
||||||
|
"Sub" => Some(("subtract", "from", Sequence::Backward)),
|
||||||
|
"Mul" => Some(("multiply", "and", Sequence::Forward)),
|
||||||
|
"Div" => Some(("divide", "by", Sequence::Forward)),
|
||||||
|
_ => None,
|
||||||
|
}?;
|
||||||
|
let sup = enum_unwrap!(sup.typarams().remove(0), TyParam::Type);
|
||||||
|
let sup = self.readable_type(&sup);
|
||||||
|
let (l, r) = if sequence == Sequence::Forward {
|
||||||
|
(sub, sup)
|
||||||
|
} else {
|
||||||
|
(sup, sub)
|
||||||
|
};
|
||||||
|
Some(AtomicStr::from(format!(
|
||||||
|
"cannot {verb} {l} {preposition} {r}"
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1594,7 +1594,7 @@ impl Context {
|
||||||
op_t,
|
op_t,
|
||||||
set! {
|
set! {
|
||||||
static_instance("R", Type),
|
static_instance("R", Type),
|
||||||
subtypeof(l, poly("Mul", params))
|
subtypeof(l, poly("Div", params))
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.register_builtin_impl("__div__", op_t, Const, Private);
|
self.register_builtin_impl("__div__", op_t, Const, Private);
|
||||||
|
|
|
@ -100,7 +100,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_var_error(
|
Err(TyCheckError::no_var_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
obj.loc(),
|
obj.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
self.get_similar_name(ident.inspect()),
|
self.get_similar_name(ident.inspect()),
|
||||||
))
|
))
|
||||||
|
@ -213,7 +213,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_var_error(
|
Err(TyCheckError::no_var_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
ident.loc(),
|
ident.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
self.get_similar_name(ident.inspect()),
|
self.get_similar_name(ident.inspect()),
|
||||||
))
|
))
|
||||||
|
@ -269,7 +269,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
name.loc(),
|
name.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
&self_t,
|
&self_t,
|
||||||
name.inspect(),
|
name.inspect(),
|
||||||
self.get_similar_attr(&self_t, name.inspect()),
|
self.get_similar_attr(&self_t, name.inspect()),
|
||||||
|
@ -308,7 +308,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
ident.loc(),
|
ident.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
&t,
|
&t,
|
||||||
ident.inspect(),
|
ident.inspect(),
|
||||||
self.get_similar_attr(&t, ident.inspect()),
|
self.get_similar_attr(&t, ident.inspect()),
|
||||||
|
@ -393,7 +393,7 @@ impl Context {
|
||||||
return Err(TyCheckError::singular_no_attr_error(
|
return Err(TyCheckError::singular_no_attr_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
method_name.loc(),
|
method_name.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
obj.__name__().unwrap_or("?"),
|
obj.__name__().unwrap_or("?"),
|
||||||
obj.ref_t(),
|
obj.ref_t(),
|
||||||
method_name.inspect(),
|
method_name.inspect(),
|
||||||
|
@ -404,7 +404,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
method_name.loc(),
|
method_name.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
obj.ref_t(),
|
obj.ref_t(),
|
||||||
method_name.inspect(),
|
method_name.inspect(),
|
||||||
self.get_similar_attr(obj.ref_t(), method_name.inspect()),
|
self.get_similar_attr(obj.ref_t(), method_name.inspect()),
|
||||||
|
@ -644,7 +644,12 @@ impl Context {
|
||||||
let new_r = self.resolve_trait(*r)?;
|
let new_r = self.resolve_trait(*r)?;
|
||||||
Ok(self.intersection(&new_l, &new_r))
|
Ok(self.intersection(&new_l, &new_r))
|
||||||
}
|
}
|
||||||
Type::Or(_, _) | Type::Not(_, _) => todo!(),
|
Type::Or(l, r) => {
|
||||||
|
let new_l = self.resolve_trait(*l)?;
|
||||||
|
let new_r = self.resolve_trait(*r)?;
|
||||||
|
Ok(self.union(&new_l, &new_r))
|
||||||
|
}
|
||||||
|
Type::Not(_, _) => todo!(),
|
||||||
other => Ok(other),
|
other => Ok(other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -951,7 +956,7 @@ impl Context {
|
||||||
);
|
);
|
||||||
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
|
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
|
||||||
log!(info "Substituted:\ninstance: {instance}");
|
log!(info "Substituted:\ninstance: {instance}");
|
||||||
let res = self.eval_t_params(instance, self.level)?;
|
let res = self.eval_t_params(instance, self.level, obj.loc())?;
|
||||||
log!(info "Params evaluated:\nres: {res}\n");
|
log!(info "Params evaluated:\nres: {res}\n");
|
||||||
self.propagate(&res, obj)?;
|
self.propagate(&res, obj)?;
|
||||||
log!(info "Propagated:\nres: {res}\n");
|
log!(info "Propagated:\nres: {res}\n");
|
||||||
|
@ -970,7 +975,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_var_error(
|
Err(TyCheckError::no_var_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
name.loc(),
|
name.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
name.inspect(),
|
name.inspect(),
|
||||||
self.get_similar_name(name.inspect()),
|
self.get_similar_name(name.inspect()),
|
||||||
))
|
))
|
||||||
|
@ -999,7 +1004,7 @@ impl Context {
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
name.loc(),
|
name.loc(),
|
||||||
namespace.clone(),
|
namespace.into(),
|
||||||
self_t,
|
self_t,
|
||||||
name.inspect(),
|
name.inspect(),
|
||||||
self.get_similar_attr(self_t, name.inspect()),
|
self.get_similar_attr(self_t, name.inspect()),
|
||||||
|
@ -1515,8 +1520,12 @@ impl Context {
|
||||||
let candidates = insts.into_iter().filter_map(move |inst| {
|
let candidates = insts.into_iter().filter_map(move |inst| {
|
||||||
if self.supertype_of(&inst.sup_trait, &sup) {
|
if self.supertype_of(&inst.sup_trait, &sup) {
|
||||||
Some(
|
Some(
|
||||||
self.eval_t_params(mono_proj(inst.sub_type, rhs), self.level)
|
self.eval_t_params(
|
||||||
.unwrap(),
|
mono_proj(inst.sub_type, rhs),
|
||||||
|
self.level,
|
||||||
|
Location::Unknown,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -17,6 +17,7 @@ use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::option::Option; // conflicting to Type::Option
|
use std::option::Option; // conflicting to Type::Option
|
||||||
|
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::dict::Dict;
|
use erg_common::dict::Dict;
|
||||||
use erg_common::error::Location;
|
use erg_common::error::Location;
|
||||||
use erg_common::impl_display_from_debug;
|
use erg_common::impl_display_from_debug;
|
||||||
|
@ -476,8 +477,8 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn caused_by(&self) -> Str {
|
pub fn caused_by(&self) -> AtomicStr {
|
||||||
self.name.clone()
|
AtomicStr::arc(&self.name[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn grow(
|
pub(crate) fn grow(
|
||||||
|
|
|
@ -106,6 +106,37 @@ impl SideEffectChecker {
|
||||||
self.check_expr(&unary.expr);
|
self.check_expr(&unary.expr);
|
||||||
}
|
}
|
||||||
Expr::Accessor(_) | Expr::Lit(_) => {}
|
Expr::Accessor(_) | Expr::Lit(_) => {}
|
||||||
|
Expr::Array(array) => match array {
|
||||||
|
Array::Normal(arr) => {
|
||||||
|
for elem in arr.elems.pos_args.iter() {
|
||||||
|
self.check_expr(&elem.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Array::WithLength(arr) => {
|
||||||
|
self.check_expr(&arr.elem);
|
||||||
|
self.check_expr(&arr.len);
|
||||||
|
}
|
||||||
|
Array::Comprehension(arr) => {
|
||||||
|
self.check_expr(&arr.elem);
|
||||||
|
self.check_expr(&arr.guard);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expr::Tuple(tuple) => match tuple {
|
||||||
|
Tuple::Normal(tuple) => {
|
||||||
|
for elem in tuple.elems.pos_args.iter() {
|
||||||
|
self.check_expr(&elem.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expr::Record(rec) => {
|
||||||
|
self.path_stack.push((Str::ever("<record>"), Private));
|
||||||
|
self.block_stack.push(Instant);
|
||||||
|
for attr in rec.attrs.iter() {
|
||||||
|
self.check_def(attr);
|
||||||
|
}
|
||||||
|
self.path_stack.pop();
|
||||||
|
self.block_stack.pop();
|
||||||
|
}
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,11 +218,18 @@ impl SideEffectChecker {
|
||||||
}
|
}
|
||||||
Expr::Array(array) => match array {
|
Expr::Array(array) => match array {
|
||||||
Array::Normal(arr) => {
|
Array::Normal(arr) => {
|
||||||
for arg in arr.elems.pos_args.iter() {
|
for elem in arr.elems.pos_args.iter() {
|
||||||
self.check_expr(&arg.expr);
|
self.check_expr(&elem.expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => todo!("{other}"),
|
Array::WithLength(arr) => {
|
||||||
|
self.check_expr(&arr.elem);
|
||||||
|
self.check_expr(&arr.len);
|
||||||
|
}
|
||||||
|
Array::Comprehension(arr) => {
|
||||||
|
self.check_expr(&arr.elem);
|
||||||
|
self.check_expr(&arr.guard);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Expr::Tuple(tuple) => match tuple {
|
Expr::Tuple(tuple) => match tuple {
|
||||||
Tuple::Normal(tup) => {
|
Tuple::Normal(tup) => {
|
||||||
|
@ -201,9 +239,13 @@ impl SideEffectChecker {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Expr::Record(record) => {
|
Expr::Record(record) => {
|
||||||
|
self.path_stack.push((Str::ever("<record>"), Private));
|
||||||
|
self.block_stack.push(Instant);
|
||||||
for attr in record.attrs.iter() {
|
for attr in record.attrs.iter() {
|
||||||
self.check_def(attr);
|
self.check_def(attr);
|
||||||
}
|
}
|
||||||
|
self.path_stack.pop();
|
||||||
|
self.block_stack.pop();
|
||||||
}
|
}
|
||||||
// 引数がproceduralでも関数呼び出しなら副作用なし
|
// 引数がproceduralでも関数呼び出しなら副作用なし
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
|
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::color::{GREEN, RED, RESET, YELLOW};
|
use erg_common::color::{GREEN, RED, RESET, YELLOW};
|
||||||
use erg_common::config::Input;
|
use erg_common::config::Input;
|
||||||
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
||||||
|
@ -96,7 +97,7 @@ pub fn readable_name(name: &str) -> &str {
|
||||||
pub struct CompileError {
|
pub struct CompileError {
|
||||||
pub core: ErrorCore,
|
pub core: ErrorCore,
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub caused_by: Str,
|
pub caused_by: AtomicStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParserRunnerError> for CompileError {
|
impl From<ParserRunnerError> for CompileError {
|
||||||
|
@ -125,7 +126,7 @@ impl ErrorDisplay for CompileError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompileError {
|
impl CompileError {
|
||||||
pub const fn new(core: ErrorCore, input: Input, caused_by: Str) -> Self {
|
pub const fn new(core: ErrorCore, input: Input, caused_by: AtomicStr) -> Self {
|
||||||
Self {
|
Self {
|
||||||
core,
|
core,
|
||||||
input,
|
input,
|
||||||
|
@ -191,7 +192,7 @@ impl CompileError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: Str) -> Self {
|
pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: AtomicStr) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
0,
|
0,
|
||||||
|
@ -233,7 +234,7 @@ impl CompileError {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TyCheckError {
|
pub struct TyCheckError {
|
||||||
pub core: ErrorCore,
|
pub core: ErrorCore,
|
||||||
pub caused_by: Str,
|
pub caused_by: AtomicStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorDisplay for TyCheckError {
|
impl ErrorDisplay for TyCheckError {
|
||||||
|
@ -252,7 +253,7 @@ impl ErrorDisplay for TyCheckError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TyCheckError {
|
impl TyCheckError {
|
||||||
pub const fn new(core: ErrorCore, caused_by: Str) -> Self {
|
pub const fn new(core: ErrorCore, caused_by: AtomicStr) -> Self {
|
||||||
Self { core, caused_by }
|
Self { core, caused_by }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +283,7 @@ impl TyCheckError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn feature_error(errno: usize, loc: Location, name: &str, caused_by: Str) -> Self {
|
pub fn feature_error(errno: usize, loc: Location, name: &str, caused_by: AtomicStr) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -300,12 +301,12 @@ impl TyCheckError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syntax_error<S: Into<Str>>(
|
pub fn syntax_error<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
desc: S,
|
desc: S,
|
||||||
hint: Option<Str>,
|
hint: Option<AtomicStr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(errno, SyntaxError, loc, desc, hint),
|
ErrorCore::new(errno, SyntaxError, loc, desc, hint),
|
||||||
|
@ -313,7 +314,12 @@ impl TyCheckError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duplicate_decl_error(errno: usize, loc: Location, caused_by: Str, name: &str) -> Self {
|
pub fn duplicate_decl_error(
|
||||||
|
errno: usize,
|
||||||
|
loc: Location,
|
||||||
|
caused_by: AtomicStr,
|
||||||
|
name: &str,
|
||||||
|
) -> Self {
|
||||||
let name = readable_name(name);
|
let name = readable_name(name);
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -326,7 +332,7 @@ impl TyCheckError {
|
||||||
"traditional_chinese" => format!("{name}已聲明"),
|
"traditional_chinese" => format!("{name}已聲明"),
|
||||||
"english" => format!("{name} is already declared"),
|
"english" => format!("{name} is already declared"),
|
||||||
),
|
),
|
||||||
Option::<Str>::None,
|
Option::<AtomicStr>::None,
|
||||||
),
|
),
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
|
@ -335,7 +341,7 @@ impl TyCheckError {
|
||||||
pub fn duplicate_definition_error(
|
pub fn duplicate_definition_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = readable_name(name);
|
let name = readable_name(name);
|
||||||
|
@ -350,7 +356,7 @@ impl TyCheckError {
|
||||||
"traditional_chinese" => format!("{name}已定義"),
|
"traditional_chinese" => format!("{name}已定義"),
|
||||||
"english" => format!("{name} is already defined"),
|
"english" => format!("{name} is already defined"),
|
||||||
),
|
),
|
||||||
Option::<Str>::None,
|
Option::<AtomicStr>::None,
|
||||||
),
|
),
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
|
@ -359,7 +365,7 @@ impl TyCheckError {
|
||||||
pub fn violate_decl_error(
|
pub fn violate_decl_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
spec_t: &Type,
|
spec_t: &Type,
|
||||||
found_t: &Type,
|
found_t: &Type,
|
||||||
|
@ -376,13 +382,18 @@ impl TyCheckError {
|
||||||
"traditional_chinese" => format!("{name}被聲明為{GREEN}{spec_t}{RESET},但分配了一個{RED}{found_t}{RESET}對象"),
|
"traditional_chinese" => format!("{name}被聲明為{GREEN}{spec_t}{RESET},但分配了一個{RED}{found_t}{RESET}對象"),
|
||||||
"english" => format!("{name} was declared as {GREEN}{spec_t}{RESET}, but an {RED}{found_t}{RESET} object is assigned"),
|
"english" => format!("{name} was declared as {GREEN}{spec_t}{RESET}, but an {RED}{found_t}{RESET} object is assigned"),
|
||||||
),
|
),
|
||||||
Option::<Str>::None,
|
Option::<AtomicStr>::None,
|
||||||
),
|
),
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn no_type_spec_error(errno: usize, loc: Location, caused_by: Str, name: &str) -> Self {
|
pub fn no_type_spec_error(
|
||||||
|
errno: usize,
|
||||||
|
loc: Location,
|
||||||
|
caused_by: AtomicStr,
|
||||||
|
name: &str,
|
||||||
|
) -> Self {
|
||||||
let name = readable_name(name);
|
let name = readable_name(name);
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -404,7 +415,7 @@ impl TyCheckError {
|
||||||
pub fn no_var_error(
|
pub fn no_var_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
similar_name: Option<&Str>,
|
similar_name: Option<&Str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -439,7 +450,7 @@ impl TyCheckError {
|
||||||
pub fn no_attr_error(
|
pub fn no_attr_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
obj_t: &Type,
|
obj_t: &Type,
|
||||||
name: &str,
|
name: &str,
|
||||||
similar_name: Option<&Str>,
|
similar_name: Option<&Str>,
|
||||||
|
@ -474,7 +485,7 @@ impl TyCheckError {
|
||||||
pub fn singular_no_attr_error(
|
pub fn singular_no_attr_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
obj_name: &str,
|
obj_name: &str,
|
||||||
obj_t: &Type,
|
obj_t: &Type,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -511,7 +522,7 @@ impl TyCheckError {
|
||||||
errno: usize,
|
errno: usize,
|
||||||
callee: &C,
|
callee: &C,
|
||||||
param_ts: impl Iterator<Item = &'a Type>,
|
param_ts: impl Iterator<Item = &'a Type>,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let param_ts = fmt_iter(param_ts);
|
let param_ts = fmt_iter(param_ts);
|
||||||
Self::new(
|
Self::new(
|
||||||
|
@ -539,12 +550,12 @@ impl TyCheckError {
|
||||||
pub fn type_mismatch_error(
|
pub fn type_mismatch_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
expect: &Type,
|
expect: &Type,
|
||||||
found: &Type,
|
found: &Type,
|
||||||
candidates: Option<Set<Type>>,
|
candidates: Option<Set<Type>>,
|
||||||
hint: Option<Str>,
|
hint: Option<AtomicStr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -566,7 +577,7 @@ impl TyCheckError {
|
||||||
pub fn return_type_error(
|
pub fn return_type_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
expect: &Type,
|
expect: &Type,
|
||||||
found: &Type,
|
found: &Type,
|
||||||
|
@ -591,7 +602,7 @@ impl TyCheckError {
|
||||||
pub fn uninitialized_error(
|
pub fn uninitialized_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
t: &Type,
|
t: &Type,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -615,7 +626,7 @@ impl TyCheckError {
|
||||||
pub fn argument_error(
|
pub fn argument_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
expect: usize,
|
expect: usize,
|
||||||
found: usize,
|
found: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -636,7 +647,7 @@ impl TyCheckError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_error(errno: usize, loc: Location, caused_by: Str, expr_t: &Type) -> Self {
|
pub fn match_error(errno: usize, loc: Location, caused_by: AtomicStr, expr_t: &Type) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -654,7 +665,7 @@ impl TyCheckError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn infer_error(errno: usize, loc: Location, caused_by: Str, expr: &str) -> Self {
|
pub fn infer_error(errno: usize, loc: Location, caused_by: AtomicStr, expr: &str) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -680,7 +691,7 @@ impl TyCheckError {
|
||||||
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
|
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reassign_error(errno: usize, loc: Location, caused_by: Str, name: &str) -> Self {
|
pub fn reassign_error(errno: usize, loc: Location, caused_by: AtomicStr, name: &str) -> Self {
|
||||||
let name = readable_name(name);
|
let name = readable_name(name);
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -703,7 +714,7 @@ impl TyCheckError {
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
callee_name: &str,
|
callee_name: &str,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
params_len: usize,
|
params_len: usize,
|
||||||
pos_args_len: usize,
|
pos_args_len: usize,
|
||||||
kw_args_len: usize,
|
kw_args_len: usize,
|
||||||
|
@ -750,7 +761,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
callee_name: &str,
|
callee_name: &str,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
missing_len: usize,
|
missing_len: usize,
|
||||||
missing_params: Vec<Str>,
|
missing_params: Vec<Str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -776,7 +787,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
callee_name: &str,
|
callee_name: &str,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
arg_name: &str,
|
arg_name: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = readable_name(callee_name);
|
let name = readable_name(callee_name);
|
||||||
|
@ -801,7 +812,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
callee_name: &str,
|
callee_name: &str,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
param_name: &str,
|
param_name: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let name = readable_name(callee_name);
|
let name = readable_name(callee_name);
|
||||||
|
@ -822,7 +833,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unused_warning(errno: usize, loc: Location, name: &str, caused_by: Str) -> Self {
|
pub fn unused_warning(errno: usize, loc: Location, name: &str, caused_by: AtomicStr) -> Self {
|
||||||
let name = readable_name(name);
|
let name = readable_name(name);
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -847,7 +858,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
rhs_t: &Type,
|
rhs_t: &Type,
|
||||||
lhs_loc: Option<Location>,
|
lhs_loc: Option<Location>,
|
||||||
rhs_loc: Option<Location>,
|
rhs_loc: Option<Location>,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let loc = match (lhs_loc, rhs_loc) {
|
let loc = match (lhs_loc, rhs_loc) {
|
||||||
(Some(l), Some(r)) => Location::pair(l, r),
|
(Some(l), Some(r)) => Location::pair(l, r),
|
||||||
|
@ -878,7 +889,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
rhs_t: &Type,
|
rhs_t: &Type,
|
||||||
lhs_loc: Option<Location>,
|
lhs_loc: Option<Location>,
|
||||||
rhs_loc: Option<Location>,
|
rhs_loc: Option<Location>,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let loc = match (lhs_loc, rhs_loc) {
|
let loc = match (lhs_loc, rhs_loc) {
|
||||||
(Some(l), Some(r)) => Location::pair(l, r),
|
(Some(l), Some(r)) => Location::pair(l, r),
|
||||||
|
@ -909,7 +920,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
sup_t: &Type,
|
sup_t: &Type,
|
||||||
sub_loc: Option<Location>,
|
sub_loc: Option<Location>,
|
||||||
sup_loc: Option<Location>,
|
sup_loc: Option<Location>,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let loc = match (sub_loc, sup_loc) {
|
let loc = match (sub_loc, sup_loc) {
|
||||||
(Some(l), Some(r)) => Location::pair(l, r),
|
(Some(l), Some(r)) => Location::pair(l, r),
|
||||||
|
@ -938,7 +949,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
errno: usize,
|
errno: usize,
|
||||||
lhs: &Predicate,
|
lhs: &Predicate,
|
||||||
rhs: &Predicate,
|
rhs: &Predicate,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
|
@ -957,7 +968,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_effect<S: Into<Str>>(errno: usize, expr: &Expr, caused_by: S) -> Self {
|
pub fn has_effect<S: Into<AtomicStr>>(errno: usize, expr: &Expr, caused_by: S) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -975,7 +986,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_error<S: Into<Str>>(
|
pub fn move_error<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
name: &str,
|
name: &str,
|
||||||
name_loc: Location,
|
name_loc: Location,
|
||||||
|
@ -1014,7 +1025,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
pub fn visibility_error(
|
pub fn visibility_error(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
caused_by: Str,
|
caused_by: AtomicStr,
|
||||||
name: &str,
|
name: &str,
|
||||||
vis: Visibility,
|
vis: Visibility,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -1051,7 +1062,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_const_expr(errno: usize, loc: Location, caused_by: Str) -> Self {
|
pub fn not_const_expr(errno: usize, loc: Location, caused_by: AtomicStr) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -1069,7 +1080,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn override_error<S: Into<Str>>(
|
pub fn override_error<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
name: &str,
|
name: &str,
|
||||||
name_loc: Location,
|
name_loc: Location,
|
||||||
|
@ -1106,7 +1117,12 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inheritance_error(errno: usize, class: String, loc: Location, caused_by: Str) -> Self {
|
pub fn inheritance_error(
|
||||||
|
errno: usize,
|
||||||
|
class: String,
|
||||||
|
loc: Location,
|
||||||
|
caused_by: AtomicStr,
|
||||||
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
ErrorCore::new(
|
ErrorCore::new(
|
||||||
errno,
|
errno,
|
||||||
|
@ -1123,6 +1139,30 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
caused_by,
|
caused_by,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_candidate_error(
|
||||||
|
errno: usize,
|
||||||
|
proj: &Type,
|
||||||
|
loc: Location,
|
||||||
|
caused_by: AtomicStr,
|
||||||
|
hint: Option<AtomicStr>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(
|
||||||
|
ErrorCore::new(
|
||||||
|
errno,
|
||||||
|
TypeError,
|
||||||
|
loc,
|
||||||
|
switch_lang!(
|
||||||
|
"japanese" => format!("{proj}の候補がありません"),
|
||||||
|
"simplified_chinese" => format!("{proj}没有候选项"),
|
||||||
|
"traditional_chinese" => format!("{proj}沒有候選項"),
|
||||||
|
"english" => format!("no candidate for {proj}"),
|
||||||
|
),
|
||||||
|
hint,
|
||||||
|
),
|
||||||
|
caused_by,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -568,6 +568,7 @@ impl ArrayWithLength {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: generators
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ArrayComprehension {
|
pub struct ArrayComprehension {
|
||||||
pub l_sqbr: Token,
|
pub l_sqbr: Token,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! implements `ASTLowerer`.
|
//! implements `ASTLowerer`.
|
||||||
//!
|
//!
|
||||||
//! ASTLowerer(ASTからHIRへの変換器)を実装
|
//! ASTLowerer(ASTからHIRへの変換器)を実装
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::{Location, MultiErrorDisplay};
|
use erg_common::error::{Location, MultiErrorDisplay};
|
||||||
use erg_common::traits::{Locational, Runnable, Stream};
|
use erg_common::traits::{Locational, Runnable, Stream};
|
||||||
|
@ -17,7 +18,7 @@ use erg_parser::Parser;
|
||||||
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
|
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
|
||||||
use erg_type::free::Constraint;
|
use erg_type::free::Constraint;
|
||||||
use erg_type::typaram::TyParam;
|
use erg_type::typaram::TyParam;
|
||||||
use erg_type::value::{TypeObj, ValueObj};
|
use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
|
||||||
use erg_type::{HasType, ParamTy, Type};
|
use erg_type::{HasType, ParamTy, Type};
|
||||||
|
|
||||||
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
|
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
|
||||||
|
@ -30,34 +31,6 @@ use crate::link::Linker;
|
||||||
use crate::varinfo::VarKind;
|
use crate::varinfo::VarKind;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
/// HACK: Cannot be methodized this because a reference has been taken immediately before.
|
|
||||||
macro_rules! check_inheritable {
|
|
||||||
($self: ident, $type_obj: expr, $sup_class: expr, $sub_sig: expr) => {
|
|
||||||
match $type_obj.require_or_sup.as_ref() {
|
|
||||||
TypeObj::Generated(gen) => {
|
|
||||||
if let Some(impls) = gen.impls.as_ref() {
|
|
||||||
if !impls.contains_intersec(&mono("InheritableType")) {
|
|
||||||
$self.errs.push(LowerError::inheritance_error(
|
|
||||||
line!() as usize,
|
|
||||||
$sup_class.to_string(),
|
|
||||||
$sup_class.loc(),
|
|
||||||
$sub_sig.ident().inspect().clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$self.errs.push(LowerError::inheritance_error(
|
|
||||||
line!() as usize,
|
|
||||||
$sup_class.to_string(),
|
|
||||||
$sup_class.loc(),
|
|
||||||
$sub_sig.ident().inspect().clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ASTLowererRunner {
|
pub struct ASTLowererRunner {
|
||||||
cfg: ErgConfig,
|
cfg: ErgConfig,
|
||||||
lowerer: ASTLowerer,
|
lowerer: ASTLowerer,
|
||||||
|
@ -109,7 +82,7 @@ impl Runnable for ASTLowererRunner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||||
let ts = Lexer::new(Input::Str(src))
|
let ts = Lexer::new(Input::Str(src))
|
||||||
.lex()
|
.lex()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||||
|
@ -186,7 +159,7 @@ impl ASTLowerer {
|
||||||
Err(LowerError::syntax_error(
|
Err(LowerError::syntax_error(
|
||||||
0,
|
0,
|
||||||
expr.loc(),
|
expr.loc(),
|
||||||
self.ctx.name.clone(),
|
AtomicStr::arc(&self.ctx.name[..]),
|
||||||
switch_lang!(
|
switch_lang!(
|
||||||
"japanese" => format!("式の評価結果(: {})が使われていません", expr.ref_t()),
|
"japanese" => format!("式の評価結果(: {})が使われていません", expr.ref_t()),
|
||||||
"simplified_chinese" => format!("表达式评估结果(: {})未使用", expr.ref_t()),
|
"simplified_chinese" => format!("表达式评估结果(: {})未使用", expr.ref_t()),
|
||||||
|
@ -237,7 +210,7 @@ impl ASTLowerer {
|
||||||
return Err(LowerError::syntax_error(
|
return Err(LowerError::syntax_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
elem.loc(),
|
elem.loc(),
|
||||||
self.ctx.name.clone(),
|
AtomicStr::arc(&self.ctx.name[..]),
|
||||||
switch_lang!(
|
switch_lang!(
|
||||||
"japanese" => "配列の要素は全て同じ型である必要があります",
|
"japanese" => "配列の要素は全て同じ型である必要があります",
|
||||||
"simplified_chinese" => "数组元素必须全部是相同类型",
|
"simplified_chinese" => "数组元素必须全部是相同类型",
|
||||||
|
@ -750,7 +723,7 @@ impl ASTLowerer {
|
||||||
self.errs.push(LowerError::duplicate_definition_error(
|
self.errs.push(LowerError::duplicate_definition_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
newly_defined_name.loc(),
|
newly_defined_name.loc(),
|
||||||
methods.name.clone(),
|
methods.name.clone().into(),
|
||||||
newly_defined_name.inspect(),
|
newly_defined_name.inspect(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
@ -782,7 +755,7 @@ impl ASTLowerer {
|
||||||
.args
|
.args
|
||||||
.get_left_or_key("Super")
|
.get_left_or_key("Super")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
check_inheritable!(self, type_obj, sup_type, &hir_def.sig);
|
Self::check_inheritable(&mut self.errs, type_obj, sup_type, &hir_def.sig);
|
||||||
// vi.t.non_default_params().unwrap()[0].typ().clone()
|
// vi.t.non_default_params().unwrap()[0].typ().clone()
|
||||||
let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
|
let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
|
||||||
ctx.get_current_scope_var("__new__"),
|
ctx.get_current_scope_var("__new__"),
|
||||||
|
@ -804,6 +777,34 @@ impl ASTLowerer {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HACK: Cannot be methodized this because `&self` has been taken immediately before.
|
||||||
|
fn check_inheritable(
|
||||||
|
errs: &mut LowerErrors,
|
||||||
|
type_obj: &GenTypeObj,
|
||||||
|
sup_class: &hir::Expr,
|
||||||
|
sub_sig: &hir::Signature,
|
||||||
|
) {
|
||||||
|
if let TypeObj::Generated(gen) = type_obj.require_or_sup.as_ref() {
|
||||||
|
if let Some(impls) = gen.impls.as_ref() {
|
||||||
|
if !impls.contains_intersec(&mono("InheritableType")) {
|
||||||
|
errs.push(LowerError::inheritance_error(
|
||||||
|
line!() as usize,
|
||||||
|
sup_class.to_string(),
|
||||||
|
sup_class.loc(),
|
||||||
|
sub_sig.ident().inspect().into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errs.push(LowerError::inheritance_error(
|
||||||
|
line!() as usize,
|
||||||
|
sup_class.to_string(),
|
||||||
|
sup_class.loc(),
|
||||||
|
sub_sig.ident().inspect().into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_override(&mut self, class: &Type, ctx: &Context) {
|
fn check_override(&mut self, class: &Type, ctx: &Context) {
|
||||||
if let Some(sups) = self.ctx.get_nominal_super_type_ctxs(class) {
|
if let Some(sups) = self.ctx.get_nominal_super_type_ctxs(class) {
|
||||||
for (sup_t, sup) in sups.skip(1) {
|
for (sup_t, sup) in sups.skip(1) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "erg_parser"
|
name = "erg_parser"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
description = "The Erg parser"
|
description = "The Erg parser"
|
||||||
authors = ["mtshiba <sbym1346@gmail.com>"]
|
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler/erg_parser"
|
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler/erg_parser"
|
||||||
|
@ -16,7 +16,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
|
||||||
traditional_chinese = [ "erg_common/traditional_chinese" ]
|
traditional_chinese = [ "erg_common/traditional_chinese" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { version = "0.4.1", path = "../erg_common" }
|
erg_common = { version = "0.4.6", path = "../erg_common" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
|
@ -2138,10 +2138,55 @@ impl ParamTuplePattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ParamRecordAttr {
|
||||||
|
pub lhs: Identifier,
|
||||||
|
pub rhs: ParamSignature,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ParamRecordAttr {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
write!(f, "{} = {}", self.lhs, self.rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ParamRecordAttr);
|
||||||
|
impl_locational!(ParamRecordAttr, lhs, rhs);
|
||||||
|
|
||||||
|
impl ParamRecordAttr {
|
||||||
|
pub const fn new(lhs: Identifier, rhs: ParamSignature) -> Self {
|
||||||
|
Self { lhs, rhs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ParamRecordAttrs {
|
||||||
|
pub(crate) elems: Vec<ParamRecordAttr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for ParamRecordAttrs {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
|
write!(f, "{}", fmt_vec_split_with(&self.elems, "; "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(ParamRecordAttrs);
|
||||||
|
impl_stream!(ParamRecordAttrs, ParamRecordAttr, elems);
|
||||||
|
|
||||||
|
impl ParamRecordAttrs {
|
||||||
|
pub const fn new(elems: Vec<ParamRecordAttr>) -> Self {
|
||||||
|
Self { elems }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self::new(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ParamRecordPattern {
|
pub struct ParamRecordPattern {
|
||||||
l_brace: Token,
|
l_brace: Token,
|
||||||
pub(crate) elems: Params,
|
pub(crate) elems: ParamRecordAttrs,
|
||||||
r_brace: Token,
|
r_brace: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2155,7 +2200,7 @@ impl_display_from_nested!(ParamRecordPattern);
|
||||||
impl_locational!(ParamRecordPattern, l_brace, r_brace);
|
impl_locational!(ParamRecordPattern, l_brace, r_brace);
|
||||||
|
|
||||||
impl ParamRecordPattern {
|
impl ParamRecordPattern {
|
||||||
pub const fn new(l_brace: Token, elems: Params, r_brace: Token) -> Self {
|
pub const fn new(l_brace: Token, elems: ParamRecordAttrs, r_brace: Token) -> Self {
|
||||||
Self {
|
Self {
|
||||||
l_brace,
|
l_brace,
|
||||||
elems,
|
elems,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//! defines `ParseError` and others.
|
//! defines `ParseError` and others.
|
||||||
//!
|
//!
|
||||||
//! パーサーが出すエラーを定義
|
//! パーサーが出すエラーを定義
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::config::Input;
|
use erg_common::config::Input;
|
||||||
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
||||||
use erg_common::traits::Stream;
|
use erg_common::traits::Stream;
|
||||||
use erg_common::Str;
|
|
||||||
use erg_common::{impl_stream_for_wrapper, switch_lang};
|
use erg_common::{impl_stream_for_wrapper, switch_lang};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -65,20 +65,20 @@ impl LexError {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syntax_error<S: Into<Str>>(
|
pub fn syntax_error<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
desc: S,
|
desc: S,
|
||||||
hint: Option<Str>,
|
hint: Option<AtomicStr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(ErrorCore::new(errno, SyntaxError, loc, desc, hint))
|
Self::new(ErrorCore::new(errno, SyntaxError, loc, desc, hint))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syntax_warning<S: Into<Str>>(
|
pub fn syntax_warning<S: Into<AtomicStr>>(
|
||||||
errno: usize,
|
errno: usize,
|
||||||
loc: Location,
|
loc: Location,
|
||||||
desc: S,
|
desc: S,
|
||||||
hint: Option<Str>,
|
hint: Option<AtomicStr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint))
|
Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use erg_common::cache::CacheSet;
|
||||||
use erg_common::config::ErgConfig;
|
use erg_common::config::ErgConfig;
|
||||||
use erg_common::config::Input;
|
use erg_common::config::Input;
|
||||||
use erg_common::traits::{Locational, Runnable, Stream};
|
use erg_common::traits::{Locational, Runnable, Stream};
|
||||||
use erg_common::Str;
|
|
||||||
use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang};
|
use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang};
|
||||||
|
|
||||||
use crate::error::{LexError, LexErrors, LexResult, LexerRunnerError, LexerRunnerErrors};
|
use crate::error::{LexError, LexErrors, LexResult, LexerRunnerError, LexerRunnerErrors};
|
||||||
|
@ -47,7 +46,7 @@ impl Runnable for LexerRunner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: Str) -> Result<String, LexerRunnerErrors> {
|
fn eval(&mut self, src: String) -> Result<String, LexerRunnerErrors> {
|
||||||
let lexer = Lexer::from_str(src);
|
let lexer = Lexer::from_str(src);
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
let ts = lexer
|
let ts = lexer
|
||||||
|
@ -97,7 +96,7 @@ impl Lexer /*<'a>*/ {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn from_str(src: Str) -> Self {
|
pub fn from_str(src: String) -> Self {
|
||||||
let escaped = normalize_newline(&src);
|
let escaped = normalize_newline(&src);
|
||||||
Lexer {
|
Lexer {
|
||||||
str_cache: CacheSet::new(),
|
str_cache: CacheSet::new(),
|
||||||
|
|
|
@ -194,7 +194,7 @@ impl Runnable for ParserRunner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: Str) -> Result<String, ParserRunnerErrors> {
|
fn eval(&mut self, src: String) -> Result<String, ParserRunnerErrors> {
|
||||||
let ast = self.parse_with_input(src)?;
|
let ast = self.parse_with_input(src)?;
|
||||||
Ok(format!("{ast}"))
|
Ok(format!("{ast}"))
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ impl ParserRunner {
|
||||||
self_.parse()
|
self_.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_with_input(&mut self, src: Str) -> Result<AST, ParserRunnerErrors> {
|
fn parse_with_input(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||||
let ts = Lexer::new(Input::Str(src))
|
let ts = Lexer::new(Input::Str(src))
|
||||||
.lex()
|
.lex()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||||
|
@ -309,18 +309,21 @@ impl Parser {
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
return Ok(block);
|
return Ok(block);
|
||||||
}
|
}
|
||||||
|
assert!(self.cur_is(Newline));
|
||||||
|
self.skip();
|
||||||
|
assert!(self.cur_is(Indent));
|
||||||
|
self.skip();
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
|
Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => {
|
||||||
|
let nl = self.lpop();
|
||||||
|
self.skip();
|
||||||
|
self.restore(nl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
Some(t) if t.category_is(TC::Separator) => {
|
Some(t) if t.category_is(TC::Separator) => {
|
||||||
self.skip();
|
self.skip();
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Indent) => {
|
|
||||||
self.skip();
|
|
||||||
}
|
|
||||||
Some(t) if t.is(Dedent) => {
|
|
||||||
self.skip();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(t) if t.is(EOF) => {
|
Some(t) if t.is(EOF) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -391,7 +394,7 @@ impl Parser {
|
||||||
fn try_reduce_acc(&mut self) -> ParseResult<Accessor> {
|
fn try_reduce_acc(&mut self) -> ParseResult<Accessor> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut acc = match self.peek() {
|
let mut acc = match self.peek() {
|
||||||
Some(t) if t.is(Symbol) => Accessor::local(self.lpop()),
|
Some(t) if t.is(Symbol) || t.is(UBar) => Accessor::local(self.lpop()),
|
||||||
Some(t) if t.is(Dot) => {
|
Some(t) if t.is(Dot) => {
|
||||||
let dot = self.lpop();
|
let dot = self.lpop();
|
||||||
let maybe_symbol = self.lpop();
|
let maybe_symbol = self.lpop();
|
||||||
|
@ -609,7 +612,8 @@ impl Parser {
|
||||||
|| t.category_is(TC::UnaryOp)
|
|| t.category_is(TC::UnaryOp)
|
||||||
|| t.is(LParen)
|
|| t.is(LParen)
|
||||||
|| t.is(LSqBr)
|
|| t.is(LSqBr)
|
||||||
|| t.is(LBrace) =>
|
|| t.is(LBrace)
|
||||||
|
|| t.is(UBar) =>
|
||||||
{
|
{
|
||||||
Some(self.try_reduce_args())
|
Some(self.try_reduce_args())
|
||||||
}
|
}
|
||||||
|
@ -670,18 +674,6 @@ impl Parser {
|
||||||
}
|
}
|
||||||
debug_power_assert!(self.cur_is(Indent));
|
debug_power_assert!(self.cur_is(Indent));
|
||||||
self.skip();
|
self.skip();
|
||||||
if !args.kw_is_empty() {
|
|
||||||
args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?);
|
|
||||||
} else {
|
|
||||||
match self.try_reduce_arg().map_err(|_| self.stack_dec())? {
|
|
||||||
PosOrKwArg::Pos(arg) => {
|
|
||||||
args.push_pos(arg);
|
|
||||||
}
|
|
||||||
PosOrKwArg::Kw(arg) => {
|
|
||||||
args.push_kw(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Comma) => {
|
Some(t) if t.is(Comma) => {
|
||||||
self.skip();
|
self.skip();
|
||||||
|
@ -704,14 +696,24 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Newline) && colon_style => {
|
Some(t) if t.is(RParen) => {
|
||||||
while self.cur_is(Newline) {
|
rp = Some(self.lpop());
|
||||||
self.skip();
|
let (pos_args, kw_args, _) = args.deconstruct();
|
||||||
}
|
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp.unwrap())));
|
||||||
if self.cur_is(Dedent) {
|
break;
|
||||||
self.skip();
|
}
|
||||||
|
Some(t) if t.is(Newline) => {
|
||||||
|
if !colon_style {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
let last = self.lpop();
|
||||||
|
if self.cur_is(Dedent) {
|
||||||
|
self.skip();
|
||||||
|
self.restore(last);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(_) if colon_style => {
|
||||||
if !args.kw_is_empty() {
|
if !args.kw_is_empty() {
|
||||||
args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?);
|
args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?);
|
||||||
} else {
|
} else {
|
||||||
|
@ -725,12 +727,6 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(t) if t.is(RParen) => {
|
|
||||||
rp = Some(self.lpop());
|
|
||||||
let (pos_args, kw_args, _) = args.deconstruct();
|
|
||||||
args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp.unwrap())));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -763,7 +759,7 @@ impl Parser {
|
||||||
self.errs.push(err);
|
self.errs.push(err);
|
||||||
return Err(());
|
return Err(());
|
||||||
};
|
};
|
||||||
let t_spec = if self.cur_is(Colon) {
|
/*let t_spec = if self.cur_is(Colon) {
|
||||||
self.skip();
|
self.skip();
|
||||||
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
let t_spec = self
|
let t_spec = self
|
||||||
|
@ -772,10 +768,10 @@ impl Parser {
|
||||||
Some(t_spec)
|
Some(t_spec)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};*/
|
||||||
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(PosOrKwArg::Kw(KwArg::new(kw, t_spec, expr)))
|
Ok(PosOrKwArg::Kw(KwArg::new(kw, None, expr)))
|
||||||
} else {
|
} else {
|
||||||
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
|
@ -808,7 +804,7 @@ impl Parser {
|
||||||
.push(ParseError::simple_syntax_error(0, acc.loc()));
|
.push(ParseError::simple_syntax_error(0, acc.loc()));
|
||||||
return Err(());
|
return Err(());
|
||||||
};
|
};
|
||||||
let t_spec = if self.cur_is(Colon) {
|
/*let t_spec = if self.cur_is(Colon) {
|
||||||
self.skip();
|
self.skip();
|
||||||
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
let t_spec = self
|
let t_spec = self
|
||||||
|
@ -817,10 +813,10 @@ impl Parser {
|
||||||
Some(t_spec)
|
Some(t_spec)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};*/
|
||||||
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let expr = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(KwArg::new(keyword, t_spec, expr))
|
Ok(KwArg::new(keyword, None, expr))
|
||||||
} else {
|
} else {
|
||||||
let loc = t.loc();
|
let loc = t.loc();
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
|
@ -853,13 +849,15 @@ impl Parser {
|
||||||
let mut defs = vec![first];
|
let mut defs = vec![first];
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
|
Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => {
|
||||||
|
let nl = self.lpop();
|
||||||
|
self.skip();
|
||||||
|
self.restore(nl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
Some(t) if t.category_is(TC::Separator) => {
|
Some(t) if t.category_is(TC::Separator) => {
|
||||||
self.skip();
|
self.skip();
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Dedent) => {
|
|
||||||
self.skip();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
|
||||||
match def {
|
match def {
|
||||||
|
@ -906,6 +904,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// chunk = normal expr + def
|
||||||
fn try_reduce_chunk(&mut self, winding: bool) -> ParseResult<Expr> {
|
fn try_reduce_chunk(&mut self, winding: bool) -> ParseResult<Expr> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
let mut stack = Vec::<ExprOrOp>::new();
|
let mut stack = Vec::<ExprOrOp>::new();
|
||||||
|
@ -926,7 +925,8 @@ impl Parser {
|
||||||
self.counter.inc();
|
self.counter.inc();
|
||||||
let block = self.try_reduce_block().map_err(|_| self.stack_dec())?;
|
let block = self.try_reduce_block().map_err(|_| self.stack_dec())?;
|
||||||
let body = DefBody::new(op, block, self.counter);
|
let body = DefBody::new(op, block, self.counter);
|
||||||
stack.push(ExprOrOp::Expr(Expr::Def(Def::new(sig, body))));
|
self.level -= 1;
|
||||||
|
return Ok(Expr::Def(Def::new(sig, body)));
|
||||||
}
|
}
|
||||||
Some(op) if op.category_is(TC::LambdaOp) => {
|
Some(op) if op.category_is(TC::LambdaOp) => {
|
||||||
let op = self.lpop();
|
let op = self.lpop();
|
||||||
|
@ -943,7 +943,7 @@ impl Parser {
|
||||||
self.counter,
|
self.counter,
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
Some(op) if op.is(Colon) => {
|
Some(op) if op.is(Colon) && !self.nth_is(1, Newline) => {
|
||||||
let _op = self.lpop();
|
let _op = self.lpop();
|
||||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
let t_spec = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let t_spec = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
|
@ -1139,6 +1139,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// chunk = expr + def
|
||||||
/// winding: true => parse paren-less tuple
|
/// winding: true => parse paren-less tuple
|
||||||
fn try_reduce_expr(&mut self, winding: bool) -> ParseResult<Expr> {
|
fn try_reduce_expr(&mut self, winding: bool) -> ParseResult<Expr> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
|
@ -1163,7 +1164,7 @@ impl Parser {
|
||||||
self.counter,
|
self.counter,
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
Some(op) if op.is(Colon) => {
|
Some(op) if op.is(Colon) && !self.nth_is(1, Newline) => {
|
||||||
let _op = self.lpop();
|
let _op = self.lpop();
|
||||||
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
let lhs = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
|
||||||
let t_spec = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
let t_spec = self.try_reduce_expr(false).map_err(|_| self.stack_dec())?;
|
||||||
|
@ -1325,7 +1326,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(t) if t.is(Symbol) || t.is(Dot) => {
|
Some(t) if t.is(Symbol) || t.is(Dot) || t.is(UBar) => {
|
||||||
let call_or_acc = self
|
let call_or_acc = self
|
||||||
.try_reduce_call_or_acc()
|
.try_reduce_call_or_acc()
|
||||||
.map_err(|_| self.stack_dec())?;
|
.map_err(|_| self.stack_dec())?;
|
||||||
|
@ -1720,7 +1721,11 @@ impl Parser {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
match accessor {
|
match accessor {
|
||||||
Accessor::Ident(ident) => {
|
Accessor::Ident(ident) => {
|
||||||
let pat = VarPattern::Ident(ident);
|
let pat = if &ident.inspect()[..] == "_" {
|
||||||
|
VarPattern::Discard(ident.name.into_token())
|
||||||
|
} else {
|
||||||
|
VarPattern::Ident(ident)
|
||||||
|
};
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(VarSignature::new(pat, None))
|
Ok(VarSignature::new(pat, None))
|
||||||
}
|
}
|
||||||
|
@ -2054,10 +2059,41 @@ impl Parser {
|
||||||
|
|
||||||
fn convert_record_to_param_record_pat(
|
fn convert_record_to_param_record_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
_record: Record,
|
record: Record,
|
||||||
) -> ParseResult<ParamRecordPattern> {
|
) -> ParseResult<ParamRecordPattern> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
todo!()
|
match record {
|
||||||
|
Record::Normal(rec) => {
|
||||||
|
let mut pats = vec![];
|
||||||
|
for mut attr in rec.attrs.into_iter() {
|
||||||
|
let lhs =
|
||||||
|
option_enum_unwrap!(attr.sig, Signature::Var).unwrap_or_else(|| todo!());
|
||||||
|
let lhs =
|
||||||
|
option_enum_unwrap!(lhs.pat, VarPattern::Ident).unwrap_or_else(|| todo!());
|
||||||
|
assert_eq!(attr.body.block.len(), 1);
|
||||||
|
let rhs = option_enum_unwrap!(attr.body.block.remove(0), Expr::Accessor)
|
||||||
|
.unwrap_or_else(|| todo!());
|
||||||
|
let rhs = self
|
||||||
|
.convert_accessor_to_param_sig(rhs)
|
||||||
|
.map_err(|_| self.stack_dec())?;
|
||||||
|
pats.push(ParamRecordAttr::new(lhs, rhs));
|
||||||
|
}
|
||||||
|
let attrs = ParamRecordAttrs::new(pats);
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(ParamRecordPattern::new(rec.l_brace, attrs, rec.r_brace))
|
||||||
|
}
|
||||||
|
Record::Shortened(rec) => {
|
||||||
|
let mut pats = vec![];
|
||||||
|
for ident in rec.idents.into_iter() {
|
||||||
|
let rhs =
|
||||||
|
ParamSignature::new(ParamPattern::VarName(ident.name.clone()), None, None);
|
||||||
|
pats.push(ParamRecordAttr::new(ident.clone(), rhs));
|
||||||
|
}
|
||||||
|
let attrs = ParamRecordAttrs::new(pats);
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(ParamRecordPattern::new(rec.l_brace, attrs, rec.r_brace))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_tuple_to_param_tuple_pat(&mut self, tuple: Tuple) -> ParseResult<ParamTuplePattern> {
|
fn convert_tuple_to_param_tuple_pat(&mut self, tuple: Tuple) -> ParseResult<ParamTuplePattern> {
|
||||||
|
@ -2146,7 +2182,11 @@ impl Parser {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
match accessor {
|
match accessor {
|
||||||
Accessor::Ident(ident) => {
|
Accessor::Ident(ident) => {
|
||||||
let pat = ParamPattern::VarName(ident.name);
|
let pat = if &ident.name.inspect()[..] == "_" {
|
||||||
|
ParamPattern::Discard(ident.name.into_token())
|
||||||
|
} else {
|
||||||
|
ParamPattern::VarName(ident.name)
|
||||||
|
};
|
||||||
self.level -= 1;
|
self.level -= 1;
|
||||||
Ok(ParamSignature::new(pat, None, None))
|
Ok(ParamSignature::new(pat, None, None))
|
||||||
}
|
}
|
||||||
|
@ -2185,10 +2225,18 @@ impl Parser {
|
||||||
|
|
||||||
fn convert_type_asc_to_lambda_sig(
|
fn convert_type_asc_to_lambda_sig(
|
||||||
&mut self,
|
&mut self,
|
||||||
_tasc: TypeAscription,
|
tasc: TypeAscription,
|
||||||
) -> ParseResult<LambdaSignature> {
|
) -> ParseResult<LambdaSignature> {
|
||||||
debug_call_info!(self);
|
debug_call_info!(self);
|
||||||
todo!()
|
let sig = self
|
||||||
|
.convert_rhs_to_param(*tasc.expr, true)
|
||||||
|
.map_err(|_| self.stack_dec())?;
|
||||||
|
self.level -= 1;
|
||||||
|
Ok(LambdaSignature::new(
|
||||||
|
Params::new(vec![sig], None, vec![], None),
|
||||||
|
None,
|
||||||
|
TypeBoundSpecs::empty(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_rhs_to_type_spec(&mut self, rhs: Expr) -> ParseResult<TypeSpec> {
|
fn convert_rhs_to_type_spec(&mut self, rhs: Expr) -> ParseResult<TypeSpec> {
|
||||||
|
|
|
@ -49,6 +49,7 @@ fn parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerError
|
||||||
dump_as_pyc: false,
|
dump_as_pyc: false,
|
||||||
python_ver: None,
|
python_ver: None,
|
||||||
py_server_timeout: 100,
|
py_server_timeout: 100,
|
||||||
|
quiet_startup: false,
|
||||||
input: input.clone(),
|
input: input.clone(),
|
||||||
module: "<module>",
|
module: "<module>",
|
||||||
verbose: 2,
|
verbose: 2,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "erg_type"
|
name = "erg_type"
|
||||||
version = "0.4.1"
|
version = "0.4.6"
|
||||||
description = "APIs for Erg types"
|
description = "APIs for Erg types"
|
||||||
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/erg-lang/erg/tree/main/compiler/erg_type"
|
repository = "https://github.com/erg-lang/erg/tree/main/compiler/erg_type"
|
||||||
|
@ -18,7 +18,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
|
||||||
traditional_chinese = [ "erg_common/traditional_chinese" ]
|
traditional_chinese = [ "erg_common/traditional_chinese" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
erg_common = { version = "0.4.1", path = "../erg_common" }
|
erg_common = { version = "0.4.6", path = "../erg_common" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::cache::CacheSet;
|
use erg_common::cache::CacheSet;
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::{ErrorCore, ErrorKind, Location};
|
use erg_common::error::{ErrorCore, ErrorKind, Location};
|
||||||
|
@ -18,8 +19,8 @@ use crate::{HasType, Type};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeserializeError {
|
pub struct DeserializeError {
|
||||||
pub errno: usize,
|
pub errno: usize,
|
||||||
pub caused_by: Str,
|
pub caused_by: AtomicStr,
|
||||||
pub desc: Str,
|
pub desc: AtomicStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for DeserializeError {
|
impl From<std::io::Error> for DeserializeError {
|
||||||
|
@ -41,13 +42,17 @@ impl From<DeserializeError> for ErrorCore {
|
||||||
ErrorKind::ImportError,
|
ErrorKind::ImportError,
|
||||||
Location::Unknown,
|
Location::Unknown,
|
||||||
err.desc,
|
err.desc,
|
||||||
Option::<Str>::None,
|
Option::<AtomicStr>::None,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeserializeError {
|
impl DeserializeError {
|
||||||
pub fn new<S: Into<Str>, T: Into<Str>>(errno: usize, caused_by: S, desc: T) -> Self {
|
pub fn new<S: Into<AtomicStr>, T: Into<AtomicStr>>(
|
||||||
|
errno: usize,
|
||||||
|
caused_by: S,
|
||||||
|
desc: T,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
errno,
|
errno,
|
||||||
caused_by: caused_by.into(),
|
caused_by: caused_by.into(),
|
||||||
|
|
|
@ -500,6 +500,10 @@ impl Predicate {
|
||||||
Self::Not(Box::new(lhs), Box::new(rhs))
|
Self::Not(Box::new(lhs), Box::new(rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_equal(&self) -> bool {
|
||||||
|
matches!(self, Self::Equal { .. })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn subject(&self) -> Option<&str> {
|
pub fn subject(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Equal { lhs, .. }
|
Self::Equal { lhs, .. }
|
||||||
|
@ -878,9 +882,23 @@ impl LimitedDisplay for RefinementType {
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
return write!(f, "...");
|
return write!(f, "...");
|
||||||
}
|
}
|
||||||
write!(f, "{{{}: ", self.var)?;
|
let first_subj = self.preds.iter().next().and_then(|p| p.subject());
|
||||||
self.t.limited_fmt(f, limit - 1)?;
|
if self
|
||||||
write!(f, " | {}}}", fmt_set_split_with(&self.preds, "; "))
|
.preds
|
||||||
|
.iter()
|
||||||
|
.all(|p| p.is_equal() && p.subject() == first_subj)
|
||||||
|
{
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for pred in self.preds.iter() {
|
||||||
|
let (_, rhs) = enum_unwrap!(pred, Predicate::Equal { lhs, rhs });
|
||||||
|
write!(f, "{}, ", rhs)?;
|
||||||
|
}
|
||||||
|
write!(f, "}}")
|
||||||
|
} else {
|
||||||
|
write!(f, "{{{}: ", self.var)?;
|
||||||
|
self.t.limited_fmt(f, limit - 1)?;
|
||||||
|
write!(f, " | {}}}", fmt_set_split_with(&self.preds, "; "))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,7 @@ f some_long_name_variable_1 + some_long_name_variable_2:
|
||||||
some_long_name_variable_3 * some_long_name_variable_4
|
some_long_name_variable_3 * some_long_name_variable_4
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
Codes above mean the same thing. This style is also useful when using `if` functions, for example.
|
||||||
f:
|
|
||||||
some_long_name_variable_1 + some_long_name_variable_2
|
|
||||||
some_long_name_variable_3 * some_long_name_variable_4
|
|
||||||
```
|
|
||||||
|
|
||||||
All three codes above mean the same thing. This style is also useful when using `if` functions, for example.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
result = if Bool.sample!():
|
result = if Bool.sample!():
|
||||||
|
@ -51,6 +45,14 @@ result = if Bool.sample!():
|
||||||
```
|
```
|
||||||
|
|
||||||
After `:`, no code other than comments may be written, and must always be on a new line.
|
After `:`, no code other than comments may be written, and must always be on a new line.
|
||||||
|
Also, you cannot use `:` immediately after a function. Only `do` and `do!` can do this.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# NG
|
||||||
|
f:
|
||||||
|
x
|
||||||
|
y
|
||||||
|
```
|
||||||
|
|
||||||
## Keyword Arguments
|
## Keyword Arguments
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,7 @@ f some_long_name_variable_1 + some_long_name_variable_2:
|
||||||
some_long_name_variable_3 * some_long_name_variable_4
|
some_long_name_variable_3 * some_long_name_variable_4
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
上の2つのコードは同じ意味です。このスタイルは`if`関数などを使用するときにも便利です。
|
||||||
f:
|
|
||||||
some_long_name_variable_1 + some_long_name_variable_2
|
|
||||||
some_long_name_variable_3 * some_long_name_variable_4
|
|
||||||
```
|
|
||||||
|
|
||||||
上の3つのコードはすべて同じ意味です。このスタイルは`if`関数などを使用するときにも便利です。
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
result = if Bool.sample!():
|
result = if Bool.sample!():
|
||||||
|
@ -52,7 +46,15 @@ result = if Bool.sample!():
|
||||||
0
|
0
|
||||||
```
|
```
|
||||||
|
|
||||||
`:`の後はコメント以外のコードを書いてはならず、必ず改行しなくてはなりません。
|
この場合、`:`の後はコメント以外のコードを書いてはならず、必ず改行しなくてはなりません。
|
||||||
|
また、関数の直後に`:`を使うことはできません。これができるのは`do`と`do!`のみです。
|
||||||
|
|
||||||
|
```python
|
||||||
|
# NG
|
||||||
|
f:
|
||||||
|
x
|
||||||
|
y
|
||||||
|
```
|
||||||
|
|
||||||
## キーワード引数(Keyword Arguments)
|
## キーワード引数(Keyword Arguments)
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,21 @@ s = if cond:
|
||||||
do "else block"
|
do "else block"
|
||||||
assert s == "then block"
|
assert s == "then block"
|
||||||
|
|
||||||
# else: binary operator
|
|
||||||
x = cond.then 1 else 2
|
|
||||||
assert x == 1
|
|
||||||
|
|
||||||
if! cond:
|
if! cond:
|
||||||
do!:
|
do!:
|
||||||
print! "then block"
|
print! "then block!"
|
||||||
do!:
|
do!:
|
||||||
print! "else block"
|
print! "else block!"
|
||||||
|
|
||||||
a = [1, 2, 3]
|
a = [1, 2, 3]
|
||||||
sum = match a:
|
sum = match a:
|
||||||
[x, y, z] -> x + y + z
|
[x, y, z] -> x + y + z
|
||||||
(x, y, z) -> x + y + z
|
(x, y, z) -> x + y + z
|
||||||
{x; y; z} -> x + y + z
|
{x; y; z} -> x + y + z
|
||||||
i: Int -> i
|
(i: Int) -> i
|
||||||
_ -> panic "unknown object"
|
_ -> panic "unknown object"
|
||||||
|
|
||||||
for! 0.., i =>
|
for! 0..1000, i =>
|
||||||
print! "i = {i}"
|
print! "i = {i}"
|
||||||
if i >= 100:
|
if i >= 100:
|
||||||
do return break()
|
do return break()
|
||||||
|
|
|
@ -1,26 +1,25 @@
|
||||||
LitExpr = Class {.i = Int}, Impl := Show
|
LitExpr = Class {.i = Int}, Impl := Show
|
||||||
LitExpr.
|
LitExpr.
|
||||||
new i = Self::__new__ {.i;}
|
new i = Self::__new__ {.i;}
|
||||||
show &self = "{self.i}"
|
show self = "{self.i}"
|
||||||
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
AddExpr.
|
AddExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} + {self.rhs}"
|
show self = "{self.lhs} + {self.rhs}"
|
||||||
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show
|
||||||
SubExpr.
|
SubExpr.
|
||||||
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
new lhs, rhs = Self::__new__ {.lhs; .rhs}
|
||||||
show &self = "{self.lhs} - {self.rhs}"
|
show self = "{self.lhs} - {self.rhs}"
|
||||||
PosExpr = Class {.expr = Expr}, Impl := Show
|
PosExpr = Class {.expr = Expr}, Impl := Show
|
||||||
PosExpr.
|
PosExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "+{self.expr}"
|
show self = "+{self.expr}"
|
||||||
NegExpr = Class {.expr = Expr}, Impl := Show
|
NegExpr = Class {.expr = Expr}, Impl := Show
|
||||||
NegExpr.
|
NegExpr.
|
||||||
new expr = Self::__new__ {.expr;}
|
new expr = Self::__new__ {.expr;}
|
||||||
show &self = "-{self.expr}"
|
show self = "-{self.expr}"
|
||||||
|
|
||||||
Expr = Enum:
|
Expr = Enum LitExpr:
|
||||||
LitExpr
|
|
||||||
AddExpr
|
AddExpr
|
||||||
SubExpr
|
SubExpr
|
||||||
NegExpr
|
NegExpr
|
||||||
|
@ -29,11 +28,11 @@ Expr.
|
||||||
add = Self.cons(AddExpr)
|
add = Self.cons(AddExpr)
|
||||||
eval self =
|
eval self =
|
||||||
match self:
|
match self:
|
||||||
l: Expr.LitExpr -> l.i
|
(l: Expr.LitExpr) -> l.i
|
||||||
a: Expr.AddExpr -> a.lhs + a.rhs
|
(a: Expr.AddExpr) -> a.lhs + a.rhs
|
||||||
s: Expr.SubExpr -> s.lhs - s.rhs
|
(s: Expr.SubExpr) -> s.lhs - s.rhs
|
||||||
p: Expr.PosExpr -> p.expr
|
(p: Expr.PosExpr) -> p.expr
|
||||||
n: Expr.NegExpr -> -n.expr
|
(n: Expr.NegExpr) -> -n.expr
|
||||||
|
|
||||||
expr = Expr.add Expr.lit(1), Expr.lit(2)
|
expr = Expr.add Expr.lit(1), Expr.lit(2)
|
||||||
print! expr # 1 + 2
|
print! expr # 1 + 2
|
||||||
|
|
24
src/dummy.rs
24
src/dummy.rs
|
@ -6,12 +6,14 @@ use std::time::Duration;
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::python_util::{exec_py, exec_pyc};
|
use erg_common::python_util::{exec_py, exec_pyc};
|
||||||
use erg_common::str::Str;
|
|
||||||
use erg_common::traits::Runnable;
|
use erg_common::traits::Runnable;
|
||||||
|
|
||||||
use erg_compiler::error::{CompileError, CompileErrors};
|
use erg_compiler::error::{CompileError, CompileErrors};
|
||||||
use erg_compiler::Compiler;
|
use erg_compiler::Compiler;
|
||||||
|
|
||||||
|
pub type EvalError = CompileError;
|
||||||
|
pub type EvalErrors = CompileErrors;
|
||||||
|
|
||||||
/// Open the Python interpreter as a server and act as an Erg interpreter by mediating communication
|
/// Open the Python interpreter as a server and act as an Erg interpreter by mediating communication
|
||||||
///
|
///
|
||||||
/// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う
|
/// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う
|
||||||
|
@ -23,19 +25,23 @@ pub struct DummyVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runnable for DummyVM {
|
impl Runnable for DummyVM {
|
||||||
type Err = CompileError;
|
type Err = EvalError;
|
||||||
type Errs = CompileErrors;
|
type Errs = EvalErrors;
|
||||||
const NAME: &'static str = "Erg interpreter";
|
const NAME: &'static str = "Erg interpreter";
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
let stream = if cfg.input.is_repl() {
|
let stream = if cfg.input.is_repl() {
|
||||||
println!("Starting the REPL server...");
|
if !cfg.quiet_startup {
|
||||||
|
println!("Starting the REPL server...");
|
||||||
|
}
|
||||||
let port = find_available_port();
|
let port = find_available_port();
|
||||||
let code = include_str!("scripts/repl_server.py")
|
let code = include_str!("scripts/repl_server.py")
|
||||||
.replace("__PORT__", port.to_string().as_str());
|
.replace("__PORT__", port.to_string().as_str());
|
||||||
exec_py(&code);
|
exec_py(&code);
|
||||||
let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
|
let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
|
||||||
println!("Connecting to the REPL server...");
|
if !cfg.quiet_startup {
|
||||||
|
println!("Connecting to the REPL server...");
|
||||||
|
}
|
||||||
loop {
|
loop {
|
||||||
match TcpStream::connect(&addr) {
|
match TcpStream::connect(&addr) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
|
@ -45,7 +51,9 @@ impl Runnable for DummyVM {
|
||||||
break Some(stream);
|
break Some(stream);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Retrying to connect to the REPL server...");
|
if !cfg.quiet_startup {
|
||||||
|
println!("Retrying to connect to the REPL server...");
|
||||||
|
}
|
||||||
sleep(Duration::from_millis(500));
|
sleep(Duration::from_millis(500));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +105,7 @@ impl Runnable for DummyVM {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, EvalErrors> {
|
||||||
self.compiler
|
self.compiler
|
||||||
.compile_and_dump_as_pyc(src, "o.pyc", "eval")?;
|
.compile_and_dump_as_pyc(src, "o.pyc", "eval")?;
|
||||||
let mut res = match self.stream.as_mut().unwrap().write("load".as_bytes()) {
|
let mut res = match self.stream.as_mut().unwrap().write("load".as_bytes()) {
|
||||||
|
@ -107,7 +115,7 @@ impl Runnable for DummyVM {
|
||||||
Result::Ok(n) => {
|
Result::Ok(n) => {
|
||||||
let s = std::str::from_utf8(&buf[..n]).unwrap();
|
let s = std::str::from_utf8(&buf[..n]).unwrap();
|
||||||
if s == "[Exception] SystemExit" {
|
if s == "[Exception] SystemExit" {
|
||||||
return Err(CompileErrors::from(CompileError::system_exit()));
|
return Err(EvalErrors::from(EvalError::system_exit()));
|
||||||
}
|
}
|
||||||
s.to_string()
|
s.to_string()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue