Do cargo fmt

This commit is contained in:
Shunsuke Shibayama 2022-08-13 07:02:07 +09:00
parent e320bd6cdd
commit 6726d93f65
48 changed files with 7294 additions and 3469 deletions

View file

@ -1,20 +1,24 @@
use std::rc::Rc;
use std::cell::RefCell;
use std::borrow::{Borrow, ToOwned}; use std::borrow::{Borrow, ToOwned};
use std::cell::RefCell;
use std::hash::Hash; use std::hash::Hash;
use std::rc::Rc;
use crate::set::Set; use crate::set::Set;
use crate::{Str, RcArray}; use crate::{RcArray, Str};
#[derive(Debug)] #[derive(Debug)]
pub struct Cache<T: ?Sized>(RefCell<Set<Rc<T>>>); pub struct Cache<T: ?Sized>(RefCell<Set<Rc<T>>>);
impl<T: ?Sized> Default for Cache<T> { impl<T: ?Sized> Default for Cache<T> {
fn default() -> Self { Self::new() } fn default() -> Self {
Self::new()
}
} }
impl<T: ?Sized> Cache<T> { impl<T: ?Sized> Cache<T> {
pub fn new() -> Self { Self(RefCell::new(Set::new())) } pub fn new() -> Self {
Self(RefCell::new(Set::new()))
}
} }
impl Clone for Cache<str> { impl Clone for Cache<str> {
@ -32,7 +36,7 @@ impl<T: Hash + Eq> Clone for Cache<T> {
impl Cache<str> { impl Cache<str> {
pub fn get(&self, s: &str) -> Str { pub fn get(&self, s: &str) -> Str {
if let Some(cached) = self.0.borrow().get(s) { if let Some(cached) = self.0.borrow().get(s) {
return cached.clone().into() return cached.clone().into();
} // &self.0 is dropped } // &self.0 is dropped
let s = Str::rc(s); let s = Str::rc(s);
self.0.borrow_mut().insert(s.clone().into_rc()); self.0.borrow_mut().insert(s.clone().into_rc());
@ -43,7 +47,7 @@ impl Cache<str> {
impl<T: Hash + Eq + Clone> Cache<[T]> { impl<T: Hash + Eq + Clone> Cache<[T]> {
pub fn get(&self, q: &[T]) -> Rc<[T]> { pub fn get(&self, q: &[T]) -> Rc<[T]> {
if let Some(cached) = self.0.borrow().get(q) { if let Some(cached) = self.0.borrow().get(q) {
return cached.clone() return cached.clone();
} // &self.0 is dropped } // &self.0 is dropped
let s = RcArray::from(q); let s = RcArray::from(q);
self.0.borrow_mut().insert(s.clone()); self.0.borrow_mut().insert(s.clone());
@ -53,9 +57,12 @@ impl<T: Hash + Eq + Clone> Cache<[T]> {
impl<T: Hash + Eq> Cache<T> { impl<T: Hash + Eq> Cache<T> {
pub fn get<Q: ?Sized + Hash + Eq>(&self, q: &Q) -> Rc<T> pub fn get<Q: ?Sized + Hash + Eq>(&self, q: &Q) -> Rc<T>
where Rc<T>: Borrow<Q>, Q: ToOwned<Owned = T> { where
Rc<T>: Borrow<Q>,
Q: ToOwned<Owned = T>,
{
if let Some(cached) = self.0.borrow().get(q) { if let Some(cached) = self.0.borrow().get(q) {
return cached.clone() return cached.clone();
} // &self.0 is dropped } // &self.0 is dropped
let s = Rc::from(q.to_owned()); let s = Rc::from(q.to_owned());
self.0.borrow_mut().insert(s.clone()); self.0.borrow_mut().insert(s.clone());

View file

@ -3,15 +3,15 @@ use std::fs::File;
use std::io::{BufReader, Read, Write}; use std::io::{BufReader, Read, Write};
use std::path::Path; use std::path::Path;
use crate::{Str}; use crate::deserialize::{DeserializeResult, Deserializer};
use crate::impl_display_from_debug; use crate::impl_display_from_debug;
use crate::value::ValueObj;
use crate::opcode::Opcode; use crate::opcode::Opcode;
use crate::python_util::detect_magic_number; use crate::python_util::detect_magic_number;
use crate::serialize::*; use crate::serialize::*;
use crate::traits::HasType; use crate::traits::HasType;
use crate::ty::{TypePair, Type}; use crate::ty::{Type, TypePair};
use crate::deserialize::{Deserializer, DeserializeResult}; use crate::value::ValueObj;
use crate::Str;
pub fn consts_into_bytes(consts: Vec<ValueObj>) -> Vec<u8> { pub fn consts_into_bytes(consts: Vec<ValueObj>) -> Vec<u8> {
let mut tuple = vec![]; let mut tuple = vec![];
@ -123,8 +123,12 @@ pub struct CodeObj {
} }
impl HasType for CodeObj { impl HasType for CodeObj {
fn ref_t(&self) -> &Type { &Type::Code } fn ref_t(&self) -> &Type {
fn signature_t(&self) -> Option<&Type> { None } &Type::Code
}
fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl fmt::Debug for CodeObj { impl fmt::Debug for CodeObj {
@ -201,7 +205,12 @@ impl CodeObj {
} }
} }
pub fn empty<S: Into<Str>, T: Into<Str>>(params: Vec<Str>, filename: S, name: T, firstlineno: u32) -> Self { pub fn empty<S: Into<Str>, T: Into<Str>>(
params: Vec<Str>,
filename: S,
name: T,
firstlineno: u32,
) -> Self {
Self { Self {
argcount: params.len() as u32, argcount: params.len() as u32,
posonlyargcount: 0, posonlyargcount: 0,
@ -226,8 +235,7 @@ impl CodeObj {
let mut f = BufReader::new(File::open(path)?); let mut f = BufReader::new(File::open(path)?);
let v = &mut Vec::with_capacity(16); let v = &mut Vec::with_capacity(16);
f.read_to_end(v)?; f.read_to_end(v)?;
let python_ver = let python_ver = get_magic_num_from_bytes(&Deserializer::consume::<4>(v));
get_magic_num_from_bytes(&Deserializer::consume::<4>(v));
let _padding = Deserializer::deserialize_u32(v); let _padding = Deserializer::deserialize_u32(v);
let _timestamp = Deserializer::deserialize_u32(v); let _timestamp = Deserializer::deserialize_u32(v);
let _padding = Deserializer::deserialize_u32(v); let _padding = Deserializer::deserialize_u32(v);
@ -238,7 +246,11 @@ impl CodeObj {
pub fn from_bytes(v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Self> { pub fn from_bytes(v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Self> {
let mut des = Deserializer::new(); let mut des = Deserializer::new();
let argcount = Deserializer::deserialize_u32(v); let argcount = Deserializer::deserialize_u32(v);
let posonlyargcount = if python_ver >= 3413 { Deserializer::deserialize_u32(v)} else { 0 }; let posonlyargcount = if python_ver >= 3413 {
Deserializer::deserialize_u32(v)
} else {
0
};
let kwonlyargcount = Deserializer::deserialize_u32(v); let kwonlyargcount = Deserializer::deserialize_u32(v);
let nlocals = Deserializer::deserialize_u32(v); let nlocals = Deserializer::deserialize_u32(v);
let stacksize = Deserializer::deserialize_u32(v); let stacksize = Deserializer::deserialize_u32(v);
@ -247,7 +259,7 @@ impl CodeObj {
let consts = des.deserialize_const_vec(v, python_ver)?; let consts = des.deserialize_const_vec(v, python_ver)?;
let names = des.deserialize_str_vec(v, python_ver)?; let names = des.deserialize_str_vec(v, python_ver)?;
let varnames = des.deserialize_str_vec(v, python_ver)?; let varnames = des.deserialize_str_vec(v, python_ver)?;
let freevars =des.deserialize_str_vec(v, python_ver)?; let freevars = des.deserialize_str_vec(v, python_ver)?;
let cellvars = des.deserialize_str_vec(v, python_ver)?; let cellvars = des.deserialize_str_vec(v, python_ver)?;
let filename = des.deserialize_str(v, python_ver)?; let filename = des.deserialize_str(v, python_ver)?;
let name = des.deserialize_str(v, python_ver)?; let name = des.deserialize_str(v, python_ver)?;
@ -269,7 +281,7 @@ impl CodeObj {
filename, filename,
name, name,
firstlineno, firstlineno,
lnotab lnotab,
)) ))
} }
@ -298,7 +310,11 @@ impl CodeObj {
bytes bytes
} }
pub fn dump_as_pyc<P: AsRef<Path>>(self, path: P, python_ver: Option<u32>) -> std::io::Result<()> { pub fn dump_as_pyc<P: AsRef<Path>>(
self,
path: P,
python_ver: Option<u32>,
) -> std::io::Result<()> {
let mut file = File::create(path)?; let mut file = File::create(path)?;
let mut bytes = Vec::with_capacity(16); let mut bytes = Vec::with_capacity(16);
let python_ver = python_ver.unwrap_or_else(|| detect_magic_number()); let python_ver = python_ver.unwrap_or_else(|| detect_magic_number());
@ -406,9 +422,12 @@ impl CodeObj {
}; };
instrs += &format!("{} ({})", arg, op); instrs += &format!("{} ({})", arg, op);
} }
Opcode::STORE_NAME | Opcode::LOAD_NAME Opcode::STORE_NAME
| Opcode::STORE_GLOBAL | Opcode::LOAD_GLOBAL | Opcode::LOAD_NAME
| Opcode::STORE_ATTR | Opcode::LOAD_ATTR | Opcode::STORE_GLOBAL
| Opcode::LOAD_GLOBAL
| Opcode::STORE_ATTR
| Opcode::LOAD_ATTR
| Opcode::LOAD_METHOD => { | Opcode::LOAD_METHOD => {
instrs += &format!("{} ({})", arg, self.names.get(*arg as usize).unwrap()); instrs += &format!("{} ({})", arg, self.names.get(*arg as usize).unwrap());
} }
@ -422,18 +441,18 @@ impl CodeObj {
} }
Opcode::LOAD_CONST => { Opcode::LOAD_CONST => {
instrs += &format!("{} ({})", arg, self.consts.get(*arg as usize).unwrap()); instrs += &format!("{} ({})", arg, self.consts.get(*arg as usize).unwrap());
}, }
Opcode::FOR_ITER => { Opcode::FOR_ITER => {
instrs += &format!("{} (to {})", arg, idx + arg*2 + 2); instrs += &format!("{} (to {})", arg, idx + arg * 2 + 2);
} }
Opcode::JUMP_FORWARD => { Opcode::JUMP_FORWARD => {
instrs += &format!("{} (to {})", arg, idx + arg*2 + 2); instrs += &format!("{} (to {})", arg, idx + arg * 2 + 2);
} }
Opcode::JUMP_ABSOLUTE => { Opcode::JUMP_ABSOLUTE => {
instrs += &format!("{} (to {})", arg, arg*2); instrs += &format!("{} (to {})", arg, arg * 2);
} }
Opcode::POP_JUMP_IF_FALSE | Opcode::POP_JUMP_IF_TRUE => { Opcode::POP_JUMP_IF_FALSE | Opcode::POP_JUMP_IF_TRUE => {
instrs += &format!("{} (to {})", arg, arg*2); instrs += &format!("{} (to {})", arg, arg * 2);
} }
Opcode::MAKE_FUNCTION => { Opcode::MAKE_FUNCTION => {
let flag = match arg { let flag = match arg {
@ -444,8 +463,10 @@ impl CodeObj {
instrs += &format!("{} {}", arg, flag); instrs += &format!("{} {}", arg, flag);
} }
// Ergでは引数で型キャストする // Ergでは引数で型キャストする
Opcode::BINARY_ADD | Opcode::BINARY_SUBTRACT Opcode::BINARY_ADD
| Opcode::BINARY_MULTIPLY | Opcode::BINARY_TRUE_DIVIDE => { | Opcode::BINARY_SUBTRACT
| Opcode::BINARY_MULTIPLY
| Opcode::BINARY_TRUE_DIVIDE => {
instrs += &format!("{} ({:?})", arg, TypePair::from(*arg)); instrs += &format!("{} ({:?})", arg, TypePair::from(*arg));
} }
other if other.take_arg() => { other if other.take_arg() => {

View file

@ -26,32 +26,42 @@ pub struct TotalCombinations<I: Iterator> {
/// ]); /// ]);
/// ///
pub fn total_combinations<I>(iter: I) -> TotalCombinations<I> pub fn total_combinations<I>(iter: I) -> TotalCombinations<I>
where I: Iterator + ExactSizeIterator, where
I::Item: Clone I: Iterator + ExactSizeIterator,
I::Item: Clone,
{ {
TotalCombinations { len: iter.len(), combinations: combinations(iter, 1) } TotalCombinations {
len: iter.len(),
combinations: combinations(iter, 1),
}
} }
impl<I> Iterator for TotalCombinations<I> impl<I> Iterator for TotalCombinations<I>
where I: Iterator, where
I::Item: Clone I: Iterator,
I::Item: Clone,
{ {
type Item = Vec<I::Item>; type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if let Some(i) = self.combinations.next() { return Some(i) } if let Some(i) = self.combinations.next() {
else { return Some(i);
} else {
self.combinations.reset(self.combinations.k() + 1); self.combinations.reset(self.combinations.k() + 1);
self.len -= 1; self.len -= 1;
if self.len == 0 { return None } if self.len == 0 {
return None;
}
self.combinations.next() self.combinations.next()
} }
} }
} }
impl<I> FusedIterator for TotalCombinations<I> impl<I> FusedIterator for TotalCombinations<I>
where I: Iterator, where
I::Item: Clone I: Iterator,
{} I::Item: Clone,
{
}
macro_rules! debug_fmt_fields { macro_rules! debug_fmt_fields {
($tyname:ident, $($($field:tt/*TODO ideally we would accept ident or tuple element here*/).+),*) => { ($tyname:ident, $($($field:tt/*TODO ideally we would accept ident or tuple element here*/).+),*) => {
@ -86,14 +96,16 @@ pub struct Combinations<I: Iterator> {
} }
impl<I> Clone for Combinations<I> impl<I> Clone for Combinations<I>
where I: Clone + Iterator, where
I: Clone + Iterator,
I::Item: Clone, I::Item: Clone,
{ {
clone_fields!(indices, pool, first); clone_fields!(indices, pool, first);
} }
impl<I> fmt::Debug for Combinations<I> impl<I> fmt::Debug for Combinations<I>
where I: Iterator + fmt::Debug, where
I: Iterator + fmt::Debug,
I::Item: fmt::Debug, I::Item: fmt::Debug,
{ {
debug_fmt_fields!(Combinations, indices, pool, first); debug_fmt_fields!(Combinations, indices, pool, first);
@ -101,7 +113,8 @@ impl<I> fmt::Debug for Combinations<I>
/// Create a new `Combinations` from a clonable iterator. /// Create a new `Combinations` from a clonable iterator.
pub fn combinations<I>(iter: I, k: usize) -> Combinations<I> pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
where I: Iterator where
I: Iterator,
{ {
let mut pool = LazyBuffer::new(iter); let mut pool = LazyBuffer::new(iter);
pool.prefill(k); pool.prefill(k);
@ -116,16 +129,22 @@ pub fn combinations<I>(iter: I, k: usize) -> Combinations<I>
impl<I: Iterator> Combinations<I> { impl<I: Iterator> Combinations<I> {
/// Returns the length of a combination produced by this iterator. /// Returns the length of a combination produced by this iterator.
#[inline] #[inline]
pub fn k(&self) -> usize { self.indices.len() } pub fn k(&self) -> usize {
self.indices.len()
}
/// Returns the (current) length of the pool from which combination elements are /// Returns the (current) length of the pool from which combination elements are
/// selected. This value can change between invocations of [`next`](Combinations::next). /// selected. This value can change between invocations of [`next`](Combinations::next).
#[inline] #[inline]
pub fn n(&self) -> usize { self.pool.len() } pub fn n(&self) -> usize {
self.pool.len()
}
/// Returns a reference to the source iterator. /// Returns a reference to the source iterator.
#[inline] #[inline]
pub fn src(&self) -> &I { &self.pool.it } pub fn src(&self) -> &I {
&self.pool.it
}
/// Resets this `Combinations` back to an initial state for combinations of length /// Resets this `Combinations` back to an initial state for combinations of length
/// `k` over the same pool data source. If `k` is larger than the current length /// `k` over the same pool data source. If `k` is larger than the current length
@ -139,7 +158,6 @@ impl<I: Iterator> Combinations<I> {
for i in 0..k { for i in 0..k {
self.indices[i] = i; self.indices[i] = i;
} }
} else { } else {
for i in 0..self.indices.len() { for i in 0..self.indices.len() {
self.indices[i] = i; self.indices[i] = i;
@ -151,8 +169,9 @@ impl<I: Iterator> Combinations<I> {
} }
impl<I> Iterator for Combinations<I> impl<I> Iterator for Combinations<I>
where I: Iterator, where
I::Item: Clone I: Iterator,
I::Item: Clone,
{ {
type Item = Vec<I::Item>; type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -183,7 +202,7 @@ impl<I> Iterator for Combinations<I>
// Increment index, and reset the ones to its right // Increment index, and reset the ones to its right
self.indices[i] += 1; self.indices[i] += 1;
for j in i+1..self.indices.len() { for j in i + 1..self.indices.len() {
self.indices[j] = self.indices[j - 1] + 1; self.indices[j] = self.indices[j - 1] + 1;
} }
} }
@ -194,6 +213,8 @@ impl<I> Iterator for Combinations<I>
} }
impl<I> FusedIterator for Combinations<I> impl<I> FusedIterator for Combinations<I>
where I: Iterator, where
I::Item: Clone I: Iterator,
{} I::Item: Clone,
{
}

View file

@ -3,20 +3,21 @@
//! コマンドオプション(パーサー)を定義する //! コマンドオプション(パーサー)を定義する
use std::env; use std::env;
use std::env::consts::{ARCH, OS}; use std::env::consts::{ARCH, OS};
use std::process;
use std::fs::File; use std::fs::File;
use std::io::{BufReader, BufRead}; use std::io::{BufRead, BufReader};
use std::process;
use crate::lazy::Lazy;
use crate::stdin; use crate::stdin;
use crate::Str; use crate::Str;
use crate::{power_assert, read_file}; use crate::{power_assert, read_file};
use crate::lazy::Lazy;
pub const SEMVER: &str = env!("CARGO_PKG_VERSION"); pub const SEMVER: &str = env!("CARGO_PKG_VERSION");
pub const GIT_HASH_SHORT: &str = env!("GIT_HASH_SHORT"); pub const GIT_HASH_SHORT: &str = env!("GIT_HASH_SHORT");
pub const BUILD_DATE: &str = env!("BUILD_DATE"); pub const BUILD_DATE: &str = env!("BUILD_DATE");
/// TODO: タグを含める /// TODO: タグを含める
pub const BUILD_INFO: Lazy<String> = Lazy::new(|| format!("(tags/?:{GIT_HASH_SHORT}, {BUILD_DATE}) on {ARCH}/{OS}")); pub const BUILD_INFO: Lazy<String> =
Lazy::new(|| format!("(tags/?:{GIT_HASH_SHORT}, {BUILD_DATE}) on {ARCH}/{OS}"));
/// 入力はファイルからだけとは限らないので /// 入力はファイルからだけとは限らないので
/// Inputで操作を一本化する /// Inputで操作を一本化する
@ -82,8 +83,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<Str> {
power_assert!(ln_begin, >=, 1); power_assert!(ln_begin, >=, 1);
match self { match self {
Self::File(filename) => { Self::File(filename) => match File::open(&filename[..]) {
match File::open(&filename[..]) {
Ok(file) => { Ok(file) => {
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);
@ -93,13 +93,12 @@ impl Input {
codes codes
} }
Err(_) => vec!["<file not found>".into()], Err(_) => vec!["<file not found>".into()],
} },
} Self::Pipe(s) | Self::Str(s) => s.split('\n').collect::<Vec<_>>()
Self::Pipe(s) | Self::Str(s) => { [ln_begin - 1..=ln_end - 1]
s.split('\n') .into_iter()
.collect::<Vec<_>>()[ln_begin-1..=ln_end-1] .map(|s| Str::rc(*s))
.into_iter().map(|s| Str::rc(*s)).collect() .collect(),
}
Self::REPL => stdin::reread_lines(ln_begin, ln_end), Self::REPL => 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"),
} }
@ -166,7 +165,9 @@ impl ErgConfig {
/// cloneのエイリアス(実際のcloneコストは低いので) /// cloneのエイリアス(実際のcloneコストは低いので)
#[inline] #[inline]
pub fn copy(&self) -> Self { self.clone() } pub fn copy(&self) -> Self {
self.clone()
}
pub fn parse() -> Self { pub fn parse() -> Self {
let mut args = env::args(); let mut args = env::args();

View file

@ -1,17 +1,17 @@
//! バイトコードからオブジェクトを復元する //! バイトコードからオブジェクトを復元する
use std::string::FromUtf8Error;
use std::process; use std::process;
use std::string::FromUtf8Error;
use crate::{Str, RcArray};
use crate::cache::Cache; use crate::cache::Cache;
use crate::{fn_name, switch_lang};
use crate::serialize::DataTypePrefix;
use crate::codeobj::CodeObj; use crate::codeobj::CodeObj;
use crate::config::{ErgConfig, Input}; use crate::config::{ErgConfig, Input};
use crate::value::ValueObj; use crate::error::{ErrorCore, ErrorKind, Location};
use crate::error::{ErrorCore, Location, ErrorKind}; use crate::serialize::DataTypePrefix;
use crate::traits::HasType; use crate::traits::HasType;
use crate::ty::{Type, TyParam}; use crate::ty::{TyParam, Type};
use crate::value::ValueObj;
use crate::{fn_name, switch_lang};
use crate::{RcArray, Str};
#[derive(Debug)] #[derive(Debug)]
pub struct DeserializeError { pub struct DeserializeError {
@ -34,24 +34,51 @@ impl From<FromUtf8Error> for DeserializeError {
impl From<DeserializeError> for ErrorCore { impl From<DeserializeError> for ErrorCore {
fn from(err: DeserializeError) -> Self { fn from(err: DeserializeError) -> Self {
ErrorCore::new(err.errno, ErrorKind::ImportError, Location::Unknown, err.desc, Option::<Str>::None) ErrorCore::new(
err.errno,
ErrorKind::ImportError,
Location::Unknown,
err.desc,
Option::<Str>::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<Str>, T: Into<Str>>(errno: usize, caused_by: S, desc: T) -> Self {
Self { errno, caused_by: caused_by.into(), desc: desc.into() } Self {
errno,
caused_by: caused_by.into(),
desc: desc.into(),
}
} }
pub fn file_broken_error() -> Self { pub fn file_broken_error() -> Self {
Self::new(0, fn_name!(), switch_lang!("the loaded .pyc file is broken", "読み込んだ.pycファイルは破損しています")) Self::new(
0,
fn_name!(),
switch_lang!(
"the loaded .pyc file is broken",
"読み込んだ.pycファイルは破損しています"
),
)
} }
pub fn type_error(expect: &Type, found: &Type) -> Self { pub fn type_error(expect: &Type, found: &Type) -> Self {
Self::new(0, fn_name!(), switch_lang!( Self::new(
format!("expect a {} object, but the deserialized object is {}", expect, found), 0,
format!("{}型オブジェクトを予期しましたが、 読み込んだオブジェクトは{}型です", expect, found) fn_name!(),
)) switch_lang!(
format!(
"expect a {} object, but the deserialized object is {}",
expect, found
),
format!(
"{}型オブジェクトを予期しましたが、 読み込んだオブジェクトは{}型です",
expect, found
)
),
)
} }
} }
@ -73,12 +100,14 @@ impl Deserializer {
} }
pub fn run(cfg: ErgConfig) { pub fn run(cfg: ErgConfig) {
let filename = if let Input::File(f) = cfg.input { f } else { let filename = if let Input::File(f) = cfg.input {
f
} else {
eprintln!("{:?} is not a filename", cfg.input); eprintln!("{:?} is not a filename", cfg.input);
process::exit(1); process::exit(1);
}; };
let codeobj = CodeObj::from_pyc(&filename[..]) let codeobj =
.expect(&format!("failed to deserialize {filename}")); CodeObj::from_pyc(&filename[..]).expect(&format!("failed to deserialize {filename}"));
println!("{}", codeobj.code_info()); println!("{}", codeobj.code_info());
} }
@ -111,26 +140,30 @@ impl Deserializer {
u32::from_le_bytes(Self::consume::<4>(v)) u32::from_le_bytes(Self::consume::<4>(v))
} }
pub fn deserialize_const(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<ValueObj> { pub fn deserialize_const(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<ValueObj> {
match DataTypePrefix::from(v.remove(0)) { match DataTypePrefix::from(v.remove(0)) {
DataTypePrefix::Int32 => { DataTypePrefix::Int32 => {
let bytes = Self::consume::<4>(v); let bytes = Self::consume::<4>(v);
Ok(ValueObj::Int(i32::from_le_bytes(bytes))) Ok(ValueObj::Int(i32::from_le_bytes(bytes)))
}, }
DataTypePrefix::BinFloat => { DataTypePrefix::BinFloat => {
let bytes = Self::consume::<8>(v); let bytes = Self::consume::<8>(v);
Ok(ValueObj::Float(f64::from_le_bytes(bytes))) Ok(ValueObj::Float(f64::from_le_bytes(bytes)))
}, }
DataTypePrefix::ShortAscii | DataTypePrefix::ShortAsciiInterned => { DataTypePrefix::ShortAscii | DataTypePrefix::ShortAsciiInterned => {
let len = v.remove(0); let len = v.remove(0);
let bytes = v.drain(..len as usize).collect(); let bytes = v.drain(..len as usize).collect();
Ok(self.get_cached_str(&String::from_utf8(bytes)?)) Ok(self.get_cached_str(&String::from_utf8(bytes)?))
}, }
DataTypePrefix::Str | DataTypePrefix::Unicode => { DataTypePrefix::Str | DataTypePrefix::Unicode => {
let len = Self::deserialize_u32(v); let len = Self::deserialize_u32(v);
let bytes = v.drain(..len as usize).collect(); let bytes = v.drain(..len as usize).collect();
Ok(self.get_cached_str(&String::from_utf8(bytes)?)) Ok(self.get_cached_str(&String::from_utf8(bytes)?))
}, }
DataTypePrefix::True => Ok(ValueObj::True), DataTypePrefix::True => Ok(ValueObj::True),
DataTypePrefix::False => Ok(ValueObj::False), DataTypePrefix::False => Ok(ValueObj::False),
DataTypePrefix::SmallTuple => { DataTypePrefix::SmallTuple => {
@ -140,7 +173,7 @@ impl Deserializer {
arr.push(self.deserialize_const(v, python_ver)?); arr.push(self.deserialize_const(v, python_ver)?);
} }
Ok(self.get_cached_arr(&arr)) Ok(self.get_cached_arr(&arr))
}, }
DataTypePrefix::Tuple => { DataTypePrefix::Tuple => {
let len = Self::deserialize_u32(v); let len = Self::deserialize_u32(v);
let mut arr = Vec::with_capacity(len as usize); let mut arr = Vec::with_capacity(len as usize);
@ -148,11 +181,14 @@ impl Deserializer {
arr.push(self.deserialize_const(v, python_ver)?); arr.push(self.deserialize_const(v, python_ver)?);
} }
Ok(self.get_cached_arr(&arr)) Ok(self.get_cached_arr(&arr))
}, }
DataTypePrefix::Code => { DataTypePrefix::Code => {
let argcount = Self::deserialize_u32(v); let argcount = Self::deserialize_u32(v);
let posonlyargcount = let posonlyargcount = if python_ver >= 3413 {
if python_ver >= 3413 { Self::deserialize_u32(v) } else { 0 }; Self::deserialize_u32(v)
} else {
0
};
let kwonlyargcount = Self::deserialize_u32(v); let kwonlyargcount = Self::deserialize_u32(v);
let nlocals = Self::deserialize_u32(v); let nlocals = Self::deserialize_u32(v);
let stacksize = Self::deserialize_u32(v); let stacksize = Self::deserialize_u32(v);
@ -183,30 +219,40 @@ impl Deserializer {
filename, filename,
name, name,
firstlineno, firstlineno,
lnotab lnotab,
))) )))
}, }
DataTypePrefix::None => Ok(ValueObj::None), DataTypePrefix::None => Ok(ValueObj::None),
other => { other => Err(DeserializeError::new(
Err(DeserializeError::new(0, fn_name!(), switch_lang!( 0,
fn_name!(),
switch_lang!(
format!("cannot deserialize this object: {}", other), format!("cannot deserialize this object: {}", other),
format!("このオブジェクトは復元できません: {}", other) format!("このオブジェクトは復元できません: {}", other)
))) ),
}, )),
} }
} }
pub fn deserialize_const_vec(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Vec<ValueObj>> { pub fn deserialize_const_vec(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<Vec<ValueObj>> {
match self.deserialize_const(v, python_ver)? { match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => Ok(arr.to_vec()), ValueObj::Array(arr) => Ok(arr.to_vec()),
other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())) other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())),
} }
} }
pub fn deserialize_const_array(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<RcArray<ValueObj>> { pub fn deserialize_const_array(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<RcArray<ValueObj>> {
match self.deserialize_const(v, python_ver)? { match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => Ok(arr), ValueObj::Array(arr) => Ok(arr),
other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())) other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())),
} }
} }
@ -217,11 +263,15 @@ impl Deserializer {
pub fn try_into_str(&mut self, c: ValueObj) -> DeserializeResult<Str> { pub fn try_into_str(&mut self, c: ValueObj) -> DeserializeResult<Str> {
match c { match c {
ValueObj::Str(s) => Ok(s), ValueObj::Str(s) => Ok(s),
other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())) other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())),
} }
} }
pub fn deserialize_str_vec(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Vec<Str>> { pub fn deserialize_str_vec(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<Vec<Str>> {
match self.deserialize_const(v, python_ver)? { match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => { ValueObj::Array(arr) => {
let mut strs = Vec::with_capacity(arr.len()); let mut strs = Vec::with_capacity(arr.len());
@ -230,14 +280,17 @@ impl Deserializer {
} }
Ok(strs) Ok(strs)
} }
other => Err(DeserializeError::type_error(&Type::array(Type::Str, TyParam::erased(Type::Nat)), &other.ref_t())) other => Err(DeserializeError::type_error(
&Type::array(Type::Str, TyParam::erased(Type::Nat)),
&other.ref_t(),
)),
} }
} }
pub fn deserialize_str(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Str> { pub fn deserialize_str(&mut self, v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Str> {
match self.deserialize_const(v, python_ver)? { match self.deserialize_const(v, python_ver)? {
ValueObj::Str(s) => Ok(s), ValueObj::Str(s) => Ok(s),
other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())) other => Err(DeserializeError::type_error(&Type::Str, &other.ref_t())),
} }
} }
@ -247,7 +300,7 @@ impl Deserializer {
0, 0,
fn_name!(), fn_name!(),
switch_lang!("failed to load bytes", "バイト列の読み込みに失敗しました"), switch_lang!("failed to load bytes", "バイト列の読み込みに失敗しました"),
)) ));
} }
let len = Self::deserialize_u32(v); let len = Self::deserialize_u32(v);
Ok(v.drain(0..len as usize).collect()) Ok(v.drain(0..len as usize).collect())

View file

@ -1,8 +1,8 @@
use std::collections::hash_map::{Keys, Values, ValuesMut, IntoValues, Iter, IntoIter, IterMut}; use std::borrow::Borrow;
use std::collections::hash_map::{IntoIter, IntoValues, Iter, IterMut, Keys, Values, ValuesMut};
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::borrow::Borrow;
use crate::fxhash::FxHashMap; use crate::fxhash::FxHashMap;
@ -18,11 +18,13 @@ macro_rules! dict {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Dict<K, V> { pub struct Dict<K, V> {
dict: FxHashMap<K, V> dict: FxHashMap<K, V>,
} }
impl<K: Hash + Eq, V: Hash + Eq> PartialEq for Dict<K, V> { impl<K: Hash + Eq, V: Hash + Eq> PartialEq for Dict<K, V> {
fn eq(&self, other: &Dict<K, V>) -> bool { self.dict == other.dict } fn eq(&self, other: &Dict<K, V>) -> bool {
self.dict == other.dict
}
} }
impl<K: Hash + Eq, V: Hash + Eq> Eq for Dict<K, V> {} impl<K: Hash + Eq, V: Hash + Eq> Eq for Dict<K, V> {}
@ -58,47 +60,73 @@ impl<K: Hash + Eq, V> FromIterator<(K, V)> for Dict<K, V> {
} }
impl<K, V> Default for Dict<K, V> { impl<K, V> Default for Dict<K, V> {
fn default() -> Dict<K, V> { Dict::new() } fn default() -> Dict<K, V> {
Dict::new()
}
} }
impl<K, V> Dict<K, V> { impl<K, V> Dict<K, V> {
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
Self{ dict: FxHashMap::default() } Self {
dict: FxHashMap::default(),
}
} }
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
Self{ dict: FxHashMap::with_capacity_and_hasher(capacity, Default::default()) } Self {
dict: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
}
} }
#[inline] #[inline]
pub fn len(&self) -> usize { self.dict.len() } pub fn len(&self) -> usize {
self.dict.len()
}
#[inline] #[inline]
pub fn capacity(&self) -> usize { self.dict.capacity() } pub fn capacity(&self) -> usize {
self.dict.capacity()
}
#[inline] #[inline]
pub fn keys(&self) -> Keys<K, V> { self.dict.keys() } pub fn keys(&self) -> Keys<K, V> {
self.dict.keys()
}
#[inline] #[inline]
pub fn values(&self) -> Values<K, V> { self.dict.values() } pub fn values(&self) -> Values<K, V> {
self.dict.values()
}
#[inline] #[inline]
pub fn values_mut(&mut self) -> ValuesMut<K, V> { self.dict.values_mut() } pub fn values_mut(&mut self) -> ValuesMut<K, V> {
self.dict.values_mut()
}
#[inline] #[inline]
pub fn into_values(self) -> IntoValues<K, V> { self.dict.into_values() } pub fn into_values(self) -> IntoValues<K, V> {
self.dict.into_values()
}
#[inline] #[inline]
pub fn iter(&self) -> Iter<K, V> { self.dict.iter() } pub fn iter(&self) -> Iter<K, V> {
self.dict.iter()
}
#[inline] #[inline]
pub fn into_iter(self) -> IntoIter<K, V> { self.dict.into_iter() } pub fn into_iter(self) -> IntoIter<K, V> {
self.dict.into_iter()
}
#[inline] #[inline]
pub fn iter_mut(&mut self) -> IterMut<K, V> { self.dict.iter_mut() } pub fn iter_mut(&mut self) -> IterMut<K, V> {
self.dict.iter_mut()
}
pub fn clear(&mut self) { self.dict.clear(); } pub fn clear(&mut self) {
self.dict.clear();
}
} }
impl<K: Hash + Eq, V> Dict<K, V> { impl<K: Hash + Eq, V> Dict<K, V> {
@ -106,7 +134,8 @@ impl<K: Hash + Eq, V> Dict<K, V> {
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where where
K: Borrow<Q>, K: Borrow<Q>,
Q: Hash + Eq { Q: Hash + Eq,
{
self.dict.get(k) self.dict.get(k)
} }
@ -114,7 +143,8 @@ impl<K: Hash + Eq, V> Dict<K, V> {
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where where
K: Borrow<Q>, K: Borrow<Q>,
Q: Hash + Eq { Q: Hash + Eq,
{
self.dict.get_mut(k) self.dict.get_mut(k)
} }
@ -122,23 +152,29 @@ impl<K: Hash + Eq, V> Dict<K, V> {
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where where
K: Borrow<Q>, K: Borrow<Q>,
Q: Hash + Eq { Q: Hash + Eq,
{
self.dict.contains_key(k) self.dict.contains_key(k)
} }
#[inline] #[inline]
pub fn insert(&mut self, k: K, v: V) { self.dict.insert(k, v); } pub fn insert(&mut self, k: K, v: V) {
self.dict.insert(k, v);
}
#[inline] #[inline]
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where where
K: Borrow<Q>, K: Borrow<Q>,
Q: Hash + Eq { Q: Hash + Eq,
{
self.dict.remove(k) self.dict.remove(k)
} }
#[inline] #[inline]
pub fn extend<I: IntoIterator<Item=(K, V)>>(&mut self, iter: I) { self.dict.extend(iter); } pub fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
self.dict.extend(iter);
}
#[inline] #[inline]
pub fn merge(&mut self, other: Self) { pub fn merge(&mut self, other: Self) {

View file

@ -3,13 +3,13 @@
//! エラー処理に関する汎用的なコンポーネントを提供する //! エラー処理に関する汎用的なコンポーネントを提供する
use std::cmp; use std::cmp;
use std::fmt; use std::fmt;
use std::io::{Write, BufWriter, stderr}; use std::io::{stderr, BufWriter, Write};
use crate::Str;
use crate::{fmt_option, switch_lang, impl_display_from_debug};
use crate::config::Input;
use crate::traits::{Stream, Locational};
use crate::color::*; use crate::color::*;
use crate::config::Input;
use crate::traits::{Locational, Stream};
use crate::Str;
use crate::{fmt_option, impl_display_from_debug, switch_lang};
/// ErrorKindと言っているが、ErrorだけでなくWarning, Exceptionも含まれる /// ErrorKindと言っているが、ErrorだけでなくWarning, Exceptionも含まれる
/// Numbering of this is not specifically related to ErrFmt.errno(). /// Numbering of this is not specifically related to ErrFmt.errno().
@ -200,8 +200,18 @@ impl From<&str> for ErrorKind {
/// points the location (of an error) in a code /// points the location (of an error) in a code
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Location { pub enum Location {
RangePair{ ln_begin: usize, col_first: (usize, usize), ln_end: usize, col_second: (usize, usize), }, RangePair {
Range{ ln_begin: usize, col_begin: usize, ln_end: usize, col_end: usize }, ln_begin: usize,
col_first: (usize, usize),
ln_end: usize,
col_second: (usize, usize),
},
Range {
ln_begin: usize,
col_begin: usize,
ln_end: usize,
col_end: usize,
},
LineRange(usize, usize), LineRange(usize, usize),
Line(usize), Line(usize),
Unknown, Unknown,
@ -210,8 +220,7 @@ pub enum Location {
impl Location { impl Location {
pub fn concat<L: Locational, R: Locational>(l: &L, r: &R) -> Self { pub fn concat<L: Locational, R: Locational>(l: &L, r: &R) -> Self {
match (l.ln_begin(), l.col_begin(), r.ln_end(), r.col_end()) { match (l.ln_begin(), l.col_begin(), r.ln_end(), r.col_end()) {
(Some(lb), Some(cb), Some(le), Some(ce)) => (Some(lb), Some(cb), Some(le), Some(ce)) => Self::range(lb, cb, le, ce),
Self::range(lb, cb, le, ce),
(Some(lb), _, Some(le), _) => Self::LineRange(lb, le), (Some(lb), _, Some(le), _) => Self::LineRange(lb, le),
(Some(l), _, _, _) | (_, _, Some(l), _) => Self::Line(l), (Some(l), _, _, _) | (_, _, Some(l), _) => Self::Line(l),
_ => Self::Unknown, _ => Self::Unknown,
@ -219,11 +228,16 @@ impl Location {
} }
pub const fn range(ln_begin: usize, col_begin: usize, ln_end: usize, col_end: usize) -> Self { pub const fn range(ln_begin: usize, col_begin: usize, ln_end: usize, col_end: usize) -> Self {
Self::Range{ ln_begin, col_begin, ln_end, col_end } Self::Range {
ln_begin,
col_begin,
ln_end,
col_end,
}
} }
pub fn pair(lhs: Self, rhs: Self) -> Self { pub fn pair(lhs: Self, rhs: Self) -> Self {
Self::RangePair{ Self::RangePair {
ln_begin: lhs.ln_begin().unwrap(), ln_begin: lhs.ln_begin().unwrap(),
col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()),
ln_end: rhs.ln_end().unwrap(), ln_end: rhs.ln_end().unwrap(),
@ -233,8 +247,8 @@ impl Location {
pub const fn ln_begin(&self) -> Option<usize> { pub const fn ln_begin(&self) -> Option<usize> {
match self { match self {
Self::RangePair{ ln_begin, .. } Self::RangePair { ln_begin, .. }
| Self::Range{ ln_begin, .. } | Self::Range { ln_begin, .. }
| Self::LineRange(ln_begin, _) | Self::LineRange(ln_begin, _)
| Self::Line(ln_begin) => Some(*ln_begin), | Self::Line(ln_begin) => Some(*ln_begin),
Self::Unknown => None, Self::Unknown => None,
@ -243,8 +257,8 @@ impl Location {
pub const fn ln_end(&self) -> Option<usize> { pub const fn ln_end(&self) -> Option<usize> {
match self { match self {
Self::RangePair{ ln_end, .. } Self::RangePair { ln_end, .. }
| Self::Range{ ln_end, .. } | Self::Range { ln_end, .. }
| Self::LineRange(ln_end, _) | Self::LineRange(ln_end, _)
| Self::Line(ln_end) => Some(*ln_end), | Self::Line(ln_end) => Some(*ln_end),
Self::Unknown => None, Self::Unknown => None,
@ -253,16 +267,22 @@ impl Location {
pub const fn col_begin(&self) -> Option<usize> { pub const fn col_begin(&self) -> Option<usize> {
match self { match self {
Self::RangePair{ col_first: (col_begin, _), .. } Self::RangePair {
| Self::Range{ col_begin, .. } => Some(*col_begin), col_first: (col_begin, _),
..
}
| Self::Range { col_begin, .. } => Some(*col_begin),
_ => None, _ => None,
} }
} }
pub const fn col_end(&self) -> Option<usize> { pub const fn col_end(&self) -> Option<usize> {
match self { match self {
Self::RangePair{ col_second: (_, col_end), .. } Self::RangePair {
| Self::Range{ col_end, .. } => Some(*col_end), col_second: (_, col_end),
..
}
| Self::Range { col_end, .. } => Some(*col_end),
_ => None, _ => None,
} }
} }
@ -280,11 +300,25 @@ pub struct ErrorCore {
} }
impl ErrorCore { impl ErrorCore {
pub fn new<S: Into<Str>>(errno: usize, kind: ErrorKind, loc: Location, desc: S, hint: Option<Str>) -> Self { pub fn new<S: Into<Str>>(
Self { errno, kind, loc, desc: desc.into(), hint } errno: usize,
kind: ErrorKind,
loc: Location,
desc: S,
hint: Option<Str>,
) -> Self {
Self {
errno,
kind,
loc,
desc: desc.into(),
hint,
}
} }
pub fn unreachable(fn_name: &str, line: u32) -> Self { Self::bug(0, Location::Unknown, fn_name, line) } pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::bug(0, Location::Unknown, fn_name, line)
}
pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
Self::new(errno, CompilerSystemError, loc, switch_lang!( Self::new(errno, CompilerSystemError, loc, switch_lang!(
@ -324,14 +358,19 @@ pub trait ErrorDisplay {
fn write_to_stderr(&self) { fn write_to_stderr(&self) {
let mut writer = BufWriter::new(stderr()); let mut writer = BufWriter::new(stderr());
writer.write(format!( writer
.write(
format!(
"{}{}{}: {}{}\n", "{}{}{}: {}{}\n",
self.format_header(), self.format_header(),
self.format_code_and_pointer(), self.format_code_and_pointer(),
self.core().kind, self.core().kind,
self.core().desc, self.core().desc,
fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), &self.core().hint), fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), &self.core().hint),
).as_bytes()).unwrap(); )
.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()
@ -351,27 +390,41 @@ pub trait ErrorDisplay {
)?; )?;
if let Some(inner) = self.ref_inner() { if let Some(inner) = self.ref_inner() {
inner.format(f) inner.format(f)
} else { Ok(()) } } else {
Ok(())
}
} }
fn format_header(&self) -> String { fn format_header(&self) -> String {
let kind = self.core().kind as u8; let kind = self.core().kind as u8;
let (color, err_or_warn) = let (color, err_or_warn) = if kind < 100 {
if kind < 100 { (RED, "Error") } (RED, "Error")
else if 100 <= kind && kind < 150 { (YELLOW, "Warning") } } else if 100 <= kind && kind < 150 {
else if 150 <= kind && kind < 200 { (DEEP_RED, "Error") } (YELLOW, "Warning")
else { ("", "Exception") }; } else if 150 <= kind && kind < 200 {
(DEEP_RED, "Error")
} else {
("", "Exception")
};
let loc = match self.core().loc { let loc = match self.core().loc {
Location::Range{ ln_begin, ln_end, .. } if ln_begin == ln_end => format!(", line {ln_begin}"), Location::Range {
Location::RangePair{ ln_begin, ln_end, .. } ln_begin, ln_end, ..
| Location::Range{ ln_begin, ln_end, .. } } if ln_begin == ln_end => format!(", line {ln_begin}"),
Location::RangePair {
ln_begin, ln_end, ..
}
| Location::Range {
ln_begin, ln_end, ..
}
| Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"),
Location::Line(lineno) => format!(", line {lineno}"), Location::Line(lineno) => format!(", line {lineno}"),
Location::Unknown => "".to_string(), Location::Unknown => "".to_string(),
}; };
let caused_by = if self.caused_by() != "" { let caused_by = if self.caused_by() != "" {
format!(", in {}", self.caused_by()) format!(", in {}", self.caused_by())
} else { "".to_string() }; } else {
"".to_string()
};
format!( format!(
"{color}{err_or_warn}[#{errno:>04}]{RESET}: File {input}{loc}{caused_by}\n", "{color}{err_or_warn}[#{errno:>04}]{RESET}: File {input}{loc}{caused_by}\n",
errno = self.core().errno, errno = self.core().errno,
@ -381,8 +434,13 @@ pub trait ErrorDisplay {
fn format_code_and_pointer(&self) -> String { fn format_code_and_pointer(&self) -> String {
match self.core().loc { match self.core().loc {
Location::RangePair{ .. } => todo!(), Location::RangePair { .. } => todo!(),
Location::Range { ln_begin, col_begin, ln_end, col_end } => { Location::Range {
ln_begin,
col_begin,
ln_end,
col_end,
} => {
let codes = if self.input() == &Input::REPL { let codes = if self.input() == &Input::REPL {
vec![self.input().reread()] vec![self.input().reread()]
} else { } else {
@ -403,13 +461,16 @@ pub trait ErrorDisplay {
} else { } else {
pointer += &"^".repeat(cmp::max(1, codes[i].len())); pointer += &"^".repeat(cmp::max(1, codes[i].len()));
} }
res += &format!("{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", code = codes[i]); res += &format!(
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
code = codes[i]
);
} }
res + RESET res + RESET
}, }
Location::LineRange(_begin, _end) => { Location::LineRange(_begin, _end) => {
todo!() todo!()
}, }
Location::Line(lineno) => { Location::Line(lineno) => {
let code = if self.input() == &Input::REPL { let code = if self.input() == &Input::REPL {
self.input().reread() self.input().reread()
@ -417,12 +478,13 @@ pub trait ErrorDisplay {
self.input().reread_lines(lineno, lineno).remove(0) self.input().reread_lines(lineno, lineno).remove(0)
}; };
format!("{CYAN}{lineno}{VBAR_UNICODE} {code}\n{RESET}") format!("{CYAN}{lineno}{VBAR_UNICODE} {code}\n{RESET}")
},
Location::Unknown => {
match self.input() {
Input::File(_) => "\n".to_string(),
other => format!("{CYAN}?{VBAR_UNICODE} {code}\n{RESET}", code = other.reread()),
} }
Location::Unknown => match self.input() {
Input::File(_) => "\n".to_string(),
other => format!(
"{CYAN}?{VBAR_UNICODE} {code}\n{RESET}",
code = other.reread()
),
}, },
} }
} }

View file

@ -74,14 +74,18 @@ impl<T: Eq> Eq for OnceCell<T> {}
impl<T> From<T> for OnceCell<T> { impl<T> From<T> for OnceCell<T> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
OnceCell { inner: UnsafeCell::new(Some(value)) } OnceCell {
inner: UnsafeCell::new(Some(value)),
}
} }
} }
impl<T> OnceCell<T> { impl<T> OnceCell<T> {
/// Creates a new empty cell. /// Creates a new empty cell.
pub const fn new() -> OnceCell<T> { pub const fn new() -> OnceCell<T> {
OnceCell { inner: UnsafeCell::new(None) } OnceCell {
inner: UnsafeCell::new(None),
}
} }
/// Gets the reference to the underlying value. /// Gets the reference to the underlying value.
@ -296,7 +300,10 @@ pub struct Lazy<T, F = fn() -> T> {
impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> { impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lazy").field("cell", &self.cell).field("init", &"..").finish() f.debug_struct("Lazy")
.field("cell", &self.cell)
.field("init", &"..")
.finish()
} }
} }
@ -319,7 +326,10 @@ impl<T, F> Lazy<T, F> {
/// # } /// # }
/// ``` /// ```
pub const fn new(init: F) -> Lazy<T, F> { pub const fn new(init: F) -> Lazy<T, F> {
Lazy { cell: OnceCell::new(), init: Cell::new(Some(init)) } Lazy {
cell: OnceCell::new(),
init: Cell::new(Some(init)),
}
} }
} }

View file

@ -60,7 +60,7 @@ impl<I, J> Index<J> for LazyBuffer<I>
where where
I: Iterator, I: Iterator,
I::Item: Sized, I::Item: Sized,
Vec<I::Item>: Index<J> Vec<I::Item>: Index<J>,
{ {
type Output = <Vec<I::Item> as Index<J>>::Output; type Output = <Vec<I::Item> as Index<J>>::Output;

View file

@ -26,5 +26,5 @@ pub fn levenshtein(lhs: &str, rhs: &str) -> usize {
.unwrap(); .unwrap();
} }
} }
return table[l_len][r_len] return table[l_len][r_len];
} }

View file

@ -2,33 +2,33 @@
use std::fmt; use std::fmt;
pub mod cache; pub mod cache;
pub mod codeobj;
pub mod color;
pub mod combinations;
pub mod config; pub mod config;
pub mod datetime; pub mod datetime;
pub mod deserialize;
pub mod dict;
pub mod error; pub mod error;
pub mod fxhash;
pub mod lazy;
pub mod lazy_buffer; pub mod lazy_buffer;
pub mod levenshtein; pub mod levenshtein;
pub mod codeobj;
pub mod combinations;
pub mod value;
pub mod color;
pub mod macros; pub mod macros;
pub mod opcode; pub mod opcode;
pub mod python_util; pub mod python_util;
pub mod rccell;
pub mod serialize; pub mod serialize;
pub mod deserialize; pub mod set;
pub mod stdin;
pub mod str;
pub mod traits; pub mod traits;
pub mod tsort; pub mod tsort;
pub mod ty; pub mod ty;
pub mod lazy; pub mod value;
pub mod rccell;
pub mod stdin;
pub mod str;
pub mod fxhash;
pub mod set;
pub mod dict;
pub use crate::str::Str;
use crate::set::Set; use crate::set::Set;
pub use crate::str::Str;
pub type RcArray<T> = std::rc::Rc<[T]>; pub type RcArray<T> = std::rc::Rc<[T]>;
@ -59,21 +59,21 @@ pub fn fmt_set_split_with<T: fmt::Display + std::hash::Hash>(s: &Set<T>, splitte
fmt_iter_split_with(s.iter(), splitter) fmt_iter_split_with(s.iter(), splitter)
} }
pub fn debug_fmt_iter<T: fmt::Debug, I: Iterator<Item=T>>(iter: I) -> String { pub fn debug_fmt_iter<T: fmt::Debug, I: Iterator<Item = T>>(iter: I) -> String {
let mut s = iter.fold("".to_string(), |sum, elem| format!("{sum}{elem:?}, ")); let mut s = iter.fold("".to_string(), |sum, elem| format!("{sum}{elem:?}, "));
s.pop(); s.pop();
s.pop(); s.pop();
s s
} }
pub fn fmt_iter<T: fmt::Display, I: Iterator<Item=T>>(iter: I) -> String { pub fn fmt_iter<T: fmt::Display, I: Iterator<Item = T>>(iter: I) -> String {
let mut s = iter.fold("".to_string(), |sum, elem| sum + &elem.to_string() + ", "); let mut s = iter.fold("".to_string(), |sum, elem| sum + &elem.to_string() + ", ");
s.pop(); s.pop();
s.pop(); s.pop();
s s
} }
pub fn fmt_iter_split_with<T: fmt::Display, I: Iterator<Item=T>>(i: I, splitter: &str) -> String { pub fn fmt_iter_split_with<T: fmt::Display, I: Iterator<Item = T>>(i: I, splitter: &str) -> String {
let mut s = i.fold("".to_string(), |sum, elem| { let mut s = i.fold("".to_string(), |sum, elem| {
sum + &elem.to_string() + splitter sum + &elem.to_string() + splitter
}); });
@ -92,8 +92,11 @@ pub fn get_hash<T: std::hash::Hash>(t: &T) -> usize {
let mut s = fxhash::FxHasher::default(); let mut s = fxhash::FxHasher::default();
t.hash(&mut s); t.hash(&mut s);
let res = std::hash::Hasher::finish(&s); let res = std::hash::Hasher::finish(&s);
if cfg!(target_pointer_width = "64") { res as usize } if cfg!(target_pointer_width = "64") {
else { (res % usize::MAX as u64) as usize } res as usize
} else {
(res % usize::MAX as u64) as usize
}
} }
/// \r\n (Windows), \r (old MacOS) -> \n (Unix) /// \r\n (Windows), \r (old MacOS) -> \n (Unix)
@ -111,7 +114,8 @@ pub fn chomp(src: &str) -> String {
pub fn try_map<T, U, E, F, I>(i: I, f: F) -> Result<Vec<U>, E> pub fn try_map<T, U, E, F, I>(i: I, f: F) -> Result<Vec<U>, E>
where where
F: Fn(T) -> Result<U, E>, F: Fn(T) -> Result<U, E>,
I: Iterator<Item=T> { I: Iterator<Item = T>,
{
let mut v = vec![]; let mut v = vec![];
for x in i { for x in i {
let y = f(x)?; let y = f(x)?;

View file

@ -21,9 +21,11 @@ macro_rules! impl_display_from_debug {
($Name: ident) => { ($Name: ident) => {
impl std::fmt::Display for $Name { impl std::fmt::Display for $Name {
#[inline] #[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{self:#?}") } fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{self:#?}")
} }
} }
};
} }
#[macro_export] #[macro_export]
@ -57,8 +59,12 @@ macro_rules! impl_display_for_enum_with_variant {
#[macro_export] #[macro_export]
macro_rules! switch_lang { macro_rules! switch_lang {
($en: expr, $jp: expr $(,)*) => {{ ($en: expr, $jp: expr $(,)*) => {{
if cfg!(feature = "japanese") { $jp } else { $en } if cfg!(feature = "japanese") {
}} $jp
} else {
$en
}
}};
} }
/// 2重のunwrapまでサポート /// 2重のunwrapまでサポート
@ -91,33 +97,58 @@ macro_rules! enum_unwrap {
#[macro_export] #[macro_export]
macro_rules! fmt_option { macro_rules! fmt_option {
($ex: expr $(,)*) => { ($ex: expr $(,)*) => {
if let Some(x) = $ex { format!("{}", x) } else { "".to_string() } if let Some(x) = $ex {
format!("{}", x)
} else {
"".to_string()
}
}; };
($ex: expr $(,)*, else $els: expr $(,)*) => { ($ex: expr $(,)*, else $els: expr $(,)*) => {
if let Some(x) = $ex { format!("{}", x) } else { $els.to_string() } if let Some(x) = $ex {
format!("{}", x)
} else {
$els.to_string()
}
}; };
(pre $prefix: expr, $ex: expr $(,)*) => { (pre $prefix: expr, $ex: expr $(,)*) => {
if let Some(x) = $ex { format!("{}{}", $prefix, x) } else { "".to_string() } if let Some(x) = $ex {
format!("{}{}", $prefix, x)
} else {
"".to_string()
}
}; };
($ex: expr, post $postfix: expr $(,)*) => { ($ex: expr, post $postfix: expr $(,)*) => {
if let Some(x) = $ex { format!("{}{}", x, $postfix) } else { "".to_string() } if let Some(x) = $ex {
format!("{}{}", x, $postfix)
} else {
"".to_string()
}
}; };
($prefix: expr, $ex: expr, $postfix: expr $(,)*) => { ($prefix: expr, $ex: expr, $postfix: expr $(,)*) => {
if let Some(x) = $ex { format!("{}{}{}", $prefix, x, $postfix) } else { "".to_string() } if let Some(x) = $ex {
format!("{}{}{}", $prefix, x, $postfix)
} else {
"".to_string()
}
}; };
} }
#[macro_export] #[macro_export]
macro_rules! switch_unreachable { macro_rules! switch_unreachable {
() => {{ () => {{
if cfg!(debug_assertions) { unreachable!() } if cfg!(debug_assertions) {
else { unsafe { std::hint::unreachable_unchecked() } } unreachable!()
}} } else {
unsafe { std::hint::unreachable_unchecked() }
}
}};
} }
#[macro_export] #[macro_export]
macro_rules! assume_unreachable { macro_rules! assume_unreachable {
() => {{ unsafe { std::hint::unreachable_unchecked() } }} () => {{
unsafe { std::hint::unreachable_unchecked() }
}};
} }
/// indicates the current invoked function. /// indicates the current invoked function.
@ -125,26 +156,33 @@ macro_rules! assume_unreachable {
macro_rules! fn_name_full { macro_rules! fn_name_full {
() => {{ () => {{
const fn dummy() {} const fn dummy() {}
fn type_name_of<T>(_: T) -> &'static str { std::any::type_name::<T>() } fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let name = type_name_of(dummy); // "~::dummy" let name = type_name_of(dummy); // "~::dummy"
&name[..name.len() - 7] // remove "::dummy" &name[..name.len() - 7] // remove "::dummy"
}} }};
} }
#[macro_export] #[macro_export]
macro_rules! fn_name { macro_rules! fn_name {
() => {{ () => {{
const fn dummy() {} const fn dummy() {}
fn type_name_of<T>(_: T) -> &'static str { std::any::type_name::<T>() } fn type_name_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
let name = type_name_of(dummy).rsplit("::").nth(1).unwrap(); let name = type_name_of(dummy).rsplit("::").nth(1).unwrap();
&name[..] &name[..]
}} }};
} }
// do not break lines (line!() is used) // do not break lines (line!() is used)
#[macro_export] #[macro_export]
macro_rules! caused_by { macro_rules! caused_by {
() => {{ let fn_name = $crate::fn_name!(); &format!("{fn_name} at line {}", line!()) }} () => {{
let fn_name = $crate::fn_name!();
&format!("{fn_name} at line {}", line!())
}};
} }
/// 一度文字列をパースするので /// 一度文字列をパースするので
@ -155,12 +193,14 @@ macro_rules! addr {
let s = format!("{:p}", &$obj); let s = format!("{:p}", &$obj);
let s = s.trim_start_matches("0x"); let s = s.trim_start_matches("0x");
u64::from_str_radix(&s, 16).unwrap() u64::from_str_radix(&s, 16).unwrap()
}} }};
} }
#[macro_export] #[macro_export]
macro_rules! addr_eq { macro_rules! addr_eq {
($l: expr, $r: expr $(,)*) => {{ &$l as *const _ == &$r as *const _ }} ($l: expr, $r: expr $(,)*) => {{
&$l as *const _ == &$r as *const _
}};
} }
#[macro_export] #[macro_export]
@ -187,10 +227,14 @@ macro_rules! power_assert {
#[macro_export] #[macro_export]
macro_rules! debug_power_assert { macro_rules! debug_power_assert {
($l: expr, $op: tt, $r: expr) => { ($l: expr, $op: tt, $r: expr) => {
if cfg!(debug_assertions) { erg_common::power_assert!($l, $op, $r) } if cfg!(debug_assertions) {
erg_common::power_assert!($l, $op, $r)
}
}; };
($ex: expr) => { ($ex: expr) => {
if cfg!(debug_assertions) { erg_common::power_assert!($ex) } if cfg!(debug_assertions) {
erg_common::power_assert!($ex)
}
}; };
} }
@ -204,7 +248,7 @@ macro_rules! debug_enum_assert {
}}; }};
($ex: expr, $TupleCons: ident, $Enum: ident :: $Variant: ident $(,)*) => {{ ($ex: expr, $TupleCons: ident, $Enum: ident :: $Variant: ident $(,)*) => {{
debug_assert!(common::enum_is!($ex, $TupleCons, $Enum::$Variant)); debug_assert!(common::enum_is!($ex, $TupleCons, $Enum::$Variant));
}} }};
} }
#[macro_export] #[macro_export]

View file

@ -294,5 +294,7 @@ impl From<u8> for Opcode {
} }
impl Opcode { impl Opcode {
pub const fn take_arg(&self) -> bool { 90 <= (*self as u8) && (*self as u8) < 220 } pub const fn take_arg(&self) -> bool {
90 <= (*self as u8) && (*self as u8) < 220
}
} }

View file

@ -31,7 +31,10 @@ pub fn detect_magic_number() -> u32 {
.output() .output()
.expect("cannot get the magic number from python") .expect("cannot get the magic number from python")
} else { } else {
let python_command = format!("{} -c 'import importlib.util as util;print(util.MAGIC_NUMBER.hex())'", which_python()); let python_command = format!(
"{} -c 'import importlib.util as util;print(util.MAGIC_NUMBER.hex())'",
which_python()
);
Command::new("sh") Command::new("sh")
.arg("-c") .arg("-c")
.arg(python_command) .arg(python_command)

View file

@ -1,7 +1,7 @@
use std::cell::{Ref, RefCell, RefMut};
use std::fmt; use std::fmt;
use std::rc::Rc;
use std::cell::{RefCell, Ref, RefMut};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct RcCell<T: ?Sized>(Rc<RefCell<T>>); pub struct RcCell<T: ?Sized>(Rc<RefCell<T>>);
@ -28,7 +28,9 @@ impl<T: Hash> Hash for RcCell<T> {
} }
impl<T: Default> Default for RcCell<T> { impl<T: Default> Default for RcCell<T> {
fn default() -> Self { Self::new(Default::default()) } fn default() -> Self {
Self::new(Default::default())
}
} }
impl<T: fmt::Display> fmt::Display for RcCell<T> { impl<T: fmt::Display> fmt::Display for RcCell<T> {
@ -38,7 +40,9 @@ impl<T: fmt::Display> fmt::Display for RcCell<T> {
} }
impl<T> RcCell<T> { impl<T> RcCell<T> {
pub fn new(t: T) -> Self { Self(Rc::new(RefCell::new(t))) } pub fn new(t: T) -> Self {
Self(Rc::new(RefCell::new(t)))
}
#[inline] #[inline]
pub fn into_inner(self) -> T { pub fn into_inner(self) -> T {
@ -52,7 +56,9 @@ impl<T> RcCell<T> {
impl<T: ?Sized> RcCell<T> { impl<T: ?Sized> RcCell<T> {
#[inline] #[inline]
pub fn copy(&self) -> Self { Self(self.0.clone()) } pub fn copy(&self) -> Self {
Self(self.0.clone())
}
#[inline] #[inline]
pub fn borrow(&self) -> Ref<'_, T> { pub fn borrow(&self) -> Ref<'_, T> {
@ -67,5 +73,7 @@ impl<T: ?Sized> RcCell<T> {
impl<T: Clone> RcCell<T> { impl<T: Clone> RcCell<T> {
#[inline] #[inline]
pub fn clone_inner(&self) -> T { self.borrow().clone() } pub fn clone_inner(&self) -> T {
self.borrow().clone()
}
} }

View file

@ -1,13 +1,13 @@
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::hash_set::{IntoIter, Iter};
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::iter::FromIterator; use std::iter::FromIterator;
use std::collections::hash_set::{Iter, IntoIter};
use crate::{fmt_iter, debug_fmt_iter};
use crate::fxhash::FxHashSet; use crate::fxhash::FxHashSet;
use crate::value::ValueObj;
use crate::ty::Type; use crate::ty::Type;
use crate::value::ValueObj;
use crate::{debug_fmt_iter, fmt_iter};
#[macro_export] #[macro_export]
macro_rules! set { macro_rules! set {
@ -21,18 +21,19 @@ macro_rules! set {
#[derive(Clone)] #[derive(Clone)]
pub struct Set<T> { pub struct Set<T> {
elems: FxHashSet<T> elems: FxHashSet<T>,
} }
impl<T: Hash + Eq> PartialEq for Set<T> { impl<T: Hash + Eq> PartialEq for Set<T> {
fn eq(&self, other: &Set<T>) -> bool { fn eq(&self, other: &Set<T>) -> bool {
self.len() == other.len() self.len() == other.len() && self.iter().all(|key| other.contains(key))
&& self.iter().all(|key| other.contains(key))
} }
} }
impl<T> Default for Set<T> { impl<T> Default for Set<T> {
fn default() -> Self { Self::new() } fn default() -> Self {
Self::new()
}
} }
impl<T: Hash + Eq> Eq for Set<T> {} impl<T: Hash + Eq> Eq for Set<T> {}
@ -44,7 +45,9 @@ impl<T: Hash> Hash for Set<T> {
} }
impl<T: Hash + Eq> From<Vec<T>> for Set<T> { impl<T: Hash + Eq> From<Vec<T>> for Set<T> {
fn from(vec: Vec<T>) -> Self { vec.into_iter().collect() } fn from(vec: Vec<T>) -> Self {
vec.into_iter().collect()
}
} }
impl<T: fmt::Debug> fmt::Debug for Set<T> { impl<T: fmt::Debug> fmt::Debug for Set<T> {
@ -70,45 +73,78 @@ impl<T: Hash + Eq> FromIterator<T> for Set<T> {
impl<T> Set<T> { impl<T> Set<T> {
#[inline] #[inline]
pub fn new() -> Self { Self{ elems: FxHashSet::default() } } pub fn new() -> Self {
Self {
elems: FxHashSet::default(),
}
}
} }
impl<T: Hash> Set<T> { impl<T: Hash> Set<T> {
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
Self{ elems: FxHashSet::with_capacity_and_hasher(capacity, Default::default()) } Self {
elems: FxHashSet::with_capacity_and_hasher(capacity, Default::default()),
}
} }
#[inline] #[inline]
pub fn len(&self) -> usize { self.elems.len() } pub fn len(&self) -> usize {
self.elems.len()
}
#[inline] #[inline]
pub fn is_empty(&self) -> bool { self.elems.is_empty() } pub fn is_empty(&self) -> bool {
self.elems.is_empty()
}
#[inline] #[inline]
pub fn iter(&self) -> Iter<'_, T> { self.elems.iter() } pub fn iter(&self) -> Iter<'_, T> {
self.elems.iter()
}
#[inline] #[inline]
pub fn into_iter(self) -> IntoIter<T> { self.elems.into_iter() } pub fn into_iter(self) -> IntoIter<T> {
self.elems.into_iter()
}
} }
impl<T: Hash + Eq> Set<T> { impl<T: Hash + Eq> Set<T> {
#[inline] #[inline]
pub fn get<Q>(&self, value: &Q) -> Option<&T> pub fn get<Q>(&self, value: &Q) -> Option<&T>
where T: Borrow<Q>, Q: ?Sized + Hash + Eq { self.elems.get(value) } where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.elems.get(value)
}
#[inline] #[inline]
pub fn contains<Q>(&self, value: &Q) -> bool pub fn contains<Q>(&self, value: &Q) -> bool
where T: Borrow<Q>, Q: ?Sized + Hash + Eq { self.elems.contains(value) } where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.elems.contains(value)
}
#[inline] #[inline]
pub fn insert(&mut self, value: T) { self.elems.insert(value); } pub fn insert(&mut self, value: T) {
self.elems.insert(value);
}
#[inline] #[inline]
pub fn remove<Q>(&mut self, value: &Q) -> bool pub fn remove<Q>(&mut self, value: &Q) -> bool
where T: Borrow<Q>, Q: ?Sized + Hash + Eq { self.elems.remove(value) } where
T: Borrow<Q>,
Q: ?Sized + Hash + Eq,
{
self.elems.remove(value)
}
#[inline] #[inline]
pub fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) { self.elems.extend(iter); } pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.elems.extend(iter);
}
#[inline] #[inline]
pub fn is_superset(&self, other: &Set<T>) -> bool { pub fn is_superset(&self, other: &Set<T>) -> bool {
@ -131,13 +167,17 @@ impl<T: Hash + Eq + Clone> Set<T> {
#[inline] #[inline]
pub fn union(&self, other: &Set<T>) -> Set<T> { pub fn union(&self, other: &Set<T>) -> Set<T> {
let u = self.elems.union(&other.elems); let u = self.elems.union(&other.elems);
Self{ elems: u.into_iter().map(|x| x.clone()).collect() } Self {
elems: u.into_iter().map(|x| x.clone()).collect(),
}
} }
#[inline] #[inline]
pub fn intersection(&self, other: &Set<T>) -> Set<T> { pub fn intersection(&self, other: &Set<T>) -> Set<T> {
let u = self.elems.intersection(&other.elems); let u = self.elems.intersection(&other.elems);
Self{ elems: u.into_iter().map(|x| x.clone()).collect() } Self {
elems: u.into_iter().map(|x| x.clone()).collect(),
}
} }
} }
@ -163,14 +203,18 @@ impl Set<ValueObj> {
} }
pub fn max(&self) -> Option<ValueObj> { pub fn max(&self) -> Option<ValueObj> {
if !self.is_homogeneous() { return None } if !self.is_homogeneous() {
return None;
}
self.iter() self.iter()
.max_by(|x, y| x.try_cmp(y).unwrap()) .max_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone) .map(Clone::clone)
} }
pub fn min(&self) -> Option<ValueObj> { pub fn min(&self) -> Option<ValueObj> {
if !self.is_homogeneous() { return None } if !self.is_homogeneous() {
return None;
}
self.iter() self.iter()
.min_by(|x, y| x.try_cmp(y).unwrap()) .min_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone) .map(Clone::clone)

View file

@ -1,5 +1,5 @@
use std::io::{stdin, BufReader, BufRead};
use std::cell::RefCell; use std::cell::RefCell;
use std::io::{stdin, BufRead, BufReader};
use crate::Str; use crate::Str;
@ -24,7 +24,7 @@ impl StdinReader {
} }
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<Str> {
self.buf[ln_begin-1..=ln_end-1].to_vec() self.buf[ln_begin - 1..=ln_end - 1].to_vec()
} }
} }

View file

@ -1,6 +1,6 @@
use std::hash::{Hash, Hasher};
use std::fmt;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Add, Deref}; use std::ops::{Add, Deref};
pub type RcStr = std::rc::Rc<str>; pub type RcStr = std::rc::Rc<str>;
@ -16,7 +16,9 @@ pub enum Str {
impl PartialEq for Str { impl PartialEq for Str {
#[inline] #[inline]
fn eq(&self, other: &Str) -> bool { &self[..] == &other[..] } fn eq(&self, other: &Str) -> bool {
&self[..] == &other[..]
}
} }
impl Add<&str> for Str { impl Add<&str> for Str {
@ -49,27 +51,37 @@ impl fmt::Display for Str {
// あえて`impl<S: Into<Str>> From<S> for Str { ... }`はしない // あえて`impl<S: Into<Str>> From<S> for Str { ... }`はしない
impl From<&'static str> for Str { impl From<&'static str> for Str {
#[inline] #[inline]
fn from(s: &'static str) -> Self { Str::ever(s) } fn from(s: &'static str) -> Self {
Str::ever(s)
}
} }
impl From<&String> for Str { impl From<&String> for Str {
#[inline] #[inline]
fn from(s: &String) -> Self { Str::Rc((&s[..]).into()) } fn from(s: &String) -> Self {
Str::Rc((&s[..]).into())
}
} }
impl From<String> for Str { impl From<String> for Str {
#[inline] #[inline]
fn from(s: String) -> Self { Str::Rc((&s[..]).into()) } fn from(s: String) -> Self {
Str::Rc((&s[..]).into())
}
} }
impl From<&RcStr> for Str { impl From<&RcStr> for Str {
#[inline] #[inline]
fn from(s: &RcStr) -> Self { Str::Rc(s.clone()) } fn from(s: &RcStr) -> Self {
Str::Rc(s.clone())
}
} }
impl From<RcStr> for Str { impl From<RcStr> for Str {
#[inline] #[inline]
fn from(s: RcStr) -> Self { Str::Rc(s) } fn from(s: RcStr) -> Self {
Str::Rc(s)
}
} }
impl From<&Str> for Str { impl From<&Str> for Str {
@ -84,7 +96,9 @@ impl From<&Str> for Str {
impl Deref for Str { impl Deref for Str {
type Target = str; type Target = str;
fn deref(&self) -> &Self::Target { self.borrow() } fn deref(&self) -> &Self::Target {
self.borrow()
}
} }
impl Borrow<str> for Str { impl Borrow<str> for Str {
@ -98,11 +112,17 @@ impl Borrow<str> for Str {
} }
impl Str { impl Str {
pub const fn ever(s: &'static str) -> Self { Str::Static(s) } pub const fn ever(s: &'static str) -> Self {
Str::Static(s)
}
pub fn rc(s: &str) -> Self { Str::Rc(s.into()) } pub fn rc(s: &str) -> Self {
Str::Rc(s.into())
}
pub fn as_ref(&self) -> &str { self.borrow() } pub fn as_ref(&self) -> &str {
self.borrow()
}
pub fn into_rc(self) -> RcStr { pub fn into_rc(self) -> RcStr {
match self { match self {
@ -112,6 +132,9 @@ impl Str {
} }
pub fn is_uppercase(&self) -> bool { pub fn is_uppercase(&self) -> bool {
self.chars().next().map(|c| c.is_uppercase()).unwrap_or(false) self.chars()
.next()
.map(|c| c.is_uppercase())
.unwrap_or(false)
} }
} }

View file

@ -1,18 +1,18 @@
//! defines common traits used in the compiler. //! defines common traits used in the compiler.
//! //!
//! コンパイラ等で汎用的に使われるトレイトを定義する //! コンパイラ等で汎用的に使われるトレイトを定義する
use std::io::{stdout, BufWriter, Write};
use std::mem;
use std::process;
use std::slice::{Iter, IterMut}; use std::slice::{Iter, IterMut};
use std::vec::IntoIter; use std::vec::IntoIter;
use std::io::{BufWriter, Write, stdout};
use std::process;
use std::mem;
use crate::Str;
use crate::{addr_eq, switch_unreachable, chomp, log};
use crate::color::{GREEN, RESET}; use crate::color::{GREEN, RESET};
use crate::config::{ErgConfig, Input}; use crate::config::{ErgConfig, Input};
use crate::error::{Location, ErrorDisplay, MultiErrorDisplay}; use crate::error::{ErrorDisplay, Location, MultiErrorDisplay};
use crate::ty::Type; use crate::ty::Type;
use crate::Str;
use crate::{addr_eq, chomp, log, switch_unreachable};
pub trait Stream<T>: Sized { pub trait Stream<T>: Sized {
fn payload(self) -> Vec<T>; fn payload(self) -> Vec<T>;
@ -20,17 +20,23 @@ pub trait Stream<T>: Sized {
fn ref_mut_payload(&mut self) -> &mut Vec<T>; fn ref_mut_payload(&mut self) -> &mut Vec<T>;
#[inline] #[inline]
fn clear(&mut self) { self.ref_mut_payload().clear(); } fn clear(&mut self) {
self.ref_mut_payload().clear();
}
#[inline] #[inline]
fn len(&self) -> usize { self.ref_payload().len() } fn len(&self) -> usize {
self.ref_payload().len()
}
fn size(&self) -> usize { fn size(&self) -> usize {
std::mem::size_of::<Vec<T>>() + std::mem::size_of::<T>() * self.ref_payload().capacity() std::mem::size_of::<Vec<T>>() + std::mem::size_of::<T>() * self.ref_payload().capacity()
} }
#[inline] #[inline]
fn is_empty(&self) -> bool { self.ref_payload().is_empty() } fn is_empty(&self) -> bool {
self.ref_payload().is_empty()
}
#[inline] #[inline]
fn insert(&mut self, idx: usize, elem: T) { fn insert(&mut self, idx: usize, elem: T) {
@ -38,89 +44,141 @@ pub trait Stream<T>: Sized {
} }
#[inline] #[inline]
fn remove(&mut self, idx: usize) -> T { self.ref_mut_payload().remove(idx) } fn remove(&mut self, idx: usize) -> T {
self.ref_mut_payload().remove(idx)
#[inline]
fn push(&mut self, elem: T) { self.ref_mut_payload().push(elem); }
fn append<S: Stream<T>>(&mut self, s: &mut S) { self.ref_mut_payload().append(s.ref_mut_payload()); }
#[inline]
fn pop(&mut self) -> Option<T> { self.ref_mut_payload().pop() }
fn lpop(&mut self) -> Option<T> {
let len = self.len();
if len == 0 { None } else { Some(self.ref_mut_payload().remove(0)) }
} }
#[inline] #[inline]
fn get(&self, idx: usize) -> Option<&T> { self.ref_payload().get(idx) } fn push(&mut self, elem: T) {
self.ref_mut_payload().push(elem);
}
fn append<S: Stream<T>>(&mut self, s: &mut S) {
self.ref_mut_payload().append(s.ref_mut_payload());
}
#[inline] #[inline]
fn get_mut(&mut self, idx: usize) -> Option<&mut T> { self.ref_mut_payload().get_mut(idx) } fn pop(&mut self) -> Option<T> {
self.ref_mut_payload().pop()
}
fn lpop(&mut self) -> Option<T> {
let len = self.len();
if len == 0 {
None
} else {
Some(self.ref_mut_payload().remove(0))
}
}
#[inline] #[inline]
fn first(&self) -> Option<&T> { self.ref_payload().first() } fn get(&self, idx: usize) -> Option<&T> {
self.ref_payload().get(idx)
}
#[inline] #[inline]
fn first_mut(&mut self) -> Option<&mut T> { self.ref_mut_payload().first_mut() } fn get_mut(&mut self, idx: usize) -> Option<&mut T> {
self.ref_mut_payload().get_mut(idx)
}
#[inline] #[inline]
fn last(&self) -> Option<&T> { self.ref_payload().last() } fn first(&self) -> Option<&T> {
self.ref_payload().first()
}
#[inline] #[inline]
fn last_mut(&mut self) -> Option<&mut T> { self.ref_mut_payload().last_mut() } fn first_mut(&mut self) -> Option<&mut T> {
self.ref_mut_payload().first_mut()
}
#[inline] #[inline]
fn iter(&self) -> Iter<'_, T> { self.ref_payload().iter() } fn last(&self) -> Option<&T> {
self.ref_payload().last()
}
#[inline] #[inline]
fn iter_mut(&mut self) -> IterMut<'_, T> { self.ref_mut_payload().iter_mut() } fn last_mut(&mut self) -> Option<&mut T> {
self.ref_mut_payload().last_mut()
}
#[inline] #[inline]
fn into_iter(self) -> IntoIter<T> { self.payload().into_iter() } fn iter(&self) -> Iter<'_, T> {
self.ref_payload().iter()
}
#[inline] #[inline]
fn take_all(&mut self) -> Vec<T> { self.ref_mut_payload().drain(..).collect() } fn iter_mut(&mut self) -> IterMut<'_, T> {
self.ref_mut_payload().iter_mut()
}
#[inline]
fn into_iter(self) -> IntoIter<T> {
self.payload().into_iter()
}
#[inline]
fn take_all(&mut self) -> Vec<T> {
self.ref_mut_payload().drain(..).collect()
}
} }
#[macro_export] #[macro_export]
macro_rules! impl_displayable_stream_for_wrapper { macro_rules! impl_displayable_stream_for_wrapper {
($Strc: ident, $Inner: ident) => { ($Strc: ident, $Inner: ident) => {
impl $Strc { impl $Strc {
pub const fn new(v: Vec<$Inner>) -> $Strc { $Strc(v) } pub const fn new(v: Vec<$Inner>) -> $Strc {
$Strc(v)
}
#[inline] #[inline]
pub fn empty() -> $Strc { $Strc(Vec::with_capacity(20)) } pub fn empty() -> $Strc {
$Strc(Vec::with_capacity(20))
}
} }
impl From<Vec<$Inner>> for $Strc { impl From<Vec<$Inner>> for $Strc {
#[inline] #[inline]
fn from(errs: Vec<$Inner>) -> Self { Self(errs) } fn from(errs: Vec<$Inner>) -> Self {
Self(errs)
}
} }
impl std::fmt::Display for $Strc { impl std::fmt::Display for $Strc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}]", erg_common::fmt_iter(self.iter()).replace("\n", "\\n")) write!(
f,
"[{}]",
erg_common::fmt_iter(self.iter()).replace("\n", "\\n")
)
} }
} }
impl Default for $Strc { impl Default for $Strc {
#[inline] #[inline]
fn default() -> Self { Self::empty() } fn default() -> Self {
Self::empty()
}
} }
impl std::ops::Index<usize> for $Strc { impl std::ops::Index<usize> for $Strc {
type Output = $Inner; type Output = $Inner;
fn index(&self, idx: usize) -> &Self::Output { erg_common::traits::Stream::get(self, idx).unwrap() } fn index(&self, idx: usize) -> &Self::Output {
erg_common::traits::Stream::get(self, idx).unwrap()
}
} }
impl erg_common::traits::Stream<$Inner> for $Strc { impl erg_common::traits::Stream<$Inner> for $Strc {
#[inline] #[inline]
fn payload(self) -> Vec<$Inner> { self.0 } fn payload(self) -> Vec<$Inner> {
self.0
}
#[inline] #[inline]
fn ref_payload(&self) -> &Vec<$Inner> { &self.0 } fn ref_payload(&self) -> &Vec<$Inner> {
&self.0
}
#[inline] #[inline]
fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> { &mut self.0 } fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> {
&mut self.0
}
} }
}; };
} }
@ -129,31 +187,47 @@ macro_rules! impl_displayable_stream_for_wrapper {
macro_rules! impl_stream_for_wrapper { macro_rules! impl_stream_for_wrapper {
($Strc: ident, $Inner: ident) => { ($Strc: ident, $Inner: ident) => {
impl $Strc { impl $Strc {
pub const fn new(v: Vec<$Inner>) -> $Strc { $Strc(v) } pub const fn new(v: Vec<$Inner>) -> $Strc {
pub const fn empty() -> $Strc { $Strc(Vec::new()) } $Strc(v)
}
pub const fn empty() -> $Strc {
$Strc(Vec::new())
}
#[inline] #[inline]
pub fn with_capacity(capacity: usize) -> $Strc { $Strc(Vec::with_capacity(capacity)) } pub fn with_capacity(capacity: usize) -> $Strc {
$Strc(Vec::with_capacity(capacity))
}
} }
impl Default for $Strc { impl Default for $Strc {
#[inline] #[inline]
fn default() -> $Strc { $Strc::with_capacity(0) } fn default() -> $Strc {
$Strc::with_capacity(0)
}
} }
impl std::ops::Index<usize> for $Strc { impl std::ops::Index<usize> for $Strc {
type Output = $Inner; type Output = $Inner;
fn index(&self, idx: usize) -> &Self::Output { erg_common::traits::Stream::get(self, idx).unwrap() } fn index(&self, idx: usize) -> &Self::Output {
erg_common::traits::Stream::get(self, idx).unwrap()
}
} }
impl erg_common::traits::Stream<$Inner> for $Strc { impl erg_common::traits::Stream<$Inner> for $Strc {
#[inline] #[inline]
fn payload(self) -> Vec<$Inner> { self.0 } fn payload(self) -> Vec<$Inner> {
self.0
}
#[inline] #[inline]
fn ref_payload(&self) -> &Vec<$Inner> { &self.0 } fn ref_payload(&self) -> &Vec<$Inner> {
&self.0
}
#[inline] #[inline]
fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> { &mut self.0 } fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> {
&mut self.0
} }
} }
};
} }
#[macro_export] #[macro_export]
@ -161,18 +235,26 @@ macro_rules! impl_stream {
($Strc: ident, $Inner: ident, $field: ident) => { ($Strc: ident, $Inner: ident, $field: ident) => {
impl erg_common::traits::Stream<$Inner> for $Strc { impl erg_common::traits::Stream<$Inner> for $Strc {
#[inline] #[inline]
fn payload(self) -> Vec<$Inner> { self.$field } fn payload(self) -> Vec<$Inner> {
self.$field
}
#[inline] #[inline]
fn ref_payload(&self) -> &Vec<$Inner> { &self.$field } fn ref_payload(&self) -> &Vec<$Inner> {
&self.$field
}
#[inline] #[inline]
fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> { &mut self.$field } fn ref_mut_payload(&mut self) -> &mut Vec<$Inner> {
&mut self.$field
}
} }
impl std::ops::Index<usize> for $Strc { impl std::ops::Index<usize> for $Strc {
type Output = $Inner; type Output = $Inner;
fn index(&self, idx: usize) -> &Self::Output { erg_common::traits::Stream::get(self, idx).unwrap() } fn index(&self, idx: usize) -> &Self::Output {
erg_common::traits::Stream::get(self, idx).unwrap()
} }
} }
};
} }
pub trait ImmutableStream<T>: Sized { pub trait ImmutableStream<T>: Sized {
@ -180,33 +262,48 @@ pub trait ImmutableStream<T>: Sized {
fn capacity(&self) -> usize; fn capacity(&self) -> usize;
#[inline] #[inline]
fn len(&self) -> usize { self.ref_payload().len() } fn len(&self) -> usize {
self.ref_payload().len()
}
fn size(&self) -> usize { fn size(&self) -> usize {
std::mem::size_of::<Vec<T>>() + std::mem::size_of::<T>() * self.capacity() std::mem::size_of::<Vec<T>>() + std::mem::size_of::<T>() * self.capacity()
} }
#[inline] #[inline]
fn is_empty(&self) -> bool { self.ref_payload().is_empty() } fn is_empty(&self) -> bool {
self.ref_payload().is_empty()
}
#[inline] #[inline]
fn get(&self, idx: usize) -> Option<&T> { self.ref_payload().get(idx) } fn get(&self, idx: usize) -> Option<&T> {
self.ref_payload().get(idx)
}
#[inline] #[inline]
fn first(&self) -> Option<&T> { self.ref_payload().first() } fn first(&self) -> Option<&T> {
self.ref_payload().first()
}
#[inline] #[inline]
fn last(&self) -> Option<&T> { self.ref_payload().last() } fn last(&self) -> Option<&T> {
self.ref_payload().last()
}
#[inline] #[inline]
fn iter(&self) -> Iter<'_, T> { self.ref_payload().iter() } fn iter(&self) -> Iter<'_, T> {
self.ref_payload().iter()
}
} }
// for Runnable::run // for Runnable::run
fn expect_block(src: &str) -> bool { fn expect_block(src: &str) -> bool {
src.ends_with(&['=', ':']) || src.ends_with(":=") src.ends_with(&['=', ':'])
|| src.ends_with("->") || src.ends_with("=>") || src.ends_with(":=")
|| src.ends_with("do") || src.ends_with("do!") || src.ends_with("->")
|| src.ends_with("=>")
|| src.ends_with("do")
|| src.ends_with("do!")
} }
/// this trait implements REPL (Read-Eval-Print-Loop) automatically /// this trait implements REPL (Read-Eval-Print-Loop) automatically
@ -220,11 +317,17 @@ pub trait Runnable: Sized {
fn clear(&mut self); fn clear(&mut self);
fn eval(&mut self, src: Str) -> Result<String, Self::Errs>; fn eval(&mut self, src: Str) -> Result<String, Self::Errs>;
fn ps1(&self) -> String { ">>> ".to_string() } // TODO: &str (VMのせいで参照をとれない) fn ps1(&self) -> String {
fn ps2(&self) -> String { "... ".to_string() } ">>> ".to_string()
} // TODO: &str (VMのせいで参照をとれない)
fn ps2(&self) -> String {
"... ".to_string()
}
#[inline] #[inline]
fn quit(&self, code: i32) { process::exit(code); } fn quit(&self, code: i32) {
process::exit(code);
}
fn run(cfg: ErgConfig) { fn run(cfg: ErgConfig) {
let mut instance = Self::new(cfg); let mut instance = Self::new(cfg);
@ -264,14 +367,16 @@ pub trait Runnable: Sized {
Ok(out) => { Ok(out) => {
output.write((out + "\n").as_bytes()).unwrap(); output.write((out + "\n").as_bytes()).unwrap();
output.flush().unwrap(); output.flush().unwrap();
}, }
Err(e) => { e.fmt_all_stderr(); } Err(e) => {
e.fmt_all_stderr();
}
} }
output.write(instance.ps1().as_bytes()).unwrap(); output.write(instance.ps1().as_bytes()).unwrap();
output.flush().unwrap(); output.flush().unwrap();
instance.clear(); instance.clear();
} }
}, }
Input::Dummy => switch_unreachable!(), Input::Dummy => switch_unreachable!(),
}; };
if let Err(e) = res { if let Err(e) = res {
@ -286,8 +391,8 @@ pub trait Locational {
fn ln_begin(&self) -> Option<usize> { fn ln_begin(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair{ ln_begin, .. } Location::RangePair { ln_begin, .. }
| Location::Range{ ln_begin, .. } | Location::Range { ln_begin, .. }
| Location::LineRange(ln_begin, _) => Some(ln_begin), | Location::LineRange(ln_begin, _) => Some(ln_begin),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),
Location::Unknown => None, Location::Unknown => None,
@ -296,8 +401,8 @@ pub trait Locational {
fn ln_end(&self) -> Option<usize> { fn ln_end(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair{ ln_end, .. } Location::RangePair { ln_end, .. }
| Location::Range{ ln_end, .. } | Location::Range { ln_end, .. }
| Location::LineRange(_, ln_end) => Some(ln_end), | Location::LineRange(_, ln_end) => Some(ln_end),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),
Location::Unknown => None, Location::Unknown => None,
@ -306,14 +411,14 @@ pub trait Locational {
fn col_begin(&self) -> Option<usize> { fn col_begin(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::Range{ col_begin, .. } => Some(col_begin), Location::Range { col_begin, .. } => Some(col_begin),
_ => None, _ => None,
} }
} }
fn col_end(&self) -> Option<usize> { fn col_end(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::Range{ col_end, .. } => Some(col_end), Location::Range { col_end, .. } => Some(col_end),
_ => None, _ => None,
} }
} }
@ -337,7 +442,12 @@ macro_rules! impl_locational {
($T: ty, $begin: ident, $end: ident) => { ($T: ty, $begin: ident, $end: ident) => {
impl Locational for $T { impl Locational for $T {
fn loc(&self) -> Location { fn loc(&self) -> Location {
match (self.$begin.ln_begin(), self.$begin.col_begin(), self.$end.ln_end(), self.$end.col_end()) { match (
self.$begin.ln_begin(),
self.$begin.col_begin(),
self.$end.ln_end(),
self.$end.col_end(),
) {
(Some(lb), Some(cb), Some(le), Some(ce)) => Location::range(lb, cb, le, ce), (Some(lb), Some(cb), Some(le), Some(ce)) => Location::range(lb, cb, le, ce),
(Some(lb), _, Some(le), _) => Location::LineRange(lb, le), (Some(lb), _, Some(le), _) => Location::LineRange(lb, le),
(Some(l), _, _, _) | (_, _, Some(l), _) => Location::Line(l), (Some(l), _, _, _) | (_, _, Some(l), _) => Location::Line(l),
@ -386,13 +496,21 @@ pub trait HasType {
// 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す // 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す
fn signature_t(&self) -> Option<&Type>; fn signature_t(&self) -> Option<&Type>;
#[inline] #[inline]
fn t(&self) -> Type { self.ref_t().clone() } fn t(&self) -> Type {
self.ref_t().clone()
}
#[inline] #[inline]
fn inner_ts(&self) -> Vec<Type> { self.ref_t().inner_ts() } fn inner_ts(&self) -> Vec<Type> {
self.ref_t().inner_ts()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { &self.ref_t().non_default_params().unwrap()[0].ty } fn lhs_t(&self) -> &Type {
&self.ref_t().non_default_params().unwrap()[0].ty
}
#[inline] #[inline]
fn rhs_t(&self) -> &Type { &self.ref_t().non_default_params().unwrap()[1].ty } fn rhs_t(&self) -> &Type {
&self.ref_t().non_default_params().unwrap()[1].ty
}
} }
#[macro_export] #[macro_export]
@ -400,7 +518,9 @@ macro_rules! impl_t {
($T: ty, $t: ident) => { ($T: ty, $t: ident) => {
impl erg_common::traits::HasType for $T { impl erg_common::traits::HasType for $T {
#[inline] #[inline]
fn ref_t(&self) -> &common::ty::Type { &common::ty::Type::$t } fn ref_t(&self) -> &common::ty::Type {
&common::ty::Type::$t
}
} }
}; };
} }
@ -408,7 +528,9 @@ macro_rules! impl_t {
/// Pythonではis演算子に相当 /// Pythonではis演算子に相当
pub trait AddrEq { pub trait AddrEq {
#[inline] #[inline]
fn addr_eq(&self, other: &Self) -> bool { addr_eq!(self, other) } fn addr_eq(&self, other: &Self) -> bool {
addr_eq!(self, other)
}
} }
pub trait __Str__ { pub trait __Str__ {

View file

@ -10,7 +10,10 @@ pub struct Node<T> {
impl<T> Node<T> { impl<T> Node<T> {
pub const fn new(id: T, depends_on: Vec<NodeIdx>) -> Self { pub const fn new(id: T, depends_on: Vec<NodeIdx>) -> Self {
Node { _id: id, depends_on,} Node {
_id: id,
depends_on,
}
} }
} }
@ -19,7 +22,9 @@ pub type Graph<T> = Vec<Node<T>>;
fn reorder_by_idx<T>(mut v: Vec<T>, idx: Vec<NodeIdx>) -> Vec<T> { fn reorder_by_idx<T>(mut v: Vec<T>, idx: Vec<NodeIdx>) -> Vec<T> {
let mut swap_table = Dict::new(); let mut swap_table = Dict::new();
for (node_id, mut sort_i) in idx.into_iter().enumerate() { for (node_id, mut sort_i) in idx.into_iter().enumerate() {
if node_id == sort_i { continue; } if node_id == sort_i {
continue;
}
while let Some(moved_to) = swap_table.get(&sort_i) { while let Some(moved_to) = swap_table.get(&sort_i) {
sort_i = *moved_to; sort_i = *moved_to;
} }
@ -32,7 +37,9 @@ fn reorder_by_idx<T>(mut v: Vec<T>, idx: Vec<NodeIdx>) -> Vec<T> {
fn dfs<T>(g: &Graph<T>, v: NodeIdx, used: &mut Vec<bool>, idx: &mut Vec<NodeIdx>) { fn dfs<T>(g: &Graph<T>, v: NodeIdx, used: &mut Vec<bool>, idx: &mut Vec<NodeIdx>) {
used[v] = true; used[v] = true;
for &node_id in g[v].depends_on.iter() { for &node_id in g[v].depends_on.iter() {
if !used[node_id] { dfs(g, node_id, used, idx); } if !used[node_id] {
dfs(g, node_id, used, idx);
}
} }
idx.push(v); idx.push(v);
} }
@ -43,7 +50,9 @@ pub fn tsort<T>(g: Graph<T>) -> Graph<T> {
let mut idx = Vec::with_capacity(n); let mut idx = Vec::with_capacity(n);
let mut used = vec![false; n]; let mut used = vec![false; n];
for v in 0..n { for v in 0..n {
if !used[v] { dfs(&g, v, &mut used, &mut idx); } if !used[v] {
dfs(&g, v, &mut used, &mut idx);
}
} }
reorder_by_idx(g, idx) reorder_by_idx(g, idx)
} }
@ -58,7 +67,13 @@ fn _test() {
let on_2 = Node::new("odd n", vec![3, 0]); let on_2 = Node::new("odd n", vec![3, 0]);
let e0_3 = Node::new("even 0", vec![]); let e0_3 = Node::new("even 0", vec![]);
let ond_4 = Node::new("odd n (decl)", vec![]); let ond_4 = Node::new("odd n (decl)", vec![]);
let sorted = vec![ond_4.clone(), o0_1.clone(), en_0.clone(), e0_3.clone(), on_2.clone()]; let sorted = vec![
ond_4.clone(),
o0_1.clone(),
en_0.clone(),
e0_3.clone(),
on_2.clone(),
];
let dag = vec![en_0, o0_1, on_2, e0_3, ond_4]; let dag = vec![en_0, o0_1, on_2, e0_3, ond_4];
assert_eq!(sorted, tsort(dag)); assert_eq!(sorted, tsort(dag));
} }

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,19 @@
//! defines `ValueObj` (used in the compiler, VM). //! defines `ValueObj` (used in the compiler, VM).
//! //!
//! コンパイラ、VM等で使われる(データも保持した)値オブジェクトを定義する //! コンパイラ、VM等で使われる(データも保持した)値オブジェクトを定義する
use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::Neg; use std::ops::Neg;
use std::rc::Rc; use std::rc::Rc;
use std::cmp::Ordering;
use crate::{Str, RcArray};
use crate::set;
use crate::{fmt_iter, switch_lang, impl_display_from_debug};
use crate::codeobj::CodeObj; use crate::codeobj::CodeObj;
use crate::serialize::*; use crate::serialize::*;
use crate::set;
use crate::traits::HasType; use crate::traits::HasType;
use crate::ty::{Type, TyParam, Predicate, ConstObj, fresh_varname}; use crate::ty::{fresh_varname, ConstObj, Predicate, TyParam, Type};
use crate::{fmt_iter, impl_display_from_debug, switch_lang};
use crate::{RcArray, Str};
/// 値オブジェクト /// 値オブジェクト
/// コンパイル時評価ができ、シリアライズも可能 /// コンパイル時評価ができ、シリアライズも可能
@ -43,9 +43,12 @@ impl fmt::Debug for ValueObj {
Self::Nat(n) => write!(f, "{n}"), Self::Nat(n) => write!(f, "{n}"),
Self::Float(fl) => { Self::Float(fl) => {
// In Rust, .0 is shown omitted. // In Rust, .0 is shown omitted.
if fl.fract() < 1e-10 { write!(f, "{fl:.1}") } if fl.fract() < 1e-10 {
else { write!(f, "{fl}") } write!(f, "{fl:.1}")
}, } else {
write!(f, "{fl}")
}
}
Self::Str(s) => write!(f, "\"{s}\""), Self::Str(s) => write!(f, "\"{s}\""),
Self::True => write!(f, "True"), Self::True => write!(f, "True"),
Self::False => write!(f, "False"), Self::False => write!(f, "False"),
@ -58,7 +61,7 @@ impl fmt::Debug for ValueObj {
s.pop(); s.pop();
s.pop(); s.pop();
write!(f, "[{s}]") write!(f, "[{s}]")
}, }
Self::Code(code) => write!(f, "{code}"), Self::Code(code) => write!(f, "{code}"),
Self::None => write!(f, "None"), Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"), Self::Ellipsis => write!(f, "Ellipsis"),
@ -132,39 +135,61 @@ impl Hash for ValueObj {
} }
impl From<i32> for ValueObj { impl From<i32> for ValueObj {
fn from(item: i32) -> Self { ValueObj::Int(item) } fn from(item: i32) -> Self {
ValueObj::Int(item)
}
} }
impl From<u64> for ValueObj { impl From<u64> for ValueObj {
fn from(item: u64) -> Self { ValueObj::Nat(item) } fn from(item: u64) -> Self {
ValueObj::Nat(item)
}
} }
impl From<usize> for ValueObj { impl From<usize> for ValueObj {
fn from(item: usize) -> Self { ValueObj::Nat(item as u64) } fn from(item: usize) -> Self {
ValueObj::Nat(item as u64)
}
} }
impl From<f64> for ValueObj { impl From<f64> for ValueObj {
fn from(item: f64) -> Self { ValueObj::Float(item) } fn from(item: f64) -> Self {
ValueObj::Float(item)
}
} }
impl From<&str> for ValueObj { impl From<&str> for ValueObj {
fn from(item: &str) -> Self { ValueObj::Str(Str::rc(item)) } fn from(item: &str) -> Self {
ValueObj::Str(Str::rc(item))
}
} }
impl From<Str> for ValueObj { impl From<Str> for ValueObj {
fn from(item: Str) -> Self { ValueObj::Str(item) } fn from(item: Str) -> Self {
ValueObj::Str(item)
}
} }
impl From<bool> for ValueObj { impl From<bool> for ValueObj {
fn from(item: bool) -> Self { if item { ValueObj::True } else { ValueObj::False } } fn from(item: bool) -> Self {
if item {
ValueObj::True
} else {
ValueObj::False
}
}
} }
impl From<CodeObj> for ValueObj { impl From<CodeObj> for ValueObj {
fn from(item: CodeObj) -> Self { ValueObj::Code(Box::new(item)) } fn from(item: CodeObj) -> Self {
ValueObj::Code(Box::new(item))
}
} }
impl From<Vec<ValueObj>> for ValueObj { impl From<Vec<ValueObj>> for ValueObj {
fn from(item: Vec<ValueObj>) -> Self { ValueObj::Array(RcArray::from(&item[..])) } fn from(item: Vec<ValueObj>) -> Self {
ValueObj::Array(RcArray::from(&item[..]))
}
} }
impl TryFrom<&ValueObj> for f64 { impl TryFrom<&ValueObj> for f64 {
@ -182,15 +207,22 @@ impl TryFrom<&ValueObj> for f64 {
} }
impl HasType for ValueObj { impl HasType for ValueObj {
fn ref_t(&self) -> &Type { panic!("cannot get reference of the const") } fn ref_t(&self) -> &Type {
panic!("cannot get reference of the const")
}
/// その要素だけの集合型を返す、クラスが欲しい場合は.classで /// その要素だけの集合型を返す、クラスが欲しい場合は.classで
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
let name = Str::from(fresh_varname()); let name = Str::from(fresh_varname());
let pred = Predicate::eq(name.clone(), TyParam::ConstObj(ConstObj::Value(self.clone()))); let pred = Predicate::eq(
Type::refinement(name, self.class(), set!{pred}) name.clone(),
TyParam::ConstObj(ConstObj::Value(self.clone())),
);
Type::refinement(name, self.class(), set! {pred})
}
fn signature_t(&self) -> Option<&Type> {
None
} }
fn signature_t(&self) -> Option<&Type> { None }
} }
impl ValueObj { impl ValueObj {
@ -210,10 +242,14 @@ impl ValueObj {
let replaced = content.trim_start_matches('\"').trim_end_matches('\"'); let replaced = content.trim_start_matches('\"').trim_end_matches('\"');
Self::Str(Str::rc(replaced)) Self::Str(Str::rc(replaced))
} }
}, }
Type::Bool => { Type::Bool => {
if &content[..] == "True" { Self::True } else { Self::False } if &content[..] == "True" {
}, Self::True
} else {
Self::False
}
}
Type::NoneType => Self::None, Type::NoneType => Self::None,
Type::Ellipsis => Self::Ellipsis, Type::Ellipsis => Self::Ellipsis,
Type::NotImplemented => Self::NotImplemented, Type::NotImplemented => Self::NotImplemented,
@ -225,17 +261,23 @@ impl ValueObj {
pub fn into_bytes(self) -> Vec<u8> { pub fn into_bytes(self) -> Vec<u8> {
match self { match self {
Self::Int(i) => { Self::Int(i) => [
[vec![DataTypePrefix::Int32 as u8], i32::from(i).to_le_bytes().to_vec()].concat() vec![DataTypePrefix::Int32 as u8],
}, i32::from(i).to_le_bytes().to_vec(),
]
.concat(),
// TODO: Natとしてシリアライズ // TODO: Natとしてシリアライズ
Self::Nat(n) => { Self::Nat(n) => [
[vec![DataTypePrefix::Int32 as u8], i32::from(n as i32).to_le_bytes().to_vec()].concat() vec![DataTypePrefix::Int32 as u8],
}, i32::from(n as i32).to_le_bytes().to_vec(),
Self::Float(f) => { ]
[vec![DataTypePrefix::BinFloat as u8], f64::from(f).to_le_bytes().to_vec()].concat() .concat(),
}, Self::Float(f) => [
Self::Str(s) => { str_into_bytes(s, false) }, vec![DataTypePrefix::BinFloat as u8],
f64::from(f).to_le_bytes().to_vec(),
]
.concat(),
Self::Str(s) => str_into_bytes(s, false),
Self::True => vec![DataTypePrefix::True as u8], Self::True => vec![DataTypePrefix::True as u8],
Self::False => vec![DataTypePrefix::False as u8], Self::False => vec![DataTypePrefix::False as u8],
// TODO: SmallTuple // TODO: SmallTuple
@ -247,14 +289,21 @@ impl ValueObj {
bytes.append(&mut obj.into_bytes()); bytes.append(&mut obj.into_bytes());
} }
bytes bytes
}, }
Self::None => { vec![DataTypePrefix::None as u8] }, Self::None => {
vec![DataTypePrefix::None as u8]
}
Self::Code(c) => c.into_bytes(3425), Self::Code(c) => c.into_bytes(3425),
// Dict // Dict
other => { panic!("{}", switch_lang!( other => {
panic!(
"{}",
switch_lang!(
format!("this object cannot be serialized: {other}"), format!("this object cannot be serialized: {other}"),
format!("このオブジェクトはシリアライズできません: {other}") format!("このオブジェクトはシリアライズできません: {other}")
)) }, )
)
}
} }
} }
@ -266,9 +315,9 @@ impl ValueObj {
Self::Str(_) => Type::Str, Self::Str(_) => Type::Str,
Self::True | Self::False => Type::Bool, Self::True | Self::False => Type::Bool,
// TODO: // TODO:
Self::Array(arr) =>Type::array( Self::Array(arr) => Type::array(
arr.iter().next().unwrap().class(), arr.iter().next().unwrap().class(),
TyParam::value(arr.len()) TyParam::value(arr.len()),
), ),
Self::Dict(_dict) => todo!(), Self::Dict(_dict) => todo!(),
Self::Code(_) => Type::Code, Self::Code(_) => Type::Code,
@ -283,13 +332,11 @@ impl ValueObj {
pub fn try_cmp(&self, other: &Self) -> Option<Ordering> { pub fn try_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) { match (self, other) {
(l, r) if l.is_num() && r.is_num() => { (l, r) if l.is_num() && r.is_num() => f64::try_from(l)
f64::try_from(l).unwrap().partial_cmp(&f64::try_from(r).unwrap()) .unwrap()
} .partial_cmp(&f64::try_from(r).unwrap()),
(Self::Inf, n) (Self::Inf, n) | (n, Self::NegInf) if n.is_num() => Some(Ordering::Greater),
| (n, Self::NegInf) if n.is_num() => Some(Ordering::Greater), (n, Self::Inf) | (Self::NegInf, n) if n.is_num() => Some(Ordering::Less),
(n, Self::Inf)
| (Self::NegInf, n) if n.is_num() => Some(Ordering::Less),
(Self::NegInf, Self::Inf) => Some(Ordering::Less), (Self::NegInf, Self::Inf) => Some(Ordering::Less),
(Self::Inf, Self::NegInf) => Some(Ordering::Greater), (Self::Inf, Self::NegInf) => Some(Ordering::Greater),
// REVIEW: 等しいとみなしてよいのか? // REVIEW: 等しいとみなしてよいのか?
@ -317,8 +364,9 @@ impl ValueObj {
(Self::Float(l), Self::Int(r)) => Some(Self::Float(l + r as f64)), (Self::Float(l), Self::Int(r)) => Some(Self::Float(l + r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 + r)), (Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 + r)),
(Self::Str(l), Self::Str(r)) => Some(Self::Str(Str::from(format!("{}{}", l, r)))), (Self::Str(l), Self::Str(r)) => Some(Self::Str(Str::from(format!("{}{}", l, r)))),
(inf @ (Self::Inf | Self::NegInf), _) (inf @ (Self::Inf | Self::NegInf), _) | (_, inf @ (Self::Inf | Self::NegInf)) => {
| (_, inf @ (Self::Inf | Self::NegInf)) => Some(inf), Some(inf)
}
_ => None, _ => None,
} }
} }
@ -336,7 +384,10 @@ impl ValueObj {
(Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 - r)), (Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 - r)),
(inf @ (Self::Inf | Self::NegInf), other) (inf @ (Self::Inf | Self::NegInf), other)
| (other, inf @ (Self::Inf | Self::NegInf)) | (other, inf @ (Self::Inf | Self::NegInf))
if other != Self::Inf && other != Self::NegInf => Some(inf), if other != Self::Inf && other != Self::NegInf =>
{
Some(inf)
}
_ => None, _ => None,
} }
} }
@ -353,8 +404,9 @@ impl ValueObj {
(Self::Float(l), Self::Int(r)) => Some(Self::Float(l * r as f64)), (Self::Float(l), Self::Int(r)) => Some(Self::Float(l * r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 * r)), (Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 * r)),
(Self::Str(l), Self::Nat(r)) => Some(Self::Str(Str::from(l.repeat(r as usize)))), (Self::Str(l), Self::Nat(r)) => Some(Self::Str(Str::from(l.repeat(r as usize)))),
(inf @ (Self::Inf | Self::NegInf), _) (inf @ (Self::Inf | Self::NegInf), _) | (_, inf @ (Self::Inf | Self::NegInf)) => {
| (_, inf @ (Self::Inf | Self::NegInf)) => Some(inf), Some(inf)
}
_ => None, _ => None,
} }
} }
@ -417,10 +469,8 @@ impl ValueObj {
(Self::Float(l), Self::Int(r)) => Some(Self::from(l == r as f64)), (Self::Float(l), Self::Int(r)) => Some(Self::from(l == r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 == r)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 == r)),
(Self::Str(l), Self::Str(r)) => Some(Self::from(l == r)), (Self::Str(l), Self::Str(r)) => Some(Self::from(l == r)),
(Self::True, Self::True) | (Self::True, Self::True) | (Self::False, Self::False) => Some(Self::True),
(Self::False, Self::False) => Some(Self::True), (Self::True, Self::False) | (Self::False, Self::True) => Some(Self::False),
(Self::True, Self::False) |
(Self::False, Self::True) => Some(Self::False),
// TODO: // TODO:
_ => None, _ => None,
} }
@ -438,10 +488,8 @@ impl ValueObj {
(Self::Float(l), Self::Int(r)) => Some(Self::from(l != r as f64)), (Self::Float(l), Self::Int(r)) => Some(Self::from(l != r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 != r)), (Self::Int(l), Self::Float(r)) => Some(Self::from(l as f64 != r)),
(Self::Str(l), Self::Str(r)) => Some(Self::from(l != r)), (Self::Str(l), Self::Str(r)) => Some(Self::from(l != r)),
(Self::True, Self::True) | (Self::True, Self::True) | (Self::False, Self::False) => Some(Self::False),
(Self::False, Self::False) => Some(Self::False), (Self::True, Self::False) | (Self::False, Self::True) => Some(Self::True),
(Self::True, Self::False) |
(Self::False, Self::True) => Some(Self::True),
_ => None, _ => None,
} }
} }

View file

@ -4,32 +4,35 @@
use std::fmt; use std::fmt;
use std::process; use std::process;
use erg_common::Str;
use erg_common::cache::Cache; use erg_common::cache::Cache;
use erg_common::{fn_name_full, enum_unwrap, switch_unreachable, debug_power_assert, log, impl_stream_for_wrapper};
use erg_common::codeobj::{CodeObj, CodeObjFlags}; use erg_common::codeobj::{CodeObj, CodeObjFlags};
use erg_common::color::{GREEN, RESET}; use erg_common::color::{GREEN, RESET};
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::value::ValueObj;
use erg_common::opcode::Opcode; use erg_common::opcode::Opcode;
use Opcode::*;
use erg_common::traits::{HasType, Locational, Stream}; use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{TypeCode, TypePair}; use erg_common::ty::{TypeCode, TypePair};
use erg_common::value::ValueObj;
use erg_common::Str;
use erg_common::{
debug_power_assert, enum_unwrap, fn_name_full, impl_stream_for_wrapper, log, switch_unreachable,
};
use Opcode::*;
use erg_parser::token::{Token, TokenKind, TokenCategory}; use erg_parser::ast::{ParamPattern, Params, VarPattern};
use erg_parser::ast::{VarPattern, ParamPattern, Params}; use erg_parser::token::{Token, TokenCategory, TokenKind};
use crate::compile::{AccessKind, Name, StoreLoadKind}; use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::error::{CompileError, CompileErrors, CompileResult}; use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::hir::{Args, Expr, Signature, VarSignature, SubrSignature, DefBody, Accessor, Block, HIR}; use crate::hir::{
Accessor, Args, Block, DefBody, Expr, Signature, SubrSignature, VarSignature, HIR,
};
use AccessKind::*; use AccessKind::*;
fn obj_name(obj: &Expr) -> Option<String> { fn obj_name(obj: &Expr) -> Option<String> {
match obj { match obj {
Expr::Accessor(Accessor::Local(n)) => Some(n.inspect().to_string()), Expr::Accessor(Accessor::Local(n)) => Some(n.inspect().to_string()),
Expr::Accessor(Accessor::Attr(a)) => Expr::Accessor(Accessor::Attr(a)) => Some(obj_name(&a.obj)? + "." + a.name.inspect()),
Some(obj_name(&a.obj)? + "." + a.name.inspect()),
Expr::Accessor(Accessor::SelfDot(n)) => Some(format!(".{}", n.inspect())), Expr::Accessor(Accessor::SelfDot(n)) => Some(format!(".{}", n.inspect())),
_ => None, _ => None,
} }
@ -38,8 +41,8 @@ fn obj_name(obj: &Expr) -> Option<String> {
fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str { fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str {
match (class, uniq_obj_name, &name[..]) { match (class, uniq_obj_name, &name[..]) {
("Array!", _, "push!") => Str::ever("append"), ("Array!", _, "push!") => Str::ever("append"),
("Complex" | "Real"| "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
("Complex" | "Real"| "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
("Module", Some("random"), "randint!") => Str::ever("randint"), ("Module", Some("random"), "randint!") => Str::ever("randint"),
_ => name, _ => name,
} }
@ -92,7 +95,9 @@ pub struct CodeGenUnit {
impl PartialEq for CodeGenUnit { impl PartialEq for CodeGenUnit {
#[inline] #[inline]
fn eq(&self, other: &Self) -> bool { self.id == other.id } fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
} }
impl fmt::Display for CodeGenUnit { impl fmt::Display for CodeGenUnit {
@ -157,7 +162,9 @@ impl CodeGenerator {
} }
#[inline] #[inline]
fn input(&self) -> &Input { &self.cfg.input } fn input(&self) -> &Input {
&self.cfg.input
}
fn get_cached(&self, s: &str) -> Str { fn get_cached(&self, s: &str) -> Str {
self.str_cache.get(s) self.str_cache.get(s)
@ -264,21 +271,30 @@ impl CodeGenerator {
.cur_block_codeobj() .cur_block_codeobj()
.names .names
.iter() .iter()
.position(|n| &**n == name) { .position(|n| &**n == name)
if current_is_toplevel || !acc_kind.is_local() { Some(Name::local(idx)) } {
else { Some(Name::global(idx)) } if current_is_toplevel || !acc_kind.is_local() {
Some(Name::local(idx))
} else {
Some(Name::global(idx))
}
} else if let Some(idx) = self } else if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
.varnames .varnames
.iter() .iter()
.position(|v| &**v == name) { .position(|v| &**v == name)
if current_is_toplevel { Some(Name::local(idx)) } {
else { Some(Name::fast(idx)) } if current_is_toplevel {
Some(Name::local(idx))
} else {
Some(Name::fast(idx))
}
} else if let Some(idx) = self } else if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
.freevars .freevars
.iter() .iter()
.position(|f| &**f == name) { .position(|f| &**f == name)
{
Some(Name::deref(idx)) Some(Name::deref(idx))
} else { } else {
None None
@ -291,20 +307,20 @@ impl CodeGenerator {
for (nth_from_toplevel, block) in self.units.iter_mut().enumerate().rev().skip(1) { for (nth_from_toplevel, block) in self.units.iter_mut().enumerate().rev().skip(1) {
let block_is_toplevel = nth_from_toplevel == 0; let block_is_toplevel = nth_from_toplevel == 0;
if let Some(_) = block.codeobj.cellvars.iter().position(|c| &**c == name) { if let Some(_) = block.codeobj.cellvars.iter().position(|c| &**c == name) {
return Some(StoreLoadKind::Deref) return Some(StoreLoadKind::Deref);
} else if let Some(idx) = block.codeobj.varnames.iter().position(|v| &**v == name) { } else if let Some(idx) = block.codeobj.varnames.iter().position(|v| &**v == name) {
if block_is_toplevel { if block_is_toplevel {
return Some(StoreLoadKind::Global) return Some(StoreLoadKind::Global);
} else { } else {
// the outer scope variable // the outer scope variable
let cellvar_name = block.codeobj.varnames.get(idx).unwrap().clone(); let cellvar_name = block.codeobj.varnames.get(idx).unwrap().clone();
block.codeobj.cellvars.push(cellvar_name); block.codeobj.cellvars.push(cellvar_name);
return Some(StoreLoadKind::Deref) return Some(StoreLoadKind::Deref);
} }
} }
if block_is_toplevel { if block_is_toplevel {
if let Some(_) = block.codeobj.names.iter().position(|n| &**n == name) { if let Some(_) = block.codeobj.names.iter().position(|n| &**n == name) {
return Some(StoreLoadKind::Global) return Some(StoreLoadKind::Global);
} }
} }
} }
@ -317,7 +333,11 @@ impl CodeGenerator {
let name = escape_name(name); let name = escape_name(name);
match self.rec_search(&name) { match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => { Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
let st = if current_is_toplevel { StoreLoadKind::Local } else { st }; let st = if current_is_toplevel {
StoreLoadKind::Local
} else {
st
};
self.mut_cur_block_codeobj().names.push(name); self.mut_cur_block_codeobj().names.push(name);
Name::new(st, self.cur_block_codeobj().names.len() - 1) Name::new(st, self.cur_block_codeobj().names.len() - 1)
} }
@ -356,9 +376,9 @@ impl CodeGenerator {
} }
fn emit_load_name_instr(&mut self, name: Str) -> CompileResult<()> { fn emit_load_name_instr(&mut self, name: Str) -> CompileResult<()> {
let name = self.local_search(&name, Name).unwrap_or_else(|| { let name = self
self.register_name(name) .local_search(&name, Name)
}); .unwrap_or_else(|| self.register_name(name));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -371,10 +391,15 @@ impl CodeGenerator {
Ok(()) Ok(())
} }
fn emit_load_attr_instr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> CompileResult<()> { fn emit_load_attr_instr(
let name = self.local_search(&name, Attr).unwrap_or_else(|| { &mut self,
self.register_attr(class, uniq_obj_name, name) class: &str,
}); uniq_obj_name: Option<&str>,
name: Str,
) -> CompileResult<()> {
let name = self
.local_search(&name, Attr)
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -386,10 +411,15 @@ impl CodeGenerator {
Ok(()) Ok(())
} }
fn emit_load_method_instr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> CompileResult<()> { fn emit_load_method_instr(
let name = self.local_search(&name, Method).unwrap_or_else(|| { &mut self,
self.register_method(class, uniq_obj_name, name) class: &str,
}); uniq_obj_name: Option<&str>,
name: Str,
) -> CompileResult<()> {
let name = self
.local_search(&name, Method)
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -402,9 +432,9 @@ impl CodeGenerator {
} }
fn emit_store_instr(&mut self, name: Str, acc_kind: AccessKind) { fn emit_store_instr(&mut self, name: Str, acc_kind: AccessKind) {
let name = self.local_search(&name, acc_kind).unwrap_or_else(|| { let name = self
self.register_name(name) .local_search(&name, acc_kind)
}); .unwrap_or_else(|| self.register_name(name));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast => Opcode::STORE_FAST, StoreLoadKind::Fast => Opcode::STORE_FAST,
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT, StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
@ -453,8 +483,15 @@ impl CodeGenerator {
fn gen_param_names(&self, params: &Params) -> Vec<Str> { fn gen_param_names(&self, params: &Params) -> Vec<Str> {
params params
.non_defaults.iter().map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")) .non_defaults
.chain(params.defaults.iter().map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))) .iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
.chain(
params
.defaults
.iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")),
)
.map(|s| self.get_cached(&s)) .map(|s| self.get_cached(&s))
.collect() .collect()
} }
@ -504,7 +541,7 @@ impl CodeGenerator {
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) { fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
if body.is_type() { if body.is_type() {
return self.emit_mono_type_def(sig, body) return self.emit_mono_type_def(sig, body);
} }
if body.block.len() == 1 { if body.block.len() == 1 {
self.codegen_expr(body.block.remove(0)); self.codegen_expr(body.block.remove(0));
@ -586,7 +623,7 @@ impl CodeGenerator {
} else { } else {
// no else block // no else block
let idx_end = self.cur_block().lasti; let idx_end = self.cur_block().lasti;
self.edit_code(idx_pop_jump_if_false + 1,idx_end / 2); self.edit_code(idx_pop_jump_if_false + 1, idx_end / 2);
self.stack_dec(); self.stack_dec();
} }
Ok(()) Ok(())
@ -879,7 +916,8 @@ impl CodeGenerator {
self.emit_load_const(lit.data); self.emit_load_const(lit.data);
} }
Expr::Accessor(Accessor::Local(l)) => { Expr::Accessor(Accessor::Local(l)) => {
self.emit_load_name_instr(l.inspect().clone()).unwrap_or_else(|err| { self.emit_load_name_instr(l.inspect().clone())
.unwrap_or_else(|err| {
self.errs.push(err); self.errs.push(err);
}); });
} }
@ -887,17 +925,19 @@ impl CodeGenerator {
let class = Str::rc(a.obj.ref_t().name()); let class = Str::rc(a.obj.ref_t().name());
let uniq_obj_name = a.obj.__name__().map(Str::rc); let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj); self.codegen_expr(*a.obj);
self.emit_load_attr_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), a.name.content.clone()) self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.errs.push(err); self.errs.push(err);
}); });
} }
Expr::Def(def) => { Expr::Def(def) => match def.sig {
match def.sig { Signature::Subr(sig) => self.emit_subr_def(sig, def.body),
Signature::Subr(sig) => { self.emit_subr_def(sig, def.body) } Signature::Var(sig) => self.emit_var_def(sig, def.body),
Signature::Var(sig) => { self.emit_var_def(sig, def.body) } },
}
}
// TODO: // TODO:
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params); let params = self.gen_param_names(&lambda.params);
@ -936,7 +976,9 @@ impl CodeGenerator {
// Range operators are not operators in Python // Range operators are not operators in Python
match &bin.op.kind { match &bin.op.kind {
// l..<r == range(l, r) // l..<r == range(l, r)
TokenKind::RightOpen => { self.emit_load_name_instr(Str::ever("range")).unwrap(); }, TokenKind::RightOpen => {
self.emit_load_name_instr(Str::ever("range")).unwrap();
}
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(), TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
_ => {} _ => {}
} }
@ -958,14 +1000,16 @@ impl CodeGenerator {
| TokenKind::NotEq | TokenKind::NotEq
| TokenKind::Gre | TokenKind::Gre
| TokenKind::GreEq => COMPARE_OP, | TokenKind::GreEq => COMPARE_OP,
TokenKind::LeftOpen | TokenKind::RightOpen TokenKind::LeftOpen
| TokenKind::Closed | TokenKind::Open => CALL_FUNCTION, // ERG_BINARY_RANGE, | TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open => CALL_FUNCTION, // ERG_BINARY_RANGE,
_ => { _ => {
self.errs.push(CompileError::feature_error( self.errs.push(CompileError::feature_error(
self.cfg.input.clone(), self.cfg.input.clone(),
bin.op.loc(), bin.op.loc(),
"", "",
bin.op.content.clone() bin.op.content.clone(),
)); ));
NOT_IMPLEMENTED NOT_IMPLEMENTED
} }
@ -977,16 +1021,22 @@ impl CodeGenerator {
TokenKind::NotEq => 3, TokenKind::NotEq => 3,
TokenKind::Gre => 4, TokenKind::Gre => 4,
TokenKind::GreEq => 5, TokenKind::GreEq => 5,
TokenKind::LeftOpen | TokenKind::RightOpen TokenKind::LeftOpen
| TokenKind::Closed | TokenKind::Open => 2, | TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open => 2,
_ => type_pair as u8, _ => type_pair as u8,
}; };
self.write_instr(instr); self.write_instr(instr);
self.write_arg(arg); self.write_arg(arg);
self.stack_dec(); self.stack_dec();
match &bin.op.kind { match &bin.op.kind {
TokenKind::LeftOpen | TokenKind::RightOpen TokenKind::LeftOpen
| TokenKind::Open | TokenKind::Closed => { self.stack_dec(); }, | TokenKind::RightOpen
| TokenKind::Open
| TokenKind::Closed => {
self.stack_dec();
}
_ => {} _ => {}
} }
} }
@ -1005,7 +1055,7 @@ impl CodeGenerator {
self.emit_call_callable_obj(obj, call.args); self.emit_call_callable_obj(obj, call.args);
} }
} }
}, }
// TODO: list comprehension // TODO: list comprehension
Expr::Array(mut arr) => { Expr::Array(mut arr) => {
let len = arr.elems.len(); let len = arr.elems.len();
@ -1021,7 +1071,12 @@ impl CodeGenerator {
} }
} }
other => { other => {
self.errs.push(CompileError::feature_error(self.cfg.input.clone(), other.loc(), "", "".into())); self.errs.push(CompileError::feature_error(
self.cfg.input.clone(),
other.loc(),
"",
"".into(),
));
self.crash("cannot compile this expression at this time"); self.crash("cannot compile this expression at this time");
} }
} }
@ -1076,7 +1131,7 @@ impl CodeGenerator {
Location::Unknown, Location::Unknown,
stack_len, stack_len,
block_id, block_id,
fn_name_full!() fn_name_full!(),
)); ));
self.crash("error in codegen_typedef_block: invalid stack size"); self.crash("error in codegen_typedef_block: invalid stack size");
} }
@ -1089,7 +1144,9 @@ impl CodeGenerator {
if !self.units.is_empty() { if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno; let ld = unit.prev_lineno - self.cur_block().prev_lineno;
if ld != 0 { if ld != 0 {
self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| { *l += ld as u8; }); self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| {
*l += ld as u8;
});
self.mut_cur_block().prev_lineno += ld; self.mut_cur_block().prev_lineno += ld;
} }
} }
@ -1098,7 +1155,11 @@ impl CodeGenerator {
fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj { fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
self.unit_size += 1; self.unit_size += 1;
let name = if let Some(name) = opt_name { name } else { "<block>".into() }; let name = if let Some(name) = opt_name {
name
} else {
"<block>".into()
};
let firstlineno = block.first().unwrap().ln_begin().unwrap(); let firstlineno = block.first().unwrap().ln_begin().unwrap();
self.units.push(CodeGenUnit::new( self.units.push(CodeGenUnit::new(
self.unit_size, self.unit_size,
@ -1127,7 +1188,7 @@ impl CodeGenerator {
Location::Unknown, Location::Unknown,
stack_len, stack_len,
block_id, block_id,
fn_name_full!() fn_name_full!(),
)); ));
self.crash("error in codegen_block: invalid stack size"); self.crash("error in codegen_block: invalid stack size");
} }
@ -1142,7 +1203,9 @@ impl CodeGenerator {
if !self.units.is_empty() { if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno; let ld = unit.prev_lineno - self.cur_block().prev_lineno;
if ld != 0 { if ld != 0 {
self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| { *l += ld as u8; }); self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| {
*l += ld as u8;
});
self.mut_cur_block().prev_lineno += ld; self.mut_cur_block().prev_lineno += ld;
} }
} }
@ -1157,7 +1220,7 @@ impl CodeGenerator {
vec![], vec![],
Str::rc(self.cfg.input.enclosed_name()), Str::rc(self.cfg.input.enclosed_name()),
"<module>", "<module>",
1 1,
)); ));
for expr in hir.module.into_iter() { for expr in hir.module.into_iter() {
self.codegen_expr(expr); self.codegen_expr(expr);
@ -1177,7 +1240,7 @@ impl CodeGenerator {
Location::Unknown, Location::Unknown,
stack_len, stack_len,
block_id, block_id,
fn_name_full!() fn_name_full!(),
)); ));
self.crash("error in codegen_module: invalid stack size"); self.crash("error in codegen_module: invalid stack size");
} }
@ -1192,7 +1255,9 @@ impl CodeGenerator {
if !self.units.is_empty() { if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno; let ld = unit.prev_lineno - self.cur_block().prev_lineno;
if ld != 0 { if ld != 0 {
self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| { *l += ld as u8; }); self.mut_cur_block_codeobj().lnotab.last_mut().map(|l| {
*l += ld as u8;
});
self.mut_cur_block().prev_lineno += ld; self.mut_cur_block().prev_lineno += ld;
} }
} }

View file

@ -3,19 +3,19 @@
//! コンパイラーを定義する //! コンパイラーを定義する
use std::path::Path; use std::path::Path;
use erg_common::Str;
use erg_common::{log};
use erg_common::codeobj::{CodeObj, CodeObjFlags}; use erg_common::codeobj::{CodeObj, CodeObjFlags};
use erg_common::color::{GREEN, RESET}; use erg_common::color::{GREEN, RESET};
use erg_common::config::{Input, ErgConfig, SEMVER, BUILD_INFO}; use erg_common::config::{ErgConfig, Input, BUILD_INFO, SEMVER};
use erg_common::error::MultiErrorDisplay; use erg_common::error::MultiErrorDisplay;
use erg_common::log;
use erg_common::traits::{Runnable, Stream}; use erg_common::traits::{Runnable, Stream};
use erg_common::Str;
use erg_parser::ParserRunner; use erg_parser::ParserRunner;
use crate::codegen::CodeGenerator; use crate::codegen::CodeGenerator;
use crate::effectcheck::SideEffectChecker; use crate::effectcheck::SideEffectChecker;
use crate::error::{TyCheckErrors, CompileError, CompileErrors}; use crate::error::{CompileError, CompileErrors, TyCheckErrors};
use crate::lower::ASTLowerer; use crate::lower::ASTLowerer;
use crate::ownercheck::OwnershipChecker; use crate::ownercheck::OwnershipChecker;
@ -43,12 +43,34 @@ pub struct Name {
} }
impl Name { impl Name {
pub const fn new(kind: StoreLoadKind, idx: usize) -> Self { Self{ kind, idx } } pub const fn new(kind: StoreLoadKind, idx: usize) -> Self {
Self { kind, idx }
}
pub const fn local(idx: usize) -> Self { Self{ kind: StoreLoadKind::Local, idx } } pub const fn local(idx: usize) -> Self {
pub const fn global(idx: usize) -> Self { Self{ kind: StoreLoadKind::Global, idx } } Self {
pub const fn deref(idx: usize) -> Self { Self{ kind: StoreLoadKind::Deref, idx } } kind: StoreLoadKind::Local,
pub const fn fast(idx: usize) -> Self { Self{ kind: StoreLoadKind::Fast, idx } } idx,
}
}
pub const fn global(idx: usize) -> Self {
Self {
kind: StoreLoadKind::Global,
idx,
}
}
pub const fn deref(idx: usize) -> Self {
Self {
kind: StoreLoadKind::Deref,
idx,
}
}
pub const fn fast(idx: usize) -> Self {
Self {
kind: StoreLoadKind::Fast,
idx,
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -59,9 +81,15 @@ pub enum AccessKind {
} }
impl AccessKind { impl AccessKind {
pub const fn is_local(&self) -> bool { matches!(self, Self::Name) } pub const fn is_local(&self) -> bool {
pub const fn is_attr(&self) -> bool { matches!(self, Self::Attr) } matches!(self, Self::Name)
pub const fn is_method(&self) -> bool { matches!(self, Self::Method) } }
pub const fn is_attr(&self) -> bool {
matches!(self, Self::Attr)
}
pub const fn is_method(&self) -> bool {
matches!(self, Self::Method)
}
} }
/// Generates a `CodeObj` from an `AST`. /// Generates a `CodeObj` from an `AST`.
@ -86,10 +114,14 @@ impl Runnable for Compiler {
} }
#[inline] #[inline]
fn input(&self) -> &Input { &self.cfg.input } fn input(&self) -> &Input {
&self.cfg.input
}
#[inline] #[inline]
fn start_message(&self) -> String { format!("Erg compiler {} {}\n", SEMVER, &*BUILD_INFO) } fn start_message(&self) -> String {
format!("Erg compiler {} {}\n", SEMVER, &*BUILD_INFO)
}
#[inline] #[inline]
fn finish(&mut self) {} fn finish(&mut self) {}
@ -106,12 +138,20 @@ impl Runnable for Compiler {
impl Compiler { impl Compiler {
fn convert(&self, errs: TyCheckErrors) -> CompileErrors { fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
errs.into_iter().map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by)).collect::<Vec<_>>().into() errs.into_iter()
.map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by))
.collect::<Vec<_>>()
.into()
} }
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(&mut self, src: Str, path: P) -> Result<(), CompileErrors> { pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(
&mut self,
src: Str,
path: P,
) -> Result<(), CompileErrors> {
let code = self.compile(src, "exec")?; let code = self.compile(src, "exec")?;
code.dump_as_pyc(path, self.cfg.python_ver).expect("failed to dump a .pyc file"); code.dump_as_pyc(path, self.cfg.python_ver)
.expect("failed to dump a .pyc file");
Ok(()) Ok(())
} }
@ -121,24 +161,41 @@ impl Compiler {
let mut parser = ParserRunner::new(self.cfg.copy()); let mut parser = ParserRunner::new(self.cfg.copy());
let ast = parser.parse_from_str(src)?; let ast = parser.parse_from_str(src)?;
if ast.is_empty() { if ast.is_empty() {
return Ok(CodeObj::empty(vec![], Str::rc(self.input().enclosed_name()), "<module>", 1)) return Ok(CodeObj::empty(
vec![],
Str::rc(self.input().enclosed_name()),
"<module>",
1,
));
}
let (hir, warns) = self
.lowerer
.lower(ast, mode)
.map_err(|errs| self.convert(errs))?;
if warns.is_empty() {
dynamic = false;
} }
let (hir, warns) = self.lowerer.lower(ast, mode).map_err(|errs| self.convert(errs))?;
if warns.is_empty() { dynamic = false; }
if self.cfg.verbose >= 2 { if self.cfg.verbose >= 2 {
let warns = self.convert(warns); let warns = self.convert(warns);
warns.fmt_all_stderr(); warns.fmt_all_stderr();
} }
let effect_checker = SideEffectChecker::new(); let effect_checker = SideEffectChecker::new();
let hir = effect_checker.check(hir).map_err(|errs| self.convert(errs))?; let hir = effect_checker
.check(hir)
.map_err(|errs| self.convert(errs))?;
let ownership_checker = OwnershipChecker::new(); let ownership_checker = OwnershipChecker::new();
let hir = ownership_checker.check(hir).map_err(|errs| self.convert(errs))?; let hir = ownership_checker
.check(hir)
.map_err(|errs| self.convert(errs))?;
let mut codeobj = self.code_generator.codegen(hir); let mut codeobj = self.code_generator.codegen(hir);
if dynamic { if dynamic {
codeobj.flags += CodeObjFlags::EvmDynamic as u32; codeobj.flags += CodeObjFlags::EvmDynamic as u32;
} }
log!("{GREEN}code object:\n{}", codeobj.code_info()); log!("{GREEN}code object:\n{}", codeobj.code_info());
log!("[DEBUG] the compiling process has completed, found errors: {}{RESET}", self.code_generator.errs.len()); log!(
"[DEBUG] the compiling process has completed, found errors: {}{RESET}",
self.code_generator.errs.len()
);
if self.code_generator.errs.is_empty() { if self.code_generator.errs.is_empty() {
Ok(codeobj) Ok(codeobj)
} else { } else {

File diff suppressed because it is too large Load diff

View file

@ -2,13 +2,13 @@
//! SideEffectCheckerを実装 //! SideEffectCheckerを実装
//! 関数や不変型に副作用がないかチェックする //! 関数や不変型に副作用がないかチェックする
use erg_common::Str;
use erg_common::color::{GREEN, RESET}; use erg_common::color::{GREEN, RESET};
use erg_common::log; use erg_common::log;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_common::Str;
use crate::error::{EffectError, EffectErrors, EffectResult}; use crate::error::{EffectError, EffectErrors, EffectResult};
use crate::hir::{HIR, Expr, Def, Accessor, Signature}; use crate::hir::{Accessor, Def, Expr, Signature, HIR};
use crate::varinfo::Visibility; use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
@ -19,11 +19,22 @@ pub struct SideEffectChecker {
} }
impl SideEffectChecker { impl SideEffectChecker {
pub fn new() -> Self { Self { path_stack: vec![], errs: EffectErrors::empty() } } pub fn new() -> Self {
Self {
path_stack: vec![],
errs: EffectErrors::empty(),
}
}
fn full_path(&self) -> String { fn full_path(&self) -> String {
self.path_stack.iter().fold(String::new(), |acc, (path, vis)| { self.path_stack
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] } .iter()
.fold(String::new(), |acc, (path, vis)| {
if vis.is_public() {
acc + "." + &path[..]
} else {
acc + "::" + &path[..]
}
}) })
} }
@ -33,7 +44,9 @@ impl SideEffectChecker {
// トップレベルでは副作用があっても問題なく、純粋性違反がないかのみチェックする // トップレベルでは副作用があっても問題なく、純粋性違反がないかのみチェックする
for expr in hir.module.iter() { for expr in hir.module.iter() {
match expr { match expr {
Expr::Def(def) => { self.check_def(def, true); }, Expr::Def(def) => {
self.check_def(def, true);
}
Expr::Call(call) => { Expr::Call(call) => {
for parg in call.args.pos_args().iter() { for parg in call.args.pos_args().iter() {
self.check_expr(&parg.expr, true); self.check_expr(&parg.expr, true);
@ -41,7 +54,7 @@ impl SideEffectChecker {
for kwarg in call.args.kw_args().iter() { for kwarg in call.args.kw_args().iter() {
self.check_expr(&kwarg.expr, true); self.check_expr(&kwarg.expr, true);
} }
}, }
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
@ -57,8 +70,13 @@ impl SideEffectChecker {
let name_and_vis = match &def.sig { let name_and_vis = match &def.sig {
Signature::Var(var) => Signature::Var(var) =>
// TODO: visibility // TODO: visibility
if let Some(name) = var.inspect() { (name.clone(), Private) } {
else { (Str::ever("::<instant>"), Private) }, if let Some(name) = var.inspect() {
(name.clone(), Private)
} else {
(Str::ever("::<instant>"), Private)
}
}
Signature::Subr(subr) => (subr.name.inspect().clone(), Private), Signature::Subr(subr) => (subr.name.inspect().clone(), Private),
}; };
self.path_stack.push(name_and_vis); self.path_stack.push(name_and_vis);
@ -71,23 +89,28 @@ impl SideEffectChecker {
(true, _) => { (true, _) => {
if !allow_inner_effect { if !allow_inner_effect {
let expr = Expr::Def(def.clone()); let expr = Expr::Def(def.clone());
self.errs.push( self.errs
EffectError::has_effect(&expr, self.full_path()) .push(EffectError::has_effect(&expr, self.full_path()));
);
} }
for chunk in def.body.block.iter() { for chunk in def.body.block.iter() {
self.check_expr(chunk, allow_inner_effect); self.check_expr(chunk, allow_inner_effect);
} }
}, }
(false, false) => { (false, false) => {
for chunk in def.body.block.iter() { for chunk in def.body.block.iter() {
self.check_expr(chunk, allow_inner_effect); self.check_expr(chunk, allow_inner_effect);
} }
},
(false, true) => { self.check_func(def); },
} }
if is_const { self.check_const(def); } (false, true) => {
if !is_procedural && is_type { self.check_immut_type(def); } self.check_func(def);
}
}
if is_const {
self.check_const(def);
}
if !is_procedural && is_type {
self.check_immut_type(def);
}
self.path_stack.pop(); self.path_stack.pop();
} }
@ -128,30 +151,31 @@ impl SideEffectChecker {
/// ``` /// ```
fn check_expr(&mut self, expr: &Expr, allow_self_effect: bool) { fn check_expr(&mut self, expr: &Expr, allow_self_effect: bool) {
match expr { match expr {
Expr::Def(def) => { self.check_def(def, allow_self_effect); }, Expr::Def(def) => {
self.check_def(def, allow_self_effect);
}
// 引数がproceduralでも関数呼び出しなら副作用なし // 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => { Expr::Call(call) => {
if self.is_procedural(&call.obj) && !allow_self_effect { if self.is_procedural(&call.obj) && !allow_self_effect {
self.errs.push( self.errs
EffectError::has_effect(expr, self.full_path()) .push(EffectError::has_effect(expr, self.full_path()));
);
} }
call.args call.args
.pos_args() .pos_args()
.iter() .iter()
.for_each(|parg|self.check_expr(&parg.expr, allow_self_effect)); .for_each(|parg| self.check_expr(&parg.expr, allow_self_effect));
call.args call.args
.kw_args() .kw_args()
.iter() .iter()
.for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect)); .for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect));
}, }
Expr::UnaryOp(unary) => { Expr::UnaryOp(unary) => {
self.check_expr(&unary.expr, allow_self_effect); self.check_expr(&unary.expr, allow_self_effect);
}, }
Expr::BinOp(bin) => { Expr::BinOp(bin) => {
self.check_expr(&bin.lhs, allow_self_effect); self.check_expr(&bin.lhs, allow_self_effect);
self.check_expr(&bin.rhs, allow_self_effect); self.check_expr(&bin.rhs, allow_self_effect);
}, }
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let is_proc = lambda.is_procedural(); let is_proc = lambda.is_procedural();
if is_proc { if is_proc {
@ -160,14 +184,16 @@ impl SideEffectChecker {
self.path_stack.push((Str::ever("<lambda>"), Private)); self.path_stack.push((Str::ever("<lambda>"), Private));
} }
if !allow_self_effect && is_proc { if !allow_self_effect && is_proc {
self.errs.push(EffectError::has_effect(expr, self.full_path())); self.errs
.push(EffectError::has_effect(expr, self.full_path()));
} }
lambda.body lambda
.body
.iter() .iter()
.for_each(|chunk| self.check_expr(chunk, allow_self_effect && is_proc)); .for_each(|chunk| self.check_expr(chunk, allow_self_effect && is_proc));
self.path_stack.pop(); self.path_stack.pop();
}, }
_ => {}, _ => {}
} }
} }

View file

@ -1,12 +1,12 @@
use std::fmt::Display; use std::fmt::Display;
use std::ops::Add; use std::ops::Add;
use erg_common::color::{GREEN, RED, YELLOW, RESET}; use erg_common::color::{GREEN, RED, RESET, YELLOW};
use erg_common::config::Input; use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorKind::*, ErrorDisplay, MultiErrorDisplay, Location}; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
use erg_common::traits::{Stream, Locational}; use erg_common::traits::{Locational, Stream};
use erg_common::ty::{Type, Predicate}; use erg_common::ty::{Predicate, Type};
use erg_common::{Str, fmt_iter}; use erg_common::{fmt_iter, Str};
use erg_common::{impl_stream_for_wrapper, switch_lang}; use erg_common::{impl_stream_for_wrapper, switch_lang};
use erg_parser::error::{ParserRunnerError, ParserRunnerErrors}; use erg_parser::error::{ParserRunnerError, ParserRunnerErrors};
@ -99,28 +99,58 @@ pub struct CompileError {
impl From<ParserRunnerError> for CompileError { impl From<ParserRunnerError> for CompileError {
fn from(err: ParserRunnerError) -> Self { fn from(err: ParserRunnerError) -> Self {
Self { core: err.core, input: err.input, caused_by: "".into() } Self {
core: err.core,
input: err.input,
caused_by: "".into(),
}
} }
} }
impl ErrorDisplay for CompileError { impl ErrorDisplay for CompileError {
fn core(&self) -> &ErrorCore { &self.core } fn core(&self) -> &ErrorCore {
fn input(&self) -> &Input { &self.input } &self.core
fn caused_by(&self) -> &str { &self.caused_by } }
fn ref_inner(&self) -> Option<&Box<Self>> { None } fn input(&self) -> &Input {
&self.input
}
fn caused_by(&self) -> &str {
&self.caused_by
}
fn ref_inner(&self) -> Option<&Box<Self>> {
None
}
} }
impl CompileError { impl CompileError {
pub const fn new(core: ErrorCore, input: Input, caused_by: Str) -> Self { Self{ core, input, caused_by } } pub const fn new(core: ErrorCore, input: Input, caused_by: Str) -> Self {
Self {
core,
input,
caused_by,
}
}
pub fn compiler_bug(errno: usize, input: Input, loc: Location, fn_name: &str, line: u32) -> Self { pub fn compiler_bug(
errno: usize,
input: Input,
loc: Location,
fn_name: &str,
line: u32,
) -> Self {
Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!( Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!(
format!("this is a bug of the Erg compiler, please report it to https://github.com/...\ncaused from: {fn_name}:{line}"), format!("this is a bug of the Erg compiler, please report it to https://github.com/...\ncaused from: {fn_name}:{line}"),
format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/...)\n{fn_name}:{line}より発生") format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/...)\n{fn_name}:{line}より発生")
), None), input, "".into()) ), None), input, "".into())
} }
pub fn stack_bug(input: Input, loc: Location, stack_len: u32, block_id: usize, fn_name: &str) -> Self { pub fn stack_bug(
input: Input,
loc: Location,
stack_len: u32,
block_id: usize,
fn_name: &str,
) -> Self {
Self::new(ErrorCore::new(0, CompilerSystemError, loc, switch_lang!( Self::new(ErrorCore::new(0, CompilerSystemError, loc, switch_lang!(
format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\ format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\
this is a bug of the Erg compiler, please report it (https://github.com/...)\n\ this is a bug of the Erg compiler, please report it (https://github.com/...)\n\
@ -132,10 +162,20 @@ 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: Str) -> Self {
Self::new(ErrorCore::new(0, FeatureError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
FeatureError,
loc,
switch_lang!(
format!("this feature({name}) is not implemented yet"), format!("this feature({name}) is not implemented yet"),
format!("この機能({name})はまだ正式に提供されていません") format!("この機能({name})はまだ正式に提供されていません")
), None), input, caused_by) ),
None,
),
input,
caused_by,
)
} }
} }
@ -146,9 +186,13 @@ pub struct TyCheckError {
} }
impl TyCheckError { impl TyCheckError {
pub const fn new(core: ErrorCore, caused_by: Str) -> Self { Self{ core, caused_by } } pub const fn new(core: ErrorCore, caused_by: Str) -> Self {
Self { core, caused_by }
}
pub fn unreachable(fn_name: &str, line: u32) -> Self { Self::new(ErrorCore::unreachable(fn_name, line), "".into()) } pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
}
pub fn checker_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { pub fn checker_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!( Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!(
@ -158,28 +202,58 @@ impl TyCheckError {
} }
pub fn feature_error(loc: Location, name: &str, caused_by: Str) -> Self { pub fn feature_error(loc: Location, name: &str, caused_by: Str) -> Self {
Self::new(ErrorCore::new(0, FeatureError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
FeatureError,
loc,
switch_lang!(
format!("this feature({name}) is not implemented yet"), format!("this feature({name}) is not implemented yet"),
format!("この機能({name})はまだ正式に提供されていません") format!("この機能({name})はまだ正式に提供されていません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn syntax_error<S: Into<Str>>(errno: usize, loc: Location, caused_by: Str, desc: S, hint: Option<Str>) -> Self { pub fn syntax_error<S: Into<Str>>(
Self::new(ErrorCore::new(errno, SyntaxError, loc, desc, hint), caused_by) errno: usize,
loc: Location,
caused_by: Str,
desc: S,
hint: Option<Str>,
) -> Self {
Self::new(
ErrorCore::new(errno, SyntaxError, loc, desc, hint),
caused_by,
)
} }
pub fn duplicate_decl_error(loc: Location, caused_by: Str, name: &str) -> Self { pub fn duplicate_decl_error(loc: Location, caused_by: Str, name: &str) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, NameError, loc, Self::new(
ErrorCore::new(
0,
NameError,
loc,
switch_lang!( switch_lang!(
format!("{name} is already declared"), format!("{name} is already declared"),
format!("{name}は既に宣言されています") format!("{name}は既に宣言されています")
), Option::<Str>::None), ),
caused_by Option::<Str>::None,
),
caused_by,
) )
} }
pub fn violate_decl_error(loc: Location, caused_by: Str, name: &str, spec_t: &Type, found_t: &Type) -> Self { pub fn violate_decl_error(
loc: Location,
caused_by: Str,
name: &str,
spec_t: &Type,
found_t: &Type,
) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, TypeError, loc, Self::new(ErrorCore::new(0, TypeError, loc,
switch_lang!( switch_lang!(
@ -192,28 +266,49 @@ impl TyCheckError {
pub fn no_type_spec_error(loc: Location, caused_by: Str, name: &str) -> Self { pub fn no_type_spec_error(loc: Location, caused_by: Str, name: &str) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, TypeError, loc, Self::new(
ErrorCore::new(
0,
TypeError,
loc,
switch_lang!( switch_lang!(
format!("the type of {name} is not specified"), format!("the type of {name} is not specified"),
format!("{name}の型が指定されていません") format!("{name}の型が指定されていません")
), None), ),
caused_by None,
),
caused_by,
) )
} }
pub fn no_var_error(loc: Location, caused_by: Str, name: &str, similar_name: Option<&Str>) -> Self { pub fn no_var_error(
loc: Location,
caused_by: Str,
name: &str,
similar_name: Option<&Str>,
) -> Self {
let name = readable_name(name); let name = readable_name(name);
let hint = similar_name.map(|n| { let hint = similar_name.map(|n| {
let n = readable_name(n); let n = readable_name(n);
switch_lang!( switch_lang!(
format!("exists a similar name variable: {n}"), format!("exists a similar name variable: {n}"),
format!("似た名前の変数があります: {n}") format!("似た名前の変数があります: {n}")
).into() )
.into()
}); });
Self::new(ErrorCore::new(0, NameError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
NameError,
loc,
switch_lang!(
format!("{RED}{name}{RESET} is not defined"), format!("{RED}{name}{RESET} is not defined"),
format!("{RED}{name}{RESET}という変数は定義されていません") format!("{RED}{name}{RESET}という変数は定義されていません")
), hint), caused_by) ),
hint,
),
caused_by,
)
} }
pub fn no_attr_error( pub fn no_attr_error(
@ -228,22 +323,47 @@ impl TyCheckError {
switch_lang!( switch_lang!(
format!("has a similar name attribute: {n}"), format!("has a similar name attribute: {n}"),
format!("似た名前の属性があります: {n}") format!("似た名前の属性があります: {n}")
).into() )
.into()
}); });
Self::new(ErrorCore::new( 0, AttributeError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
AttributeError,
loc,
switch_lang!(
format!("{obj_t} object has no attribute {RED}{name}{RESET}"), format!("{obj_t} object has no attribute {RED}{name}{RESET}"),
format!("{obj_t}型オブジェクトに{RED}{name}{RESET}という属性はありません") format!("{obj_t}型オブジェクトに{RED}{name}{RESET}という属性はありません")
), hint), ),
hint,
),
caused_by, caused_by,
) )
} }
pub fn callable_impl_error<'a, C: Locational + Display>(callee: &C, param_ts: impl Iterator<Item=&'a Type>, caused_by: Str) -> Self { pub fn callable_impl_error<'a, C: Locational + Display>(
callee: &C,
param_ts: impl Iterator<Item = &'a Type>,
caused_by: Str,
) -> Self {
let param_ts = fmt_iter(param_ts); let param_ts = fmt_iter(param_ts);
Self::new(ErrorCore::new(0, NotImplementedError, callee.loc(), switch_lang!( Self::new(
format!("{callee} is not a Callable object that takes {param_ts} as an argument"), ErrorCore::new(
format!("{callee}{param_ts}を引数に取る呼び出し可能オブジェクトではありません") 0,
), None), caused_by) NotImplementedError,
callee.loc(),
switch_lang!(
format!(
"{callee} is not a Callable object that takes {param_ts} as an argument"
),
format!(
"{callee}は{param_ts}を引数に取る呼び出し可能オブジェクトではありません"
)
),
None,
),
caused_by,
)
} }
pub fn type_mismatch_error( pub fn type_mismatch_error(
@ -276,10 +396,19 @@ impl TyCheckError {
pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self { pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, NameError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
NameError,
loc,
switch_lang!(
format!("{name}: {t} is not initialized"), format!("{name}: {t} is not initialized"),
format!("{name}: {t}は初期化されていません") format!("{name}: {t}は初期化されていません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn argument_error(loc: Location, caused_by: Str, expect: usize, found: usize) -> Self { pub fn argument_error(loc: Location, caused_by: Str, expect: usize, found: usize) -> Self {
@ -290,25 +419,52 @@ impl TyCheckError {
} }
pub fn match_error(loc: Location, caused_by: Str, expr_t: &Type) -> Self { pub fn match_error(loc: Location, caused_by: Str, expr_t: &Type) -> Self {
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
TypeError,
loc,
switch_lang!(
format!("not all patterns of type {expr_t} are covered"), format!("not all patterns of type {expr_t} are covered"),
format!("{expr_t}型の全パターンを網羅していません") format!("{expr_t}型の全パターンを網羅していません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn infer_error(loc: Location, caused_by: Str, expr: &str) -> Self { pub fn infer_error(loc: Location, caused_by: Str, expr: &str) -> Self {
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
TypeError,
loc,
switch_lang!(
format!("failed to infer the type of {expr}"), format!("failed to infer the type of {expr}"),
format!("{expr}の型が推論できません") format!("{expr}の型が推論できません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self { pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, AssignError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
AssignError,
loc,
switch_lang!(
format!("cannot assign twice to the immutable variable {name}"), format!("cannot assign twice to the immutable variable {name}"),
format!("定数{name}には再代入できません") format!("定数{name}には再代入できません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn too_many_args_error( pub fn too_many_args_error(
@ -317,19 +473,32 @@ impl TyCheckError {
caused_by: Str, caused_by: Str,
params_len: usize, params_len: usize,
pos_args_len: usize, pos_args_len: usize,
kw_args_len: usize kw_args_len: usize,
) -> Self { ) -> Self {
let name = readable_name(callee_name); let name = readable_name(callee_name);
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(
format!("too many arguments for {name}: ErrorCore::new(
0,
TypeError,
loc,
switch_lang!(
format!(
"too many arguments for {name}:
total expected params: {GREEN}{params_len}{RESET} total expected params: {GREEN}{params_len}{RESET}
passed positional args: {RED}{pos_args_len}{RESET} passed positional args: {RED}{pos_args_len}{RESET}
passed keyword args: {RED}{kw_args_len}{RESET}"), passed keyword args: {RED}{kw_args_len}{RESET}"
format!("{name}に渡された引数の数が多すぎます。 ),
format!(
"{name}に渡された引数の数が多すぎます。
: {GREEN}{params_len}{RESET} : {GREEN}{params_len}{RESET}
: {RED}{pos_args_len}{RESET} : {RED}{pos_args_len}{RESET}
: {RED}{kw_args_len}{RESET}") : {RED}{kw_args_len}{RESET}"
), None), caused_by) )
),
None,
),
caused_by,
)
} }
pub fn multiple_args_error( pub fn multiple_args_error(
@ -339,10 +508,19 @@ passed keyword args: {RED}{kw_args_len}{RESET}"),
arg_name: &str, arg_name: &str,
) -> Self { ) -> Self {
let name = readable_name(callee_name); let name = readable_name(callee_name);
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
TypeError,
loc,
switch_lang!(
format!("{name}'s argument {RED}{arg_name}{RESET} is passed multiple times"), format!("{name}'s argument {RED}{arg_name}{RESET} is passed multiple times"),
format!("{name}の引数{RED}{arg_name}{RESET}が複数回渡されています") format!("{name}の引数{RED}{arg_name}{RESET}が複数回渡されています")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn unexpected_kw_arg_error( pub fn unexpected_kw_arg_error(
@ -352,21 +530,45 @@ passed keyword args: {RED}{kw_args_len}{RESET}"),
param_name: &str, param_name: &str,
) -> Self { ) -> Self {
let name = readable_name(callee_name); let name = readable_name(callee_name);
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
TypeError,
loc,
switch_lang!(
format!("{name} got unexpected keyword argument {RED}{param_name}{RESET}"), format!("{name} got unexpected keyword argument {RED}{param_name}{RESET}"),
format!("{name}には予期しないキーワード引数{RED}{param_name}{RESET}が渡されています") format!("{name}には予期しないキーワード引数{RED}{param_name}{RESET}が渡されています")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn unused_warning(loc: Location, name: &str, caused_by: Str) -> Self { pub fn unused_warning(loc: Location, name: &str, caused_by: Str) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new(ErrorCore::new(0, UnusedWarning, loc, switch_lang!( Self::new(
ErrorCore::new(
0,
UnusedWarning,
loc,
switch_lang!(
format!("{YELLOW}{name}{RESET} is not used"), format!("{YELLOW}{name}{RESET} is not used"),
format!("{YELLOW}{name}{RESET}は使用されていません") format!("{YELLOW}{name}{RESET}は使用されていません")
), None), caused_by) ),
None,
),
caused_by,
)
} }
pub fn unification_error(lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>, caused_by: Str) -> Self { pub fn unification_error(
lhs_t: &Type,
rhs_t: &Type,
lhs_loc: Option<Location>,
rhs_loc: Option<Location>,
caused_by: Str,
) -> 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),
(Some(l), None) => l, (Some(l), None) => l,
@ -379,7 +581,13 @@ passed keyword args: {RED}{kw_args_len}{RESET}"),
), None), caused_by) ), None), caused_by)
} }
pub fn re_unification_error(lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>, caused_by: Str) -> Self { pub fn re_unification_error(
lhs_t: &Type,
rhs_t: &Type,
lhs_loc: Option<Location>,
rhs_loc: Option<Location>,
caused_by: Str,
) -> 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),
(Some(l), None) => l, (Some(l), None) => l,
@ -392,7 +600,13 @@ passed keyword args: {RED}{kw_args_len}{RESET}"),
), None), caused_by) ), None), caused_by)
} }
pub fn subtyping_error(sub_t: &Type, sup_t: &Type, sub_loc: Option<Location>, sup_loc: Option<Location>, caused_by: Str) -> Self { pub fn subtyping_error(
sub_t: &Type,
sup_t: &Type,
sub_loc: Option<Location>,
sup_loc: Option<Location>,
caused_by: Str,
) -> 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),
(Some(l), None) => l, (Some(l), None) => l,
@ -413,17 +627,46 @@ passed keyword args: {RED}{kw_args_len}{RESET}"),
} }
pub fn has_effect<S: Into<Str>>(expr: &Expr, caused_by: S) -> Self { pub fn has_effect<S: Into<Str>>(expr: &Expr, caused_by: S) -> Self {
Self::new(ErrorCore::new(0, HasEffect, expr.loc(), switch_lang!( Self::new(
ErrorCore::new(
0,
HasEffect,
expr.loc(),
switch_lang!(
format!("this expression causes a side-effect"), format!("this expression causes a side-effect"),
format!("この式には副作用があります") format!("この式には副作用があります")
), None), caused_by.into()) ),
None,
),
caused_by.into(),
)
} }
pub fn move_error<S: Into<Str>>(name: &str, name_loc: Location, moved_loc: Location, caused_by: S) -> Self { pub fn move_error<S: Into<Str>>(
Self::new(ErrorCore::new(0, MoveError, name_loc, switch_lang!( name: &str,
format!("{RED}{name}{RESET} was moved in line {}", moved_loc.ln_begin().unwrap()), name_loc: Location,
format!("{RED}{name}{RESET}{}行目ですでに移動されています", moved_loc.ln_begin().unwrap()) moved_loc: Location,
), None), caused_by.into()) caused_by: S,
) -> Self {
Self::new(
ErrorCore::new(
0,
MoveError,
name_loc,
switch_lang!(
format!(
"{RED}{name}{RESET} was moved in line {}",
moved_loc.ln_begin().unwrap()
),
format!(
"{RED}{name}{RESET}は{}行目ですでに移動されています",
moved_loc.ln_begin().unwrap()
)
),
None,
),
caused_by.into(),
)
} }
} }
@ -433,7 +676,9 @@ pub struct TyCheckErrors(Vec<TyCheckError>);
impl_stream_for_wrapper!(TyCheckErrors, TyCheckError); impl_stream_for_wrapper!(TyCheckErrors, TyCheckError);
impl From<Vec<TyCheckError>> for TyCheckErrors { impl From<Vec<TyCheckError>> for TyCheckErrors {
fn from(errs: Vec<TyCheckError>) -> Self { Self(errs) } fn from(errs: Vec<TyCheckError>) -> Self {
Self(errs)
}
} }
impl Add for TyCheckErrors { impl Add for TyCheckErrors {
@ -444,7 +689,9 @@ impl Add for TyCheckErrors {
} }
impl From<TyCheckError> for TyCheckErrors { impl From<TyCheckError> for TyCheckErrors {
fn from(err: TyCheckError) -> Self { Self(vec![err]) } fn from(err: TyCheckError) -> Self {
Self(vec![err])
}
} }
pub type TyCheckResult<T> = Result<T, TyCheckError>; pub type TyCheckResult<T> = Result<T, TyCheckError>;
@ -481,11 +728,15 @@ impl From<ParserRunnerErrors> for CompileErrors {
} }
impl From<Vec<CompileError>> for CompileErrors { impl From<Vec<CompileError>> for CompileErrors {
fn from(errs: Vec<CompileError>) -> Self { Self(errs) } fn from(errs: Vec<CompileError>) -> Self {
Self(errs)
}
} }
impl From<CompileError> for CompileErrors { impl From<CompileError> for CompileErrors {
fn from(err: CompileError) -> Self { Self(vec![err]) } fn from(err: CompileError) -> Self {
Self(vec![err])
}
} }
impl MultiErrorDisplay<CompileError> for CompileErrors {} impl MultiErrorDisplay<CompileError> for CompileErrors {}

View file

@ -1,13 +1,13 @@
use std::mem; use std::mem;
use erg_common::Str;
use erg_common::{fn_name, set};
use erg_common::value::ValueObj;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::rccell::RcCell; use erg_common::rccell::RcCell;
use erg_common::set::{Set}; use erg_common::set::Set;
use erg_common::traits::Stream; use erg_common::traits::Stream;
use erg_common::ty::{OpKind, TyParam, Type, Predicate, TyBound, ConstObj, SubrKind}; use erg_common::ty::{ConstObj, OpKind, Predicate, SubrKind, TyBound, TyParam, Type};
use erg_common::value::ValueObj;
use erg_common::Str;
use erg_common::{fn_name, set};
use OpKind::*; use OpKind::*;
use erg_parser::ast::*; use erg_parser::ast::*;
@ -25,11 +25,15 @@ struct SubstContext {
impl SubstContext { impl SubstContext {
pub fn new(substituted: &Type, ty_ctx: &Context) -> Self { pub fn new(substituted: &Type, ty_ctx: &Context) -> Self {
let param_names = ty_ctx.impls.iter() let param_names = ty_ctx
.impls
.iter()
.filter(|(_, vi)| vi.kind.is_parameter()) .filter(|(_, vi)| vi.kind.is_parameter())
.map(|(name, _)| name.inspect().clone()); .map(|(name, _)| name.inspect().clone());
let self_ = SubstContext{ let self_ = SubstContext {
params: param_names.zip(substituted.typarams().into_iter()).collect(), params: param_names
.zip(substituted.typarams().into_iter())
.collect(),
}; };
// REVIEW: 順番は保証されるか? 引数がunnamed_paramsに入る可能性は? // REVIEW: 順番は保証されるか? 引数がunnamed_paramsに入る可能性は?
self_ self_
@ -53,26 +57,30 @@ impl SubstContext {
ty_ctx.unify_tp(param, v, None, false)?; ty_ctx.unify_tp(param, v, None, false)?;
} }
} else { } else {
if fv.is_unbound() { panic!() } if fv.is_unbound() {
panic!()
} }
} }
TyParam::BinOp{ lhs, rhs, .. } => { }
TyParam::BinOp { lhs, rhs, .. } => {
self.substitute_tp(lhs, ty_ctx)?; self.substitute_tp(lhs, ty_ctx)?;
self.substitute_tp(rhs, ty_ctx)?; self.substitute_tp(rhs, ty_ctx)?;
} }
TyParam::UnaryOp{ val, .. } => { TyParam::UnaryOp { val, .. } => {
self.substitute_tp(val, ty_ctx)?; self.substitute_tp(val, ty_ctx)?;
} }
TyParam::Array(args) TyParam::Array(args)
| TyParam::Tuple(args) | TyParam::Tuple(args)
| TyParam::App{ args, .. } | TyParam::App { args, .. }
| TyParam::PolyQVar{ args, .. } => { | TyParam::PolyQVar { args, .. } => {
for arg in args.iter() { for arg in args.iter() {
self.substitute_tp(arg, ty_ctx)?; self.substitute_tp(arg, ty_ctx)?;
} }
} }
TyParam::Type(t) => { self.substitute_t(t, ty_ctx)?; }, TyParam::Type(t) => {
TyParam::MonoProj{ obj, attr } => todo!("{obj}.{attr}"), self.substitute_t(t, ty_ctx)?;
}
TyParam::MonoProj { obj, attr } => todo!("{obj}.{attr}"),
_ => {} _ => {}
} }
Ok(()) Ok(())
@ -98,15 +106,18 @@ impl SubstContext {
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Evaluator { pub struct Evaluator {}
}
impl Evaluator { impl Evaluator {
#[inline] #[inline]
pub fn new() -> Self { Self::default() } pub fn new() -> Self {
Self::default()
}
#[inline] #[inline]
pub(crate) fn eval_const_lit(&self, lit: &Literal) -> ValueObj { ValueObj::from(lit) } pub(crate) fn eval_const_lit(&self, lit: &Literal) -> ValueObj {
ValueObj::from(lit)
}
fn eval_const_acc(&self, _acc: &Accessor) -> Option<ValueObj> { fn eval_const_acc(&self, _acc: &Accessor) -> Option<ValueObj> {
todo!() todo!()
@ -142,7 +153,9 @@ impl Evaluator {
Accessor::SelfDot(_name) => todo!(), Accessor::SelfDot(_name) => todo!(),
Accessor::Subscr(_subscr) => todo!(), Accessor::Subscr(_subscr) => todo!(),
} }
} else { None } } else {
None
}
} }
fn eval_const_def(&self, def: &Def) -> Option<ValueObj> { fn eval_const_def(&self, def: &Def) -> Option<ValueObj> {
@ -175,25 +188,50 @@ impl Evaluator {
fn eval_bin_lit(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> { fn eval_bin_lit(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
match op { match op {
Add => lhs.try_add(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), Add => lhs
Sub => lhs.try_sub(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), .try_add(rhs)
Mul => lhs.try_mul(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), .ok_or(EvalError::unreachable(fn_name!(), line!())),
Div => lhs.try_div(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), Sub => lhs
Gt => lhs.try_gt(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), .try_sub(rhs)
Ge => lhs.try_ge(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), .ok_or(EvalError::unreachable(fn_name!(), line!())),
Eq => lhs.try_eq(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), Mul => lhs
Ne => lhs.try_ne(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())), .try_mul(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
Div => lhs
.try_div(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
Gt => lhs
.try_gt(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
Ge => lhs
.try_ge(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
Eq => lhs
.try_eq(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
Ne => lhs
.try_ne(rhs)
.ok_or(EvalError::unreachable(fn_name!(), line!())),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn eval_bin_tp(&self, op: OpKind, lhs: &TyParam, rhs: &TyParam) -> EvalResult<TyParam> { pub(crate) fn eval_bin_tp(
&self,
op: OpKind,
lhs: &TyParam,
rhs: &TyParam,
) -> EvalResult<TyParam> {
match (lhs, rhs) { match (lhs, rhs) {
(TyParam::ConstObj(ConstObj::Value(lhs)), TyParam::ConstObj(ConstObj::Value(rhs))) => (TyParam::ConstObj(ConstObj::Value(lhs)), TyParam::ConstObj(ConstObj::Value(rhs))) => {
self.eval_bin_lit(op, lhs.clone(), rhs.clone()) self.eval_bin_lit(op, lhs.clone(), rhs.clone())
.map(|v| TyParam::value(v)), .map(|v| TyParam::value(v))
(TyParam::ConstObj(ConstObj::MutValue(lhs)), TyParam::ConstObj(ConstObj::Value(rhs))) => }
self.eval_bin_lit(op, lhs.borrow().clone(), rhs.clone()) (
TyParam::ConstObj(ConstObj::MutValue(lhs)),
TyParam::ConstObj(ConstObj::Value(rhs)),
) => self
.eval_bin_lit(op, lhs.borrow().clone(), rhs.clone())
.map(|v| TyParam::ConstObj(ConstObj::MutValue(RcCell::new(v)))), .map(|v| TyParam::ConstObj(ConstObj::MutValue(RcCell::new(v)))),
(TyParam::FreeVar(fv), r) => { (TyParam::FreeVar(fv), r) => {
if fv.is_linked() { if fv.is_linked() {
@ -201,16 +239,15 @@ impl Evaluator {
} else { } else {
Err(EvalError::unreachable(fn_name!(), line!())) Err(EvalError::unreachable(fn_name!(), line!()))
} }
}, }
(l, TyParam::FreeVar(fv)) => { (l, TyParam::FreeVar(fv)) => {
if fv.is_linked() { if fv.is_linked() {
self.eval_bin_tp(op, l, &*fv.crack()) self.eval_bin_tp(op, l, &*fv.crack())
} else { } else {
Err(EvalError::unreachable(fn_name!(), line!())) Err(EvalError::unreachable(fn_name!(), line!()))
} }
}, }
(e @ TyParam::Erased(_), _) (e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e.clone()),
| (_, e @ TyParam::Erased(_)) => Ok(e.clone()),
(l, r) => todo!("{l} {op} {r}"), (l, r) => todo!("{l} {op} {r}"),
} }
} }
@ -220,20 +257,21 @@ impl Evaluator {
Pos => todo!(), Pos => todo!(),
Neg => todo!(), Neg => todo!(),
Invert => todo!(), Invert => todo!(),
Mutate => if let ConstObj::Value(v) = val { Mutate => {
if let ConstObj::Value(v) = val {
Ok(ConstObj::MutValue(RcCell::new(v))) Ok(ConstObj::MutValue(RcCell::new(v)))
} else { todo!() }, } else {
todo!()
}
}
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> { fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> {
match val { match val {
TyParam::ConstObj(c) => TyParam::ConstObj(c) => self.eval_unary_lit(op, c.clone()).map(|c| TyParam::cons(c)),
self.eval_unary_lit(op, c.clone()).map(|c| TyParam::cons(c)), TyParam::FreeVar(fv) if fv.is_linked() => self.eval_unary_tp(op, &*fv.crack()),
TyParam::FreeVar(fv) if fv.is_linked() => {
self.eval_unary_tp(op, &*fv.crack())
},
e @ TyParam::Erased(_) => Ok(e.clone()), e @ TyParam::Erased(_) => Ok(e.clone()),
other => todo!("{op} {other}"), other => todo!("{op} {other}"),
} }
@ -246,37 +284,41 @@ impl Evaluator {
/// 量化変数などはそのまま返す /// 量化変数などはそのまま返す
pub(crate) fn eval_tp(&self, p: &TyParam, ctx: &Context) -> EvalResult<TyParam> { pub(crate) fn eval_tp(&self, p: &TyParam, ctx: &Context) -> EvalResult<TyParam> {
match p { match p {
TyParam::FreeVar(fv) if fv.is_linked() => TyParam::FreeVar(fv) if fv.is_linked() => self.eval_tp(&fv.crack(), ctx),
self.eval_tp(&fv.crack(), ctx), TyParam::Mono(name) => ctx
TyParam::Mono(name) => .consts
ctx.consts.get(name) .get(name)
.and_then(|c| match c { .and_then(|c| match c {
ConstObj::Value(v) => Some(TyParam::value(v.clone())), ConstObj::Value(v) => Some(TyParam::value(v.clone())),
_ => None, _ => None,
}).ok_or(EvalError::unreachable(fn_name!(), line!())), })
TyParam::BinOp{ op, lhs, rhs } => .ok_or(EvalError::unreachable(fn_name!(), line!())),
self.eval_bin_tp(*op, lhs, rhs), TyParam::BinOp { op, lhs, rhs } => self.eval_bin_tp(*op, lhs, rhs),
TyParam::UnaryOp{ op, val } => TyParam::UnaryOp { op, val } => self.eval_unary_tp(*op, val),
self.eval_unary_tp(*op, val), TyParam::App { name, args } => self.eval_app(name, args),
TyParam::App{ name, args } => p @ (TyParam::Type(_)
self.eval_app(name, args), | TyParam::Erased(_)
p @ ( | TyParam::ConstObj(_)
TyParam::Type(_) | TyParam::Erased(_) | TyParam::ConstObj(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_) | TyParam::FreeVar(_)
) => Ok(p.clone()), | TyParam::MonoQVar(_)) => Ok(p.clone()),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn eval_t(&self, substituted: Type, ctx: &Context, level: usize) -> EvalResult<Type> { pub(crate) fn eval_t(
&self,
substituted: Type,
ctx: &Context,
level: usize,
) -> EvalResult<Type> {
match substituted { match substituted {
Type::FreeVar(fv) if fv.is_linked() => Type::FreeVar(fv) if fv.is_linked() => self.eval_t(fv.crack().clone(), ctx, level),
self.eval_t(fv.crack().clone(), ctx, level),
Type::Subr(mut subr) => { Type::Subr(mut subr) => {
let kind = match subr.kind { let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => { SubrKind::FuncMethod(self_t) => {
SubrKind::fn_met(self.eval_t(*self_t, ctx, level)?) SubrKind::fn_met(self.eval_t(*self_t, ctx, level)?)
} }
SubrKind::ProcMethod{ before, after } => { SubrKind::ProcMethod { before, after } => {
let before = self.eval_t(*before, ctx, level)?; let before = self.eval_t(*before, ctx, level)?;
if let Some(after) = after { if let Some(after) = after {
let after = self.eval_t(*after, ctx, level)?; let after = self.eval_t(*after, ctx, level)?;
@ -294,34 +336,41 @@ impl Evaluator {
p.ty = self.eval_t(mem::take(&mut p.ty), ctx, level)?; p.ty = self.eval_t(mem::take(&mut p.ty), ctx, level)?;
} }
let return_t = self.eval_t(*subr.return_t, ctx, level)?; let return_t = self.eval_t(*subr.return_t, ctx, level)?;
Ok(Type::subr(kind, subr.non_default_params, subr.default_params, return_t)) Ok(Type::subr(
}, kind,
Type::Array{ t, len } => { subr.non_default_params,
subr.default_params,
return_t,
))
}
Type::Array { t, len } => {
let t = self.eval_t(*t, ctx, level)?; let t = self.eval_t(*t, ctx, level)?;
let len = self.eval_tp(&len, ctx)?; let len = self.eval_tp(&len, ctx)?;
Ok(Type::array(t, len)) Ok(Type::array(t, len))
}, }
Type::Refinement(refine) => { Type::Refinement(refine) => {
let mut preds = Set::with_capacity(refine.preds.len()); let mut preds = Set::with_capacity(refine.preds.len());
for pred in refine.preds.into_iter() { for pred in refine.preds.into_iter() {
preds.insert(self.eval_pred(pred, ctx)?); preds.insert(self.eval_pred(pred, ctx)?);
} }
Ok(Type::refinement(refine.var, *refine.t, preds)) Ok(Type::refinement(refine.var, *refine.t, preds))
}, }
// [?T; 0].MutType! == [?T; !0] // [?T; 0].MutType! == [?T; !0]
Type::MonoProj{ lhs, rhs } => { Type::MonoProj { lhs, rhs } => {
for ty_ctx in ctx.get_sorted_supertypes(&lhs) { for ty_ctx in ctx.get_sorted_supertypes(&lhs) {
if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) { if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) {
if let ConstObj::Type(quant_t) = obj { if let ConstObj::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, ty_ctx, level)?; let t = subst_ctx.substitute(*quant_t, ty_ctx, level)?;
let t = self.eval_t(t, ctx, level)?; let t = self.eval_t(t, ctx, level)?;
return Ok(t) return Ok(t);
} else { todo!() } } else {
todo!()
}
} }
} }
todo!() todo!()
}, }
Type::Range(l) => Ok(Type::range(self.eval_t(*l, ctx, level)?)), Type::Range(l) => Ok(Type::range(self.eval_t(*l, ctx, level)?)),
Type::Iter(l) => Ok(Type::iter(self.eval_t(*l, ctx, level)?)), Type::Iter(l) => Ok(Type::iter(self.eval_t(*l, ctx, level)?)),
Type::Ref(l) => Ok(Type::refer(self.eval_t(*l, ctx, level)?)), Type::Ref(l) => Ok(Type::refer(self.eval_t(*l, ctx, level)?)),
@ -329,87 +378,109 @@ impl Evaluator {
Type::Option(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)), Type::Option(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)),
Type::OptionMut(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)), Type::OptionMut(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)),
Type::VarArgs(l) => Ok(Type::var_args(self.eval_t(*l, ctx, level)?)), Type::VarArgs(l) => Ok(Type::var_args(self.eval_t(*l, ctx, level)?)),
Type::Poly{ name, mut params } => { Type::Poly { name, mut params } => {
for p in params.iter_mut() { for p in params.iter_mut() {
*p = self.eval_tp(&mem::take(p), ctx)?; *p = self.eval_tp(&mem::take(p), ctx)?;
} }
Ok(Type::poly(name, params)) Ok(Type::poly(name, params))
}, }
other if other.is_monomorphic() => Ok(other), other if other.is_monomorphic() => Ok(other),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn _eval_bound(&self, bound: TyBound, ctx: &Context, level: usize) -> EvalResult<TyBound> { pub(crate) fn _eval_bound(
&self,
bound: TyBound,
ctx: &Context,
level: usize,
) -> EvalResult<TyBound> {
match bound { match bound {
TyBound::Subtype{ sub, sup } => TyBound::Subtype { sub, sup } => Ok(TyBound::subtype(
Ok(TyBound::subtype(
self.eval_t(sub, ctx, level)?, self.eval_t(sub, ctx, level)?,
self.eval_t(sup, ctx, level)?
)),
TyBound::Supertype{ sup, sub } =>
Ok(TyBound::supertype(
self.eval_t(sup, ctx, level)?, self.eval_t(sup, ctx, level)?,
self.eval_t(sub, ctx, level)? )),
TyBound::Supertype { sup, sub } => Ok(TyBound::supertype(
self.eval_t(sup, ctx, level)?,
self.eval_t(sub, ctx, level)?,
)), )),
TyBound::Sandwiched { sub, mid, sup } => { TyBound::Sandwiched { sub, mid, sup } => {
let sub = self.eval_t(sub, ctx, level)?; let sub = self.eval_t(sub, ctx, level)?;
let mid = self.eval_t(mid, ctx, level)?; let mid = self.eval_t(mid, ctx, level)?;
let sup = self.eval_t(sup, ctx, level)?; let sup = self.eval_t(sup, ctx, level)?;
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(inst, self.eval_t(t, ctx, level)?)), Ok(TyBound::instance(inst, self.eval_t(t, ctx, level)?))
}
} }
} }
pub(crate) fn eval_pred(&self, p: Predicate, ctx: &Context) -> EvalResult<Predicate> { pub(crate) fn eval_pred(&self, p: Predicate, ctx: &Context) -> EvalResult<Predicate> {
match p { match p {
Predicate::Value(_) | Predicate::Const(_) => Ok(p), Predicate::Value(_) | Predicate::Const(_) => Ok(p),
Predicate::Equal{ lhs, rhs } => Predicate::Equal { lhs, rhs } => Ok(Predicate::eq(lhs, self.eval_tp(&rhs, ctx)?)),
Ok(Predicate::eq(lhs, self.eval_tp(&rhs, ctx)?)), Predicate::NotEqual { lhs, rhs } => Ok(Predicate::ne(lhs, self.eval_tp(&rhs, ctx)?)),
Predicate::NotEqual{ lhs, rhs } => Predicate::LessEqual { lhs, rhs } => Ok(Predicate::le(lhs, self.eval_tp(&rhs, ctx)?)),
Ok(Predicate::ne(lhs, self.eval_tp(&rhs, ctx)?)), Predicate::GreaterEqual { lhs, rhs } => {
Predicate::LessEqual{ lhs, rhs } => Ok(Predicate::ge(lhs, self.eval_tp(&rhs, ctx)?))
Ok(Predicate::le(lhs, self.eval_tp(&rhs, ctx)?)), }
Predicate::GreaterEqual{ lhs, rhs } => Predicate::And(l, r) => Ok(Predicate::and(
Ok(Predicate::ge(lhs, self.eval_tp(&rhs, ctx)?)), self.eval_pred(*l, ctx)?,
Predicate::And(l, r) => self.eval_pred(*r, ctx)?,
Ok(Predicate::and(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)), )),
Predicate::Or(l, r) => Predicate::Or(l, r) => Ok(Predicate::or(
Ok(Predicate::or(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)), self.eval_pred(*l, ctx)?,
Predicate::Not(l, r) => self.eval_pred(*r, ctx)?,
Ok(Predicate::not(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)), )),
Predicate::Not(l, r) => Ok(Predicate::not(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
} }
} }
pub(crate) fn get_tp_t(&self, p: &TyParam, bounds: Option<&Set<TyBound>>, ctx: &Context) -> EvalResult<Type> { pub(crate) fn get_tp_t(
&self,
p: &TyParam,
bounds: Option<&Set<TyBound>>,
ctx: &Context,
) -> EvalResult<Type> {
let p = self.eval_tp(p, ctx)?; let p = self.eval_tp(p, ctx)?;
match p { match p {
TyParam::ConstObj(ConstObj::Value(v)) => Ok(Type::enum_t(set![v])), TyParam::ConstObj(ConstObj::Value(v)) => Ok(Type::enum_t(set![v])),
TyParam::ConstObj(ConstObj::MutValue(v)) => Ok(v.borrow().class().mutate()), TyParam::ConstObj(ConstObj::MutValue(v)) => Ok(v.borrow().class().mutate()),
TyParam::Erased(t) => Ok((&*t).clone()), TyParam::Erased(t) => Ok((&*t).clone()),
TyParam::FreeVar(fv) => TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() { Ok(t) } else { todo!() }, if let Some(t) = fv.type_of() {
Ok(t)
} else {
todo!()
}
}
TyParam::Type(_) => Ok(Type::Type), TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => TyParam::Mono(name) => ctx
ctx.consts.get(&name) .consts
.get(&name)
.and_then(|c| match c { .and_then(|c| match c {
ConstObj::Value(v) => Some(Type::enum_t(set![v.clone()])), ConstObj::Value(v) => Some(Type::enum_t(set![v.clone()])),
_ => None, _ => None,
}).ok_or(EvalError::unreachable(fn_name!(), line!())), })
.ok_or(EvalError::unreachable(fn_name!(), line!())),
TyParam::MonoQVar(name) => { TyParam::MonoQVar(name) => {
if let Some(bs) = bounds { if let Some(bs) = bounds {
if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(&name)) { if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(&name)) {
Ok(bound.t().clone()) Ok(bound.t().clone())
} else { todo!() } } else {
} else { todo!() } todo!()
}, }
TyParam::UnaryOp{ op, val } => { } else {
match op { todo!()
}
}
TyParam::UnaryOp { op, val } => match op {
OpKind::Mutate => Ok(self.get_tp_t(&val, bounds, ctx)?.mutate()), OpKind::Mutate => Ok(self.get_tp_t(&val, bounds, ctx)?.mutate()),
_ => todo!(), _ => todo!(),
}
}, },
other => todo!("{other}"), other => todo!("{other}"),
} }
@ -420,15 +491,22 @@ impl Evaluator {
match p { match p {
TyParam::ConstObj(ConstObj::Value(v)) => Ok(v.class()), TyParam::ConstObj(ConstObj::Value(v)) => Ok(v.class()),
TyParam::Erased(t) => Ok((&*t).clone()), TyParam::Erased(t) => Ok((&*t).clone()),
| TyParam::FreeVar(fv) => TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() { Ok(t) } else { todo!() }, if let Some(t) = fv.type_of() {
Ok(t)
} else {
todo!()
}
}
TyParam::Type(_) => Ok(Type::Type), TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => TyParam::Mono(name) => ctx
ctx.consts.get(&name) .consts
.get(&name)
.and_then(|c| match c { .and_then(|c| match c {
ConstObj::Value(v) => Some(v.class()), ConstObj::Value(v) => Some(v.class()),
_ => None, _ => None,
}).ok_or(EvalError::unreachable(fn_name!(), line!())), })
.ok_or(EvalError::unreachable(fn_name!(), line!())),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
@ -439,21 +517,27 @@ impl Evaluator {
(TyParam::Type(l), TyParam::Type(r)) => l == r, (TyParam::Type(l), TyParam::Type(r)) => l == r,
(TyParam::ConstObj(l), TyParam::ConstObj(r)) => l == r, (TyParam::ConstObj(l), TyParam::ConstObj(r)) => l == r,
(TyParam::Erased(l), TyParam::Erased(r)) => l == r, (TyParam::Erased(l), TyParam::Erased(r)) => l == r,
(TyParam::FreeVar{ .. }, TyParam::FreeVar{ .. }) => true, (TyParam::FreeVar { .. }, TyParam::FreeVar { .. }) => true,
(TyParam::Mono(l), TyParam::Mono(r)) => { (TyParam::Mono(l), TyParam::Mono(r)) => {
if l == r { true } if l == r {
else if let (Some(l), Some(r)) = (ctx.consts.get(l), ctx.consts.get(r)) { l == r } true
else { } else if let (Some(l), Some(r)) = (ctx.consts.get(l), ctx.consts.get(r)) {
l == r
} else {
// lとrが型の場合は... // lとrが型の場合は...
false false
} }
}, }
(TyParam::BinOp{ .. }, TyParam::BinOp{ .. }) => todo!(), (TyParam::BinOp { .. }, TyParam::BinOp { .. }) => todo!(),
(TyParam::UnaryOp{ .. }, TyParam::UnaryOp{ .. }) => todo!(), (TyParam::UnaryOp { .. }, TyParam::UnaryOp { .. }) => todo!(),
(TyParam::App{ .. }, TyParam::App{ .. }) => todo!(), (TyParam::App { .. }, TyParam::App { .. }) => todo!(),
(TyParam::Mono(m), TyParam::ConstObj(l)) (TyParam::Mono(m), TyParam::ConstObj(l)) | (TyParam::ConstObj(l), TyParam::Mono(m)) => {
| (TyParam::ConstObj(l), TyParam::Mono(m)) => if let Some(o) = ctx.consts.get(m) {
if let Some(o) = ctx.consts.get(m) { o == l } else { true }, o == l
} else {
true
}
}
(TyParam::MonoQVar(_), _) | (_, TyParam::MonoQVar(_)) => false, (TyParam::MonoQVar(_), _) | (_, TyParam::MonoQVar(_)) => false,
(l, r) => todo!("l: {l}, r: {r}"), (l, r) => todo!("l: {l}, r: {r}"),
} }

View file

@ -1,19 +1,18 @@
/// defines High-level Intermediate Representation /// defines High-level Intermediate Representation
use std::fmt; use std::fmt;
use erg_common::{Str};
use erg_common::value::ValueObj;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::traits::{HasType, Locational, Stream, NestedDisplay}; use erg_common::traits::{HasType, Locational, NestedDisplay, Stream};
use erg_common::ty::{Type, TyParam, Constraint}; use erg_common::ty::{Constraint, TyParam, Type};
use erg_common::value::ValueObj;
use erg_common::Str;
use erg_common::{ use erg_common::{
impl_locational, impl_locational_for_enum, impl_display_for_enum, impl_display_from_nested, impl_locational, impl_locational_for_enum,
impl_stream_for_wrapper, impl_display_for_enum, impl_nested_display_for_enum, impl_stream_for_wrapper,
impl_nested_display_for_enum, impl_display_from_nested,
}; };
use erg_parser::ast::{fmt_lines, DefId, Params, VarName, VarPattern};
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_parser::ast::{VarName, VarPattern, Params, DefId, fmt_lines};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Literal { pub struct Literal {
@ -24,9 +23,13 @@ pub struct Literal {
impl HasType for Literal { impl HasType for Literal {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl NestedDisplay for Literal { impl NestedDisplay for Literal {
@ -39,13 +42,19 @@ impl_display_from_nested!(Literal);
impl Locational for Literal { impl Locational for Literal {
#[inline] #[inline]
fn loc(&self) -> Location { self.token.loc() } fn loc(&self) -> Location {
self.token.loc()
}
} }
impl From<Token> for Literal { impl From<Token> for Literal {
fn from(token: Token) -> Self { fn from(token: Token) -> Self {
let data = ValueObj::from_str(Type::from(token.kind), token.content.clone()); let data = ValueObj::from_str(Type::from(token.kind), token.content.clone());
Self { t: data.t(), data, token } Self {
t: data.t(),
data,
token,
}
} }
} }
@ -53,7 +62,11 @@ impl Literal {
pub fn new(c: ValueObj, lineno: usize, col: usize) -> Self { pub fn new(c: ValueObj, lineno: usize, col: usize) -> Self {
let kind = TokenKind::from(&c); let kind = TokenKind::from(&c);
let token = Token::new(kind, c.to_string(), lineno, col); let token = Token::new(kind, c.to_string(), lineno, col);
Self { t: c.t(), data: c, token } Self {
t: c.t(),
data: c,
token,
}
} }
#[inline] #[inline]
@ -76,11 +89,15 @@ impl NestedDisplay for PosArg {
impl_display_from_nested!(PosArg); impl_display_from_nested!(PosArg);
impl Locational for PosArg { impl Locational for PosArg {
fn loc(&self) -> Location { self.expr.loc() } fn loc(&self) -> Location {
self.expr.loc()
}
} }
impl PosArg { impl PosArg {
pub const fn new(expr: Expr) -> Self { Self { expr } } pub const fn new(expr: Expr) -> Self {
Self { expr }
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -105,7 +122,9 @@ impl Locational for KwArg {
} }
impl KwArg { impl KwArg {
pub const fn new(keyword: Token, expr: Expr) -> Self { Self { keyword, expr } } pub const fn new(keyword: Token, expr: Expr) -> Self {
Self { keyword, expr }
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -117,8 +136,12 @@ pub struct Args {
impl NestedDisplay for Args { impl NestedDisplay for Args {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
if !self.pos_args.is_empty() { fmt_lines(self.pos_args.iter(), f, level)?; } if !self.pos_args.is_empty() {
if !self.kw_args.is_empty() { fmt_lines(self.kw_args.iter(), f, level)?; } fmt_lines(self.pos_args.iter(), f, level)?;
}
if !self.kw_args.is_empty() {
fmt_lines(self.kw_args.iter(), f, level)?;
}
Ok(()) Ok(())
} }
} }
@ -132,7 +155,10 @@ impl Locational for Args {
} else if !self.kw_args.is_empty() { } else if !self.kw_args.is_empty() {
Location::concat(self.kw_args.first().unwrap(), self.kw_args.last().unwrap()) Location::concat(self.kw_args.first().unwrap(), self.kw_args.last().unwrap())
} else if !self.pos_args.is_empty() { } else if !self.pos_args.is_empty() {
Location::concat(self.pos_args.first().unwrap(), self.pos_args.last().unwrap()) Location::concat(
self.pos_args.first().unwrap(),
self.pos_args.last().unwrap(),
)
} else { } else {
Location::Unknown Location::Unknown
} }
@ -142,8 +168,16 @@ impl Locational for Args {
// impl_stream!(Args, KwArg, kw_args); // impl_stream!(Args, KwArg, kw_args);
impl Args { impl Args {
pub const fn new(pos_args: Vec<PosArg>, kw_args: Vec<KwArg>, paren: Option<(Token, Token)>) -> Self { pub const fn new(
Self { pos_args, kw_args, paren } pos_args: Vec<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
) -> Self {
Self {
pos_args,
kw_args,
paren,
}
} }
pub const fn empty() -> Self { pub const fn empty() -> Self {
@ -156,11 +190,17 @@ impl Args {
} }
#[inline] #[inline]
pub fn kw_len(&self) -> usize { self.kw_args.len() } pub fn kw_len(&self) -> usize {
self.kw_args.len()
}
pub fn pos_args(&self) -> &[PosArg] { &self.pos_args[..] } pub fn pos_args(&self) -> &[PosArg] {
&self.pos_args[..]
}
pub fn kw_args(&self) -> &[KwArg] { &self.kw_args[..] } pub fn kw_args(&self) -> &[KwArg] {
&self.kw_args[..]
}
pub fn push_pos(&mut self, pos: PosArg) { pub fn push_pos(&mut self, pos: PosArg) {
self.pos_args.push(pos); self.pos_args.push(pos);
@ -174,7 +214,7 @@ impl Args {
if self.pos_args.get(index).is_some() { if self.pos_args.get(index).is_some() {
self.pos_args.remove(index).expr self.pos_args.remove(index).expr
} else { } else {
self.kw_args.remove(index-self.pos_args.len()).expr self.kw_args.remove(index - self.pos_args.len()).expr
} }
} }
@ -183,8 +223,8 @@ impl Args {
if self.pos_args.get(index).is_some() { if self.pos_args.get(index).is_some() {
Some(self.pos_args.remove(index).expr) Some(self.pos_args.remove(index).expr)
} else { } else {
self.kw_args.get(index-self.pos_args.len())?; self.kw_args.get(index - self.pos_args.len())?;
Some(self.kw_args.remove(index-self.pos_args.len()).expr) Some(self.kw_args.remove(index - self.pos_args.len()).expr)
} }
} }
@ -202,7 +242,9 @@ impl Args {
if self.pos_args.get(index).is_some() { if self.pos_args.get(index).is_some() {
self.pos_args.get(index).map(|a| &a.expr) self.pos_args.get(index).map(|a| &a.expr)
} else { } else {
self.kw_args.get(index-self.pos_args.len()).map(|a| &a.expr) self.kw_args
.get(index - self.pos_args.len())
.map(|a| &a.expr)
} }
} }
} }
@ -220,7 +262,9 @@ impl fmt::Display for Local {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() { let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})") format!("(__name__ = {__name__})")
} else { "".to_string() }; } else {
"".to_string()
};
if self.t != Type::ASTOmitted { if self.t != Type::ASTOmitted {
write!(f, "{} (: {}){}", self.name.content, self.t, __name__) write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
} else { } else {
@ -231,31 +275,43 @@ impl fmt::Display for Local {
impl HasType for Local { impl HasType for Local {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl Locational for Local { impl Locational for Local {
#[inline] #[inline]
fn loc(&self) -> Location { self.name.loc() } fn loc(&self) -> Location {
self.name.loc()
}
} }
impl Local { impl Local {
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self { Self{ name, __name__, t } } pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self {
Self { name, __name__, t }
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで // &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline] #[inline]
pub fn inspect(&self) -> &Str { &self.name.content } pub fn inspect(&self) -> &Str {
&self.name.content
}
pub const fn __name__(&self) -> Option<&Str> { self.__name__.as_ref() } pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Attribute { pub struct Attribute {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub name: Token, pub name: Token,
t: Type t: Type,
} }
impl fmt::Display for Attribute { impl fmt::Display for Attribute {
@ -268,14 +324,22 @@ impl_locational!(Attribute, obj, name);
impl HasType for Attribute { impl HasType for Attribute {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl Attribute { impl Attribute {
pub fn new(obj: Expr, name: Token, t: Type) -> Self { pub fn new(obj: Expr, name: Token, t: Type) -> Self {
Self { obj: Box::new(obj), name, t } Self {
obj: Box::new(obj),
name,
t,
}
} }
} }
@ -283,7 +347,7 @@ impl Attribute {
pub struct Subscript { pub struct Subscript {
obj: Box<Expr>, obj: Box<Expr>,
index: Box<Expr>, index: Box<Expr>,
t: Type t: Type,
} }
impl fmt::Display for Subscript { impl fmt::Display for Subscript {
@ -296,14 +360,22 @@ impl_locational!(Subscript, obj, index);
impl HasType for Subscript { impl HasType for Subscript {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl Subscript { impl Subscript {
pub fn new(obj: Expr, index: Expr, t: Type) -> Self { pub fn new(obj: Expr, index: Expr, t: Type) -> Self {
Self { obj: Box::new(obj), index: Box::new(index), t } Self {
obj: Box::new(obj),
index: Box::new(index),
t,
}
} }
} }
@ -339,13 +411,19 @@ impl HasType for Accessor {
} }
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl Accessor { impl Accessor {
pub const fn local(symbol: Token, t: Type) -> Self { Self::Local(Local::new(symbol, None, t)) } pub const fn local(symbol: Token, t: Type) -> Self {
Self::Local(Local::new(symbol, None, t))
}
pub const fn self_dot(name: Token, t: Type) -> Self { Self::SelfDot(Local::new(name, None, t)) } pub const fn self_dot(name: Token, t: Type) -> Self {
Self::SelfDot(Local::new(name, None, t))
}
pub fn attr(obj: Expr, name: Token, t: Type) -> Self { pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
Self::Attr(Attribute::new(obj, name, t)) Self::Attr(Attribute::new(obj, name, t))
@ -358,18 +436,18 @@ impl Accessor {
pub fn var_full_name(&self) -> Option<String> { pub fn var_full_name(&self) -> Option<String> {
match self { match self {
Self::Local(local) => Some(local.inspect().to_string()), Self::Local(local) => Some(local.inspect().to_string()),
Self::Attr(attr) => Self::Attr(attr) => attr
attr.obj.var_full_name().map(|n| n + "." + attr.name.inspect()), .obj
Self::Subscr(_) .var_full_name()
| Self::SelfDot(_) => todo!(), .map(|n| n + "." + attr.name.inspect()),
Self::Subscr(_) | Self::SelfDot(_) => todo!(),
} }
} }
// 参照するオブジェクト自体が持っている固有の名前 // 参照するオブジェクト自体が持っている固有の名前
pub fn __name__(&self) -> Option<&str> { pub fn __name__(&self) -> Option<&str> {
match self { match self {
Self::Local(local) Self::Local(local) | Self::SelfDot(local) => local.__name__().map(|s| &s[..]),
| Self::SelfDot(local) => local.__name__().map(|s| &s[..]),
_ => None, _ => None,
} }
} }
@ -386,9 +464,13 @@ pub struct Array {
impl HasType for Array { impl HasType for Array {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl NestedDisplay for Array { impl NestedDisplay for Array {
@ -405,12 +487,26 @@ impl_display_from_nested!(Array);
impl_locational!(Array, l_sqbr, r_sqbr); impl_locational!(Array, l_sqbr, r_sqbr);
impl Array { impl Array {
pub fn new(l_sqbr: Token, r_sqbr: Token, level: usize, elems: Args, guard: Option<Expr>) -> Self { pub fn new(
let elem_t = elems.pos_args().first() l_sqbr: Token,
r_sqbr: Token,
level: usize,
elems: Args,
guard: Option<Expr>,
) -> Self {
let elem_t = elems
.pos_args()
.first()
.map(|a| a.expr.t()) .map(|a| a.expr.t())
.unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type))); .unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type)));
let t = Type::array(elem_t, TyParam::value(elems.len())); let t = Type::array(elem_t, TyParam::value(elems.len()));
Self { l_sqbr, r_sqbr, t, elems, guard: guard.map(Box::new) } Self {
l_sqbr,
r_sqbr,
t,
elems,
guard: guard.map(Box::new),
}
} }
pub fn push(&mut self, elem: Expr) { pub fn push(&mut self, elem: Expr) {
@ -426,10 +522,16 @@ pub struct Dict {
} }
impl HasType for Dict { impl HasType for Dict {
fn ref_t(&self) -> &Type { todo!() } fn ref_t(&self) -> &Type {
fn t(&self) -> Type { todo!() } todo!()
}
fn t(&self) -> Type {
todo!()
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl NestedDisplay for Dict { impl NestedDisplay for Dict {
@ -443,7 +545,11 @@ impl_locational!(Dict, l_brace, r_brace);
impl Dict { impl Dict {
pub const fn new(l_brace: Token, r_brace: Token, attrs: Args) -> Self { pub const fn new(l_brace: Token, r_brace: Token, attrs: Args) -> Self {
Self { l_brace, r_brace, attrs } Self {
l_brace,
r_brace,
attrs,
}
} }
} }
@ -466,13 +572,21 @@ impl NestedDisplay for BinOp {
impl HasType for BinOp { impl HasType for BinOp {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() } fn ref_t(&self) -> &Type {
&self.sig_t.return_t().unwrap()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { &self.sig_t.lhs_t() } fn lhs_t(&self) -> &Type {
&self.sig_t.lhs_t()
}
#[inline] #[inline]
fn rhs_t(&self) -> &Type { &self.sig_t.rhs_t() } fn rhs_t(&self) -> &Type {
&self.sig_t.rhs_t()
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t)
}
} }
impl_display_from_nested!(BinOp); impl_display_from_nested!(BinOp);
@ -480,7 +594,12 @@ impl_locational!(BinOp, lhs, rhs);
impl BinOp { impl BinOp {
pub fn new(op: Token, lhs: Expr, rhs: Expr, sig_t: Type) -> Self { pub fn new(op: Token, lhs: Expr, rhs: Expr, sig_t: Type) -> Self {
Self { op, lhs: Box::new(lhs), rhs: Box::new(rhs), sig_t } Self {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
sig_t,
}
} }
} }
@ -493,13 +612,21 @@ pub struct UnaryOp {
impl HasType for UnaryOp { impl HasType for UnaryOp {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() } fn ref_t(&self) -> &Type {
&self.sig_t.return_t().unwrap()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { self.expr.ref_t() } fn lhs_t(&self) -> &Type {
self.expr.ref_t()
}
#[inline] #[inline]
fn rhs_t(&self) -> &Type { panic!("invalid operation") } fn rhs_t(&self) -> &Type {
panic!("invalid operation")
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t)
}
} }
impl NestedDisplay for UnaryOp { impl NestedDisplay for UnaryOp {
@ -514,7 +641,11 @@ impl_locational!(UnaryOp, op, expr);
impl UnaryOp { impl UnaryOp {
pub fn new(op: Token, expr: Expr, sig_t: Type) -> Self { pub fn new(op: Token, expr: Expr, sig_t: Type) -> Self {
Self { op, expr: Box::new(expr), sig_t } Self {
op,
expr: Box::new(expr),
sig_t,
}
} }
} }
@ -538,13 +669,21 @@ impl_display_from_nested!(Call);
impl HasType for Call { impl HasType for Call {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() } fn ref_t(&self) -> &Type {
&self.sig_t.return_t().unwrap()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { self.sig_t.lhs_t() } fn lhs_t(&self) -> &Type {
self.sig_t.lhs_t()
}
#[inline] #[inline]
fn rhs_t(&self) -> &Type { self.sig_t.rhs_t() } fn rhs_t(&self) -> &Type {
self.sig_t.rhs_t()
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t)
}
} }
impl Locational for Call { impl Locational for Call {
@ -555,11 +694,16 @@ impl Locational for Call {
impl Call { impl Call {
pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self { pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self {
Self { obj: Box::new(obj), args, sig_t } Self {
obj: Box::new(obj),
args,
sig_t,
}
} }
pub fn is_import_call(&self) -> bool { pub fn is_import_call(&self) -> bool {
self.obj.var_full_name() self.obj
.var_full_name()
.map(|s| &s[..] == "import" || &s[..] == "pyimport") .map(|s| &s[..] == "import" || &s[..] == "pyimport")
.unwrap_or(false) .unwrap_or(false)
} }
@ -570,11 +714,17 @@ pub struct Block(Vec<Expr>);
impl HasType for Block { impl HasType for Block {
#[inline] #[inline]
fn ref_t(&self) -> &Type { self.last().unwrap().ref_t() } fn ref_t(&self) -> &Type {
self.last().unwrap().ref_t()
}
#[inline] #[inline]
fn t(&self) -> Type { self.last().unwrap().t() } fn t(&self) -> Type {
self.last().unwrap().t()
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { self.last().unwrap().signature_t() } fn signature_t(&self) -> Option<&Type> {
self.last().unwrap().signature_t()
}
} }
impl NestedDisplay for Block { impl NestedDisplay for Block {
@ -605,13 +755,19 @@ impl fmt::Display for VarSignature {
} }
impl Locational for VarSignature { impl Locational for VarSignature {
fn loc(&self) -> Location { self.pat.loc() } fn loc(&self) -> Location {
self.pat.loc()
}
} }
impl VarSignature { impl VarSignature {
pub const fn new(pat: VarPattern, t: Type) -> Self { Self{ pat, t } } pub const fn new(pat: VarPattern, t: Type) -> Self {
Self { pat, t }
}
pub fn inspect(&self) -> Option<&Str> { self.pat.inspect() } pub fn inspect(&self) -> Option<&Str> {
self.pat.inspect()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -635,10 +791,12 @@ impl Locational for SubrSignature {
impl SubrSignature { impl SubrSignature {
pub const fn new(name: VarName, params: Params, t: Type) -> Self { pub const fn new(name: VarName, params: Params, t: Type) -> Self {
Self{ name, params, t } Self { name, params, t }
} }
pub fn is_procedural(&self) -> bool { self.name.is_procedural() } pub fn is_procedural(&self) -> bool {
self.name.is_procedural()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -647,14 +805,18 @@ pub struct Lambda {
op: Token, op: Token,
pub body: Block, pub body: Block,
pub id: usize, pub id: usize,
t: Type t: Type,
} }
impl HasType for Lambda { impl HasType for Lambda {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl NestedDisplay for Lambda { impl NestedDisplay for Lambda {
@ -669,10 +831,18 @@ impl_locational!(Lambda, params, body);
impl Lambda { impl Lambda {
pub const fn new(id: usize, params: Params, op: Token, body: Block, t: Type) -> Self { pub const fn new(id: usize, params: Params, op: Token, body: Block, t: Type) -> Self {
Self { id, params, op, body, t } Self {
id,
params,
op,
body,
t,
}
} }
pub fn is_procedural(&self) -> bool { self.op.is(TokenKind::ProcArrow) } pub fn is_procedural(&self) -> bool {
self.op.is(TokenKind::ProcArrow)
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -685,7 +855,9 @@ impl_display_for_enum!(Signature; Var, Subr,);
impl_locational_for_enum!(Signature; Var, Subr,); impl_locational_for_enum!(Signature; Var, Subr,);
impl Signature { impl Signature {
pub const fn is_subr(&self) -> bool { matches!(self, Self::Subr(_)) } pub const fn is_subr(&self) -> bool {
matches!(self, Self::Subr(_))
}
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
@ -720,34 +892,44 @@ impl_display_from_nested!(Decl);
impl Locational for Decl { impl Locational for Decl {
#[inline] #[inline]
fn loc(&self) -> Location { self.sig.loc() } fn loc(&self) -> Location {
self.sig.loc()
}
} }
impl Decl { impl Decl {
pub const fn spec_t(&self) -> &Type { &self.t } pub const fn spec_t(&self) -> &Type {
&self.t
}
pub const fn is_sub(&self) -> bool { self.sig.is_subr() } pub const fn is_sub(&self) -> bool {
self.sig.is_subr()
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DefBody { pub struct DefBody {
pub op: Token, pub op: Token,
pub block: Block, pub block: Block,
pub id : DefId, pub id: DefId,
} }
impl_locational!(DefBody, op, block); impl_locational!(DefBody, op, block);
impl DefBody { impl DefBody {
pub const fn new(op: Token, block: Block, id: DefId) -> Self { Self { op, block, id } } pub const fn new(op: Token, block: Block, id: DefId) -> Self {
Self { op, block, id }
}
pub fn is_type(&self) -> bool { pub fn is_type(&self) -> bool {
match self.block.first().unwrap() { match self.block.first().unwrap() {
Expr::Call(call) => { Expr::Call(call) => {
if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() { if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() {
&local.inspect()[..] == "Type" &local.inspect()[..] == "Type"
} else { false } } else {
}, false
}
}
_ => false, _ => false,
} }
} }
@ -770,7 +952,9 @@ impl_display_from_nested!(Def);
impl_locational!(Def, sig, body); impl_locational!(Def, sig, body);
impl Def { impl Def {
pub const fn new(sig: Signature, body: DefBody) -> Self { Self { sig, body } } pub const fn new(sig: Signature, body: DefBody) -> Self {
Self { sig, body }
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -872,5 +1056,7 @@ impl std::fmt::Display for HIR {
} }
impl HIR { impl HIR {
pub const fn new(name: Str, module: Module) -> Self { Self { name, module } } pub const fn new(name: Str, module: Module) -> Self {
Self { name, module }
}
} }

View file

@ -1,21 +1,21 @@
//! defines type information for builtin objects (in `Context`) //! defines type information for builtin objects (in `Context`)
//! //!
//! 組み込みオブジェクトの型情報を(Contextに)定義 //! 組み込みオブジェクトの型情報を(Contextに)定義
use erg_common::{Str};
use erg_common::{set, debug_power_assert};
use erg_common::ty::{Type, TyParam, ConstObj};
use Type::*;
use erg_common::ty::type_constrs::*; use erg_common::ty::type_constrs::*;
use erg_common::ty::{ConstObj, TyParam, Type};
use erg_common::Str;
use erg_common::{debug_power_assert, set};
use ParamSpec as PS; use ParamSpec as PS;
use Type::*;
use erg_parser::ast::{VarName}; use erg_parser::ast::VarName;
use crate::varinfo::{Mutability, Visibility, VarInfo, VarKind}; use crate::context::{Context, DefaultInfo, ParamSpec};
use crate::context::{Context, ParamSpec, DefaultInfo}; use crate::varinfo::{Mutability, VarInfo, VarKind, Visibility};
use Visibility::*; use DefaultInfo::*;
use Mutability::*; use Mutability::*;
use VarKind::*; use VarKind::*;
use DefaultInfo::*; use Visibility::*;
// NOTE: TyParam::MonoQuantVarは生成時に型を指定する必要があるが、逆にそちらがあれば型境界を指定しなくてもよい // NOTE: TyParam::MonoQuantVarは生成時に型を指定する必要があるが、逆にそちらがあれば型境界を指定しなくてもよい
impl Context { impl Context {
@ -24,7 +24,8 @@ impl Context {
if self.decls.get(&name).is_some() { if self.decls.get(&name).is_some() {
panic!("already registered: {name}"); panic!("already registered: {name}");
} else { } else {
self.decls.insert(name, VarInfo::new(t, Immutable, vis, Builtin)); self.decls
.insert(name, VarInfo::new(t, Immutable, vis, Builtin));
} }
} }
@ -50,7 +51,8 @@ impl Context {
panic!("{} has already been registered", t.name()); panic!("{} has already been registered", t.name());
} else { } else {
let name = VarName::from_str(Str::rc(t.name())); let name = VarName::from_str(Str::rc(t.name()));
self.impls.insert(name, VarInfo::new(Type, muty, Private, Builtin)); self.impls
.insert(name, VarInfo::new(Type, muty, Private, Builtin));
self.types.insert(t, ctx); self.types.insert(t, ctx);
} }
} }
@ -60,20 +62,24 @@ impl Context {
panic!("{} has already been registered", name); panic!("{} has already been registered", name);
} else { } else {
let name = VarName::from_static(name); let name = VarName::from_static(name);
self.impls.insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); self.impls
.insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin));
for method_name in ctx.impls.keys() { for method_name in ctx.impls.keys() {
if let Some(patches) = self._method_impl_patches.get_mut(method_name) { if let Some(patches) = self._method_impl_patches.get_mut(method_name) {
patches.push(name.clone()); patches.push(name.clone());
} else { } else {
self._method_impl_patches.insert(method_name.clone(), vec![name.clone()]); self._method_impl_patches
.insert(method_name.clone(), vec![name.clone()]);
} }
} }
debug_power_assert!(ctx.super_classes.len(), ==, 1); debug_power_assert!(ctx.super_classes.len(), ==, 1);
if let Some(target_type) = ctx.super_classes.first() { if let Some(target_type) = ctx.super_classes.first() {
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
self.glue_patch_and_types.push( self.glue_patch_and_types.push((
(VarName::from_str(ctx.name.clone()), target_type.clone(), impl_trait.clone()) VarName::from_str(ctx.name.clone()),
); target_type.clone(),
impl_trait.clone(),
));
} }
} }
self.patches.insert(name, ctx); self.patches.insert(name, ctx);
@ -87,33 +93,54 @@ impl Context {
let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL); let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL);
// __eq__: |Self <: Eq; R <: Eq()| Self(R).(R) -> Bool // __eq__: |Self <: Eq; R <: Eq()| Self(R).(R) -> Bool
let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool); let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool);
let op_t = quant(op_t, set!{subtype(mono_q("Self"), mono("Eq")), subtype(mono_q("R"), poly("Eq", vec![]))}); let op_t = quant(
op_t,
set! {subtype(mono_q("Self"), mono("Eq")), subtype(mono_q("R"), poly("Eq", vec![]))},
);
eq.register_decl("__eq__", op_t.clone(), Public); eq.register_decl("__eq__", op_t.clone(), Public);
let mut ord = Self::poly_trait("Ord", vec![PS::t("R", WithDefault)], vec![mono("Eq")], Self::TOP_LEVEL); let mut ord = Self::poly_trait(
"Ord",
vec![PS::t("R", WithDefault)],
vec![mono("Eq")],
Self::TOP_LEVEL,
);
let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool); let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool);
let op_t = quant(op_t, set!{subtype(mono_q("Self"), mono("Ord")), subtype(mono_q("R"), poly("Ord", vec![]))}); let op_t = quant(
op_t,
set! {subtype(mono_q("Self"), mono("Ord")), subtype(mono_q("R"), poly("Ord", vec![]))},
);
ord.register_decl("__lt__", op_t.clone(), Public); ord.register_decl("__lt__", op_t.clone(), Public);
let mut seq = Self::poly_trait("Seq", vec![PS::t("T", NonDefault)], vec![], Self::TOP_LEVEL); let mut seq =
Self::poly_trait("Seq", vec![PS::t("T", NonDefault)], vec![], Self::TOP_LEVEL);
let self_t = poly_q("Self", vec![TyParam::t(mono_q("T"))]); let self_t = poly_q("Self", vec![TyParam::t(mono_q("T"))]);
let t = fn0_met(self_t.clone(), Nat); let t = fn0_met(self_t.clone(), Nat);
let t = quant(t, set!{subtype(self_t.clone(), mono("Seq"))}); let t = quant(t, set! {subtype(self_t.clone(), mono("Seq"))});
seq.register_decl("__len__", t, Public); seq.register_decl("__len__", t, Public);
let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T")); let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T"));
let t = quant(t, set!{subtype(self_t, mono("Seq")), static_instance("T", Type)}); let t = quant(
t,
set! {subtype(self_t, mono("Seq")), static_instance("T", Type)},
);
seq.register_decl("get", t, Public); seq.register_decl("get", t, Public);
let (r, o) = (mono_q("R"), mono_q("O")); let (r, o) = (mono_q("R"), mono_q("O"));
let (r_bound, o_bound) = (static_instance("R", Type), static_instance("O", Type)); let (r_bound, o_bound) = (static_instance("R", Type), static_instance("O", Type));
let params = vec![PS::t("R", WithDefault), PS::t("O", WithDefault)]; let params = vec![PS::t("R", WithDefault), PS::t("O", WithDefault)];
let ty_params = vec![mono_q_tp("R"), mono_q_tp("O")]; let ty_params = vec![mono_q_tp("R"), mono_q_tp("O")];
let mut add_ro = Self::poly_trait("Add", params.clone(), vec![], Self::TOP_LEVEL); let mut add_ro = Self::poly_trait("Add", params.clone(), vec![], Self::TOP_LEVEL);
let self_bound = subtype(poly_q("Self", ty_params.clone()), poly("Add", ty_params.clone())); let self_bound = subtype(
poly_q("Self", ty_params.clone()),
poly("Add", ty_params.clone()),
);
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone());
let op_t = quant(op_t, set!{r_bound.clone(), o_bound.clone(), self_bound}); let op_t = quant(op_t, set! {r_bound.clone(), o_bound.clone(), self_bound});
add_ro.register_decl("__add__", op_t, Public); add_ro.register_decl("__add__", op_t, Public);
let mut sub_ro = Self::poly_trait("Sub", params.clone(), vec![], Self::TOP_LEVEL); let mut sub_ro = Self::poly_trait("Sub", params.clone(), vec![], Self::TOP_LEVEL);
let self_bound = subtype(poly_q("Self", ty_params.clone()), poly("Sub", ty_params.clone())); let self_bound = subtype(
poly_q("Self", ty_params.clone()),
poly("Sub", ty_params.clone()),
);
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone());
let op_t = quant(op_t, set!{r_bound.clone(), o_bound.clone(), self_bound}); let op_t = quant(op_t, set! {r_bound.clone(), o_bound.clone(), self_bound});
sub_ro.register_decl("__sub__", op_t, Public); sub_ro.register_decl("__sub__", op_t, Public);
let mut mul_ro = Self::poly_trait("Mul", params.clone(), vec![], Self::TOP_LEVEL); let mut mul_ro = Self::poly_trait("Mul", params.clone(), vec![], Self::TOP_LEVEL);
let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), o.clone()); let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), o.clone());
@ -121,22 +148,47 @@ impl Context {
let mut div_ro = Self::poly_trait("Div", params.clone(), vec![], Self::TOP_LEVEL); let mut div_ro = Self::poly_trait("Div", params.clone(), vec![], Self::TOP_LEVEL);
let op_t = fn1_met(poly("Div", ty_params.clone()), r, o); let op_t = fn1_met(poly("Div", ty_params.clone()), r, o);
div_ro.register_decl("__div__", op_t, Public); div_ro.register_decl("__div__", op_t, Public);
let sup = poly("Add", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "AddO")]); let sup = poly(
"Add",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "AddO"),
],
);
let mut add = Self::mono_trait("Add", vec![sup], Self::TOP_LEVEL); let mut add = Self::mono_trait("Add", vec![sup], Self::TOP_LEVEL);
add.register_decl("AddO", Type, Public); add.register_decl("AddO", Type, Public);
let sup = poly("Sub", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "SubO")]); let sup = poly(
"Sub",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "SubO"),
],
);
let mut sub = Self::mono_trait("Sub", vec![sup], Self::TOP_LEVEL); let mut sub = Self::mono_trait("Sub", vec![sup], Self::TOP_LEVEL);
sub.register_decl("SubO", Type, Public); sub.register_decl("SubO", Type, Public);
let sup = poly("Mul", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "MulO")]); let sup = poly(
"Mul",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "MulO"),
],
);
let mut mul = Self::mono_trait("Mul", vec![sup], Self::TOP_LEVEL); let mut mul = Self::mono_trait("Mul", vec![sup], Self::TOP_LEVEL);
mul.register_decl("MulO", Type, Public); mul.register_decl("MulO", Type, Public);
let sup = Type::poly("Div", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "DivO")]); let sup = Type::poly(
"Div",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "DivO"),
],
);
let mut div = Self::mono_trait("Div", vec![sup], Self::TOP_LEVEL); let mut div = Self::mono_trait("Div", vec![sup], Self::TOP_LEVEL);
div.register_decl("DivO", Type, Public); div.register_decl("DivO", Type, Public);
let num = Self::mono_trait("Num", vec![ let num = Self::mono_trait(
mono("Eq"), "Num",
mono("Add"), mono("Sub"), mono("Mul"), vec![mono("Eq"), mono("Add"), mono("Sub"), mono("Mul")],
], Self::TOP_LEVEL); Self::TOP_LEVEL,
);
self.register_type(mono("Eq"), eq, Const); self.register_type(mono("Eq"), eq, Const);
self.register_type(mono("Ord"), ord, Const); self.register_type(mono("Ord"), ord, Const);
self.register_type(mono("Seq"), seq, Const); self.register_type(mono("Seq"), seq, Const);
@ -150,7 +202,7 @@ impl Context {
fn init_builtin_classes(&mut self) { fn init_builtin_classes(&mut self) {
let mut obj = Self::mono_class("Obj", vec![], vec![], Self::TOP_LEVEL); let mut obj = Self::mono_class("Obj", vec![], vec![], Self::TOP_LEVEL);
let t = fn0_met(mono_q("Self"), mono_q("Self")); let t = fn0_met(mono_q("Self"), mono_q("Self"));
let t = quant(t, set!{subtype(mono_q("Self"), mono("Obj"))}); let t = quant(t, set! {subtype(mono_q("Self"), mono("Obj"))});
obj.register_impl("clone", t, Const, Public); obj.register_impl("clone", t, Const, Public);
obj.register_impl("__module__", Str, Const, Public); obj.register_impl("__module__", Str, Const, Public);
obj.register_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public); obj.register_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public);
@ -170,39 +222,67 @@ impl Context {
); );
// let mut record = Self::mono_trait("Record", vec![Obj], Self::TOP_LEVEL); // let mut record = Self::mono_trait("Record", vec![Obj], Self::TOP_LEVEL);
// let mut class = Self::mono_class("Class", vec![Type, Obj], Self::TOP_LEVEL); // let mut class = Self::mono_class("Class", vec![Type, Obj], Self::TOP_LEVEL);
let mut float = Self::mono_class("Float", vec![Obj], vec![ let mut float = Self::mono_class(
"Float",
vec![Obj],
vec![
mono("Num"), mono("Num"),
mono("Ord"), mono("Eq"), mono("Ord"),
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"), mono("Eq"),
mono("Add"),
mono("Sub"),
mono("Mul"),
mono("Div"),
mono("Mutate"), mono("Mutate"),
], Self::TOP_LEVEL); ],
Self::TOP_LEVEL,
);
let op_t = fn1_met(Float, Float, Float); let op_t = fn1_met(Float, Float, Float);
float.register_impl("__add__", op_t.clone(), Const, Public); float.register_impl("__add__", op_t.clone(), Const, Public);
float.register_impl("__sub__", op_t.clone(), Const, Public); float.register_impl("__sub__", op_t.clone(), Const, Public);
float.register_impl("__mul__", op_t.clone(), Const, Public); float.register_impl("__mul__", op_t.clone(), Const, Public);
float.register_impl("__div__", op_t , Const, Public); float.register_impl("__div__", op_t, Const, Public);
float.register_impl("Real", Float, Const, Public); float.register_impl("Real", Float, Const, Public);
float.register_impl("Imag", Float, Const, Public); float.register_impl("Imag", Float, Const, Public);
let mut ratio = Self::mono_class("Ratio", vec![Obj], vec![ let mut ratio = Self::mono_class(
"Ratio",
vec![Obj],
vec![
mono("Num"), mono("Num"),
mono("Ord"), mono("Eq"), mono("Ord"),
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"), mono("Eq"),
mono("Add"),
mono("Sub"),
mono("Mul"),
mono("Div"),
mono("Mutate"), mono("Mutate"),
], Self::TOP_LEVEL); ],
Self::TOP_LEVEL,
);
let op_t = fn1_met(Ratio, Ratio, Ratio); let op_t = fn1_met(Ratio, Ratio, Ratio);
ratio.register_impl("__add__", op_t.clone(), Const, Public); ratio.register_impl("__add__", op_t.clone(), Const, Public);
ratio.register_impl("__sub__", op_t.clone(), Const, Public); ratio.register_impl("__sub__", op_t.clone(), Const, Public);
ratio.register_impl("__mul__", op_t.clone(), Const, Public); ratio.register_impl("__mul__", op_t.clone(), Const, Public);
ratio.register_impl("__div__", op_t , Const, Public); ratio.register_impl("__div__", op_t, Const, Public);
ratio.register_impl("Real", Ratio, Const, Public); ratio.register_impl("Real", Ratio, Const, Public);
ratio.register_impl("Imag", Ratio, Const, Public); ratio.register_impl("Imag", Ratio, Const, Public);
let mut int = Self::mono_class("Int", vec![Obj], vec![ let mut int = Self::mono_class(
"Int",
vec![Obj],
vec![
mono("Num"), mono("Num"),
mono("Rational"), mono("Integral"), mono("Rational"),
mono("Ord"), mono("Eq"), mono("Integral"),
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"), mono("Ord"),
mono("Eq"),
mono("Add"),
mono("Sub"),
mono("Mul"),
mono("Div"),
mono("Mutate"), mono("Mutate"),
], Self::TOP_LEVEL); ],
Self::TOP_LEVEL,
);
int.register_impl("abs", fn0_met(Int, Nat), Immutable, Public); int.register_impl("abs", fn0_met(Int, Nat), Immutable, Public);
// __div__ is not included in Int (cast to Float) // __div__ is not included in Int (cast to Float)
let op_t = fn1_met(Int, Int, Int); let op_t = fn1_met(Int, Int, Int);
@ -211,60 +291,110 @@ impl Context {
int.register_impl("__mul__", op_t, Const, Public); int.register_impl("__mul__", op_t, Const, Public);
int.register_impl("Real", Int, Const, Public); int.register_impl("Real", Int, Const, Public);
int.register_impl("Imag", Int, Const, Public); int.register_impl("Imag", Int, Const, Public);
int.super_traits.push(poly("Add", vec![ty_tp(Int), ty_tp(Int)])); int.super_traits
int.super_traits.push(poly("Sub", vec![ty_tp(Int), ty_tp(Int)])); .push(poly("Add", vec![ty_tp(Int), ty_tp(Int)]));
int.super_traits.push(poly("Mul", vec![ty_tp(Int), ty_tp(Int)])); int.super_traits
int.super_traits.push(poly("Div", vec![ty_tp(Int), ty_tp(Ratio)])); .push(poly("Sub", vec![ty_tp(Int), ty_tp(Int)]));
let mut nat = Self::mono_class("Nat", vec![Int, Obj], vec![ int.super_traits
.push(poly("Mul", vec![ty_tp(Int), ty_tp(Int)]));
int.super_traits
.push(poly("Div", vec![ty_tp(Int), ty_tp(Ratio)]));
let mut nat = Self::mono_class(
"Nat",
vec![Int, Obj],
vec![
mono("Num"), mono("Num"),
mono("Rational"), mono("Integral"), mono("Rational"),
mono("Ord"), mono("Eq"), mono("Integral"),
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"), mono("Ord"),
mono("Eq"),
mono("Add"),
mono("Sub"),
mono("Mul"),
mono("Div"),
mono("Mutate"), mono("Mutate"),
Obj, Obj,
], Self::TOP_LEVEL); ],
Self::TOP_LEVEL,
);
// __sub__, __div__ is not included in Nat (cast to Int) // __sub__, __div__ is not included in Nat (cast to Int)
let op_t = fn1_met(Nat, Nat, Nat); let op_t = fn1_met(Nat, Nat, Nat);
nat.register_impl("__add__", op_t.clone(), Const, Public); nat.register_impl("__add__", op_t.clone(), Const, Public);
nat.register_impl("__mul__", op_t, Const, Public); nat.register_impl("__mul__", op_t, Const, Public);
nat.register_impl( nat.register_impl(
"times!", "times!",
Type::pr_met(Nat, None, vec![param_t("p", nd_proc(vec![], NoneType))], vec![], NoneType), Type::pr_met(
Nat,
None,
vec![param_t("p", nd_proc(vec![], NoneType))],
vec![],
NoneType,
),
Immutable, Immutable,
Public Public,
); );
nat.register_impl("Real", Nat, Const, Public); nat.register_impl("Real", Nat, Const, Public);
nat.register_impl("Imag", Nat, Const, Public); nat.register_impl("Imag", Nat, Const, Public);
nat.super_traits.push(poly("Add", vec![ty_tp(Nat), ty_tp(Nat)])); nat.super_traits
nat.super_traits.push(poly("Sub", vec![ty_tp(Nat), ty_tp(Nat)])); .push(poly("Add", vec![ty_tp(Nat), ty_tp(Nat)]));
nat.super_traits.push(poly("Mul", vec![ty_tp(Nat), ty_tp(Nat)])); nat.super_traits
nat.super_traits.push(poly("Div", vec![ty_tp(Nat), ty_tp(Ratio)])); .push(poly("Sub", vec![ty_tp(Nat), ty_tp(Nat)]));
let mut bool_ = Self::mono_class("Bool", vec![Nat, Int, Obj], vec![ nat.super_traits
.push(poly("Mul", vec![ty_tp(Nat), ty_tp(Nat)]));
nat.super_traits
.push(poly("Div", vec![ty_tp(Nat), ty_tp(Ratio)]));
let mut bool_ = Self::mono_class(
"Bool",
vec![Nat, Int, Obj],
vec![
mono("Num"), mono("Num"),
mono("Rational"), mono("Integral"), mono("Rational"),
mono("Ord"), mono("Eq"), mono("Integral"),
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"), mono("Ord"),
mono("Eq"),
mono("Add"),
mono("Sub"),
mono("Mul"),
mono("Div"),
mono("Mutate"), mono("Mutate"),
Obj, Obj,
], Self::TOP_LEVEL); ],
Self::TOP_LEVEL,
);
bool_.register_impl("__and__", fn1_met(Bool, Bool, Bool), Const, Public); bool_.register_impl("__and__", fn1_met(Bool, Bool, Bool), Const, Public);
bool_.register_impl("__or__", fn1_met(Bool, Bool, Bool), Const, Public); bool_.register_impl("__or__", fn1_met(Bool, Bool, Bool), Const, Public);
let mut str_ = Self::mono_class("Str", vec![Obj], vec![ let mut str_ = Self::mono_class(
mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(Str)]), "Str",
], Self::TOP_LEVEL); vec![Obj],
vec![mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(Str)])],
Self::TOP_LEVEL,
);
str_.register_impl("__add__", fn1_met(Str, Str, Str), Const, Public); str_.register_impl("__add__", fn1_met(Str, Str, Str), Const, Public);
str_.register_impl("replace", Type::fn_met( str_.register_impl(
"replace",
Type::fn_met(
Str, Str,
vec![param_t("pat", Str), param_t("into", Str)], vec![param_t("pat", Str), param_t("into", Str)],
vec![], Str), vec![],
Str,
),
Immutable, Immutable,
Public Public,
);
str_.super_traits
.push(poly("Add", vec![ty_tp(Str), ty_tp(Str)]));
let mut array = Self::poly_class(
"Array",
vec![PS::t_nd("T"), PS::named_nd("N", Nat)],
vec![Obj],
vec![
mono("Eq"),
mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]),
poly("Output", vec![ty_tp(mono_q("T"))]),
],
Self::TOP_LEVEL,
); );
str_.super_traits.push(poly("Add", vec![ty_tp(Str), ty_tp(Str)]));
let mut array = Self::poly_class("Array", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], vec![Obj], vec![
mono("Eq"), mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))])
], Self::TOP_LEVEL);
let n = mono_q_tp("N"); let n = mono_q_tp("N");
let m = mono_q_tp("M"); let m = mono_q_tp("M");
let array_t = Type::array(mono_q("T"), n.clone()); let array_t = Type::array(mono_q("T"), n.clone());
@ -272,37 +402,77 @@ impl Context {
array_t.clone(), array_t.clone(),
vec![param_t("rhs", Type::array(mono_q("T"), m.clone()))], vec![param_t("rhs", Type::array(mono_q("T"), m.clone()))],
vec![], vec![],
Type::array(mono_q("T"), n + m) Type::array(mono_q("T"), n + m),
);
let t = quant(
t,
set! {static_instance("N", Nat), static_instance("M", Nat)},
); );
let t = quant(t, set!{static_instance("N", Nat), static_instance("M", Nat)});
array.register_impl("concat", t, Immutable, Public); array.register_impl("concat", t, Immutable, Public);
let mut_type = ConstObj::t(Type::poly("Array!", vec![ let mut_type = ConstObj::t(Type::poly(
TyParam::t(mono_q("T")), "Array!",
TyParam::mono_q("N").mutate(), vec![TyParam::t(mono_q("T")), TyParam::mono_q("N").mutate()],
])); ));
// [T; N].MutType! = [T; !N] (neither [T!; N] nor [T; N]!) // [T; N].MutType! = [T; !N] (neither [T!; N] nor [T; N]!)
array.register_const("MutType!", mut_type); array.register_const("MutType!", mut_type);
let mut type_ = Self::mono_class("Type", vec![Obj], vec![mono("Eq"), mono("Named")], Self::TOP_LEVEL); let mut type_ = Self::mono_class(
type_.register_impl("mro", Type::array(Type, TyParam::erased(Nat)), Immutable, Public); "Type",
let module = Self::mono_class("Module", vec![Obj], vec![mono("Eq"), mono("Named")], Self::TOP_LEVEL); vec![Obj],
vec![mono("Eq"), mono("Named")],
Self::TOP_LEVEL,
);
type_.register_impl(
"mro",
Type::array(Type, TyParam::erased(Nat)),
Immutable,
Public,
);
let module = Self::mono_class(
"Module",
vec![Obj],
vec![mono("Eq"), mono("Named")],
Self::TOP_LEVEL,
);
let array_mut_t = Type::poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N")]); let array_mut_t = Type::poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N")]);
let mut array_mut = Self::poly_class("Array!", vec![PS::t_nd("T"), PS::named_nd("N", NatMut)], vec![Obj], vec![ let mut array_mut = Self::poly_class(
mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(mono_q("T"))]) "Array!",
], Self::TOP_LEVEL); vec![PS::t_nd("T"), PS::named_nd("N", NatMut)],
vec![Obj],
vec![
mono("Eq"),
mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]),
],
Self::TOP_LEVEL,
);
let t = Type::pr_met( let t = Type::pr_met(
Type::ref_mut(array_mut_t.clone()), Type::ref_mut(array_mut_t.clone()),
Some(Type::ref_mut(poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N") + value(1)]))), Some(Type::ref_mut(poly(
"Array!",
vec![TyParam::t(mono_q("T")), mono_q_tp("N") + value(1)],
))),
vec![param_t("elem", mono_q("T"))], vec![param_t("elem", mono_q("T"))],
vec![], vec![],
Type::NoneType, Type::NoneType,
); );
let t = quant(t, set!{static_instance("T", Type), static_instance("N", NatMut)}); let t = quant(
t,
set! {static_instance("T", Type), static_instance("N", NatMut)},
);
array_mut.register_impl("push!", t, Immutable, Public); array_mut.register_impl("push!", t, Immutable, Public);
let range_t = Type::poly("Range", vec![TyParam::t(mono_q("T"))]); let range_t = Type::poly("Range", vec![TyParam::t(mono_q("T"))]);
let range = Self::poly_class("Range", vec![PS::t_nd("T")], vec![Obj], vec![ let range = Self::poly_class(
mono("Eq"), mono("Mutate"), "Range",
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))]) vec![PS::t_nd("T")],
], Self::TOP_LEVEL); vec![Obj],
vec![
mono("Eq"),
mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]),
poly("Output", vec![ty_tp(mono_q("T"))]),
],
Self::TOP_LEVEL,
);
self.register_type(Obj, obj, Const); self.register_type(Obj, obj, Const);
// self.register_type(Type::mono("Record"), vec![], record, Const); // self.register_type(Type::mono("Record"), vec![], record, Const);
// self.register_type(Type::mono("Class"), vec![], class, Const); // self.register_type(Type::mono("Class"), vec![], class, Const);
@ -321,23 +491,34 @@ impl Context {
fn init_builtin_funcs(&mut self) { fn init_builtin_funcs(&mut self) {
let t_abs = nd_func(vec![param_t("n", mono("Num"))], Nat); let t_abs = nd_func(vec![param_t("n", mono("Num"))], Nat);
let t_assert = func(vec![param_t("condition", Bool)], vec![param_t("err_message", Str)], NoneType); let t_assert = func(
vec![param_t("condition", Bool)],
vec![param_t("err_message", Str)],
NoneType,
);
let t_classof = nd_func(vec![param_t("o", Obj)], Type::option(Class)); let t_classof = nd_func(vec![param_t("o", Obj)], Type::option(Class));
let t_compile = nd_func(vec![param_t("src", Str)], Code); let t_compile = nd_func(vec![param_t("src", Str)], Code);
let t_cond = nd_func( let t_cond = nd_func(
vec![param_t("condition", Bool), param_t("then", mono_q("T")), param_t("else", mono_q("T"))], vec![
param_t("condition", Bool),
param_t("then", mono_q("T")),
param_t("else", mono_q("T")),
],
mono_q("T"), mono_q("T"),
); );
let t_cond = quant(t_cond, set!{static_instance("T", Type)}); let t_cond = quant(t_cond, set! {static_instance("T", Type)});
let t_discard = nd_func(vec![param_t("o", Obj)], NoneType); let t_discard = nd_func(vec![param_t("o", Obj)], NoneType);
let t_id = nd_func(vec![param_t("o", Obj)], Nat); let t_id = nd_func(vec![param_t("o", Obj)], Nat);
// FIXME: quantify // FIXME: quantify
let t_if = func( let t_if = func(
vec![param_t("cond", Bool), param_t("then", nd_func(vec![], mono_q("T")))], vec![
param_t("cond", Bool),
param_t("then", nd_func(vec![], mono_q("T"))),
],
vec![param_t("else", nd_func(vec![], mono_q("T")))], vec![param_t("else", nd_func(vec![], mono_q("T")))],
Type::option(mono_q("T")), Type::option(mono_q("T")),
); );
let t_if = quant(t_if, set!{static_instance("T", Type)}); let t_if = quant(t_if, set! {static_instance("T", Type)});
let t_import = nd_func(vec![param_t("path", Str)], Module); let t_import = nd_func(vec![param_t("path", Str)], Module);
let t_log = nd_func(vec![param_t("objs", Type::var_args(Obj))], NoneType); let t_log = nd_func(vec![param_t("objs", Type::var_args(Obj))], NoneType);
let t_pyimport = nd_func(vec![param_t("path", Str)], Module); let t_pyimport = nd_func(vec![param_t("path", Str)], Module);
@ -348,7 +529,7 @@ impl Context {
self.register_impl("compile", t_compile, Const, Private); self.register_impl("compile", t_compile, Const, Private);
self.register_impl("cond", t_cond, Const, Private); self.register_impl("cond", t_cond, Const, Private);
self.register_impl("discard", t_discard, Const, Private); self.register_impl("discard", t_discard, Const, Private);
self.register_impl("id" , t_id, Const, Private); self.register_impl("id", t_id, Const, Private);
self.register_impl("if", t_if, Const, Private); self.register_impl("if", t_if, Const, Private);
self.register_impl("log", t_log, Const, Private); self.register_impl("log", t_log, Const, Private);
self.register_impl("import", t_import, Const, Private); self.register_impl("import", t_import, Const, Private);
@ -357,17 +538,35 @@ impl Context {
} }
fn init_builtin_procs(&mut self) { fn init_builtin_procs(&mut self) {
let t_print = nd_proc(vec![param_t("objs", Type::var_args(Type::refer(Obj)))], NoneType); let t_print = nd_proc(
vec![param_t("objs", Type::var_args(Type::refer(Obj)))],
NoneType,
);
let t_input = nd_proc(vec![param_t("msg", Str)], Str); let t_input = nd_proc(vec![param_t("msg", Str)], Str);
let t_if = proc( let t_if = proc(
vec![param_t("cond", Bool), param_t("then", nd_proc(vec![], mono_q("T")))], vec![
param_t("cond", Bool),
param_t("then", nd_proc(vec![], mono_q("T"))),
],
vec![param_t("else", nd_proc(vec![], mono_q("T")))], vec![param_t("else", nd_proc(vec![], mono_q("T")))],
Type::option(mono_q("T")) Type::option(mono_q("T")),
);
let t_if = quant(t_if, set! {static_instance("T", Type)});
let t_for = nd_proc(
vec![
param_t("iter", Type::iter(mono_q("T"))),
param_t("p", nd_proc(vec![anon(mono_q("T"))], NoneType)),
],
NoneType,
);
let t_for = quant(t_for, set! {static_instance("T", Type)});
let t_while = nd_proc(
vec![
param_t("cond", BoolMut),
param_t("p", nd_proc(vec![], NoneType)),
],
NoneType,
); );
let t_if = quant(t_if, set!{static_instance("T", Type)});
let t_for = nd_proc(vec![param_t("iter", Type::iter(mono_q("T"))), param_t("p", nd_proc(vec![anon(mono_q("T"))], NoneType))], NoneType);
let t_for = quant(t_for, set!{static_instance("T", Type)});
let t_while = nd_proc(vec![param_t("cond", BoolMut), param_t("p", nd_proc(vec![], NoneType))], NoneType);
self.register_impl("print!", t_print, Const, Private); self.register_impl("print!", t_print, Const, Private);
self.register_impl("input!", t_input, Const, Private); self.register_impl("input!", t_input, Const, Private);
self.register_impl("if!", t_if, Const, Private); self.register_impl("if!", t_if, Const, Private);
@ -382,41 +581,47 @@ impl Context {
let o = mono_q("O"); let o = mono_q("O");
let params = vec![mono_q_tp("R"), mono_q_tp("O")]; let params = vec![mono_q_tp("R"), mono_q_tp("O")];
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), o.clone());
let op_t = quant(op_t, set!{ let op_t = quant(
op_t,
set! {
static_instance("R", Type), static_instance("R", Type),
static_instance("O", Type), static_instance("O", Type),
subtype(l.clone(), poly("Add", params.clone())) subtype(l.clone(), poly("Add", params.clone()))
}); },
);
self.register_impl("__add__", op_t, Const, Private); self.register_impl("__add__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), o.clone());
let op_t = quant(op_t, set!{ let op_t = quant(
op_t,
set! {
static_instance("R", Type), static_instance("R", Type),
static_instance("O", Type), static_instance("O", Type),
subtype(l.clone(), poly("Sub", params.clone())) subtype(l.clone(), poly("Sub", params.clone()))
}); },
);
self.register_impl("__sub__", op_t, Const, Private); self.register_impl("__sub__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), o.clone());
let op_t = quant(op_t, set!{subtype(l.clone(), poly("Mul", params.clone()))}); let op_t = quant(op_t, set! {subtype(l.clone(), poly("Mul", params.clone()))});
self.register_impl("__mul__", op_t, Const, Private); self.register_impl("__mul__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), o.clone());
let op_t = quant(op_t, set!{subtype(l, poly("Mul", params.clone()))}); let op_t = quant(op_t, set! {subtype(l, poly("Mul", params.clone()))});
self.register_impl("__div__", op_t, Const, Private); self.register_impl("__div__", op_t, Const, Private);
let m = mono_q("M"); let m = mono_q("M");
let op_t = Type::func2(m.clone(), m.clone(), m.clone()); let op_t = Type::func2(m.clone(), m.clone(), m.clone());
let op_t = quant(op_t, set!{subtype(m, poly("Mul", vec![]))}); let op_t = quant(op_t, set! {subtype(m, poly("Mul", vec![]))});
self.register_impl("__pow__", op_t, Const, Private); self.register_impl("__pow__", op_t, Const, Private);
let d = mono_q("D"); let d = mono_q("D");
let op_t = Type::func2(d.clone(), d.clone(), d.clone()); let op_t = Type::func2(d.clone(), d.clone(), d.clone());
let op_t = quant(op_t, set!{subtype(d, poly("Div", vec![]))}); let op_t = quant(op_t, set! {subtype(d, poly("Div", vec![]))});
self.register_impl("__mod__", op_t, Const, Private); self.register_impl("__mod__", op_t, Const, Private);
let e = mono_q("E"); let e = mono_q("E");
let op_t = Type::func2(e.clone(), e.clone(), Bool); let op_t = Type::func2(e.clone(), e.clone(), Bool);
let op_t = quant(op_t, set!{subtype(e, poly("Eq", vec![]))}); let op_t = quant(op_t, set! {subtype(e, poly("Eq", vec![]))});
self.register_impl("__eq__", op_t.clone(), Const, Private); self.register_impl("__eq__", op_t.clone(), Const, Private);
self.register_impl("__ne__", op_t, Const, Private); self.register_impl("__ne__", op_t, Const, Private);
let o = mono_q("O"); let o = mono_q("O");
let op_t = Type::func2(o.clone(), o.clone(), Bool); let op_t = Type::func2(o.clone(), o.clone(), Bool);
let op_t = quant(op_t, set!{subtype(o, poly("Ord", vec![]))}); let op_t = quant(op_t, set! {subtype(o, poly("Ord", vec![]))});
self.register_impl("__lt__", op_t.clone(), Const, Private); self.register_impl("__lt__", op_t.clone(), Const, Private);
self.register_impl("__le__", op_t.clone(), Const, Private); self.register_impl("__le__", op_t.clone(), Const, Private);
self.register_impl("__gt__", op_t.clone(), Const, Private); self.register_impl("__gt__", op_t.clone(), Const, Private);
@ -427,18 +632,18 @@ impl Context {
// TODO: Boolの+/-は警告を出したい // TODO: Boolの+/-は警告を出したい
let n = mono_q("N"); let n = mono_q("N");
let op_t = fn0_met(n.clone(), n.clone()); let op_t = fn0_met(n.clone(), n.clone());
let op_t = quant(op_t, set!{subtype(n, mono("Num"))}); let op_t = quant(op_t, set! {subtype(n, mono("Num"))});
self.register_decl("__pos__", op_t.clone(), Private); self.register_decl("__pos__", op_t.clone(), Private);
self.register_decl("__neg__", op_t, Private); self.register_decl("__neg__", op_t, Private);
let t = mono_q("T"); let t = mono_q("T");
let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone())); let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone()));
let op_t = quant(op_t, set!{subtype(t, mono("Ord"))}); let op_t = quant(op_t, set! {subtype(t, mono("Ord"))});
self.register_decl("__rng__", op_t.clone(), Private); self.register_decl("__rng__", op_t.clone(), Private);
self.register_decl("__lorng__", op_t.clone(), Private); self.register_decl("__lorng__", op_t.clone(), Private);
self.register_decl("__rorng__", op_t.clone(), Private); self.register_decl("__rorng__", op_t.clone(), Private);
self.register_decl("__orng__", op_t, Private); self.register_decl("__orng__", op_t, Private);
let op_t = Type::func1(mono_q("T"), Type::mono_proj(mono_q("T"), "MutType!")); let op_t = Type::func1(mono_q("T"), Type::mono_proj(mono_q("T"), "MutType!"));
let op_t = quant(op_t, set!{subtype(mono_q("T"), mono("Mutate"))}); let op_t = quant(op_t, set! {subtype(mono_q("T"), mono("Mutate"))});
self.register_impl("__mutate__", op_t, Const, Private); self.register_impl("__mutate__", op_t, Const, Private);
} }
@ -448,24 +653,44 @@ impl Context {
let o = mono_q_tp("O"); let o = mono_q_tp("O");
let p = mono_q_tp("P"); let p = mono_q_tp("P");
let params = vec![ let params = vec![
PS::named_nd("M", Int), PS::named_nd("N", Int), PS::named_nd("M", Int),
PS::named_nd("O", Int), PS::named_nd("P", Int), PS::named_nd("N", Int),
PS::named_nd("O", Int),
PS::named_nd("P", Int),
]; ];
// Interval is a bounding patch connecting M..N and (Add(O..P, M+O..N..P), Sub(O..P, M-P..N-O)) // Interval is a bounding patch connecting M..N and (Add(O..P, M+O..N..P), Sub(O..P, M-P..N-O))
let mut interval = Self::poly_patch("Interval", params, vec![Type::from(&m..=&n)], vec![ let mut interval = Self::poly_patch(
poly("Add", vec![TyParam::from(&o..=&p), TyParam::from(m.clone() + o.clone() ..= n.clone() + p.clone())]), "Interval",
poly("Sub", vec![TyParam::from(&o..=&p), TyParam::from(m.clone() - p.clone() ..= n.clone() - o.clone())]), params,
], Self::TOP_LEVEL); vec![Type::from(&m..=&n)],
vec![
poly(
"Add",
vec![
TyParam::from(&o..=&p),
TyParam::from(m.clone() + o.clone()..=n.clone() + p.clone()),
],
),
poly(
"Sub",
vec![
TyParam::from(&o..=&p),
TyParam::from(m.clone() - p.clone()..=n.clone() - o.clone()),
],
),
],
Self::TOP_LEVEL,
);
let op_t = fn1_met( let op_t = fn1_met(
Type::from(&m..=&n), Type::from(&m..=&n),
Type::from(&o..=&p), Type::from(&o..=&p),
Type::from(m.clone() + o.clone() ..= n.clone() + p.clone()), Type::from(m.clone() + o.clone()..=n.clone() + p.clone()),
); );
interval.register_impl("__add__", op_t, Const, Public); interval.register_impl("__add__", op_t, Const, Public);
let op_t = fn1_met( let op_t = fn1_met(
Type::from(&m..=&n), Type::from(&m..=&n),
Type::from(&o..=&p), Type::from(&o..=&p),
Type::from(m - p ..= n - o), Type::from(m - p..=n - o),
); );
interval.register_impl("__sub__", op_t, Const, Public); interval.register_impl("__sub__", op_t, Const, Public);
self.register_patch("Interval", interval, Const); self.register_patch("Interval", interval, Const);
@ -488,13 +713,30 @@ impl Context {
pub(crate) fn init_py_random_mod() -> Self { pub(crate) fn init_py_random_mod() -> Self {
let mut random = Context::module("random".into(), 10); let mut random = Context::module("random".into(), 10);
random.register_impl("seed!", Type::proc(vec![], vec![ random.register_impl(
"seed!",
Type::proc(
vec![],
vec![
param_t("a", Type::mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray param_t("a", Type::mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
param_t("version", Type::Int), param_t("version", Type::Int),
], NoneType), Immutable, Public); ],
random.register_impl("randint!", nd_proc(vec![param_t("a", Int), param_t("b", Int)], Int), Immutable, Public); NoneType,
let t = nd_proc(vec![param_t("seq", Type::poly("Seq", vec![ty_tp(mono_q("T"))]))], mono_q("T")); ),
let t = quant(t, set!{static_instance("T", Type)}); Immutable,
Public,
);
random.register_impl(
"randint!",
nd_proc(vec![param_t("a", Int), param_t("b", Int)], Int),
Immutable,
Public,
);
let t = nd_proc(
vec![param_t("seq", Type::poly("Seq", vec![ty_tp(mono_q("T"))]))],
mono_q("T"),
);
let t = quant(t, set! {static_instance("T", Type)});
random.register_impl("choice!", t, Immutable, Public); random.register_impl("choice!", t, Immutable, Public);
random random
} }

View file

@ -12,7 +12,7 @@ pub mod hir;
pub mod initialize; pub mod initialize;
pub mod lower; pub mod lower;
pub use lower::ASTLowerer; pub use lower::ASTLowerer;
pub mod context;
pub mod optimize; pub mod optimize;
pub mod ownercheck; pub mod ownercheck;
pub mod context;
pub mod varinfo; pub mod varinfo;

View file

@ -1,21 +1,21 @@
//! implements `ASTLowerer`. //! implements `ASTLowerer`.
//! //!
//! ASTLowerer(ASTからHIRへの変換器)を実装 //! ASTLowerer(ASTからHIRへの変換器)を実装
use erg_common::{switch_lang, log, fn_name};
use erg_common::color::{GREEN, RED, RESET}; use erg_common::color::{GREEN, RED, RESET};
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::traits::{Locational, Stream, HasType};
use erg_common::ty::{Type, ParamTy};
use erg_common::get_hash; use erg_common::get_hash;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ParamTy, Type};
use erg_common::{fn_name, log, switch_lang};
use erg_parser::ast; use erg_parser::ast;
use erg_parser::ast::{AST}; use erg_parser::ast::AST;
use crate::hir;
use crate::hir::{HIR};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::context::{Context, ContextKind, RegistrationMode}; use crate::context::{Context, ContextKind, RegistrationMode};
use crate::varinfo::{Visibility}; use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir;
use crate::hir::HIR;
use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
/// Singleton that checks types of an AST, and convert (lower) it into a HIR /// Singleton that checks types of an AST, and convert (lower) it into a HIR
@ -36,23 +36,31 @@ impl ASTLowerer {
Some(Context::init_builtins()), Some(Context::init_builtins()),
vec![], vec![],
vec![], vec![],
0 0,
), ),
errs: LowerErrors::empty(), errs: LowerErrors::empty(),
warns: LowerWarnings::empty(), warns: LowerWarnings::empty(),
} }
} }
fn return_t_check(&self, loc: Location, name: &str, expect: &Type, found: &Type) -> LowerResult<()> { fn return_t_check(
&self,
loc: Location,
name: &str,
expect: &Type,
found: &Type,
) -> LowerResult<()> {
self.mod_ctx self.mod_ctx
.unify(expect, found, Some(loc), None) .unify(expect, found, Some(loc), None)
.or_else(|_| Err(LowerError::type_mismatch_error( .or_else(|_| {
Err(LowerError::type_mismatch_error(
loc, loc,
self.mod_ctx.caused_by(), self.mod_ctx.caused_by(),
name, name,
expect, expect,
found, found,
))) ))
})
} }
fn use_check(&self, expr: hir::Expr, mode: &str) -> LowerResult<hir::Expr> { fn use_check(&self, expr: hir::Expr, mode: &str) -> LowerResult<hir::Expr> {
@ -65,10 +73,13 @@ impl ASTLowerer {
"the evaluation result of the expression is not used", "the evaluation result of the expression is not used",
"式の評価結果が使われていません", "式の評価結果が使われていません",
), ),
Some(switch_lang!( Some(
switch_lang!(
"if you don't use the value, use `discard` function", "if you don't use the value, use `discard` function",
"値を使わない場合は、discard関数を使用してください", "値を使わない場合は、discard関数を使用してください",
).into()) )
.into(),
),
)) ))
} else { } else {
Ok(expr) Ok(expr)
@ -83,7 +94,13 @@ impl ASTLowerer {
fn lower_array(&mut self, array: ast::Array, check: bool) -> LowerResult<hir::Array> { fn lower_array(&mut self, array: ast::Array, check: bool) -> LowerResult<hir::Array> {
log!("[DEBUG] entered {}({array})", fn_name!()); log!("[DEBUG] entered {}({array})", fn_name!());
let mut hir_array = hir::Array::new(array.l_sqbr, array.r_sqbr, self.mod_ctx.level, hir::Args::empty(), None); let mut hir_array = hir::Array::new(
array.l_sqbr,
array.r_sqbr,
self.mod_ctx.level,
hir::Args::empty(),
None,
);
for elem in array.elems.into_iters().0 { for elem in array.elems.into_iters().0 {
hir_array.push(self.lower_expr(elem.expr, check)?); hir_array.push(self.lower_expr(elem.expr, check)?);
} }
@ -100,19 +117,24 @@ impl ASTLowerer {
self.mod_ctx.get_local_t(&n.symbol, &self.mod_ctx.name)?, self.mod_ctx.get_local_t(&n.symbol, &self.mod_ctx.name)?,
self.mod_ctx.get_local_uniq_obj_name(&n.symbol), self.mod_ctx.get_local_uniq_obj_name(&n.symbol),
) )
} else { (Type::ASTOmitted, None) }; } else {
(Type::ASTOmitted, None)
};
let acc = hir::Accessor::Local(hir::Local::new(n.symbol, __name__, t)); let acc = hir::Accessor::Local(hir::Local::new(n.symbol, __name__, t));
Ok(acc) Ok(acc)
} }
ast::Accessor::Attr(a) => { ast::Accessor::Attr(a) => {
let obj = self.lower_expr(*a.obj, true)?; let obj = self.lower_expr(*a.obj, true)?;
let t = if check { let t = if check {
self.mod_ctx.get_attr_t(&obj, &a.name.symbol, &self.mod_ctx.name)? self.mod_ctx
} else { Type::ASTOmitted }; .get_attr_t(&obj, &a.name.symbol, &self.mod_ctx.name)?
} else {
Type::ASTOmitted
};
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, a.name.symbol, t)); let acc = hir::Accessor::Attr(hir::Attribute::new(obj, a.name.symbol, t));
Ok(acc) Ok(acc)
} }
_ => todo!() _ => todo!(),
} }
} }
@ -122,7 +144,9 @@ impl ASTLowerer {
let lhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?); let lhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
let rhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?); let rhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
let args = [lhs, rhs]; let args = [lhs, rhs];
let t = self.mod_ctx.get_binop_t(&bin.op, &args, &self.mod_ctx.name)?; let t = self
.mod_ctx
.get_binop_t(&bin.op, &args, &self.mod_ctx.name)?;
let mut args = args.into_iter(); let mut args = args.into_iter();
let lhs = args.next().unwrap().expr; let lhs = args.next().unwrap().expr;
let rhs = args.next().unwrap().expr; let rhs = args.next().unwrap().expr;
@ -134,7 +158,9 @@ impl ASTLowerer {
let mut args = unary.args.into_iter(); let mut args = unary.args.into_iter();
let arg = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?); let arg = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
let args = [arg]; let args = [arg];
let t = self.mod_ctx.get_unaryop_t(&unary.op, &args, &self.mod_ctx.name)?; let t = self
.mod_ctx
.get_unaryop_t(&unary.op, &args, &self.mod_ctx.name)?;
let mut args = args.into_iter(); let mut args = args.into_iter();
let expr = args.next().unwrap().expr; let expr = args.next().unwrap().expr;
Ok(hir::UnaryOp::new(unary.op, expr, t)) Ok(hir::UnaryOp::new(unary.op, expr, t))
@ -143,15 +169,27 @@ impl ASTLowerer {
fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> { fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!("[DEBUG] entered {}({}(...))", fn_name!(), call.obj); log!("[DEBUG] entered {}({}(...))", fn_name!(), call.obj);
let (pos_args, kw_args, paren) = call.args.deconstruct(); let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new(Vec::with_capacity(pos_args.len()), Vec::with_capacity(kw_args.len()), paren); let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
Vec::with_capacity(kw_args.len()),
paren,
);
for arg in pos_args.into_iter() { for arg in pos_args.into_iter() {
hir_args.push_pos(hir::PosArg::new(self.lower_expr(arg.expr, true)?)); hir_args.push_pos(hir::PosArg::new(self.lower_expr(arg.expr, true)?));
} }
for arg in kw_args.into_iter() { for arg in kw_args.into_iter() {
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr, true)?)); hir_args.push_kw(hir::KwArg::new(
arg.keyword,
self.lower_expr(arg.expr, true)?,
));
} }
let mut obj = self.lower_expr(*call.obj, false)?; let mut obj = self.lower_expr(*call.obj, false)?;
let t = self.mod_ctx.get_call_t(&mut obj, hir_args.pos_args(), hir_args.kw_args(), &self.mod_ctx.name)?; let t = self.mod_ctx.get_call_t(
&mut obj,
hir_args.pos_args(),
hir_args.kw_args(),
&self.mod_ctx.name,
)?;
Ok(hir::Call::new(obj, hir_args, t)) Ok(hir::Call::new(obj, hir_args, t))
} }
@ -160,42 +198,80 @@ impl ASTLowerer {
let is_procedural = lambda.is_procedural(); let is_procedural = lambda.is_procedural();
let id = get_hash(&lambda.sig); let id = get_hash(&lambda.sig);
let name = format!("<lambda_{id}>"); let name = format!("<lambda_{id}>");
let kind = if is_procedural { ContextKind::Proc } else { ContextKind::Func }; let kind = if is_procedural {
ContextKind::Proc
} else {
ContextKind::Func
};
self.mod_ctx.grow(&name, kind, Private)?; self.mod_ctx.grow(&name, kind, Private)?;
self.mod_ctx.assign_params(&lambda.sig.params, None) self.mod_ctx
.map_err(|e| { self.pop_append_errs(); e })?; .assign_params(&lambda.sig.params, None)
self.mod_ctx.preregister(lambda.body.ref_payload()) .map_err(|e| {
.map_err(|e| { self.pop_append_errs(); e })?; self.pop_append_errs();
let body = self.lower_block(lambda.body) e
.map_err(|e| { self.pop_append_errs(); e })?; })?;
self.mod_ctx
.preregister(lambda.body.ref_payload())
.map_err(|e| {
self.pop_append_errs();
e
})?;
let body = self.lower_block(lambda.body).map_err(|e| {
self.pop_append_errs();
e
})?;
// impls => named non-default params + named default params + embedded params (will be discarded) // impls => named non-default params + named default params + embedded params (will be discarded)
// unnnamed_params => unnamed non-default params + unnamed default params // unnnamed_params => unnamed non-default params + unnamed default params
// non default params = [unnamed non-default params + unnamed default params].sorted() // sort by pos // non default params = [unnamed non-default params + unnamed default params].sorted() // sort by pos
// default params = [unnamed default params, named default params].sorted() // default params = [unnamed default params, named default params].sorted()
let (named_non_default_params, named_default_params) = { let (named_non_default_params, named_default_params) = {
let (named_default_params, named_non_default_params_and_embeddeds): (Vec<_>, Vec<_>) = self.mod_ctx.impls.iter() let (named_default_params, named_non_default_params_and_embeddeds): (Vec<_>, Vec<_>) =
self.mod_ctx
.impls
.iter()
.filter(|(_, v)| v.kind.is_parameter()) .filter(|(_, v)| v.kind.is_parameter())
.partition(|(_, v)| v.kind.has_default()); .partition(|(_, v)| v.kind.has_default());
let (_, named_non_default_params): (Vec<_>, Vec<_>)= named_non_default_params_and_embeddeds.into_iter() let (_, named_non_default_params): (Vec<_>, Vec<_>) =
named_non_default_params_and_embeddeds
.into_iter()
.partition(|(_, v)| v.kind.is_embedded_param()); .partition(|(_, v)| v.kind.is_embedded_param());
( (
named_non_default_params.into_iter() named_non_default_params
.map(|(n, v)| (v.kind.pos_as_param().unwrap(), ParamTy::new(Some(n.inspect().clone()), v.t()))) .into_iter()
.map(|(n, v)| {
(
v.kind.pos_as_param().unwrap(),
ParamTy::new(Some(n.inspect().clone()), v.t()),
)
})
.collect::<Vec<_>>(),
named_default_params
.into_iter()
.map(|(n, v)| {
(
v.kind.pos_as_param().unwrap(),
ParamTy::new(Some(n.inspect().clone()), v.t()),
)
})
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
named_default_params.into_iter()
.map(|(n, v)| (v.kind.pos_as_param().unwrap(), ParamTy::new(Some(n.inspect().clone()), v.t())))
.collect::<Vec<_>>()
) )
}; };
let (unnamed_non_default_params, unnamed_default_params) = { let (unnamed_non_default_params, unnamed_default_params) = {
let (unnamed_default_params, unnamed_non_default_params): (Vec<_>, Vec<_>) = self.mod_ctx.unnamed_params.iter() let (unnamed_default_params, unnamed_non_default_params): (Vec<_>, Vec<_>) = self
.mod_ctx
.unnamed_params
.iter()
.map(|v| (v, ParamTy::anonymous(v.t()))) .map(|v| (v, ParamTy::anonymous(v.t())))
.partition(|(v, _)| v.kind.has_default()); .partition(|(v, _)| v.kind.has_default());
( (
unnamed_non_default_params.into_iter() unnamed_non_default_params
.map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt)).collect(), .into_iter()
unnamed_default_params.into_iter() .map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt))
.map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt)).collect(), .collect(),
unnamed_default_params
.into_iter()
.map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt))
.collect(),
) )
}; };
let non_default_params = { let non_default_params = {
@ -208,22 +284,32 @@ impl ASTLowerer {
a.sort_by(|(l, _), (r, _)| l.cmp(r)); a.sort_by(|(l, _), (r, _)| l.cmp(r));
a.into_iter().map(|(_, p)| p).collect::<Vec<_>>() a.into_iter().map(|(_, p)| p).collect::<Vec<_>>()
}; };
let bounds = self.mod_ctx.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal) let bounds = self
.map_err(|e| { self.pop_append_errs(); e })?; .mod_ctx
.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)
.map_err(|e| {
self.pop_append_errs();
e
})?;
self.pop_append_errs(); self.pop_append_errs();
let t = if is_procedural { let t = if is_procedural {
Type::proc(non_default_params, default_params, body.t()) Type::proc(non_default_params, default_params, body.t())
} else { } else {
Type::func(non_default_params, default_params, body.t()) Type::func(non_default_params, default_params, body.t())
}; };
let t = if bounds.is_empty() { t } else { Type::quantified(t, bounds) }; let t = if bounds.is_empty() {
t
} else {
Type::quantified(t, bounds)
};
Ok(hir::Lambda::new(id, lambda.sig.params, lambda.op, body, t)) Ok(hir::Lambda::new(id, lambda.sig.params, lambda.op, body, t))
} }
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> { fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
log!("[DEBUG] entered {}({})", fn_name!(), def.sig); log!("[DEBUG] entered {}({})", fn_name!(), def.sig);
// FIXME: Instant // FIXME: Instant
self.mod_ctx.grow(def.sig.name_as_str(), ContextKind::Instant, Private)?; self.mod_ctx
.grow(def.sig.name_as_str(), ContextKind::Instant, Private)?;
let res = match def.sig { let res = match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
@ -233,13 +319,20 @@ impl ASTLowerer {
res res
} }
fn lower_var_def(&mut self, sig: ast::VarSignature, body: ast::DefBody) -> LowerResult<hir::Def> { fn lower_var_def(
&mut self,
sig: ast::VarSignature,
body: ast::DefBody,
) -> LowerResult<hir::Def> {
log!("[DEBUG] entered {}({sig})", fn_name!()); log!("[DEBUG] entered {}({sig})", fn_name!());
self.mod_ctx.preregister(body.block.ref_payload())?; self.mod_ctx.preregister(body.block.ref_payload())?;
let block = self.lower_block(body.block)?; let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t(); let found_body_t = block.ref_t();
let opt_expect_body_t = self.mod_ctx let opt_expect_body_t = self
.outer.as_ref().unwrap() .mod_ctx
.outer
.as_ref()
.unwrap()
.get_current_scope_local_var(sig.inspect().unwrap()) .get_current_scope_local_var(sig.inspect().unwrap())
.map(|vi| vi.t.clone()); .map(|vi| vi.t.clone());
let name = sig.pat.inspect().unwrap(); let name = sig.pat.inspect().unwrap();
@ -250,17 +343,25 @@ impl ASTLowerer {
} }
let id = body.id; let id = body.id;
// TODO: cover all VarPatterns // TODO: cover all VarPatterns
self.mod_ctx.outer.as_mut().unwrap().assign_var(&sig, id, found_body_t)?; self.mod_ctx
.outer
.as_mut()
.unwrap()
.assign_var(&sig, id, found_body_t)?;
match block.first().unwrap() { match block.first().unwrap() {
hir::Expr::Call(call) => { hir::Expr::Call(call) => {
if let ast::VarPattern::VarName(name) = &sig.pat { if let ast::VarPattern::VarName(name) = &sig.pat {
if call.is_import_call() { if call.is_import_call() {
self.mod_ctx.outer.as_mut() self.mod_ctx
.outer
.as_mut()
.unwrap() .unwrap()
.import_mod(name, &call.args.pos_args().first().unwrap().expr)?; .import_mod(name, &call.args.pos_args().first().unwrap().expr)?;
} }
} else { todo!() } } else {
}, todo!()
}
}
_other => {} _other => {}
} }
let sig = hir::VarSignature::new(sig.pat, found_body_t.clone()); let sig = hir::VarSignature::new(sig.pat, found_body_t.clone());
@ -269,27 +370,41 @@ impl ASTLowerer {
} }
// NOTE: 呼ばれている間はinner scopeなので注意 // NOTE: 呼ばれている間はinner scopeなので注意
fn lower_subr_def(&mut self, sig: ast::SubrSignature, body: ast::DefBody) -> LowerResult<hir::Def> { fn lower_subr_def(
&mut self,
sig: ast::SubrSignature,
body: ast::DefBody,
) -> LowerResult<hir::Def> {
log!("[DEBUG] entered {}({sig})", fn_name!()); log!("[DEBUG] entered {}({sig})", fn_name!());
let t = self.mod_ctx let t = self
.outer.as_ref().unwrap() .mod_ctx
.outer
.as_ref()
.unwrap()
.get_current_scope_local_var(sig.name.inspect()) .get_current_scope_local_var(sig.name.inspect())
.unwrap_or_else(|| { .unwrap_or_else(|| {
log!("{}\n", sig.name.inspect()); log!("{}\n", sig.name.inspect());
log!("{}\n", self.mod_ctx.outer.as_ref().unwrap()); log!("{}\n", self.mod_ctx.outer.as_ref().unwrap());
panic!() panic!()
}) // FIXME: or instantiate }) // FIXME: or instantiate
.t.clone(); .t
.clone();
self.mod_ctx.assign_params(&sig.params, None)?; self.mod_ctx.assign_params(&sig.params, None)?;
self.mod_ctx.preregister(body.block.ref_payload())?; self.mod_ctx.preregister(body.block.ref_payload())?;
let block = self.lower_block(body.block)?; let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t(); let found_body_t = block.ref_t();
let expect_body_t = t.return_t().unwrap(); let expect_body_t = t.return_t().unwrap();
if let Err(e) = self.return_t_check(sig.loc(), sig.name.inspect(), expect_body_t, found_body_t) { if let Err(e) =
self.return_t_check(sig.loc(), sig.name.inspect(), expect_body_t, found_body_t)
{
self.errs.push(e); self.errs.push(e);
} }
let id = body.id; let id = body.id;
self.mod_ctx.outer.as_mut().unwrap().assign_subr(&sig, id, found_body_t)?; self.mod_ctx
.outer
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let sig = hir::SubrSignature::new(sig.name, sig.params, t); let sig = hir::SubrSignature::new(sig.name, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
@ -300,30 +415,14 @@ impl ASTLowerer {
fn lower_expr(&mut self, expr: ast::Expr, check: bool) -> LowerResult<hir::Expr> { fn lower_expr(&mut self, expr: ast::Expr, check: bool) -> LowerResult<hir::Expr> {
log!("[DEBUG] entered {}", fn_name!()); log!("[DEBUG] entered {}", fn_name!());
match expr { match expr {
ast::Expr::Lit(lit) => { ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(hir::Literal::from(lit.token))),
Ok(hir::Expr::Lit(hir::Literal::from(lit.token))) ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr, check)?)),
}, ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.lower_acc(acc, check)?)),
ast::Expr::Array(arr) => { ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)),
Ok(hir::Expr::Array(self.lower_array(arr, check)?)) ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
} ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)),
ast::Expr::Accessor(acc) => { ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
Ok(hir::Expr::Accessor(self.lower_acc(acc, check)?)) ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
}
ast::Expr::BinOp(bin) => {
Ok(hir::Expr::BinOp(self.lower_bin(bin)?))
}
ast::Expr::UnaryOp(unary) => {
Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?))
}
ast::Expr::Call(call) => {
Ok(hir::Expr::Call(self.lower_call(call)?))
}
ast::Expr::Lambda(lambda) => {
Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?))
}
ast::Expr::Def(def) => {
Ok(hir::Expr::Def(self.lower_def(def)?))
}
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
@ -343,14 +442,24 @@ impl ASTLowerer {
let mut module = hir::Module::with_capacity(ast.module.len()); let mut module = hir::Module::with_capacity(ast.module.len());
self.mod_ctx.preregister(ast.module.ref_payload())?; self.mod_ctx.preregister(ast.module.ref_payload())?;
for expr in ast.module.into_iter() { for expr in ast.module.into_iter() {
match self.lower_expr(expr, true) match self
.and_then(|e| self.use_check(e, mode)) { .lower_expr(expr, true)
Ok(expr) => { module.push(expr); } .and_then(|e| self.use_check(e, mode))
Err(e) => { self.errs.push(e); }, {
Ok(expr) => {
module.push(expr);
}
Err(e) => {
self.errs.push(e);
}
} }
} }
let hir = HIR::new(ast.name, module); let hir = HIR::new(ast.name, module);
log!("[DEBUG] {}() has completed, found errors: {}", fn_name!(), self.errs.len()); log!(
"[DEBUG] {}() has completed, found errors: {}",
fn_name!(),
self.errs.len()
);
if self.errs.is_empty() { if self.errs.is_empty() {
log!("HIR:\n{hir}"); log!("HIR:\n{hir}");
log!("[DEBUG] the type-checking process has completed.{RESET}"); log!("[DEBUG] the type-checking process has completed.{RESET}");

View file

@ -4,8 +4,8 @@ extern crate erg_parser;
use std::process; use std::process;
use erg_common::config::ErgConfig;
use erg_common::deserialize::Deserializer; use erg_common::deserialize::Deserializer;
use erg_common::config::{ErgConfig};
use erg_common::traits::Runnable; use erg_common::traits::Runnable;
use erg_compiler::Compiler; use erg_compiler::Compiler;
@ -16,10 +16,18 @@ use erg_parser::ParserRunner;
fn main() { fn main() {
let cfg = ErgConfig::parse(); let cfg = ErgConfig::parse();
match cfg.mode { match cfg.mode {
"lex" => { LexerRunner::run(cfg); } "lex" => {
"parse" => { ParserRunner::run(cfg); } LexerRunner::run(cfg);
"compile" | "exec" => { Compiler::run(cfg); } }
"read" => { Deserializer::run(cfg); } "parse" => {
ParserRunner::run(cfg);
}
"compile" | "exec" => {
Compiler::run(cfg);
}
"read" => {
Deserializer::run(cfg);
}
other => { other => {
println!("invalid mode: {other}"); println!("invalid mode: {other}");
process::exit(1); process::exit(1);

View file

@ -1,15 +1,17 @@
use crate::error::CompileWarnings;
use crate::hir::HIR; use crate::hir::HIR;
use crate::error::{CompileWarnings};
#[derive(Debug)] #[derive(Debug)]
pub struct HIROptimizer { pub struct HIROptimizer {}
}
impl HIROptimizer { impl HIROptimizer {
pub fn fold_constants(&mut self, mut _hir: HIR) -> HIR { todo!() } pub fn fold_constants(&mut self, mut _hir: HIR) -> HIR {
todo!()
}
pub fn eliminate_unused_variables(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) { todo!() } pub fn eliminate_unused_variables(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) {
todo!()
}
pub fn eliminate_dead_code(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) { pub fn eliminate_dead_code(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) {
todo!() todo!()

View file

@ -1,14 +1,14 @@
use erg_common::Str;
use erg_common::{log};
use erg_common::color::{GREEN, RESET}; use erg_common::color::{GREEN, RESET};
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::log;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{Stream, Locational, HasType}; use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ArgsOwnership, Ownership}; use erg_common::ty::{ArgsOwnership, Ownership};
use erg_common::Str;
use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult}; use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult};
use crate::hir::{HIR, Def, Signature, Accessor, Block, Expr}; use crate::hir::{Accessor, Block, Def, Expr, Signature, HIR};
use crate::varinfo::Visibility; use crate::varinfo::Visibility;
use Visibility::*; use Visibility::*;
@ -42,8 +42,14 @@ impl OwnershipChecker {
} }
fn full_path(&self) -> String { fn full_path(&self) -> String {
self.path_stack.iter().fold(String::new(), |acc, (path, vis)| { self.path_stack
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] } .iter()
.fold(String::new(), |acc, (path, vis)| {
if vis.is_public() {
acc + "." + &path[..]
} else {
acc + "::" + &path[..]
}
}) })
} }
@ -52,11 +58,15 @@ impl OwnershipChecker {
pub fn check(mut self, hir: HIR) -> OwnershipResult<HIR> { pub fn check(mut self, hir: HIR) -> OwnershipResult<HIR> {
log!("{GREEN}[DEBUG] the ownership checking process has started.{RESET}"); log!("{GREEN}[DEBUG] the ownership checking process has started.{RESET}");
self.path_stack.push((hir.name.clone(), Private)); self.path_stack.push((hir.name.clone(), Private));
self.dict.insert(Str::from(self.full_path()), LocalVars::default()); self.dict
.insert(Str::from(self.full_path()), LocalVars::default());
for chunk in hir.module.iter() { for chunk in hir.module.iter() {
self.check_expr(chunk, Ownership::Owned); self.check_expr(chunk, Ownership::Owned);
} }
log!("{GREEN}[DEBUG] the ownership checking process has completed, found errors: {}{RESET}", self.errs.len()); log!(
"{GREEN}[DEBUG] the ownership checking process has completed, found errors: {}{RESET}",
self.errs.len()
);
if self.errs.is_empty() { if self.errs.is_empty() {
Ok(hir) Ok(hir)
} else { } else {
@ -77,18 +87,26 @@ impl OwnershipChecker {
let name_and_vis = match &def.sig { let name_and_vis = match &def.sig {
Signature::Var(var) => Signature::Var(var) =>
// TODO: visibility // TODO: visibility
if let Some(name) = var.inspect() { (name.clone(), Private) } {
else { (Str::ever("::<instant>"), Private) }, if let Some(name) = var.inspect() {
(name.clone(), Private)
} else {
(Str::ever("::<instant>"), Private)
}
}
Signature::Subr(subr) => (subr.name.inspect().clone(), Private), Signature::Subr(subr) => (subr.name.inspect().clone(), Private),
}; };
self.path_stack.push(name_and_vis); self.path_stack.push(name_and_vis);
self.dict.insert(Str::from(self.full_path()), LocalVars::default()); self.dict
.insert(Str::from(self.full_path()), LocalVars::default());
self.check_block(&def.body.block); self.check_block(&def.body.block);
self.path_stack.pop(); self.path_stack.pop();
}, }
Expr::Accessor(Accessor::Local(local)) => { Expr::Accessor(Accessor::Local(local)) => {
for n in 0..self.path_stack.len() { for n in 0..self.path_stack.len() {
if let Some(moved_loc) = self.nth_outer_scope(n).dropped_vars.get(local.inspect()) { if let Some(moved_loc) =
self.nth_outer_scope(n).dropped_vars.get(local.inspect())
{
let moved_loc = *moved_loc; let moved_loc = *moved_loc;
self.errs.push(OwnershipError::move_error( self.errs.push(OwnershipError::move_error(
local.inspect(), local.inspect(),
@ -102,34 +120,44 @@ impl OwnershipChecker {
log!("dropped: {}", local.inspect()); log!("dropped: {}", local.inspect());
self.drop(local.inspect(), expr.loc()); self.drop(local.inspect(), expr.loc());
} }
}, }
Expr::Accessor(Accessor::Attr(a)) => { Expr::Accessor(Accessor::Attr(a)) => {
if a.ref_t().is_mut() { todo!("ownership checking {a}") } if a.ref_t().is_mut() {
}, todo!("ownership checking {a}")
}
}
Expr::Accessor(_a) => todo!(), Expr::Accessor(_a) => todo!(),
// TODO: referenced // TODO: referenced
Expr::Call(call) => { Expr::Call(call) => {
self.check_expr(&call.obj, ownership); self.check_expr(&call.obj, ownership);
let args_ownership = call.signature_t().unwrap().args_ownership(); let args_ownership = call.signature_t().unwrap().args_ownership();
match args_ownership { match args_ownership {
ArgsOwnership::Args{ self_, non_defaults, defaults } => { ArgsOwnership::Args {
self_,
non_defaults,
defaults,
} => {
if let Some(ownership) = self_ { if let Some(ownership) = self_ {
self.check_expr(&call.obj, ownership); self.check_expr(&call.obj, ownership);
} }
let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults.iter() let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults
.iter()
.enumerate() .enumerate()
.partition(|(i, _)| *i == call.args.pos_args().len()); .partition(|(i, _)| *i == call.args.pos_args().len());
for (parg, (_, ownership)) in call.args.pos_args() for (parg, (_, ownership)) in
.iter() call.args.pos_args().iter().zip(nd_ownerships.into_iter())
.zip(nd_ownerships.into_iter()) { {
self.check_expr(&parg.expr, *ownership); self.check_expr(&parg.expr, *ownership);
} }
for (kwarg, (_, ownership)) in call.args.kw_args() for (kwarg, (_, ownership)) in call
.args
.kw_args()
.iter() .iter()
.zip(d_ownerships.into_iter().chain(defaults.iter().enumerate())) { .zip(d_ownerships.into_iter().chain(defaults.iter().enumerate()))
{
self.check_expr(&kwarg.expr, *ownership); self.check_expr(&kwarg.expr, *ownership);
} }
}, }
ArgsOwnership::VarArgs(ownership) => { ArgsOwnership::VarArgs(ownership) => {
for parg in call.args.pos_args().iter() { for parg in call.args.pos_args().iter() {
self.check_expr(&parg.expr, ownership); self.check_expr(&parg.expr, ownership);
@ -137,38 +165,39 @@ impl OwnershipChecker {
for kwarg in call.args.kw_args().iter() { for kwarg in call.args.kw_args().iter() {
self.check_expr(&kwarg.expr, ownership); self.check_expr(&kwarg.expr, ownership);
} }
}, }
other => todo!("{other:?}"), other => todo!("{other:?}"),
} }
}, }
// TODO: referenced // TODO: referenced
Expr::BinOp(binop) => { Expr::BinOp(binop) => {
self.check_expr(&binop.lhs, ownership); self.check_expr(&binop.lhs, ownership);
self.check_expr(&binop.rhs, ownership); self.check_expr(&binop.rhs, ownership);
}, }
Expr::UnaryOp(unary) => { Expr::UnaryOp(unary) => {
self.check_expr(&unary.expr, ownership); self.check_expr(&unary.expr, ownership);
}, }
Expr::Array(arr) => { Expr::Array(arr) => {
for a in arr.elems.pos_args().iter() { for a in arr.elems.pos_args().iter() {
self.check_expr(&a.expr, ownership); self.check_expr(&a.expr, ownership);
} }
}, }
Expr::Dict(dict) => { Expr::Dict(dict) => {
for a in dict.attrs.kw_args().iter() { for a in dict.attrs.kw_args().iter() {
// self.check_expr(&a.key); // self.check_expr(&a.key);
self.check_expr(&a.expr, ownership); self.check_expr(&a.expr, ownership);
} }
}, }
// TODO: capturing // TODO: capturing
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let name_and_vis = (Str::from(format!("<lambda_{}>", lambda.id)), Private); let name_and_vis = (Str::from(format!("<lambda_{}>", lambda.id)), Private);
self.path_stack.push(name_and_vis); self.path_stack.push(name_and_vis);
self.dict.insert(Str::from(self.full_path()), LocalVars::default()); self.dict
.insert(Str::from(self.full_path()), LocalVars::default());
self.check_block(&lambda.body); self.check_block(&lambda.body);
self.path_stack.pop(); self.path_stack.pop();
}, }
_ => {}, _ => {}
} }
} }
@ -180,11 +209,16 @@ impl OwnershipChecker {
#[inline] #[inline]
fn nth_outer_scope(&mut self, n: usize) -> &mut LocalVars { fn nth_outer_scope(&mut self, n: usize) -> &mut LocalVars {
let path = self.path_stack.iter() let path = self.path_stack.iter().take(self.path_stack.len() - n).fold(
.take(self.path_stack.len() - n) String::new(),
.fold(String::new(), |acc, (path, vis)| { |acc, (path, vis)| {
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] } if vis.is_public() {
}); acc + "." + &path[..]
} else {
acc + "::" + &path[..]
}
},
);
self.dict.get_mut(&path[..]).unwrap() self.dict.get_mut(&path[..]).unwrap()
} }
@ -194,18 +228,22 @@ impl OwnershipChecker {
for name in sig.pat.inspects() { for name in sig.pat.inspects() {
self.current_scope().alive_vars.insert(name.clone()); self.current_scope().alive_vars.insert(name.clone());
} }
}, }
Signature::Subr(sig) => { Signature::Subr(sig) => {
self.current_scope().alive_vars.insert(sig.name.inspect().clone()); self.current_scope()
}, .alive_vars
.insert(sig.name.inspect().clone());
}
} }
} }
fn drop(&mut self, name: &Str, moved_loc: Location) { fn drop(&mut self, name: &Str, moved_loc: Location) {
for n in 0..self.path_stack.len() { for n in 0..self.path_stack.len() {
if self.nth_outer_scope(n).alive_vars.remove(name) { if self.nth_outer_scope(n).alive_vars.remove(name) {
self.nth_outer_scope(n).dropped_vars.insert(name.clone(), moved_loc); self.nth_outer_scope(n)
return .dropped_vars
.insert(name.clone(), moved_loc);
return;
} }
} }
panic!("variable not found: {name}"); panic!("variable not found: {name}");

View file

@ -1,8 +1,8 @@
use std::fmt; use std::fmt;
use erg_common::Str;
use erg_common::ty::{Type};
use erg_common::traits::HasType; use erg_common::traits::HasType;
use erg_common::ty::Type;
use erg_common::Str;
use erg_parser::ast::DefId; use erg_parser::ast::DefId;
@ -17,12 +17,16 @@ impl From<&str> for Mutability {
fn from(item: &str) -> Self { fn from(item: &str) -> Self {
if item.chars().next().unwrap().is_uppercase() { if item.chars().next().unwrap().is_uppercase() {
Self::Const Self::Const
} else { Self::Immutable } } else {
Self::Immutable
}
} }
} }
impl Mutability { impl Mutability {
pub const fn is_const(&self) -> bool { matches!(self, Self::Const) } pub const fn is_const(&self) -> bool {
matches!(self, Self::Const)
}
} }
use Mutability::*; use Mutability::*;
@ -35,8 +39,12 @@ pub enum Visibility {
} }
impl Visibility { impl Visibility {
pub const fn is_public(&self) -> bool { matches!(self, Self::Public) } pub const fn is_public(&self) -> bool {
pub const fn is_private(&self) -> bool { matches!(self, Self::Private) } matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
} }
use Visibility::*; use Visibility::*;
@ -50,9 +58,9 @@ pub enum ParamId {
PatWithDefault(usize), PatWithDefault(usize),
/// 変数パターン /// 変数パターン
/// e.g. `z` of `f [x, y], z = ...` /// e.g. `z` of `f [x, y], z = ...`
VarNonDefault{ keyword: Str, pos: usize }, VarNonDefault { keyword: Str, pos: usize },
/// e.g. `z` of `f [x, y], z |= 0 = ...` /// e.g. `z` of `f [x, y], z |= 0 = ...`
VarWithDefault{ keyword: Str, pos: usize }, VarWithDefault { keyword: Str, pos: usize },
/// パターンに埋め込まれた変数パターン /// パターンに埋め込まれた変数パターン
/// この場合デフォルト値はない /// この場合デフォルト値はない
/// e.g. `x` or `y` of `f [x, y], z = ...` /// e.g. `x` or `y` of `f [x, y], z = ...`
@ -60,31 +68,37 @@ pub enum ParamId {
} }
impl ParamId { impl ParamId {
pub const fn var_default(keyword: Str, pos: usize) -> Self { Self::VarWithDefault{ keyword, pos } } pub const fn var_default(keyword: Str, pos: usize) -> Self {
pub const fn var_non_default(keyword: Str, pos: usize) -> Self { Self::VarNonDefault{ keyword, pos } } Self::VarWithDefault { keyword, pos }
}
pub const fn var_non_default(keyword: Str, pos: usize) -> Self {
Self::VarNonDefault { keyword, pos }
}
pub const fn pos(&self) -> Option<usize> { pub const fn pos(&self) -> Option<usize> {
match self { match self {
Self::PatNonDefault(pos) Self::PatNonDefault(pos)
| Self::PatWithDefault(pos) | Self::PatWithDefault(pos)
| Self::VarNonDefault{ pos, .. } | Self::VarNonDefault { pos, .. }
| Self::VarWithDefault{ pos, .. } => Some(*pos), | Self::VarWithDefault { pos, .. } => Some(*pos),
_ => None, _ => None,
} }
} }
pub const fn has_default(&self) -> bool { pub const fn has_default(&self) -> bool {
matches!(self, Self::PatWithDefault(_) | Self::VarWithDefault{ .. }) matches!(self, Self::PatWithDefault(_) | Self::VarWithDefault { .. })
} }
pub const fn is_embedded(&self) -> bool { matches!(self, Self::Embedded(_)) } pub const fn is_embedded(&self) -> bool {
matches!(self, Self::Embedded(_))
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum VarKind { pub enum VarKind {
Defined(DefId), Defined(DefId),
Declared, Declared,
Parameter{ def_id: DefId, param_id: ParamId }, Parameter { def_id: DefId, param_id: ParamId },
Generated, Generated,
DoesNotExist, DoesNotExist,
Builtin, Builtin,
@ -92,25 +106,25 @@ pub enum VarKind {
impl VarKind { impl VarKind {
pub const fn parameter(def_id: DefId, param_id: ParamId) -> Self { pub const fn parameter(def_id: DefId, param_id: ParamId) -> Self {
Self::Parameter{ def_id, param_id } Self::Parameter { def_id, param_id }
} }
pub const fn pos_as_param(&self) -> Option<usize> { pub const fn pos_as_param(&self) -> Option<usize> {
match self { match self {
Self::Parameter{ param_id, .. } => param_id.pos(), Self::Parameter { param_id, .. } => param_id.pos(),
_ => None, _ => None,
} }
} }
pub const fn has_default(&self) -> bool { pub const fn has_default(&self) -> bool {
match self { match self {
Self::Parameter{ param_id, .. } => param_id.has_default(), Self::Parameter { param_id, .. } => param_id.has_default(),
_ => false, _ => false,
} }
} }
pub const fn is_parameter(&self) -> bool { pub const fn is_parameter(&self) -> bool {
matches!(self, Self::Parameter{ .. }) matches!(self, Self::Parameter { .. })
} }
pub const fn is_embedded_param(&self) -> bool { pub const fn is_embedded_param(&self) -> bool {
@ -128,19 +142,28 @@ pub struct VarInfo {
impl fmt::Display for VarInfo { impl fmt::Display for VarInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "VarInfo{{t: {}, muty: {:?}, vis: {:?} kind: {:?}}}", self.t, self.muty, self.vis, self.kind) write!(
f,
"VarInfo{{t: {}, muty: {:?}, vis: {:?} kind: {:?}}}",
self.t, self.muty, self.vis, self.kind
)
} }
} }
impl HasType for VarInfo { impl HasType for VarInfo {
#[inline] #[inline]
fn ref_t(&self) -> &Type { &self.t } fn ref_t(&self) -> &Type {
&self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { None } fn signature_t(&self) -> Option<&Type> {
None
}
} }
impl VarInfo { impl VarInfo {
pub const ILLEGAL: &'static Self = &VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist); pub const ILLEGAL: &'static Self =
&VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist);
pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self { pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self {
Self { t, muty, vis, kind } Self { t, muty, vis, kind }
@ -148,7 +171,7 @@ impl VarInfo {
pub fn same_id_as(&self, id: DefId) -> bool { pub fn same_id_as(&self, id: DefId) -> bool {
match self.kind { match self.kind {
VarKind::Defined(i) | VarKind::Parameter{ def_id: i, .. } => id == i, VarKind::Defined(i) | VarKind::Parameter { def_id: i, .. } => id == i,
_ => false, _ => false,
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -5,18 +5,17 @@
//! 型チェックなどによる検証は行わない //! 型チェックなどによる検証は行わない
#![allow(dead_code)] #![allow(dead_code)]
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{enum_unwrap, set}; use erg_common::{enum_unwrap, set};
use erg_common::{Str};
use erg_common::set::{Set};
use erg_common::traits::{Stream, Locational};
use crate::token::{Token, TokenKind};
use crate::ast::{ use crate::ast::{
Module, Expr, Lambda, Call, Def, Accessor, Accessor, Args, Block, Call, Def, DefBody, Expr, Lambda, LambdaSignature, Module,
LambdaSignature, PosArg, Signature, SubrSignature, Args, NonDefaultParamSignature, ParamPattern, Params, PosArg, Signature, SubrSignature,
ParamPattern, NonDefaultParamSignature, Params, VarName, TypeBoundSpecs, VarName, VarPattern,
TypeBoundSpecs, DefBody, Block, VarPattern
}; };
use crate::token::{Token, TokenKind};
#[derive(Debug)] #[derive(Debug)]
pub struct Desugarer { pub struct Desugarer {
@ -24,7 +23,11 @@ pub struct Desugarer {
} }
impl Desugarer { impl Desugarer {
pub fn new() -> Desugarer { Self { desugared: Set::default() } } pub fn new() -> Desugarer {
Self {
desugared: Set::default(),
}
}
pub fn desugar(&mut self, module: Module) -> Module { pub fn desugar(&mut self, module: Module) -> Module {
self.desugar_multiple_pattern_def(module) self.desugar_multiple_pattern_def(module)
@ -42,40 +45,66 @@ impl Desugarer {
match chunk { match chunk {
Expr::Def(def) if def.is_subr() => { Expr::Def(def) if def.is_subr() => {
if let Some(Expr::Def(previous)) = new.last() { if let Some(Expr::Def(previous)) = new.last() {
if previous.is_subr() && previous.sig.name_as_str() == def.sig.name_as_str() { if previous.is_subr() && previous.sig.name_as_str() == def.sig.name_as_str()
{
let mut previous = enum_unwrap!(new.pop().unwrap(), Expr::Def); let mut previous = enum_unwrap!(new.pop().unwrap(), Expr::Def);
let name = def.sig.name().unwrap().clone(); let name = def.sig.name().unwrap().clone();
let op = Token::from_str(TokenKind::FuncArrow, "->"); let op = Token::from_str(TokenKind::FuncArrow, "->");
let (call, return_t_spec) = if previous.body.block.len() == 1 let (call, return_t_spec) = if previous.body.block.len() == 1
&& previous.body.block.first().unwrap().is_match_call() { && previous.body.block.first().unwrap().is_match_call()
let mut call = enum_unwrap!(previous.body.block.remove(0), Expr::Call); {
let mut call =
enum_unwrap!(previous.body.block.remove(0), Expr::Call);
let sig = enum_unwrap!(def.sig, Signature::Subr); let sig = enum_unwrap!(def.sig, Signature::Subr);
let return_t_spec = sig.return_t_spec; let return_t_spec = sig.return_t_spec;
let first_arg = sig.params.non_defaults.first().unwrap(); let first_arg = sig.params.non_defaults.first().unwrap();
// 最後の定義の引数名を関数全体の引数名にする // 最後の定義の引数名を関数全体の引数名にする
if let Some(name) = first_arg.inspect() { if let Some(name) = first_arg.inspect() {
call.args.remove_pos(0); call.args.remove_pos(0);
let arg = PosArg::new(Expr::local(name, first_arg.ln_begin().unwrap(), first_arg.col_begin().unwrap())); let arg = PosArg::new(Expr::local(
name,
first_arg.ln_begin().unwrap(),
first_arg.col_begin().unwrap(),
));
call.args.insert_pos(0, arg); call.args.insert_pos(0, arg);
} }
let sig = LambdaSignature::new(sig.params, return_t_spec.clone(), sig.bounds); let sig = LambdaSignature::new(
sig.params,
return_t_spec.clone(),
sig.bounds,
);
let new_branch = Lambda::new(sig, op, def.body.block, def.body.id); let new_branch = Lambda::new(sig, op, def.body.block, def.body.id);
call.args.push_pos(PosArg::new(Expr::Lambda(new_branch))); call.args.push_pos(PosArg::new(Expr::Lambda(new_branch)));
(call, return_t_spec) (call, return_t_spec)
} else { } else {
let sig = enum_unwrap!(previous.sig, Signature::Subr); let sig = enum_unwrap!(previous.sig, Signature::Subr);
let match_symbol = Expr::static_local("match"); let match_symbol = Expr::static_local("match");
let sig = LambdaSignature::new(sig.params, sig.return_t_spec, sig.bounds); let sig =
let first_branch = Lambda::new(sig, op.clone(), previous.body.block, previous.body.id); LambdaSignature::new(sig.params, sig.return_t_spec, sig.bounds);
let first_branch = Lambda::new(
sig,
op.clone(),
previous.body.block,
previous.body.id,
);
let sig = enum_unwrap!(def.sig, Signature::Subr); let sig = enum_unwrap!(def.sig, Signature::Subr);
let return_t_spec = sig.return_t_spec; let return_t_spec = sig.return_t_spec;
let sig = LambdaSignature::new(sig.params, return_t_spec.clone(), sig.bounds); let sig = LambdaSignature::new(
let second_branch = Lambda::new(sig, op, def.body.block, def.body.id); sig.params,
let args = Args::new(vec![ return_t_spec.clone(),
sig.bounds,
);
let second_branch =
Lambda::new(sig, op, def.body.block, def.body.id);
let args = Args::new(
vec![
PosArg::new(Expr::dummy_local("_")), // dummy argument, will be removed in line 56 PosArg::new(Expr::dummy_local("_")), // dummy argument, will be removed in line 56
PosArg::new(Expr::Lambda(first_branch)), PosArg::new(Expr::Lambda(first_branch)),
PosArg::new(Expr::Lambda(second_branch)) PosArg::new(Expr::Lambda(second_branch)),
], vec![], None); ],
vec![],
None,
);
let call = Call::new(match_symbol, args); let call = Call::new(match_symbol, args);
(call, return_t_spec) (call, return_t_spec)
}; };
@ -85,12 +114,23 @@ impl Desugarer {
TokenKind::Symbol, TokenKind::Symbol,
param_name, param_name,
name.ln_begin().unwrap(), name.ln_begin().unwrap(),
name.col_end().unwrap() + 1 // HACK: `(name) %x = ...`という形を想定 name.col_end().unwrap() + 1, // HACK: `(name) %x = ...`という形を想定
)); ));
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None); let param =
NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
let params = Params::new(vec![param], vec![], None); let params = Params::new(vec![param], vec![], None);
let sig = Signature::Subr(SubrSignature::new(set!{}, name, params, return_t_spec, TypeBoundSpecs::empty())); let sig = Signature::Subr(SubrSignature::new(
let body = DefBody::new(def.body.op, Block::new(vec![Expr::Call(call)]), def.body.id); set! {},
name,
params,
return_t_spec,
TypeBoundSpecs::empty(),
));
let body = DefBody::new(
def.body.op,
Block::new(vec![Expr::Call(call)]),
def.body.id,
);
let def = Def::new(sig, body); let def = Def::new(sig, body);
new.push(Expr::Def(def)); new.push(Expr::Def(def));
} else { } else {
@ -99,8 +139,10 @@ impl Desugarer {
} else { } else {
new.push(Expr::Def(def)); new.push(Expr::Def(def));
} }
}, }
other => { new.push(other); }, other => {
new.push(other);
}
} }
} }
new new
@ -123,13 +165,15 @@ impl Desugarer {
if let Signature::Var(v) = &def.sig { if let Signature::Var(v) = &def.sig {
match &v.pat { match &v.pat {
VarPattern::Array(_a) => {} VarPattern::Array(_a) => {}
VarPattern::Record(_r) => {}, VarPattern::Record(_r) => {}
_ => {} _ => {}
} }
} }
new.push(Expr::Def(def)); new.push(Expr::Def(def));
}, }
other => { new.push(other); }, other => {
new.push(other);
}
} }
} }
new new

View file

@ -1,11 +1,11 @@
//! defines `ParseError` and others. //! defines `ParseError` and others.
//! //!
//! パーサーが出すエラーを定義 //! パーサーが出すエラーを定義
use erg_common::{impl_stream_for_wrapper, switch_lang};
use erg_common::Str;
use erg_common::config::Input; use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorDisplay, MultiErrorDisplay, Location, ErrorKind::*}; 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};
#[derive(Debug)] #[derive(Debug)]
pub struct LexError(ErrorCore); pub struct LexError(ErrorCore);
@ -16,7 +16,9 @@ pub struct LexErrors(Vec<LexError>);
impl_stream_for_wrapper!(LexErrors, LexError); impl_stream_for_wrapper!(LexErrors, LexError);
impl LexError { impl LexError {
pub const fn new(core: ErrorCore) -> Self { Self(core) } pub const fn new(core: ErrorCore) -> Self {
Self(core)
}
pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!( Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!(
@ -26,21 +28,43 @@ impl LexError {
} }
pub fn feature_error(errno: usize, loc: Location, name: &str) -> Self { pub fn feature_error(errno: usize, loc: Location, name: &str) -> Self {
Self::new(ErrorCore::new(errno, FeatureError, loc, switch_lang!( Self::new(ErrorCore::new(
errno,
FeatureError,
loc,
switch_lang!(
format!("this feature({name}) is not implemented yet"), format!("this feature({name}) is not implemented yet"),
format!("この機能({name})はまだ正式に提供されていません") format!("この機能({name})はまだ正式に提供されていません")
), None)) ),
None,
))
} }
pub fn simple_syntax_error(errno: usize, loc: Location) -> Self { pub fn simple_syntax_error(errno: usize, loc: Location) -> Self {
Self::new(ErrorCore::new(errno, SyntaxError, loc, switch_lang!("invalid syntax", "不正な構文です"), None)) Self::new(ErrorCore::new(
errno,
SyntaxError,
loc,
switch_lang!("invalid syntax", "不正な構文です"),
None,
))
} }
pub fn syntax_error<S: Into<Str>>(errno: usize, loc: Location, desc: S, hint: Option<Str>) -> Self { pub fn syntax_error<S: Into<Str>>(
errno: usize,
loc: Location,
desc: S,
hint: Option<Str>,
) -> 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>>(errno: usize,loc: Location, desc: S, hint: Option<Str>) -> Self { pub fn syntax_warning<S: Into<Str>>(
errno: usize,
loc: Location,
desc: S,
hint: Option<Str>,
) -> Self {
Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint)) Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint))
} }
} }
@ -57,7 +81,9 @@ pub struct DesugaringError {
} }
impl DesugaringError { impl DesugaringError {
pub const fn new(core: ErrorCore) -> Self { Self{ core }} pub const fn new(core: ErrorCore) -> Self {
Self { core }
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -74,14 +100,24 @@ pub struct ParserRunnerError {
} }
impl ErrorDisplay for ParserRunnerError { impl ErrorDisplay for ParserRunnerError {
fn core(&self) -> &ErrorCore { &self.core } fn core(&self) -> &ErrorCore {
fn input(&self) -> &Input { &self.input } &self.core
fn caused_by(&self) -> &str { "" } }
fn ref_inner(&self) -> Option<&Box<Self>> { None } fn input(&self) -> &Input {
&self.input
}
fn caused_by(&self) -> &str {
""
}
fn ref_inner(&self) -> Option<&Box<Self>> {
None
}
} }
impl ParserRunnerError { impl ParserRunnerError {
pub const fn new(core: ErrorCore, input: Input) -> Self { Self{ core, input } } pub const fn new(core: ErrorCore, input: Input) -> Self {
Self { core, input }
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -93,7 +129,11 @@ impl MultiErrorDisplay<ParserRunnerError> for ParserRunnerErrors {}
impl ParserRunnerErrors { impl ParserRunnerErrors {
pub fn convert(input: &Input, errs: ParseErrors) -> Self { pub fn convert(input: &Input, errs: ParseErrors) -> Self {
Self(errs.into_iter().map(|err| ParserRunnerError::new(err.0, input.clone())).collect()) Self(
errs.into_iter()
.map(|err| ParserRunnerError::new(err.0, input.clone()))
.collect(),
)
} }
} }

View file

@ -1,12 +1,12 @@
//! defines and implements `Lexer` (Tokenizer). //! defines and implements `Lexer` (Tokenizer).
use erg_common::cache::Cache; use erg_common::cache::Cache;
use erg_common::Str;
use erg_common::{fn_name_full, switch_lang, debug_power_assert, normalize_newline};
use erg_common::config::Input;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
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 crate::error::{LexerRunnerError, LexerRunnerErrors, LexError, LexErrors, LexResult}; use crate::error::{LexError, LexErrors, LexResult, LexerRunnerError, LexerRunnerErrors};
use crate::token::{Token, TokenCategory, TokenKind, TokenStream}; use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
use TokenKind::*; use TokenKind::*;
@ -20,13 +20,19 @@ impl Runnable for LexerRunner {
type Errs = LexerRunnerErrors; type Errs = LexerRunnerErrors;
#[inline] #[inline]
fn new(cfg: ErgConfig) -> Self { Self { cfg } } fn new(cfg: ErgConfig) -> Self {
Self { cfg }
}
#[inline] #[inline]
fn input(&self) -> &Input { &self.cfg.input } fn input(&self) -> &Input {
&self.cfg.input
}
#[inline] #[inline]
fn start_message(&self) -> String { "Erg lexer\n".to_string() } fn start_message(&self) -> String {
"Erg lexer\n".to_string()
}
#[inline] #[inline]
fn finish(&mut self) {} fn finish(&mut self) {}
@ -37,11 +43,16 @@ impl Runnable for LexerRunner {
fn eval(&mut self, src: Str) -> Result<String, LexerRunnerErrors> { fn eval(&mut self, src: Str) -> 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.lex().map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; let ts = lexer
.lex()
.map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?;
println!("{ts}"); println!("{ts}");
Ok(ts.to_string()) Ok(ts.to_string())
} else { } else {
Ok(lexer.lex().map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?.to_string()) Ok(lexer
.lex()
.map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?
.to_string())
} }
} }
} }
@ -96,18 +107,29 @@ impl Lexer /*<'a>*/ {
let mut errs = LexErrors::empty(); let mut errs = LexErrors::empty();
for i in self.into_iter() { for i in self.into_iter() {
match i { match i {
Ok(token) => { result.push(token) } Ok(token) => result.push(token),
Err(err) => { errs.push(err); } Err(err) => {
errs.push(err);
} }
} }
if errs.is_empty() { Ok(result) } else { Err(errs) } }
if errs.is_empty() {
Ok(result)
} else {
Err(errs)
}
} }
fn emit_token(&mut self, kind: TokenKind, cont: &str) -> Token { fn emit_token(&mut self, kind: TokenKind, cont: &str) -> Token {
let cont = self.str_cache.get(cont); let cont = self.str_cache.get(cont);
// cannot use String::len() for multi-byte characters // cannot use String::len() for multi-byte characters
let cont_len = cont.chars().count(); let cont_len = cont.chars().count();
let token = Token::new(kind, cont, self.lineno_token_starts + 1, self.col_token_starts); let token = Token::new(
kind,
cont,
self.lineno_token_starts + 1,
self.col_token_starts,
);
self.prev_token = token.clone(); self.prev_token = token.clone();
self.col_token_starts += cont_len; self.col_token_starts += cont_len;
token token
@ -160,8 +182,7 @@ impl Lexer /*<'a>*/ {
fn is_definable_operator(s: &str) -> bool { fn is_definable_operator(s: &str) -> bool {
match s { match s {
"+" | "-" | "*" | "/" | "//" | "**" | "%" | ".." | "..=" | "~" | "&&" | "||" | "^^" "+" | "-" | "*" | "/" | "//" | "**" | "%" | ".." | "..=" | "~" | "&&" | "||" | "^^"
| ">>" | "<<" | "==" | "!=" | ">" | "<" | ">=" | "<=" | ">>" | "<<" | "==" | "!=" | ">" | "<" | ">=" | "<=" | "dot" | "cross" => true,
| "dot" | "cross" => true,
_ => false, _ => false,
} }
} }
@ -187,7 +208,9 @@ impl Lexer /*<'a>*/ {
} }
} }
fn is_zero(s: &str) -> bool { s.replace("-0", "").replace("0", "").is_empty() } fn is_zero(s: &str) -> bool {
s.replace("-0", "").replace("0", "").is_empty()
}
/// emit_tokenで一気にcol_token_startsを移動させるのでここでは移動させない /// emit_tokenで一気にcol_token_startsを移動させるのでここでは移動させない
fn consume(&mut self) -> Option<char> { fn consume(&mut self) -> Option<char> {
@ -220,10 +243,15 @@ impl Lexer /*<'a>*/ {
while self.peek_cur_ch().map(|cur| cur != '\n').unwrap_or(false) { while self.peek_cur_ch().map(|cur| cur != '\n').unwrap_or(false) {
if Self::is_bidi(self.peek_cur_ch().unwrap()) { if Self::is_bidi(self.peek_cur_ch().unwrap()) {
let comment = self.emit_token(Illegal, &s); let comment = self.emit_token(Illegal, &s);
return Err(LexError::syntax_error(0, comment.loc(), switch_lang!( return Err(LexError::syntax_error(
0,
comment.loc(),
switch_lang!(
"invalid unicode character (bi-directional override) in comments", "invalid unicode character (bi-directional override) in comments",
"不正なユニコード文字(双方向オーバーライド)がコメント中に使用されています" "不正なユニコード文字(双方向オーバーライド)がコメント中に使用されています"
), None)) ),
None,
));
} }
s.push(self.consume().unwrap()); s.push(self.consume().unwrap());
} }
@ -239,7 +267,7 @@ impl Lexer /*<'a>*/ {
let dedent = self.emit_token(Dedent, ""); let dedent = self.emit_token(Dedent, "");
self.indent_stack.pop(); self.indent_stack.pop();
self.col_token_starts = 0; self.col_token_starts = 0;
return Some(Ok(dedent)) return Some(Ok(dedent));
} }
let mut spaces = "".to_string(); let mut spaces = "".to_string();
while let Some(' ') = self.peek_cur_ch() { while let Some(' ') = self.peek_cur_ch() {
@ -248,10 +276,12 @@ impl Lexer /*<'a>*/ {
// indent in the first line: error // indent in the first line: error
if !spaces.is_empty() && self.cursor == 0 { if !spaces.is_empty() && self.cursor == 0 {
let space = self.emit_token(Illegal, &spaces); let space = self.emit_token(Illegal, &spaces);
Some(Err(LexError::syntax_error(0, space.loc(), switch_lang!( Some(Err(LexError::syntax_error(
"invalid indent", 0,
"インデントが不正です" space.loc(),
), None))) switch_lang!("invalid indent", "インデントが不正です"),
None,
)))
} else if self.prev_token.is(Newline) { } else if self.prev_token.is(Newline) {
self.lex_indent_dedent(spaces) self.lex_indent_dedent(spaces)
} else { } else {
@ -265,21 +295,30 @@ impl Lexer /*<'a>*/ {
// same as the CPython's limit // same as the CPython's limit
if spaces.len() > 100 { if spaces.len() > 100 {
let token = self.emit_token(Indent, &spaces); let token = self.emit_token(Indent, &spaces);
return Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( return Some(Err(LexError::syntax_error(
"indentation is too deep", 0,
"インデントが深すぎます" token.loc(),
), Some(switch_lang!( switch_lang!("indentation is too deep", "インデントが深すぎます"),
Some(
switch_lang!(
"The code is too complicated. Please split the process.", "The code is too complicated. Please split the process.",
"コードが複雑すぎます。処理を分割してください" "コードが複雑すぎます。処理を分割してください"
).into())))) )
.into(),
),
)));
} }
// ignore indents if the current line is a comment // ignore indents if the current line is a comment
if let Some('#') = self.peek_cur_ch() { if let Some('#') = self.peek_cur_ch() {
if let Err(e) = self.lex_comment() { return Some(Err(e)) } if let Err(e) = self.lex_comment() {
return Some(Err(e));
}
} }
let mut is_valid_dedent = false; let mut is_valid_dedent = false;
let calc_indent_and_validate = |sum: usize, x: &usize| { let calc_indent_and_validate = |sum: usize, x: &usize| {
if sum + *x == spaces.len() { is_valid_dedent = true; } if sum + *x == spaces.len() {
is_valid_dedent = true;
}
sum + *x sum + *x
}; };
let sum_indent = self.indent_stack.iter().fold(0, calc_indent_and_validate); let sum_indent = self.indent_stack.iter().fold(0, calc_indent_and_validate);
@ -296,12 +335,16 @@ impl Lexer /*<'a>*/ {
Some(Ok(dedent)) Some(Ok(dedent))
} else { } else {
let invalid_dedent = self.emit_token(Dedent, ""); let invalid_dedent = self.emit_token(Dedent, "");
Some(Err(LexError::syntax_error(0, invalid_dedent.loc(), switch_lang!( Some(Err(LexError::syntax_error(
"invalid indent", 0,
"インデントが不正です" invalid_dedent.loc(),
), None))) switch_lang!("invalid indent", "インデントが不正です"),
None,
)))
} }
} else /* if indent_sum == space.len() */ { } else
/* if indent_sum == space.len() */
{
self.col_token_starts += spaces.len(); self.col_token_starts += spaces.len();
None None
} }
@ -328,19 +371,20 @@ impl Lexer /*<'a>*/ {
while let Some(ch) = self.peek_cur_ch() { while let Some(ch) = self.peek_cur_ch() {
match ch { match ch {
// `.` may be a dot operator, don't consume // `.` may be a dot operator, don't consume
'.' => { return self.lex_num_dot(num) }, '.' => return self.lex_num_dot(num),
n if n.is_ascii_digit() || n == '_' => { n if n.is_ascii_digit() || n == '_' => {
num.push(self.consume().unwrap()); num.push(self.consume().unwrap());
} }
c if Self::is_valid_symbol_ch(c) => { c if Self::is_valid_symbol_ch(c) => {
// exponent (e.g. 10e+3) // exponent (e.g. 10e+3)
if c == 'e' if c == 'e'
&& (self.peek_next_ch() == Some('+') || self.peek_next_ch() == Some('-')) { && (self.peek_next_ch() == Some('+') || self.peek_next_ch() == Some('-'))
return self.lex_exponent(num) {
return self.lex_exponent(num);
} else { } else {
// IntLit * Symbol(e.g. 3x + 1) // IntLit * Symbol(e.g. 3x + 1)
let token = self.emit_token(Illegal, &(num + &c.to_string())); let token = self.emit_token(Illegal, &(num + &c.to_string()));
return Err(LexError::feature_error(0, token.loc(), "*-less multiply")) return Err(LexError::feature_error(0, token.loc(), "*-less multiply"));
} }
} }
_ => { _ => {
@ -348,7 +392,11 @@ impl Lexer /*<'a>*/ {
} }
} }
} }
let kind = if num.starts_with('-') && !Self::is_zero(&num) { IntLit } else { NatLit }; let kind = if num.starts_with('-') && !Self::is_zero(&num) {
IntLit
} else {
NatLit
};
Ok(self.emit_token(kind, &num)) Ok(self.emit_token(kind, &num))
} }
@ -364,9 +412,13 @@ impl Lexer /*<'a>*/ {
// method call of IntLit // method call of IntLit
// or range operator (e.g. 1..) // or range operator (e.g. 1..)
Some(c) if Self::is_valid_symbol_ch(c) || c == '.' => { Some(c) if Self::is_valid_symbol_ch(c) || c == '.' => {
let kind = if num.starts_with('-') && !Self::is_zero(&num) { IntLit } else { NatLit }; let kind = if num.starts_with('-') && !Self::is_zero(&num) {
IntLit
} else {
NatLit
};
Ok(self.emit_token(kind, &num)) Ok(self.emit_token(kind, &num))
}, }
Some('_') => { Some('_') => {
self.consume(); self.consume();
let token = self.emit_token(Illegal, &(num + "_")); let token = self.emit_token(Illegal, &(num + "_"));
@ -387,7 +439,7 @@ impl Lexer /*<'a>*/ {
if cur.is_ascii_digit() || cur == '_' { if cur.is_ascii_digit() || cur == '_' {
num.push(self.consume().unwrap()); num.push(self.consume().unwrap());
} else if cur == 'e' { } else if cur == 'e' {
return self.lex_exponent(num) return self.lex_exponent(num);
} else { } else {
break; break;
} }
@ -409,7 +461,12 @@ impl Lexer /*<'a>*/ {
} }
if cont.is_empty() { if cont.is_empty() {
let token = self.emit_token(Illegal, &self.peek_cur_ch().unwrap().to_string()); let token = self.emit_token(Illegal, &self.peek_cur_ch().unwrap().to_string());
return Err(LexError::compiler_bug(0, token.loc(), fn_name_full!(), line!())) return Err(LexError::compiler_bug(
0,
token.loc(),
fn_name_full!(),
line!(),
));
} }
// dot: scalar product, cross: vector product // dot: scalar product, cross: vector product
// An alphabetical operator can also declare as a function, so checking is necessary // An alphabetical operator can also declare as a function, so checking is necessary
@ -441,24 +498,34 @@ impl Lexer /*<'a>*/ {
if c == '\"' && s.chars().last() != Some('\\') { if c == '\"' && s.chars().last() != Some('\\') {
s.push(self.consume().unwrap()); s.push(self.consume().unwrap());
let token = self.emit_token(StrLit, &s); let token = self.emit_token(StrLit, &s);
return Ok(token) return Ok(token);
} else { } else {
let c = self.consume().unwrap(); let c = self.consume().unwrap();
s.push(c); s.push(c);
if Self::is_bidi(c) { if Self::is_bidi(c) {
let token = self.emit_token(Illegal, &s); let token = self.emit_token(Illegal, &s);
return Err(LexError::syntax_error(0, token.loc(), switch_lang!( return Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
"invalid unicode character (bi-directional override) in string literal", "invalid unicode character (bi-directional override) in string literal",
"不正なユニコード文字(双方向オーバーライド)が文字列中に使用されています" "不正なユニコード文字(双方向オーバーライド)が文字列中に使用されています"
), None)) ),
None,
));
} }
} }
} }
let token = self.emit_token(Illegal, &s); let token = self.emit_token(Illegal, &s);
Err(LexError::syntax_error(0, token.loc(), switch_lang!( Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
"the string is not closed by \"", "the string is not closed by \"",
"文字列が\"によって閉じられていません" "文字列が\"によって閉じられていません"
), None)) ),
None,
))
} }
} }
@ -467,14 +534,16 @@ impl Iterator for Lexer /*<'a>*/ {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.prev_token.is(TokenKind::EOF) { if self.prev_token.is(TokenKind::EOF) {
return None return None;
} }
let indent_dedent = self.lex_space_indent_dedent(); let indent_dedent = self.lex_space_indent_dedent();
if indent_dedent.is_some() { if indent_dedent.is_some() {
return indent_dedent return indent_dedent;
} }
if let Some('#') = self.peek_cur_ch() { if let Some('#') = self.peek_cur_ch() {
if let Err(e) = self.lex_comment() { return Some(Err(e)) } if let Err(e) = self.lex_comment() {
return Some(Err(e));
}
} }
match self.consume() { match self.consume() {
Some('(') => self.accept(LParen, "("), Some('(') => self.accept(LParen, "("),
@ -497,10 +566,12 @@ impl Iterator for Lexer /*<'a>*/ {
} }
} else { } else {
let token = self.emit_token(Illegal, "<."); let token = self.emit_token(Illegal, "<.");
Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( Some(Err(LexError::syntax_error(
"no such operator: <.", 0,
"<.という演算子はありません" token.loc(),
), None))) switch_lang!("no such operator: <.", "<.という演算子はありません"),
None,
)))
} }
} }
Some('=') => { Some('=') => {
@ -524,30 +595,24 @@ impl Iterator for Lexer /*<'a>*/ {
} }
_ => self.accept(Gre, ">"), _ => self.accept(Gre, ">"),
}, },
Some('.') => { Some('.') => match self.peek_cur_ch() {
match self.peek_cur_ch() {
Some('.') => { Some('.') => {
self.consume(); self.consume();
match self.peek_cur_ch() { match self.peek_cur_ch() {
Some('<') => { Some('<') => {
self.consume(); self.consume();
self.accept(RightOpen, "..<") self.accept(RightOpen, "..<")
}, }
Some('.') => { Some('.') => {
self.consume(); self.consume();
self.accept(EllipsisLit, "...") self.accept(EllipsisLit, "...")
}
_ => self.accept(Closed, ".."),
}
}
Some(c) if c.is_ascii_digit() => Some(self.lex_ratio(".".into())),
_ => self.accept(Dot, "."),
}, },
_ => {
self.accept(Closed, "..")
}
}
}
Some(c) if c.is_ascii_digit() => {
Some(self.lex_ratio(".".into()))
}
_ => self.accept(Dot, ".")
}
}
Some(',') => self.accept(Comma, ","), Some(',') => self.accept(Comma, ","),
Some(':') => match self.peek_cur_ch() { Some(':') => match self.peek_cur_ch() {
Some(':') => { Some(':') => {
@ -570,8 +635,7 @@ impl Iterator for Lexer /*<'a>*/ {
self.accept(Amper, "&") self.accept(Amper, "&")
} }
} }
Some('|') => { Some('|') => match self.peek_cur_ch() {
match self.peek_cur_ch() {
Some('|') => { Some('|') => {
self.consume(); self.consume();
self.accept(BitOr, "||") self.accept(BitOr, "||")
@ -580,11 +644,8 @@ impl Iterator for Lexer /*<'a>*/ {
self.consume(); self.consume();
self.accept(OrEqual, "|=") self.accept(OrEqual, "|=")
} }
_ => { _ => self.accept(VBar, "|"),
self.accept(VBar, "|") },
}
}
}
Some('^') => { Some('^') => {
if let Some('^') = self.peek_cur_ch() { if let Some('^') = self.peek_cur_ch() {
self.consume(); self.consume();
@ -635,7 +696,11 @@ impl Iterator for Lexer /*<'a>*/ {
self.accept(Minus, "-") self.accept(Minus, "-")
} else { } else {
// IntLit (negative number) // IntLit (negative number)
if self.peek_cur_ch().map(|t| t.is_ascii_digit()).unwrap_or(false) { if self
.peek_cur_ch()
.map(|t| t.is_ascii_digit())
.unwrap_or(false)
{
Some(self.lex_num('-')) Some(self.lex_num('-'))
} else { } else {
self.accept(Minus, "-") self.accept(Minus, "-")
@ -675,10 +740,12 @@ impl Iterator for Lexer /*<'a>*/ {
} }
Some('\t') => { Some('\t') => {
let token = self.emit_token(Illegal, "\t"); let token = self.emit_token(Illegal, "\t");
Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( Some(Err(LexError::syntax_error(
"cannot use a tab as a space", 0,
"タブ文字は使用できません" token.loc(),
), Some(switch_lang!("use spaces", "スペースを使用してください").into())))) switch_lang!("cannot use a tab as a space", "タブ文字は使用できません"),
Some(switch_lang!("use spaces", "スペースを使用してください").into()),
)))
} }
// TODO: // TODO:
Some('\\') => self.deny_feature("\\", "ignoring line break"), Some('\\') => self.deny_feature("\\", "ignoring line break"),
@ -693,22 +760,32 @@ impl Iterator for Lexer /*<'a>*/ {
while let Some(c) = self.consume() { while let Some(c) = self.consume() {
if c == '`' { if c == '`' {
if Self::is_definable_operator(&op[..]) { if Self::is_definable_operator(&op[..]) {
return self.accept(Symbol, &op) return self.accept(Symbol, &op);
} else { } else {
let token = self.emit_token(Illegal, &op); let token = self.emit_token(Illegal, &op);
return Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( return Some(Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
format!("`{}` cannot be defined by user", &token.content), format!("`{}` cannot be defined by user", &token.content),
format!("`{}`はユーザー定義できません", &token.content) format!("`{}`はユーザー定義できません", &token.content)
), None))) ),
None,
)));
} }
} }
op.push(c); op.push(c);
} }
let token = self.emit_token(Illegal, &op); let token = self.emit_token(Illegal, &op);
Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( Some(Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
format!("back quotes (`) not closed"), format!("back quotes (`) not closed"),
format!("バッククォート(`)が閉じられていません") format!("バッククォート(`)が閉じられていません")
), None))) ),
None,
)))
} }
// IntLit or RatioLit // IntLit or RatioLit
Some(n) if n.is_ascii_digit() => Some(self.lex_num(n)), Some(n) if n.is_ascii_digit() => Some(self.lex_num(n)),
@ -717,10 +794,15 @@ impl Iterator for Lexer /*<'a>*/ {
// Invalid character (e.g. space-like character) // Invalid character (e.g. space-like character)
Some(invalid) => { Some(invalid) => {
let token = self.emit_token(Illegal, &invalid.to_string()); let token = self.emit_token(Illegal, &invalid.to_string());
Some(Err(LexError::syntax_error(0, token.loc(), switch_lang!( Some(Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
format!("invalid character: '{invalid}'"), format!("invalid character: '{invalid}'"),
format!("この文字は使用できません: '{invalid}'") format!("この文字は使用できません: '{invalid}'")
), None))) ),
None,
)))
} }
None => { None => {
if self.indent_stack.len() == 0 { if self.indent_stack.len() == 0 {

View file

@ -2,9 +2,9 @@
//! and performs type checking and other optimizations if necessary. //! and performs type checking and other optimizations if necessary.
extern crate erg_common; extern crate erg_common;
pub mod ast;
pub mod desugar; pub mod desugar;
pub mod error; pub mod error;
pub mod ast;
pub mod lex; pub mod lex;
pub mod parse; pub mod parse;
pub mod token; pub mod token;

View file

@ -12,8 +12,12 @@ use erg_parser::ParserRunner;
fn main() { fn main() {
let cfg = ErgConfig::parse(); let cfg = ErgConfig::parse();
match cfg.mode { match cfg.mode {
"lex" => { LexerRunner::run(cfg); } "lex" => {
"parse" | "exec" => { ParserRunner::run(cfg); } LexerRunner::run(cfg);
}
"parse" | "exec" => {
ParserRunner::run(cfg);
}
other => { other => {
println!("invalid mode: {other}"); println!("invalid mode: {other}");
process::exit(1); process::exit(1);

File diff suppressed because it is too large Load diff

View file

@ -130,7 +130,11 @@ mod tests {
let cfg = ErgConfig::new("exec", 1, false, None, input.clone(), "<module>", 2); let cfg = ErgConfig::new("exec", 1, false, None, input.clone(), "<module>", 2);
let lexer = Lexer::new(input.clone()); let lexer = Lexer::new(input.clone());
let mut parser = ParserRunner::new(cfg); let mut parser = ParserRunner::new(cfg);
match parser.parse(lexer.lex().map_err(|errs| ParserRunnerErrors::convert(&input, errs))?) { match parser.parse(
lexer
.lex()
.map_err(|errs| ParserRunnerErrors::convert(&input, errs))?,
) {
Ok(module) => { Ok(module) => {
println!("{module}"); println!("{module}");
Ok(()) Ok(())

View file

@ -4,12 +4,12 @@
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use erg_common::str::Str;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::impl_displayable_stream_for_wrapper; use erg_common::impl_displayable_stream_for_wrapper;
use erg_common::traits::{Stream, Locational}; use erg_common::str::Str;
use erg_common::value::ValueObj; use erg_common::traits::{Locational, Stream};
use erg_common::ty::Type; use erg_common::ty::Type;
use erg_common::value::ValueObj;
/// 意味論的名前と記号自体の名前が混在しているが、Pythonの名残である /// 意味論的名前と記号自体の名前が混在しているが、Pythonの名残である
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -243,11 +243,13 @@ impl TokenKind {
pub const fn category(&self) -> TokenCategory { pub const fn category(&self) -> TokenCategory {
match self { match self {
Symbol => TokenCategory::Symbol, Symbol => TokenCategory::Symbol,
NatLit | IntLit | RatioLit | StrLit | BoolLit NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | NoImplLit
| NoneLit | EllipsisLit | NoImplLit | InfLit => TokenCategory::Literal, | InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreStar | PreBitNot | Mutate => TokenCategory::UnaryOp, PrePlus | PreMinus | PreStar | PreBitNot | Mutate => TokenCategory::UnaryOp,
Try => TokenCategory::PostfixOp, Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | OrEqual => TokenCategory::SpecialBinOp, Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | OrEqual => {
TokenCategory::SpecialBinOp
}
Equal => TokenCategory::DefOp, Equal => TokenCategory::DefOp,
FuncArrow | ProcArrow => TokenCategory::LambdaOp, FuncArrow | ProcArrow => TokenCategory::LambdaOp,
Semi | Newline => TokenCategory::Separator, Semi | Newline => TokenCategory::Separator,
@ -276,8 +278,7 @@ impl TokenKind {
BitXor => 130, // ^^ BitXor => 130, // ^^
BitOr => 120, // || BitOr => 120, // ||
Closed | LeftOpen | RightOpen | Open => 100, // range operators Closed | LeftOpen | RightOpen | Open => 100, // range operators
Less | Gre | LessEq | GreEq | DblEq | NotEq Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
| InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
AndOp => 80, // and AndOp => 80, // and
OrOp => 70, // or OrOp => 70, // or
FuncArrow | ProcArrow => 60, // -> => FuncArrow | ProcArrow => 60, // -> =>
@ -286,7 +287,7 @@ impl TokenKind {
Equal | OrEqual => 20, // = |= Equal | OrEqual => 20, // = |=
Newline | Semi => 10, // \n ; Newline | Semi => 10, // \n ;
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
_ => { return None }, _ => return None,
}; };
Some(prec) Some(prec)
} }
@ -302,7 +303,9 @@ impl TokenKind {
impl fmt::Display for TokenKind { impl fmt::Display for TokenKind {
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self:?}") } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self:?}")
}
} }
#[derive(Clone, Eq)] #[derive(Clone, Eq)]
@ -350,7 +353,9 @@ impl fmt::Display for Token {
// the values of lineno and col are not relevant for comparison // the values of lineno and col are not relevant for comparison
impl PartialEq for Token { impl PartialEq for Token {
#[inline] #[inline]
fn eq(&self, other: &Self) -> bool { self.is(other.kind) && self.content == other.content } fn eq(&self, other: &Self) -> bool {
self.is(other.kind) && self.content == other.content
}
} }
impl Hash for Token { impl Hash for Token {
@ -362,7 +367,9 @@ impl Hash for Token {
impl Locational for Token { impl Locational for Token {
fn loc(&self) -> Location { fn loc(&self) -> Location {
if self.lineno == 0 { Location::Unknown } else { if self.lineno == 0 {
Location::Unknown
} else {
Location::range( Location::range(
self.lineno, self.lineno,
self.col_begin, self.col_begin,
@ -373,43 +380,79 @@ impl Locational for Token {
} }
#[inline] #[inline]
fn col_end(&self) -> Option<usize> { Some(self.col_begin + self.content.len()) } fn col_end(&self) -> Option<usize> {
Some(self.col_begin + self.content.len())
}
} }
impl Token { impl Token {
#[inline] #[inline]
pub fn dummy() -> Self { pub fn dummy() -> Self {
Token{ kind: TokenKind::Illegal, content: "DUMMY".into(), lineno: 1, col_begin: 0 } Token {
kind: TokenKind::Illegal,
content: "DUMMY".into(),
lineno: 1,
col_begin: 0,
}
} }
#[inline] #[inline]
pub fn new<S: Into<Str>>(kind: TokenKind, cont: S, lineno: usize, col_begin: usize) -> Self { pub fn new<S: Into<Str>>(kind: TokenKind, cont: S, lineno: usize, col_begin: usize) -> Self {
Token{ kind, content: cont.into(), lineno, col_begin } Token {
kind,
content: cont.into(),
lineno,
col_begin,
}
} }
#[inline] #[inline]
pub fn from_str(kind: TokenKind, cont: &str) -> Self { pub fn from_str(kind: TokenKind, cont: &str) -> Self {
Token{ kind, content: Str::rc(cont), lineno: 0, col_begin: 0 } Token {
kind,
content: Str::rc(cont),
lineno: 0,
col_begin: 0,
}
} }
#[inline] #[inline]
pub fn symbol(cont: &str) -> Self { Self::from_str(TokenKind::Symbol, cont) } pub fn symbol(cont: &str) -> Self {
Self::from_str(TokenKind::Symbol, cont)
pub const fn static_symbol(s: &'static str) -> Self {
Token{ kind: TokenKind::Symbol, content: Str::ever(s), lineno: 0, col_begin: 0 }
} }
pub const fn category(&self) -> TokenCategory { self.kind.category() } pub const fn static_symbol(s: &'static str) -> Self {
Token {
kind: TokenKind::Symbol,
content: Str::ever(s),
lineno: 0,
col_begin: 0,
}
}
pub fn category_is(&self, category: TokenCategory) -> bool { self.kind.category() == category } pub const fn category(&self) -> TokenCategory {
self.kind.category()
}
pub fn is(&self, kind: TokenKind) -> bool { self.kind == kind } pub fn category_is(&self, category: TokenCategory) -> bool {
self.kind.category() == category
}
pub const fn is_block_op(&self) -> bool { self.category().is_block_op() } pub fn is(&self, kind: TokenKind) -> bool {
self.kind == kind
}
pub const fn inspect(&self) -> &Str { &self.content } pub const fn is_block_op(&self) -> bool {
self.category().is_block_op()
}
pub fn is_procedural(&self) -> bool { self.inspect().ends_with("!") } pub const fn inspect(&self) -> &Str {
&self.content
}
pub fn is_procedural(&self) -> bool {
self.inspect().ends_with("!")
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,15 +1,15 @@
use std::net::TcpStream;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::TcpStream;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use erg_common::config::{ErgConfig, Input, SEMVER, BUILD_INFO}; use erg_common::config::{ErgConfig, Input, BUILD_INFO, SEMVER};
use erg_common::python_util::exec_py; use erg_common::python_util::exec_py;
use erg_common::str::Str; use erg_common::str::Str;
use erg_common::traits::Runnable; use erg_common::traits::Runnable;
use erg_compiler::Compiler;
use erg_compiler::error::{CompileError, CompileErrors}; use erg_compiler::error::{CompileError, CompileErrors};
use erg_compiler::Compiler;
/// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う /// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う
#[derive(Debug)] #[derive(Debug)]
@ -33,7 +33,7 @@ impl Runnable for DummyVM {
let addr = format!("{repl_server_ip}:{repl_server_port}"); let addr = format!("{repl_server_ip}:{repl_server_port}");
let stream = loop { let stream = loop {
match TcpStream::connect(&addr) { match TcpStream::connect(&addr) {
Ok(stream) => { break stream }, Ok(stream) => break stream,
Err(_) => { Err(_) => {
println!("Retrying to connect to the REPL server..."); println!("Retrying to connect to the REPL server...");
sleep(Duration::from_millis(500)); sleep(Duration::from_millis(500));
@ -49,10 +49,14 @@ impl Runnable for DummyVM {
} }
#[inline] #[inline]
fn input(&self) -> &Input { &self.cfg.input } fn input(&self) -> &Input {
&self.cfg.input
}
#[inline] #[inline]
fn start_message(&self) -> String { format!("Erg interpreter {} {}\n", SEMVER, &*BUILD_INFO) } fn start_message(&self) -> String {
format!("Erg interpreter {} {}\n", SEMVER, &*BUILD_INFO)
}
fn finish(&mut self) { fn finish(&mut self) {
self.stream.write("exit".as_bytes()).unwrap(); self.stream.write("exit".as_bytes()).unwrap();
@ -88,7 +92,7 @@ impl Runnable for DummyVM {
panic!("{}", format!("Read error: {e}")); panic!("{}", format!("Read error: {e}"));
} }
} }
}, }
Result::Err(e) => panic!("{}", format!("Sending error: {e}")), Result::Err(e) => panic!("{}", format!("Sending error: {e}")),
}; };
if res.ends_with("None") { if res.ends_with("None") {

View file

@ -1,10 +1,10 @@
extern crate erg;
extern crate erg_compiler; extern crate erg_compiler;
extern crate erg_parser; extern crate erg_parser;
extern crate erg;
use std::process; use std::process;
use erg_common::config::{ErgConfig}; use erg_common::config::ErgConfig;
use erg_common::deserialize::Deserializer; use erg_common::deserialize::Deserializer;
use erg_common::traits::Runnable; use erg_common::traits::Runnable;
@ -18,11 +18,21 @@ use erg::dummy::DummyVM;
fn main() { fn main() {
let cfg = ErgConfig::parse(); let cfg = ErgConfig::parse();
match cfg.mode { match cfg.mode {
"lex" => { LexerRunner::run(cfg); } "lex" => {
"parse" => { ParserRunner::run(cfg); } LexerRunner::run(cfg);
"compile" => { Compiler::run(cfg); } }
"exec" => { DummyVM::run(cfg); } "parse" => {
"read" => { Deserializer::run(cfg); } ParserRunner::run(cfg);
}
"compile" => {
Compiler::run(cfg);
}
"exec" => {
DummyVM::run(cfg);
}
"read" => {
Deserializer::run(cfg);
}
other => { other => {
eprintln!("invalid mode: {other}"); eprintln!("invalid mode: {other}");
process::exit(1); process::exit(1);