Create erg_type crate

This commit is contained in:
Shunsuke Shibayama 2022-08-26 11:52:11 +09:00
parent e4e89f38f9
commit 5b5234f477
43 changed files with 2995 additions and 8238 deletions

9
Cargo.lock generated
View file

@ -20,6 +20,7 @@ dependencies = [
"erg_common",
"erg_compiler",
"erg_parser",
"erg_type",
]
[[package]]
@ -35,6 +36,7 @@ version = "0.2.8"
dependencies = [
"erg_common",
"erg_parser",
"erg_type",
]
[[package]]
@ -44,6 +46,13 @@ dependencies = [
"erg_common",
]
[[package]]
name = "erg_type"
version = "0.2.8"
dependencies = [
"erg_common",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"

View file

@ -15,6 +15,7 @@ members = [
"compiler/erg_common",
"compiler/erg_compiler",
"compiler/erg_parser",
"compiler/erg_type",
]
[features]
@ -23,27 +24,32 @@ debug = [
"erg_common/debug",
"erg_parser/debug",
"erg_compiler/debug",
"erg_type/debug",
]
japanese = [
"erg_common/japanese",
"erg_parser/japanese",
"erg_compiler/japanese",
"erg_type/japanese",
]
simplified_chinese = [
"erg_common/simplified_chinese",
"erg_parser/simplified_chinese",
"erg_compiler/simplified_chinese",
"erg_type/simplified_chinese",
]
traditional_chinese = [
"erg_common/traditional_chinese",
"erg_parser/traditional_chinese",
"erg_compiler/traditional_chinese",
"erg_type/traditional_chinese",
]
[dependencies]
erg_common = { version = "0.2.8", path = "./compiler/erg_common" }
erg_parser = { version = "0.2.8", path = "./compiler/erg_parser" }
erg_compiler = { version = "0.2.8", path = "./compiler/erg_compiler" }
erg_type = { version = "0.2.8", path = "./compiler/erg_type" }
# [workspace]
# member = ["cm", "dyne"]

View file

@ -1,505 +0,0 @@
use std::fmt;
use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;
use crate::deserialize::{DeserializeResult, Deserializer};
use crate::impl_display_from_debug;
use crate::opcode::Opcode;
use crate::python_util::detect_magic_number;
use crate::serialize::*;
use crate::traits::HasType;
use crate::ty::{Type, TypePair};
use crate::value::ValueObj;
use crate::Str;
pub fn consts_into_bytes(consts: Vec<ValueObj>) -> Vec<u8> {
let mut tuple = vec![];
if consts.len() > u8::MAX as usize {
tuple.push(DataTypePrefix::Tuple as u8);
tuple.append(&mut (consts.len() as u32).to_le_bytes().to_vec());
} else {
tuple.push(DataTypePrefix::SmallTuple as u8);
tuple.push(consts.len() as u8);
}
for obj in consts {
tuple.append(&mut obj.into_bytes());
}
tuple
}
/// Bit masks for CodeObj.flags
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum CodeObjFlags {
Optimized = 0x0001,
NewLocals = 0x0002,
VarArgs = 0x0004,
VarKeywords = 0x0008,
Nested = 0x0010,
Generator = 0x0020,
NoFree = 0x0040,
Coroutine = 0x0080,
IterableCoroutine = 0x0100,
AsyncGenerator = 0x0200,
// CO_GENERATOR_ALLOWED = 0x0400,
FutureDivision = 0x2000,
FutureAbsoluteImport = 0x4000,
FutureWithStatement = 0x8000,
FuturePrintFunction = 0x1_0000,
FutureUnicodeLiterals = 0x2_0000,
FutureBarryAsBDFL = 0x4_0000,
FutureGeneratorStop = 0x8_0000,
FutureAnnotations = 0x10_0000,
// Erg-specific flags
EvmDynParam = 0x1000_0000,
EvmNoGC = 0x4000_0000,
Illegal = 0x0000,
}
impl From<u32> for CodeObjFlags {
fn from(flags: u32) -> Self {
match flags {
0x0001 => Self::Optimized,
0x0002 => Self::NewLocals,
0x0004 => Self::VarArgs,
0x0008 => Self::VarKeywords,
0x0010 => Self::Nested,
0x0020 => Self::Generator,
0x0040 => Self::NoFree,
0x0080 => Self::Coroutine,
0x0100 => Self::IterableCoroutine,
0x0200 => Self::AsyncGenerator,
// CO_GENERATOR_ALLOWED,
0x2000 => Self::FutureDivision,
0x4000 => Self::FutureAbsoluteImport,
0x8000 => Self::FutureWithStatement,
0x1_0000 => Self::FuturePrintFunction,
0x2_0000 => Self::FutureUnicodeLiterals,
0x4_0000 => Self::FutureBarryAsBDFL,
0x8_0000 => Self::FutureGeneratorStop,
0x10_0000 => Self::FutureAnnotations,
// EVM flags
0x1000_0000 => Self::EvmDynParam,
0x4000_0000 => Self::EvmNoGC,
_ => Self::Illegal,
}
}
}
impl CodeObjFlags {
pub const fn is_in(&self, flags: u32) -> bool {
(flags & *self as u32) != 0
}
}
/// Implementation of `PyCodeObject`, see Include/cpython/code.h in CPython for details.
///
/// 各属性をErg側のObjに変換すると遅くなりそうなので、アクサスされたときのみ変換して提供する
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CodeObj {
pub argcount: u32,
pub posonlyargcount: u32,
pub kwonlyargcount: u32,
pub nlocals: u32, // == params + local vars
pub stacksize: u32,
pub flags: u32,
pub code: Vec<u8>,
pub consts: Vec<ValueObj>, // objects used in the code (literal)
pub names: Vec<Str>, // names used in the code object
pub varnames: Vec<Str>, // names defined in the code object
pub freevars: Vec<Str>, // names captured from the outer scope
pub cellvars: Vec<Str>, // names used in the inner function (closure)
pub filename: Str,
pub name: Str,
pub firstlineno: u32,
// lnotab (line number table): see Object/lnotab_notes.txt in CPython for details
// e.g. +12bytes, +3line -> [.., 0x1C, 0x03, ..]
// ([sdelta, ldelta, sdelta, ldelta, ..])
// if delta > 255 -> [255, 0, 255-delta, ...]
pub lnotab: Vec<u8>,
}
impl HasType for CodeObj {
fn ref_t(&self) -> &Type {
&Type::Code
}
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
fn signature_t(&self) -> Option<&Type> {
None
}
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl fmt::Debug for CodeObj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"<code object {} at {:p}, file \"{}\", line {}>",
self.name, self, self.filename, self.firstlineno
)
}
}
impl_display_from_debug!(CodeObj);
impl Default for CodeObj {
fn default() -> Self {
Self {
argcount: 0,
posonlyargcount: 0,
kwonlyargcount: 0,
nlocals: 0,
stacksize: 2, // Seems to be the default in CPython, but not sure why
flags: CodeObjFlags::NoFree as u32,
code: Vec::new(),
consts: Vec::new(),
names: Vec::new(),
varnames: Vec::new(),
freevars: Vec::new(),
cellvars: Vec::new(),
filename: "<dummy>".into(),
name: "<dummy>".into(),
firstlineno: 1,
lnotab: Vec::new(),
}
}
}
impl CodeObj {
pub fn new<S: Into<Str>>(
argcount: u32,
posonlyargcount: u32,
kwonlyargcount: u32,
nlocals: u32,
stacksize: u32,
flags: u32,
code: Vec<u8>,
consts: Vec<ValueObj>,
names: Vec<Str>,
varnames: Vec<Str>,
freevars: Vec<Str>,
cellvars: Vec<Str>,
filename: Str,
name: S,
firstlineno: u32,
lnotab: Vec<u8>,
) -> Self {
Self {
argcount,
posonlyargcount,
kwonlyargcount,
nlocals,
stacksize,
flags,
code,
consts,
names,
varnames,
freevars,
cellvars,
filename,
name: name.into(),
firstlineno,
lnotab,
}
}
pub fn empty<S: Into<Str>, T: Into<Str>>(
params: Vec<Str>,
filename: S,
name: T,
firstlineno: u32,
) -> Self {
Self {
argcount: params.len() as u32,
posonlyargcount: 0,
kwonlyargcount: 0,
nlocals: params.len() as u32,
stacksize: 2, // Seems to be the default in CPython, but not sure why
flags: CodeObjFlags::NoFree as u32,
code: Vec::with_capacity(8),
consts: Vec::with_capacity(4),
names: Vec::with_capacity(3),
varnames: params,
freevars: Vec::new(),
cellvars: Vec::new(),
filename: filename.into(),
name: name.into(),
firstlineno,
lnotab: Vec::with_capacity(4),
}
}
pub fn from_pyc<P: AsRef<Path>>(path: P) -> DeserializeResult<Self> {
let mut f = BufReader::new(File::open(path)?);
let v = &mut Vec::with_capacity(16);
f.read_to_end(v)?;
let python_ver = get_magic_num_from_bytes(&Deserializer::consume::<4>(v));
let _padding = Deserializer::deserialize_u32(v);
let _timestamp = Deserializer::deserialize_u32(v);
let _padding = Deserializer::deserialize_u32(v);
let code = Self::from_bytes(v, python_ver)?;
Ok(code)
}
pub fn from_bytes(v: &mut Vec<u8>, python_ver: u32) -> DeserializeResult<Self> {
let mut des = Deserializer::new();
let argcount = Deserializer::deserialize_u32(v);
let posonlyargcount = if python_ver >= 3413 {
Deserializer::deserialize_u32(v)
} else {
0
};
let kwonlyargcount = Deserializer::deserialize_u32(v);
let nlocals = Deserializer::deserialize_u32(v);
let stacksize = Deserializer::deserialize_u32(v);
let flags = Deserializer::deserialize_u32(v);
let code = des.deserialize_bytes(v)?;
let consts = des.deserialize_const_vec(v, python_ver)?;
let names = 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 cellvars = des.deserialize_str_vec(v, python_ver)?;
let filename = des.deserialize_str(v, python_ver)?;
let name = des.deserialize_str(v, python_ver)?;
let firstlineno = Deserializer::deserialize_u32(v);
let lnotab = des.deserialize_bytes(v)?;
Ok(CodeObj::new(
argcount,
posonlyargcount,
kwonlyargcount,
nlocals,
stacksize,
flags,
code,
consts,
names,
varnames,
freevars,
cellvars,
filename,
name,
firstlineno,
lnotab,
))
}
pub fn into_bytes(self, python_ver: u32) -> Vec<u8> {
let mut bytes = vec![DataTypePrefix::Code as u8];
bytes.append(&mut self.argcount.to_le_bytes().to_vec());
if python_ver >= 3413 {
bytes.append(&mut self.posonlyargcount.to_le_bytes().to_vec());
}
bytes.append(&mut self.kwonlyargcount.to_le_bytes().to_vec());
bytes.append(&mut self.nlocals.to_le_bytes().to_vec());
bytes.append(&mut self.stacksize.to_le_bytes().to_vec());
bytes.append(&mut self.flags.to_le_bytes().to_vec());
// co_code is represented as PyStrObject (Not Ascii, Unicode)
bytes.append(&mut raw_string_into_bytes(self.code));
bytes.append(&mut consts_into_bytes(self.consts)); // write as PyTupleObject
bytes.append(&mut strs_into_bytes(self.names));
bytes.append(&mut strs_into_bytes(self.varnames));
bytes.append(&mut strs_into_bytes(self.freevars));
bytes.append(&mut strs_into_bytes(self.cellvars));
bytes.append(&mut str_into_bytes(self.filename, false));
bytes.append(&mut str_into_bytes(self.name, true));
bytes.append(&mut self.firstlineno.to_le_bytes().to_vec());
// lnotab is represented as PyStrObject
bytes.append(&mut raw_string_into_bytes(self.lnotab));
bytes
}
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 bytes = Vec::with_capacity(16);
let python_ver = python_ver.unwrap_or_else(detect_magic_number);
bytes.append(&mut get_magic_num_bytes(python_ver).to_vec());
bytes.append(&mut vec![0; 4]); // padding
bytes.append(&mut get_timestamp_bytes().to_vec());
bytes.append(&mut vec![0; 4]); // padding
bytes.append(&mut self.into_bytes(python_ver));
file.write_all(&bytes[..])?;
Ok(())
}
fn tables_info(&self) -> String {
let mut tables = "".to_string();
if !self.consts.is_empty() {
tables += "Constants:\n";
}
for (i, obj) in self.consts.iter().enumerate() {
tables += &format!(" {}: {}\n", i, obj);
}
if !self.names.is_empty() {
tables += "Names:\n";
}
for (i, name) in self.names.iter().enumerate() {
tables += &format!(" {}: {}\n", i, name);
}
if !self.varnames.is_empty() {
tables += "Varnames:\n";
}
for (i, varname) in self.varnames.iter().enumerate() {
tables += &format!(" {}: {}\n", i, varname);
}
if !self.cellvars.is_empty() {
tables += "Cellvars:\n";
}
for (i, cellvar) in self.cellvars.iter().enumerate() {
tables += &format!(" {}: {}\n", i, cellvar);
}
if !self.freevars.is_empty() {
tables += "Freevars:\n";
}
for (i, freevar) in self.freevars.iter().enumerate() {
tables += &format!(" {}: {}\n", i, freevar);
}
tables
}
fn attrs_info(&self) -> String {
let mut attrs = "".to_string();
attrs += &format!("Name: {}\n", self.name);
attrs += &format!("FileName: {}\n", self.filename);
attrs += &format!("Argument count: {}\n", self.argcount);
attrs += &format!("Positional-only arguments: {}\n", self.posonlyargcount);
attrs += &format!("Kw-only arguments: {}\n", self.kwonlyargcount);
attrs += &format!("Number of locals: {}\n", self.nlocals);
attrs += &format!("Stack size: {}\n", self.stacksize);
let mut flagged = "".to_string();
for i in 0..32 {
if (self.flags & (1 << i)) != 0 {
let flag: CodeObjFlags = 2u32.pow(i).into();
flagged += &format!("{:?}, ", flag);
}
}
flagged.pop();
flagged.pop();
attrs += &format!("Flags: {}\n", flagged);
attrs
}
fn instr_info(&self) -> String {
let mut lnotab_iter = self.lnotab.iter();
let mut code_iter = self.code.iter();
let mut idx = 0;
let mut line_offset = 0;
let mut lineno = self.firstlineno as u8;
let mut sdelta = lnotab_iter.next().unwrap_or(&0);
let mut ldelta = lnotab_iter.next().unwrap_or(&0);
let mut instrs = "".to_string();
instrs += &format!("lnotab: {:?}\n", self.lnotab);
if *sdelta != 0 {
instrs += &format!("{}:\n", lineno);
}
loop {
if *sdelta == line_offset {
line_offset = 0;
lineno += ldelta;
instrs += &format!("{}:\n", lineno);
sdelta = lnotab_iter.next().unwrap_or(&0);
ldelta = lnotab_iter.next().unwrap_or(&0);
}
if let (Some(op), Some(arg)) = (code_iter.next(), code_iter.next()) {
let op = Opcode::from(*op);
let s_op = op.to_string();
instrs += &format!("{:>15} {:<25}", idx, s_op);
match op {
Opcode::COMPARE_OP => {
let op = match arg {
0 => "<",
1 => "<=",
2 => "==",
3 => "!=",
4 => ">",
5 => ">=",
_ => "?",
};
instrs += &format!("{} ({})", arg, op);
}
Opcode::STORE_NAME
| Opcode::LOAD_NAME
| Opcode::STORE_GLOBAL
| Opcode::LOAD_GLOBAL
| Opcode::STORE_ATTR
| Opcode::LOAD_ATTR
| Opcode::LOAD_METHOD => {
instrs += &format!("{} ({})", arg, self.names.get(*arg as usize).unwrap());
}
Opcode::STORE_DEREF | Opcode::LOAD_DEREF => {
instrs +=
&format!("{} ({})", arg, self.freevars.get(*arg as usize).unwrap());
}
Opcode::STORE_FAST | Opcode::LOAD_FAST => {
instrs +=
&format!("{} ({})", arg, self.varnames.get(*arg as usize).unwrap());
}
Opcode::LOAD_CONST => {
instrs += &format!("{} ({})", arg, self.consts.get(*arg as usize).unwrap());
}
Opcode::FOR_ITER => {
instrs += &format!("{} (to {})", arg, idx + arg * 2 + 2);
}
Opcode::JUMP_FORWARD => {
instrs += &format!("{} (to {})", arg, idx + arg * 2 + 2);
}
Opcode::JUMP_ABSOLUTE => {
instrs += &format!("{} (to {})", arg, arg * 2);
}
Opcode::POP_JUMP_IF_FALSE | Opcode::POP_JUMP_IF_TRUE => {
instrs += &format!("{} (to {})", arg, arg * 2);
}
Opcode::MAKE_FUNCTION => {
let flag = match arg {
8 => "(closure)",
// TODO:
_ => "",
};
instrs += &format!("{} {}", arg, flag);
}
// Ergでは引数で型キャストする
Opcode::BINARY_ADD
| Opcode::BINARY_SUBTRACT
| Opcode::BINARY_MULTIPLY
| Opcode::BINARY_TRUE_DIVIDE => {
instrs += &format!("{} ({:?})", arg, TypePair::from(*arg));
}
other if other.take_arg() => {
instrs += &format!("{}", arg);
}
_ => {}
}
instrs.push('\n');
idx += 2;
line_offset += 2;
} else {
break;
}
}
instrs
}
pub fn code_info(&self) -> String {
let mut info = "".to_string();
info += &format!("Disassembly of {:?}:\n", self);
info += &self.attrs_info();
info += &self.tables_info();
info += &self.instr_info();
info.push('\n');
for cons in self.consts.iter() {
if let ValueObj::Code(c) = cons {
info += &c.code_info();
}
}
info
}
}

View file

@ -1,327 +0,0 @@
//! バイトコードからオブジェクトを復元する
use std::process;
use std::string::FromUtf8Error;
use crate::cache::Cache;
use crate::codeobj::CodeObj;
use crate::config::{ErgConfig, Input};
use crate::error::{ErrorCore, ErrorKind, Location};
use crate::serialize::DataTypePrefix;
use crate::traits::HasType;
use crate::ty::Type;
use crate::typaram::TyParam;
use crate::value::ValueObj;
use crate::{fn_name, switch_lang};
use crate::{RcArray, Str};
#[derive(Debug)]
pub struct DeserializeError {
pub errno: usize,
pub caused_by: Str,
pub desc: Str,
}
impl From<std::io::Error> for DeserializeError {
fn from(err: std::io::Error) -> Self {
Self::new(0, "io::Error::into", err.to_string())
}
}
impl From<FromUtf8Error> for DeserializeError {
fn from(err: FromUtf8Error) -> Self {
Self::new(0, "Str::try_from", err.to_string())
}
}
impl From<DeserializeError> for ErrorCore {
fn from(err: DeserializeError) -> Self {
ErrorCore::new(
err.errno,
ErrorKind::ImportError,
Location::Unknown,
err.desc,
Option::<Str>::None,
)
}
}
impl DeserializeError {
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(),
}
}
pub fn file_broken_error() -> Self {
Self::new(
0,
fn_name!(),
switch_lang!(
"japanese" => "読み込んだ.pycファイルは破損しています",
"simplified_chinese" => "加载的.pyc文件已损坏",
"traditional_chinese" => "加載的.pyc文件已損壞",
"english" => "the loaded .pyc file is broken",
),
)
}
pub fn type_error(expect: &Type, found: &Type) -> Self {
Self::new(
0,
fn_name!(),
switch_lang!(
"japanese" => format!(
"{}型オブジェクトを予期しましたが、 読み込んだオブジェクトは{}型です",
expect, found
),
"simplified_chinese" => format!(
"期望一个{}对象,但反序列化的对象是{}",
expect, found
),
"traditional_chinese" => format!(
"期望一個{}對象,但反序列化的對像是{}",
expect, found
),
"english" => format!(
"expect a {} object, but the deserialized object is {}",
expect, found
),
),
)
}
}
pub type DeserializeResult<T> = Result<T, DeserializeError>;
#[derive(Default)]
pub struct Deserializer {
str_cache: Cache<str>,
arr_cache: Cache<[ValueObj]>,
dict_cache: Cache<[(ValueObj, ValueObj)]>,
}
impl Deserializer {
pub fn new() -> Self {
Self {
str_cache: Cache::new(),
arr_cache: Cache::new(),
dict_cache: Cache::new(),
}
}
pub fn run(cfg: ErgConfig) {
let filename = if let Input::File(f) = cfg.input {
f
} else {
eprintln!("{:?} is not a filename", cfg.input);
process::exit(1);
};
let codeobj = CodeObj::from_pyc(&filename[..])
.unwrap_or_else(|_| panic!("failed to deserialize {filename}"));
println!("{}", codeobj.code_info());
}
fn get_cached_str(&mut self, s: &str) -> ValueObj {
ValueObj::Str(self.str_cache.get(s))
}
fn get_cached_arr(&mut self, arr: &[ValueObj]) -> ValueObj {
ValueObj::Array(self.arr_cache.get(arr))
}
/// TODO: 使わない?
pub fn get_cached_dict(&mut self, dict: &[(ValueObj, ValueObj)]) -> ValueObj {
ValueObj::Dict(self.dict_cache.get(dict))
}
pub fn vec_to_bytes<const LEN: usize>(vector: Vec<u8>) -> [u8; LEN] {
let mut arr = [0u8; LEN];
for (arr_elem, vec_elem) in arr.iter_mut().zip(vector.iter()) {
*arr_elem = *vec_elem;
}
arr
}
pub fn consume<const LEN: usize>(v: &mut Vec<u8>) -> [u8; LEN] {
Self::vec_to_bytes::<LEN>(v.drain(..LEN).collect::<Vec<_>>())
}
pub fn deserialize_u32(v: &mut Vec<u8>) -> u32 {
u32::from_le_bytes(Self::consume::<4>(v))
}
pub fn deserialize_const(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<ValueObj> {
match DataTypePrefix::from(v.remove(0)) {
DataTypePrefix::Int32 => {
let bytes = Self::consume::<4>(v);
Ok(ValueObj::Int(i32::from_le_bytes(bytes)))
}
DataTypePrefix::BinFloat => {
let bytes = Self::consume::<8>(v);
Ok(ValueObj::Float(f64::from_le_bytes(bytes)))
}
DataTypePrefix::ShortAscii | DataTypePrefix::ShortAsciiInterned => {
let len = v.remove(0);
let bytes = v.drain(..len as usize).collect();
Ok(self.get_cached_str(&String::from_utf8(bytes)?))
}
DataTypePrefix::Str | DataTypePrefix::Unicode => {
let len = Self::deserialize_u32(v);
let bytes = v.drain(..len as usize).collect();
Ok(self.get_cached_str(&String::from_utf8(bytes)?))
}
DataTypePrefix::True => Ok(ValueObj::Bool(true)),
DataTypePrefix::False => Ok(ValueObj::Bool(false)),
DataTypePrefix::SmallTuple => {
let len = v.remove(0);
let mut arr = Vec::with_capacity(len as usize);
for _ in 0..len {
arr.push(self.deserialize_const(v, python_ver)?);
}
Ok(self.get_cached_arr(&arr))
}
DataTypePrefix::Tuple => {
let len = Self::deserialize_u32(v);
let mut arr = Vec::with_capacity(len as usize);
for _ in 0..len {
arr.push(self.deserialize_const(v, python_ver)?);
}
Ok(self.get_cached_arr(&arr))
}
DataTypePrefix::Code => {
let argcount = Self::deserialize_u32(v);
let posonlyargcount = if python_ver >= 3413 {
Self::deserialize_u32(v)
} else {
0
};
let kwonlyargcount = Self::deserialize_u32(v);
let nlocals = Self::deserialize_u32(v);
let stacksize = Self::deserialize_u32(v);
let flags = Self::deserialize_u32(v);
let code = self.deserialize_bytes(v)?;
let consts = self.deserialize_const_vec(v, python_ver)?;
let names = self.deserialize_str_vec(v, python_ver)?;
let varnames = self.deserialize_str_vec(v, python_ver)?;
let freevars = self.deserialize_str_vec(v, python_ver)?;
let cellvars = self.deserialize_str_vec(v, python_ver)?;
let filename = self.deserialize_str(v, python_ver)?;
let name = self.deserialize_str(v, python_ver)?;
let firstlineno = Self::deserialize_u32(v);
let lnotab = self.deserialize_bytes(v)?;
Ok(ValueObj::from(CodeObj::new(
argcount,
posonlyargcount,
kwonlyargcount,
nlocals,
stacksize,
flags,
code,
consts,
names,
varnames,
freevars,
cellvars,
filename,
name,
firstlineno,
lnotab,
)))
}
DataTypePrefix::None => Ok(ValueObj::None),
other => Err(DeserializeError::new(
0,
fn_name!(),
switch_lang!(
"japanese" => format!("このオブジェクトは復元できません: {}", other),
"simplified_chinese" => format!("无法反序列化此对象:{}", other),
"traditional_chinese" => format!("無法反序列化此對象:{}", other),
"english" => format!("cannot deserialize this object: {}", other),
),
)),
}
}
pub fn deserialize_const_vec(
&mut self,
v: &mut Vec<u8>,
python_ver: u32,
) -> DeserializeResult<Vec<ValueObj>> {
match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => Ok(arr.to_vec()),
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>> {
match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => Ok(arr),
other => Err(DeserializeError::type_error(&Type::Str, other.ref_t())),
}
}
pub fn array_into_const(&mut self, arr: &[ValueObj]) -> ValueObj {
self.get_cached_arr(arr)
}
pub fn try_into_str(&mut self, c: ValueObj) -> DeserializeResult<Str> {
match c {
ValueObj::Str(s) => Ok(s),
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>> {
match self.deserialize_const(v, python_ver)? {
ValueObj::Array(arr) => {
let mut strs = Vec::with_capacity(arr.len());
for c in arr.iter().cloned() {
strs.push(self.try_into_str(c)?);
}
Ok(strs)
}
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> {
match self.deserialize_const(v, python_ver)? {
ValueObj::Str(s) => Ok(s),
other => Err(DeserializeError::type_error(&Type::Str, other.ref_t())),
}
}
pub fn deserialize_bytes(&self, v: &mut Vec<u8>) -> DeserializeResult<Vec<u8>> {
if DataTypePrefix::from(v.remove(0)) != DataTypePrefix::Str {
return Err(DeserializeError::new(
0,
fn_name!(),
switch_lang!(
"japanese" => "バイト列の読み込みに失敗しました",
"simplified_chinese" => "未能加载字节",
"traditional_chinese" => "未能加載字節",
"english" => "failed to load bytes",
),
));
}
let len = Self::deserialize_u32(v);
Ok(v.drain(0..len as usize).collect())
}
}

View file

@ -1,472 +0,0 @@
use std::cell::{Ref, RefMut};
use std::fmt;
use std::mem;
use crate::rccell::RcCell;
use crate::traits::LimitedDisplay;
use crate::ty::Type;
use crate::typaram::TyParam;
use crate::Str;
pub type Level = usize;
pub type Id = usize;
thread_local! {
static UNBOUND_ID: RcCell<usize> = RcCell::new(0);
static REFINEMENT_VAR_ID: RcCell<usize> = RcCell::new(0);
}
pub fn fresh_varname() -> String {
REFINEMENT_VAR_ID.with(|id| {
*id.borrow_mut() += 1;
let i = *id.borrow();
format!("%v{i}")
})
}
pub fn fresh_param_name() -> String {
REFINEMENT_VAR_ID.with(|id| {
*id.borrow_mut() += 1;
let i = *id.borrow();
format!("%p{i}")
})
}
pub trait HasLevel {
fn level(&self) -> Option<Level>;
fn update_level(&self, level: Level);
fn lift(&self);
}
// REVIEW: TyBoundと微妙に役割が被っている
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constraint {
// : Type --> (:> Never, <: Obj)
// :> Sub --> (:> Sub, <: Obj)
// <: Sup --> (:> Never, <: Sup)
/// :> Sub, <: Sup
Sandwiched {
sub: Type,
sup: Type,
},
// : Int, ...
TypeOf(Type),
Uninited,
}
impl fmt::Display for Constraint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.limited_fmt(f, 10)
}
}
impl LimitedDisplay for Constraint {
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
if limit == 0 {
return write!(f, "...");
}
match self {
Self::Sandwiched { sub, sup } => match (sub == &Type::Never, sup == &Type::Obj) {
(true, true) => write!(f, ": Type (:> Never, <: Obj)"),
(true, false) => {
write!(f, "<: ")?;
sup.limited_fmt(f, limit - 1)
}
(false, true) => {
write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)
}
(false, false) => {
write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)?;
write!(f, ", <: ")?;
sup.limited_fmt(f, limit - 1)
}
},
Self::TypeOf(t) => {
write!(f, ": ")?;
t.limited_fmt(f, limit - 1)
}
Self::Uninited => write!(f, "<uninited>"),
}
}
}
impl Constraint {
pub const fn sandwiched(sub: Type, sup: Type) -> Self {
Self::Sandwiched { sub, sup }
}
pub fn type_of(t: Type) -> Self {
if &t == &Type::Type {
Self::sandwiched(Type::Never, Type::Obj)
} else {
Self::TypeOf(t)
}
}
pub const fn subtype_of(sup: Type) -> Self {
Self::sandwiched(Type::Never, sup)
}
pub const fn supertype_of(sub: Type) -> Self {
Self::sandwiched(sub, Type::Obj)
}
pub const fn is_uninited(&self) -> bool {
matches!(self, Self::Uninited)
}
pub fn get_type(&self) -> Option<&Type> {
match self {
Self::TypeOf(ty) => Some(ty),
Self::Sandwiched {
sub: Type::Never,
sup: Type::Obj,
} => Some(&Type::Type),
_ => None,
}
}
pub fn get_sub_type(&self) -> Option<&Type> {
match self {
Self::Sandwiched { sub, .. } => Some(sub),
_ => None,
}
}
pub fn get_super_type(&self) -> Option<&Type> {
match self {
Self::Sandwiched { sup, .. } => Some(sup),
_ => None,
}
}
pub fn get_sub_sup_type(&self) -> Option<(&Type, &Type)> {
match self {
Self::Sandwiched { sub, sup } => Some((sub, sup)),
_ => None,
}
}
pub fn get_super_type_mut(&mut self) -> Option<&mut Type> {
match self {
Self::Sandwiched { sup, .. } => Some(sup),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum FreeKind<T> {
Linked(T),
Unbound {
id: Id,
lev: Level,
constraint: Constraint,
},
NamedUnbound {
name: Str,
lev: Level,
constraint: Constraint,
},
}
impl<T: LimitedDisplay> fmt::Display for FreeKind<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.limited_fmt(f, 10)
}
}
impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
if limit == 0 {
return write!(f, "...");
}
match self {
Self::Linked(t) => t.limited_fmt(f, limit),
Self::NamedUnbound {
name,
lev,
constraint,
} => {
write!(f, "?{name}(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")[{lev}]")
}
Self::Unbound {
id,
lev,
constraint,
} => {
write!(f, "?{id}(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")[{lev}]")
}
}
}
}
impl<T> FreeKind<T> {
pub const fn unbound(id: Id, lev: Level, constraint: Constraint) -> Self {
Self::Unbound {
id,
lev,
constraint,
}
}
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self {
Self::NamedUnbound {
name,
lev,
constraint,
}
}
pub const fn constraint(&self) -> Option<&Constraint> {
match self {
Self::Unbound { constraint, .. } | Self::NamedUnbound { constraint, .. } => {
Some(constraint)
}
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Free<T>(RcCell<FreeKind<T>>);
impl<T: LimitedDisplay> fmt::Display for Free<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.borrow())
}
}
impl<T: LimitedDisplay> LimitedDisplay for Free<T> {
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
self.0.borrow().limited_fmt(f, limit)
}
}
impl<T> Free<T> {
pub fn borrow(&self) -> Ref<'_, FreeKind<T>> {
self.0.borrow()
}
pub fn borrow_mut(&self) -> RefMut<'_, FreeKind<T>> {
self.0.borrow_mut()
}
}
impl<T: Clone + HasLevel> Free<T> {
pub fn new(f: FreeKind<T>) -> Self {
Self(RcCell::new(f))
}
pub fn new_unbound(level: Level, constraint: Constraint) -> Self {
UNBOUND_ID.with(|id| {
*id.borrow_mut() += 1;
Self(RcCell::new(FreeKind::unbound(
*id.borrow(),
level,
constraint,
)))
})
}
pub fn new_named_unbound(name: Str, level: Level, constraint: Constraint) -> Self {
Self(RcCell::new(FreeKind::named_unbound(
name, level, constraint,
)))
}
pub fn new_linked(t: T) -> Self {
Self(RcCell::new(FreeKind::Linked(t)))
}
pub fn link(&self, to: &T) {
*self.0.borrow_mut() = FreeKind::Linked(to.clone());
}
pub fn update_level(&self, level: Level) {
match &mut *self.0.borrow_mut() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } if level < *lev => {
*lev = level;
}
FreeKind::Linked(t) => {
t.update_level(level);
}
_ => {}
}
}
pub fn lift(&self) {
match &mut *self.0.borrow_mut() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => {
*lev += 1;
}
FreeKind::Linked(t) => {
if let Some(lev) = t.level() {
t.update_level(lev + 1);
}
}
}
}
pub fn level(&self) -> Option<Level> {
match &*self.0.borrow() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => Some(*lev),
FreeKind::Linked(t) => t.level(),
}
}
pub fn update_constraint(&self, new_constraint: Constraint) {
match &mut *self.0.borrow_mut() {
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
*constraint = new_constraint;
}
_ => {}
}
}
pub fn get_name(&self) -> Option<Str> {
match self.0.clone_inner() {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound { .. } => None,
FreeKind::NamedUnbound { name, .. } => Some(name),
}
}
pub fn unwrap_unbound(self) -> (Option<Str>, usize, Constraint) {
match self.0.clone_inner() {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound {
constraint, lev, ..
} => (None, lev, constraint),
FreeKind::NamedUnbound {
name,
lev,
constraint,
} => (Some(name), lev, constraint),
}
}
pub fn unwrap_linked(self) -> T {
match self.0.clone_inner() {
FreeKind::Linked(t) => t,
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
panic!("the value is unbounded")
}
}
}
/// returns linked type (panic if self is unbounded)
/// NOTE: check by `.is_linked` before call
pub fn crack(&self) -> Ref<'_, T> {
Ref::map(self.0.borrow(), |f| match f {
FreeKind::Linked(t) => t,
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
panic!("the value is unbounded")
}
})
}
pub fn crack_constraint(&self) -> Ref<'_, Constraint> {
Ref::map(self.0.borrow(), |f| match f {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
constraint
}
})
}
pub fn type_of(&self) -> Option<Type> {
self.0
.borrow()
.constraint()
.and_then(|c| c.get_type().cloned())
}
pub fn crack_subtype(&self) -> Option<Type> {
self.0
.borrow()
.constraint()
.and_then(|c| c.get_super_type().cloned())
}
pub fn crack_bound_types(&self) -> Option<(Type, Type)> {
self.0
.borrow()
.constraint()
.and_then(|c| c.get_sub_sup_type().map(|(l, r)| (l.clone(), r.clone())))
}
pub fn is_unbound(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. }
)
}
pub fn constraint_is_typeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_type().is_some()
)
}
pub fn constraint_is_supertypeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_type().is_some()
)
}
pub fn constraint_is_subtypeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_super_type().is_some()
)
}
pub fn constraint_is_sandwiched(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_sup_type().is_some()
)
}
pub fn is_linked(&self) -> bool {
matches!(&*self.0.borrow(), FreeKind::Linked(_))
}
pub fn unbound_name(&self) -> Option<Str> {
match &*self.0.borrow() {
FreeKind::NamedUnbound { name, .. } => Some(name.clone()),
_ => None,
}
}
}
impl Free<TyParam> {
pub fn map<F>(&self, f: F)
where
F: Fn(TyParam) -> TyParam,
{
match &mut *self.0.borrow_mut() {
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
panic!("the value is unbounded")
}
FreeKind::Linked(t) => {
*t = f(mem::take(t));
}
}
}
}
pub type FreeTyVar = Free<Type>;
pub type FreeTyParam = Free<TyParam>;

View file

@ -2,14 +2,11 @@
use std::fmt;
pub mod cache;
pub mod codeobj;
pub mod color;
pub mod config;
pub mod datetime;
pub mod deserialize;
pub mod dict;
pub mod error;
pub mod free;
pub mod fxhash;
pub mod levenshtein;
pub mod macros;
@ -22,9 +19,7 @@ pub mod stdin;
pub mod str;
pub mod traits;
pub mod tsort;
pub mod ty;
pub mod typaram;
pub mod value;
pub mod vis;
use crate::set::Set;
pub use crate::str::Str;

View file

@ -5,8 +5,6 @@ use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use crate::fxhash::FxHashSet;
use crate::ty::Type;
use crate::value::ValueObj;
use crate::{debug_fmt_iter, fmt_iter};
#[macro_export]
@ -201,33 +199,3 @@ impl<T: Hash + Ord> Set<T> {
self.iter().min_by(|x, y| x.cmp(y))
}
}
impl Set<ValueObj> {
// false -> SyntaxError
pub fn is_homogeneous(&self) -> bool {
let l_first = self.iter().next().unwrap().class();
self.iter().all(|c| c.class() == l_first)
}
pub fn inner_class(&self) -> Type {
self.iter().next().unwrap().class()
}
pub fn max(&self) -> Option<ValueObj> {
if !self.is_homogeneous() {
return None;
}
self.iter()
.max_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone)
}
pub fn min(&self) -> Option<ValueObj> {
if !self.is_homogeneous() {
return None;
}
self.iter()
.min_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone)
}
}

View file

@ -11,7 +11,6 @@ use std::vec::IntoIter;
use crate::color::{GREEN, RESET};
use crate::config::{ErgConfig, Input, BUILD_DATE, GIT_HASH_SHORT, SEMVER};
use crate::error::{ErrorDisplay, ErrorKind, Location, MultiErrorDisplay};
use crate::ty::Type;
use crate::Str;
use crate::{addr_eq, chomp, log, switch_unreachable};
@ -513,106 +512,6 @@ macro_rules! impl_nested_display_for_enum {
}
}
/// cloneのコストがあるためなるべく.ref_tを使うようにすること
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
#[allow(unused_variables)]
pub trait HasType {
fn ref_t(&self) -> &Type;
// 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す
fn signature_t(&self) -> Option<&Type>;
// 最後にHIR全体の型変数を消すために使う
fn ref_mut_t(&mut self) -> &mut Type;
fn signature_mut_t(&mut self) -> Option<&mut Type>;
#[inline]
fn t(&self) -> Type {
self.ref_t().clone()
}
#[inline]
fn inner_ts(&self) -> Vec<Type> {
self.ref_t().inner_ts()
}
#[inline]
fn lhs_t(&self) -> &Type {
&self.ref_t().non_default_params().unwrap()[0].ty
}
#[inline]
fn rhs_t(&self) -> &Type {
&self.ref_t().non_default_params().unwrap()[1].ty
}
}
#[macro_export]
macro_rules! impl_t {
($T: ty) => {
impl $crate::traits::HasType for $T {
#[inline]
fn ref_t(&self) -> &Type {
&self.t
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
};
($T: ty, $sig_t: ident) => {
impl $crate::traits::HasType for $T {
#[inline]
fn ref_t(&self) -> &Type {
&self.t
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
Some(&self.$sig_t)
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
&mut self.$sig_t
}
}
};
}
#[macro_export]
macro_rules! impl_t_for_enum {
($Enum: ident; $($Variant: ident $(,)?)*) => {
impl $crate::traits::HasType for $Enum {
fn ref_t(&self) -> &Type {
match self {
$($Enum::$Variant(v) => v.ref_t(),)*
}
}
fn ref_mut_t(&mut self) -> &mut Type {
match self {
$($Enum::$Variant(v) => v.ref_mut_t(),)*
}
}
fn signature_t(&self) -> Option<&Type> {
match self {
$($Enum::$Variant(v) => v.signature_t(),)*
}
}
fn signature_mut_t(&mut self) -> Option<&mut Type> {
match self {
$($Enum::$Variant(v) => v.signature_mut_t(),)*
}
}
}
}
}
/// Pythonではis演算子に相当
pub trait AddrEq {
#[inline]

File diff suppressed because it is too large Load diff

View file

@ -1,702 +0,0 @@
use std::cmp::Ordering;
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub};
use crate::free::{Constraint, FreeKind, FreeTyParam, HasLevel, Level};
use crate::traits::LimitedDisplay;
use crate::ty::Type;
use crate::value::ValueObj;
use crate::Str;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum OpKind {
Add,
Sub,
Mul,
Div,
Pow,
Mod,
Pos,
Neg,
Invert,
Gt,
Lt,
Ge,
Le,
Eq,
Ne,
And,
Or,
BitAnd,
BitOr,
BitXor,
Shl,
Shr,
Mutate,
}
impl fmt::Display for OpKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Add => write!(f, "+"),
Self::Sub => write!(f, "-"),
Self::Mul => write!(f, "*"),
Self::Div => write!(f, "/"),
Self::Pow => write!(f, "**"),
Self::Mod => write!(f, "%"),
Self::Pos => write!(f, "+"),
Self::Neg => write!(f, "-"),
Self::Invert => write!(f, "~"),
Self::Gt => write!(f, ">"),
Self::Lt => write!(f, "<"),
Self::Ge => write!(f, ">="),
Self::Le => write!(f, "<="),
Self::Eq => write!(f, "=="),
Self::Ne => write!(f, "!="),
Self::And => write!(f, "and"),
Self::Or => write!(f, "or"),
Self::BitAnd => write!(f, "&&"),
Self::BitOr => write!(f, "||"),
Self::BitXor => write!(f, "^^"),
Self::Shl => write!(f, "<<"),
Self::Shr => write!(f, ">>"),
Self::Mutate => write!(f, "!"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IntervalOp {
/// ..
Closed,
/// <..
LeftOpen,
/// ..<
RightOpen,
/// <..<
Open,
}
impl IntervalOp {
pub const fn is_closed(&self) -> bool {
matches!(self, Self::Closed)
}
pub const fn is_left_open(&self) -> bool {
matches!(self, Self::LeftOpen | Self::Open)
}
pub const fn is_right_open(&self) -> bool {
matches!(self, Self::RightOpen | Self::Open)
}
pub const fn is_open(&self) -> bool {
matches!(self, Self::Open)
}
}
impl fmt::Display for IntervalOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Closed => write!(f, ".."),
Self::LeftOpen => write!(f, "<.."),
Self::RightOpen => write!(f, "..<"),
Self::Open => write!(f, "<..<"),
}
}
}
/// 型引数
/// データのみ、その評価結果は別に持つ
/// * Literal: 1, "aa", True, None, ... (don't use container literals, they can only hold literals)
/// * Type: Int, Add(?R, ?O), ...
/// * Mono: I, N, ...
/// * Attr: math.PI, ...
/// * Array: `[1, 2, N]`
/// * Tuple: (1, N, True)
/// * App: Array(Int), Fib(10), ...
/// * QuantVar: N: Nat, ...
/// * FreeVar: ?I: Int, ...
/// * UnaryOp: -N, ~B, ...
/// * BinOp: 1 + 1, N * 2, ...
/// * Erased: _: Type, _: Nat, ...
#[derive(Debug, Clone, Hash)]
pub enum TyParam {
Value(ValueObj),
Type(Box<Type>),
Array(Vec<TyParam>),
Tuple(Vec<TyParam>),
Mono(Str),
MonoProj {
obj: Box<TyParam>,
attr: Str,
},
App {
name: Str,
args: Vec<TyParam>,
},
UnaryOp {
op: OpKind,
val: Box<TyParam>,
},
BinOp {
op: OpKind,
lhs: Box<TyParam>,
rhs: Box<TyParam>,
},
Erased(Box<Type>),
MonoQVar(Str),
PolyQVar {
name: Str,
args: Vec<TyParam>,
},
FreeVar(FreeTyParam),
Failure,
}
impl PartialEq for TyParam {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Value(l), Self::Value(r)) => l == r,
(Self::Type(l), Self::Type(r)) => l == r,
(Self::Array(l), Self::Array(r)) => l == r,
(Self::Tuple(l), Self::Tuple(r)) => l == r,
(Self::Mono(l), Self::Mono(r)) | (Self::MonoQVar(l), Self::MonoQVar(r)) => l == r,
(
Self::MonoProj { obj, attr },
Self::MonoProj {
obj: r_obj,
attr: r_attr,
},
) => obj == r_obj && attr == r_attr,
(
Self::App {
name: ln,
args: lps,
}
| Self::PolyQVar {
name: ln,
args: lps,
},
Self::App {
name: rn,
args: rps,
}
| Self::PolyQVar {
name: rn,
args: rps,
},
) => ln == rn && lps == rps,
(
Self::UnaryOp { op, val },
Self::UnaryOp {
op: r_op,
val: r_val,
},
) => op == r_op && val == r_val,
(
Self::BinOp { op, lhs, rhs },
Self::BinOp {
op: r_op,
lhs: r_lhs,
rhs: r_rhs,
},
) => op == r_op && lhs == r_lhs && rhs == r_rhs,
(Self::Erased(l), Self::Erased(r)) => l == r,
(Self::FreeVar(l), Self::FreeVar(r)) => l == r,
(Self::FreeVar(fv), other) => match &*fv.borrow() {
FreeKind::Linked(t) => t == other,
_ => false,
},
(self_, Self::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) => t == self_,
_ => false,
},
(Self::Failure, Self::Failure) => true,
_ => false,
}
}
}
impl Eq for TyParam {}
impl fmt::Display for TyParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.limited_fmt(f, 10)
}
}
impl LimitedDisplay for TyParam {
fn limited_fmt(&self, f: &mut fmt::Formatter<'_>, limit: usize) -> fmt::Result {
if limit == 0 {
return write!(f, "...");
}
match self {
Self::Value(v) => write!(f, "{v}"),
Self::Failure => write!(f, "<Failure>"),
Self::Type(t) => t.limited_fmt(f, limit - 1),
Self::FreeVar(fv) => fv.limited_fmt(f, limit - 1),
Self::UnaryOp { op, val } => {
write!(f, "{}", op)?;
val.limited_fmt(f, limit - 1)
}
Self::BinOp { op, lhs, rhs } => {
lhs.limited_fmt(f, limit - 1)?;
write!(f, " {} ", op)?;
rhs.limited_fmt(f, limit - 1)
}
Self::App { name, args } => {
write!(f, "{}", name)?;
write!(f, "(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
arg.limited_fmt(f, limit - 1)?;
}
write!(f, ")")?;
Ok(())
}
Self::PolyQVar { name, args } => {
write!(f, "'{}", name)?;
write!(f, "(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
arg.limited_fmt(f, limit - 1)?;
}
write!(f, ")")?;
Ok(())
}
Self::Erased(t) => {
write!(f, "_: ")?;
t.limited_fmt(f, limit - 1)
}
Self::Mono(name) => write!(f, "{}", name),
Self::MonoQVar(name) => write!(f, "'{}", name),
Self::MonoProj { obj, attr } => {
write!(f, "{}.", obj)?;
write!(f, "{}", attr)
}
Self::Array(arr) => {
write!(f, "[")?;
for (i, t) in arr.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
t.limited_fmt(f, limit - 1)?;
}
write!(f, "]")
}
Self::Tuple(tuple) => {
write!(f, "(")?;
for (i, t) in tuple.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
t.limited_fmt(f, limit - 1)?;
}
write!(f, ")")
}
}
}
}
impl Default for TyParam {
#[inline]
fn default() -> Self {
Self::Failure
}
}
impl Add for TyParam {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::bin(OpKind::Add, self, rhs)
}
}
impl Sub for TyParam {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self::bin(OpKind::Sub, self, rhs)
}
}
impl Mul for TyParam {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::bin(OpKind::Mul, self, rhs)
}
}
impl Div for TyParam {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self::bin(OpKind::Div, self, rhs)
}
}
impl Neg for TyParam {
type Output = Self;
fn neg(self) -> Self::Output {
Self::unary(OpKind::Neg, self)
}
}
impl From<Range<TyParam>> for TyParam {
fn from(r: Range<TyParam>) -> Self {
Self::t(Type::int_interval(IntervalOp::RightOpen, r.start, r.end))
}
}
impl From<Range<&TyParam>> for TyParam {
fn from(r: Range<&TyParam>) -> Self {
Self::t(Type::int_interval(
IntervalOp::RightOpen,
r.start.clone(),
r.end.clone(),
))
}
}
impl From<RangeInclusive<TyParam>> for TyParam {
fn from(r: RangeInclusive<TyParam>) -> Self {
let (start, end) = r.into_inner();
Self::t(Type::int_interval(IntervalOp::Closed, start, end))
}
}
impl From<RangeInclusive<&TyParam>> for TyParam {
fn from(r: RangeInclusive<&TyParam>) -> Self {
let (start, end) = r.into_inner();
Self::t(Type::int_interval(
IntervalOp::Closed,
start.clone(),
end.clone(),
))
}
}
impl<V: Into<ValueObj>> From<V> for TyParam {
fn from(v: V) -> Self {
Self::Value(v.into())
}
}
impl HasLevel for TyParam {
fn level(&self) -> Option<Level> {
match self {
Self::Type(t) => t.level(),
Self::FreeVar(fv) => fv.level(),
Self::UnaryOp { val, .. } => val.level(),
Self::BinOp { lhs, rhs, .. } => lhs.level().and_then(|l| rhs.level().map(|r| l.max(r))),
_ => None,
}
}
fn update_level(&self, level: Level) {
match self {
Self::FreeVar(fv) => fv.update_level(level),
Self::UnaryOp { val, .. } => val.update_level(level),
Self::BinOp { lhs, rhs, .. } => {
lhs.update_level(level);
rhs.update_level(level);
}
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
for arg in args.iter() {
arg.update_level(level);
}
}
_ => {}
}
}
fn lift(&self) {
match self {
Self::FreeVar(fv) => fv.lift(),
Self::UnaryOp { val, .. } => val.lift(),
Self::BinOp { lhs, rhs, .. } => {
lhs.lift();
rhs.lift();
}
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
for arg in args.iter() {
arg.lift();
}
}
_ => {}
}
}
}
impl TyParam {
pub fn t(t: Type) -> Self {
Self::Type(Box::new(t))
}
pub fn mono<S: Into<Str>>(name: S) -> Self {
Self::Mono(name.into())
}
pub fn mono_q<S: Into<Str>>(name: S) -> Self {
Self::MonoQVar(name.into())
}
pub fn mono_proj<S: Into<Str>>(obj: TyParam, attr: S) -> Self {
Self::MonoProj {
obj: Box::new(obj),
attr: attr.into(),
}
}
// TODO: polymorphic type
pub fn array_t(t: Str, len: TyParam) -> Self {
Self::Array(vec![TyParam::t(Type::mono(t)), len])
}
pub fn free_var(level: usize, t: Type) -> Self {
let constraint = Constraint::type_of(t);
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
}
pub fn named_free_var(name: Str, level: usize, t: Type) -> Self {
let constraint = Constraint::type_of(t);
Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constraint))
}
#[inline]
pub fn value<V: Into<ValueObj>>(v: V) -> Self {
Self::Value(v.into())
}
#[inline]
pub fn unary(op: OpKind, val: TyParam) -> Self {
Self::UnaryOp {
op,
val: Box::new(val),
}
}
#[inline]
pub fn mutate(self) -> Self {
Self::unary(OpKind::Mutate, self)
}
#[inline]
pub fn bin(op: OpKind, lhs: TyParam, rhs: TyParam) -> Self {
Self::BinOp {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
}
}
pub fn app(name: &'static str, args: Vec<TyParam>) -> Self {
Self::App {
name: Str::ever(name),
args,
}
}
#[inline]
pub fn erased(t: Type) -> Self {
Self::Erased(Box::new(t))
}
// if self: Ratio, Succ(self) => self+ε
pub fn succ(self) -> Self {
Self::app("Succ", vec![self])
}
// if self: Ratio, Pred(self) => self-ε
pub fn pred(self) -> Self {
Self::app("Pred", vec![self])
}
pub fn name(&self) -> Option<Str> {
match self {
Self::Type(t) => Some(t.name()),
Self::Mono(name) => Some(name.clone()),
Self::MonoQVar(name) => Some(name.clone()),
_ => None,
}
}
pub fn tvar_name(&self) -> Option<Str> {
match self {
Self::Type(t) => t.tvar_name(),
Self::FreeVar(fv) => fv.unbound_name(),
Self::MonoQVar(name) => Some(name.clone()),
_ => None,
}
}
// 定数の比較など環境が必要な場合はContext::try_cmpを使う
pub fn cheap_cmp(&self, r: &TyParam) -> Option<TyParamOrdering> {
match (self, r) {
(Self::Type(l), Self::Type(r)) =>
if l == r { Some(TyParamOrdering::Equal) } else { Some(TyParamOrdering::NotEqual) },
(Self::Value(l), Self::Value(r)) =>
l.try_cmp(r).map(Into::into),
(Self::FreeVar(fv), p) if fv.is_linked() =>
fv.crack().cheap_cmp(p),
(p, Self::FreeVar(fv)) if fv.is_linked() =>
p.cheap_cmp(&*fv.crack()),
(Self::FreeVar{ .. } | Self::Erased(_), Self::FreeVar{ .. } | Self::Erased(_))
/* if v.is_unbound() */ => Some(Any),
(Self::App{ name, args }, Self::App{ name: rname, args: rargs })
| (Self::PolyQVar{ name, args }, Self::PolyQVar{ name: rname, args: rargs }) =>
if name == rname
&& args.len() == rargs.len()
&& args.iter().zip(rargs.iter()).all(|(l, r)| l.cheap_cmp(r) == Some(Equal)) {
Some(TyParamOrdering::Equal)
} else {
Some(TyParamOrdering::NotEqual)
},
(l, r @ (Self::Erased(_) | Self::Mono{ .. } | Self::FreeVar{ .. })) =>
r.cheap_cmp(l).map(|ord| ord.reverse()),
_ => None,
}
}
pub fn has_qvar(&self) -> bool {
match self {
Self::MonoQVar(_) | Self::PolyQVar { .. } => true,
Self::FreeVar(fv) => {
if fv.is_unbound() {
true
} else {
fv.crack().has_qvar()
}
}
Self::Type(t) => t.has_qvar(),
Self::MonoProj { obj, .. } => obj.has_qvar(),
Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_qvar()),
Self::UnaryOp { val, .. } => val.has_qvar(),
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
Self::Erased(t) => t.has_qvar(),
_ => false,
}
}
pub fn has_unbound_var(&self) -> bool {
match self {
Self::FreeVar(fv) => {
if fv.is_unbound() {
true
} else {
fv.crack().has_unbound_var()
}
}
Self::Type(t) => t.has_unbound_var(),
Self::MonoProj { obj, .. } => obj.has_unbound_var(),
Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_unbound_var()),
Self::UnaryOp { val, .. } => val.has_unbound_var(),
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
Self::App { args, .. } | Self::PolyQVar { args, .. } => {
args.iter().any(|p| p.has_unbound_var())
}
Self::Erased(t) => t.has_unbound_var(),
_ => false,
}
}
pub fn has_no_unbound_var(&self) -> bool {
!self.has_unbound_var()
}
pub fn has_upper_bound(&self) -> bool {
match self {
// TODO: 型によっては上限がある
// また、上限がないもの同士の加算等も上限はない
Self::Erased(_) | Self::MonoQVar(_) => false,
Self::FreeVar(fv) => !fv.is_unbound(), // != fv.is_linked(),
_ => true,
}
}
pub fn has_lower_bound(&self) -> bool {
match self {
Self::Erased(_) | Self::MonoQVar(_) => false,
Self::FreeVar(fv) => !fv.is_unbound(),
_ => true,
}
}
pub fn update_constraint(&self, new_constraint: Constraint) {
match self {
Self::Type(t) => t.update_constraint(new_constraint),
_ => {}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum TyParamOrdering {
Less,
Equal,
Greater,
LessEqual, // Less or Equal
NotEqual, // Less or Greater
GreaterEqual, // Greater or Equal
Any,
NoRelation,
}
use TyParamOrdering::*;
impl From<Ordering> for TyParamOrdering {
fn from(o: Ordering) -> Self {
match o {
Ordering::Less => Less,
Ordering::Equal => Equal,
Ordering::Greater => Greater,
}
}
}
impl TryFrom<TyParamOrdering> for Ordering {
type Error = ();
fn try_from(o: TyParamOrdering) -> Result<Self, Self::Error> {
match o {
Less => Ok(Ordering::Less),
Equal => Ok(Ordering::Equal),
Greater => Ok(Ordering::Greater),
_ => Err(()),
}
}
}
impl TyParamOrdering {
pub const fn is_lt(&self) -> bool {
matches!(self, Less | LessEqual | Any)
}
pub const fn is_le(&self) -> bool {
matches!(self, Less | Equal | LessEqual | Any)
}
pub const fn is_gt(&self) -> bool {
matches!(self, Greater | GreaterEqual | Any)
}
pub const fn is_ge(&self) -> bool {
matches!(self, Greater | Equal | GreaterEqual | Any)
}
pub const fn is_eq(&self) -> bool {
matches!(self, Equal | Any)
}
pub const fn is_ne(&self) -> bool {
matches!(self, Less | Greater | NotEqual | Any)
}
pub const fn reverse(&self) -> Self {
match self {
Less => Greater,
Greater => Less,
LessEqual => GreaterEqual,
GreaterEqual => LessEqual,
Equal => NotEqual,
NotEqual => Equal,
Any | NoRelation => Any,
}
}
}

View file

@ -1,683 +0,0 @@
//! defines `ValueObj` (used in the compiler, VM).
//!
//! コンパイラ、VM等で使われる(データも保持した)値オブジェクトを定義する
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Neg;
use std::rc::Rc;
use crate::codeobj::CodeObj;
use crate::dict::Dict;
use crate::free::fresh_varname;
use crate::rccell::RcCell;
use crate::serialize::*;
use crate::set;
use crate::traits::HasType;
use crate::ty::{ConstSubr, Predicate, Type};
use crate::typaram::TyParam;
use crate::{fmt_iter, impl_display_from_debug, switch_lang};
use crate::{RcArray, Str};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
Private,
Public,
}
impl Visibility {
pub const fn is_public(&self) -> bool {
matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
}
/// same structure as `Identifier`, but only for Record fields.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field {
vis: Visibility,
symbol: Str,
}
impl fmt::Display for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.vis == Visibility::Public {
write!(f, ".{}", self.symbol)
} else {
write!(f, "{}", self.symbol)
}
}
}
impl Borrow<str> for Field {
#[inline]
fn borrow(&self) -> &str {
&self.symbol[..]
}
}
impl Borrow<Str> for Field {
#[inline]
fn borrow(&self) -> &Str {
&self.symbol
}
}
impl Field {
pub const fn new(vis: Visibility, symbol: Str) -> Self {
Field { vis, symbol }
}
}
/// 値オブジェクト
/// コンパイル時評価ができ、シリアライズも可能
#[derive(Clone, PartialEq, Default)]
pub enum ValueObj {
Int(i32),
Nat(u64),
Float(f64),
Str(Str),
Bool(bool),
Array(Rc<[ValueObj]>),
Dict(Rc<[(ValueObj, ValueObj)]>),
Record(Dict<Field, ValueObj>),
Code(Box<CodeObj>),
Subr(ConstSubr),
Type(Box<Type>),
None,
Ellipsis,
NotImplemented,
NegInf,
Inf,
Mut(RcCell<ValueObj>),
#[default]
Illegal, // to avoid conversions with TryFrom
}
impl fmt::Debug for ValueObj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Int(i) => write!(f, "{i}"),
Self::Nat(n) => write!(f, "{n}"),
Self::Float(fl) => {
// In Rust, .0 is shown omitted.
if fl.fract() < 1e-10 {
write!(f, "{fl:.1}")
} else {
write!(f, "{fl}")
}
}
Self::Str(s) => write!(f, "\"{s}\""),
Self::Bool(b) => {
if *b {
write!(f, "True")
} else {
write!(f, "False")
}
}
Self::Array(arr) => write!(f, "[{}]", fmt_iter(arr.iter())),
Self::Dict(dict) => {
write!(f, "{{")?;
for (i, (k, v)) in dict.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", k, v)?;
}
write!(f, "}}")
}
Self::Code(code) => write!(f, "{code}"),
Self::Record(rec) => {
write!(f, "{{")?;
for (i, (k, v)) in rec.iter().enumerate() {
if i != 0 {
write!(f, "; ")?;
}
write!(f, "{k} = {v}")?;
}
write!(f, "}}")
}
Self::Subr(subr) => write!(f, "{subr:?}"),
Self::Type(t) => write!(f, "{t}"),
Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"),
Self::NotImplemented => write!(f, "NotImplemented"),
Self::NegInf => write!(f, "-Inf"),
Self::Inf => write!(f, "Inf"),
Self::Mut(v) => write!(f, "!{:?}", v.borrow()),
Self::Illegal => write!(f, "<illegal>"),
}
}
}
impl_display_from_debug!(ValueObj);
impl Eq for ValueObj {}
impl Neg for ValueObj {
type Output = Self;
#[inline]
fn neg(self) -> Self {
match self {
Self::Int(i) => Self::Int(-i),
Self::Nat(n) => Self::Int(-(n as i32)),
Self::Float(fl) => Self::Float(-fl),
Self::Inf => Self::NegInf,
Self::NegInf => Self::Inf,
other => panic!("cannot negate {other}"),
}
}
}
// FIXME:
impl Hash for ValueObj {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Self::Int(i) => i.hash(state),
Self::Nat(n) => n.hash(state),
// TODO:
Self::Float(f) => f.to_bits().hash(state),
Self::Str(s) => s.hash(state),
Self::Bool(b) => b.hash(state),
Self::Array(arr) => arr.hash(state),
Self::Dict(dict) => dict.hash(state),
Self::Code(code) => code.hash(state),
Self::Record(rec) => rec.hash(state),
Self::Subr(subr) => subr.hash(state),
Self::Type(t) => t.hash(state),
Self::None => {
"literal".hash(state);
"None".hash(state)
}
Self::Ellipsis => {
"literal".hash(state);
"Ellipsis".hash(state)
}
Self::NotImplemented => {
"literal".hash(state);
"NotImplemented".hash(state)
}
Self::NegInf => {
"literal".hash(state);
"NegInf".hash(state)
}
Self::Inf => {
"literal".hash(state);
"Inf".hash(state)
}
Self::Mut(v) => v.borrow().hash(state),
Self::Illegal => {
"literal".hash(state);
"illegal".hash(state)
}
}
}
}
impl From<i32> for ValueObj {
fn from(item: i32) -> Self {
ValueObj::Int(item)
}
}
impl From<u64> for ValueObj {
fn from(item: u64) -> Self {
ValueObj::Nat(item)
}
}
impl From<usize> for ValueObj {
fn from(item: usize) -> Self {
ValueObj::Nat(item as u64)
}
}
impl From<f64> for ValueObj {
fn from(item: f64) -> Self {
ValueObj::Float(item)
}
}
impl From<&str> for ValueObj {
fn from(item: &str) -> Self {
ValueObj::Str(Str::rc(item))
}
}
impl From<Str> for ValueObj {
fn from(item: Str) -> Self {
ValueObj::Str(item)
}
}
impl From<bool> for ValueObj {
fn from(item: bool) -> Self {
ValueObj::Bool(item)
}
}
impl From<CodeObj> for ValueObj {
fn from(item: CodeObj) -> Self {
ValueObj::Code(Box::new(item))
}
}
impl From<Vec<ValueObj>> for ValueObj {
fn from(item: Vec<ValueObj>) -> Self {
ValueObj::Array(RcArray::from(&item[..]))
}
}
impl TryFrom<&ValueObj> for f64 {
type Error = ();
fn try_from(val: &ValueObj) -> Result<f64, Self::Error> {
match val {
ValueObj::Int(i) => Ok(*i as f64),
ValueObj::Nat(n) => Ok(*n as f64),
ValueObj::Float(f) => Ok(*f),
ValueObj::Inf => Ok(f64::INFINITY),
ValueObj::NegInf => Ok(f64::NEG_INFINITY),
ValueObj::Mut(v) => f64::try_from(&*v.borrow()).map_err(|_| ()),
_ => Err(()),
}
}
}
impl HasType for ValueObj {
fn ref_t(&self) -> &Type {
panic!("cannot get reference of the const")
}
fn ref_mut_t(&mut self) -> &mut Type {
panic!("cannot get mutable reference of the const")
}
/// その要素だけの集合型を返す、クラスが欲しい場合は.classで
#[inline]
fn t(&self) -> Type {
let name = Str::from(fresh_varname());
let pred = Predicate::eq(name.clone(), TyParam::Value(self.clone()));
Type::refinement(name, self.class(), set! {pred})
}
fn signature_t(&self) -> Option<&Type> {
None
}
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl ValueObj {
pub fn t(t: Type) -> Self {
ValueObj::Type(Box::new(t))
}
pub fn is_num(&self) -> bool {
match self {
Self::Int(_) | Self::Nat(_) | Self::Float(_) | Self::Bool(_) => true,
Self::Mut(n) => n.borrow().is_num(),
_ => false,
}
}
pub const fn is_mut(&self) -> bool {
matches!(self, Self::Mut(_))
}
pub fn from_str(t: Type, content: Str) -> Self {
match t {
Type::Int => Self::Int(content.replace('_', "").parse::<i32>().unwrap()),
Type::Nat => Self::Nat(content.replace('_', "").parse::<u64>().unwrap()),
Type::Float => Self::Float(content.replace('_', "").parse::<f64>().unwrap()),
// TODO:
Type::Ratio => Self::Float(content.replace('_', "").parse::<f64>().unwrap()),
Type::Str => {
if &content[..] == "\"\"" {
Self::Str(Str::from(""))
} else {
let replaced = content.trim_start_matches('\"').trim_end_matches('\"');
Self::Str(Str::rc(replaced))
}
}
Type::Bool => Self::Bool(&content[..] == "True"),
Type::NoneType => Self::None,
Type::Ellipsis => Self::Ellipsis,
Type::NotImplemented => Self::NotImplemented,
Type::Inf => Self::Inf,
Type::NegInf => Self::NegInf,
_ => todo!("{t} {content}"),
}
}
pub fn into_bytes(self) -> Vec<u8> {
match self {
Self::Int(i) => [vec![DataTypePrefix::Int32 as u8], i.to_le_bytes().to_vec()].concat(),
// TODO: Natとしてシリアライズ
Self::Nat(n) => [
vec![DataTypePrefix::Int32 as u8],
(n as i32).to_le_bytes().to_vec(),
]
.concat(),
Self::Float(f) => [
vec![DataTypePrefix::BinFloat as u8],
f.to_le_bytes().to_vec(),
]
.concat(),
Self::Str(s) => str_into_bytes(s, false),
Self::Bool(true) => vec![DataTypePrefix::True as u8],
Self::Bool(false) => vec![DataTypePrefix::False as u8],
// TODO: SmallTuple
Self::Array(arr) => {
let mut bytes = Vec::with_capacity(arr.len());
bytes.push(DataTypePrefix::Tuple as u8);
bytes.append(&mut (arr.len() as u32).to_le_bytes().to_vec());
for obj in arr.iter().cloned() {
bytes.append(&mut obj.into_bytes());
}
bytes
}
Self::None => {
vec![DataTypePrefix::None as u8]
}
Self::Code(c) => c.into_bytes(3425),
// Dict
other => {
panic!(
"{}",
switch_lang!(
"japanese" => format!("このオブジェクトはシリアライズできません: {other}"),
"simplified_chinese" => format!("此对象无法序列化:{other}"),
"traditional_chinese" => format!("此對象無法序列化:{other}"),
"english" => format!("this object cannot be serialized: {other}"),
)
)
}
}
}
pub fn class(&self) -> Type {
match self {
Self::Int(_) => Type::Int,
Self::Nat(_) => Type::Nat,
Self::Float(_) => Type::Float,
Self::Str(_) => Type::Str,
Self::Bool(_) => Type::Bool,
// TODO:
Self::Array(arr) => Type::array(
arr.iter().next().unwrap().class(),
TyParam::value(arr.len()),
),
Self::Dict(_dict) => todo!(),
Self::Code(_) => Type::Code,
Self::Record(rec) => {
Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect())
}
Self::Subr(_) => todo!(),
Self::Type(_) => Type::Type,
Self::None => Type::NoneType,
Self::Ellipsis => Type::Ellipsis,
Self::NotImplemented => Type::NotImplemented,
Self::Inf => Type::Inf,
Self::NegInf => Type::NegInf,
Self::Mut(m) => match &*m.borrow() {
Self::Int(_) => Type::mono("Int!"),
Self::Nat(_) => Type::mono("Nat!"),
Self::Float(_) => Type::mono("Float!"),
Self::Str(_) => Type::mono("Str!"),
Self::Bool(_) => Type::mono("Bool!"),
Self::Array(arr) => Type::poly(
"Array!",
vec![
TyParam::t(arr.iter().next().unwrap().class()),
TyParam::value(arr.len()).mutate(),
],
),
Self::Dict(_dict) => todo!(),
Self::Code(_) => Type::Code,
Self::None => Type::NoneType,
other => panic!("{other} object cannot be mutated"),
},
Self::Illegal => todo!(),
}
}
pub fn try_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(l, r) if l.is_num() && r.is_num() => f64::try_from(l)
.unwrap()
.partial_cmp(&f64::try_from(r).unwrap()),
(Self::Inf, n) | (n, Self::NegInf) if n.is_num() => Some(Ordering::Greater),
(n, Self::Inf) | (Self::NegInf, n) if n.is_num() => Some(Ordering::Less),
(Self::NegInf, Self::Inf) => Some(Ordering::Less),
(Self::Inf, Self::NegInf) => Some(Ordering::Greater),
// REVIEW: 等しいとみなしてよいのか?
(Self::Inf, Self::Inf) | (Self::NegInf, Self::NegInf) => Some(Ordering::Equal),
(Self::Mut(m), other) => m.borrow().try_cmp(other),
(self_, Self::Mut(m)) => self_.try_cmp(&*m.borrow()),
/* (Self::PlusEpsilon(l), r) => l.try_cmp(r)
.map(|o| if matches!(o, Ordering::Equal) { Ordering::Less } else { o }),
(l, Self::PlusEpsilon(r)) => l.try_cmp(r)
.map(|o| if matches!(o, Ordering::Equal) { Ordering::Greater } else { o }),
*/
(_s, _o) => {
if let Some(ValueObj::Bool(b)) = _s.clone().try_eq(_o.clone()) {
if b {
Some(Ordering::Equal)
} else {
None
}
} else {
None
}
}
}
}
// REVIEW: allow_divergenceオプションを付けるべきか?
pub fn try_add(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::Int(l + r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l + r)),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l + r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l + r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 + r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::Float(l - r as f64)),
(Self::Int(l), Self::Float(r)) => Some(Self::Float(l as f64 - r)),
(Self::Nat(l), Self::Float(r)) => Some(Self::Float(l as f64 - r)),
(Self::Float(l), Self::Int(r)) => Some(Self::Float(l - r as f64)),
(Self::Str(l), Self::Str(r)) => Some(Self::Str(Str::from(format!("{}{}", l, r)))),
(inf @ (Self::Inf | Self::NegInf), _) | (_, inf @ (Self::Inf | Self::NegInf)) => {
Some(inf)
}
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_add(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_add(m.borrow().clone()),
_ => None,
}
}
pub fn try_sub(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::Int(l - r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Int((l - r) as i32)),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l - r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l - r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 - r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l - r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 - r)),
(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)),
(inf @ (Self::Inf | Self::NegInf), other)
| (other, inf @ (Self::Inf | Self::NegInf))
if other != Self::Inf && other != Self::NegInf =>
{
Some(inf)
}
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_sub(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_sub(m.borrow().clone()),
_ => None,
}
}
pub fn try_mul(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l * r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Nat(l * r)),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l * r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::Int(l * r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::Int(l as i32 * r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l * r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 * r)),
(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::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)) => {
Some(inf)
}
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_mul(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_mul(m.borrow().clone()),
_ => None,
}
}
pub fn try_div(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::Float(l as f64 / r as f64)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::Float(l as f64 / r as f64)),
(Self::Float(l), Self::Float(r)) => Some(Self::Float(l / r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::Float(l as f64 / r as f64)),
(Self::Nat(l), Self::Int(r)) => Some(Self::Float(l as f64 / r as f64)),
(Self::Float(l), Self::Nat(r)) => Some(Self::Float(l / r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 / r)),
(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::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_div(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_div(m.borrow().clone()),
// TODO: x/±Inf = 0
_ => None,
}
}
pub fn try_gt(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l > r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::from(l > r)),
(Self::Float(l), Self::Float(r)) => Some(Self::from(l > r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l > r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 > r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l > r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 > r)),
(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::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_gt(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_gt(m.borrow().clone()),
_ => None,
}
}
pub fn try_ge(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l >= r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::from(l >= r)),
(Self::Float(l), Self::Float(r)) => Some(Self::from(l >= r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l >= r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 >= r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l >= r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 >= r)),
(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::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_ge(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_ge(m.borrow().clone()),
_ => None,
}
}
pub fn try_eq(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l == r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::from(l == r)),
(Self::Float(l), Self::Float(r)) => Some(Self::from(l == r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l == r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 == r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l == r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 == r)),
(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::Str(l), Self::Str(r)) => Some(Self::from(l == r)),
(Self::Bool(l), Self::Bool(r)) => Some(Self::from(l == r)),
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_eq(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_eq(m.borrow().clone()),
// TODO:
_ => None,
}
}
pub fn try_ne(self, other: Self) -> Option<Self> {
match (self, other) {
(Self::Int(l), Self::Int(r)) => Some(Self::from(l != r)),
(Self::Nat(l), Self::Nat(r)) => Some(Self::from(l != r)),
(Self::Float(l), Self::Float(r)) => Some(Self::from(l != r)),
(Self::Int(l), Self::Nat(r)) => Some(Self::from(l != r as i32)),
(Self::Nat(l), Self::Int(r)) => Some(Self::from(l as i32 != r)),
(Self::Float(l), Self::Nat(r)) => Some(Self::from(l != r as f64)),
(Self::Nat(l), Self::Float(r)) => Some(Self::from(l as f64 != r)),
(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::Str(l), Self::Str(r)) => Some(Self::from(l != r)),
(Self::Bool(l), Self::Bool(r)) => Some(Self::from(l != r)),
(Self::Mut(m), other) => {
{
let ref_m = &mut *m.borrow_mut();
*ref_m = mem::take(ref_m).try_ne(other)?;
}
Some(Self::Mut(m))
}
(self_, Self::Mut(m)) => self_.try_ne(m.borrow().clone()),
_ => None,
}
}
}

View file

@ -0,0 +1,57 @@
use std::borrow::Borrow;
use std::fmt;
use crate::Str;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
Private,
Public,
}
impl Visibility {
pub const fn is_public(&self) -> bool {
matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
}
/// same structure as `Identifier`, but only for Record fields.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field {
vis: Visibility,
symbol: Str,
}
impl fmt::Display for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.vis == Visibility::Public {
write!(f, ".{}", self.symbol)
} else {
write!(f, "{}", self.symbol)
}
}
}
impl Borrow<str> for Field {
#[inline]
fn borrow(&self) -> &str {
&self.symbol[..]
}
}
impl Borrow<Str> for Field {
#[inline]
fn borrow(&self) -> &Str {
&self.symbol
}
}
impl Field {
pub const fn new(vis: Visibility, symbol: Str) -> Self {
Field { vis, symbol }
}
}

View file

@ -5,20 +5,21 @@ description = "Centimetre: the Erg compiler"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler"
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler"
documentation = "https://docs.rs/erg_compiler"
homepage = "https://erg-lang.github.io/"
[features]
# when "debug" feature is turned on, that of parser will also be turned on.
debug = [ "erg_common/debug", "erg_parser/debug" ]
japanese = [ "erg_common/japanese", "erg_parser/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese" ]
debug = [ "erg_common/debug", "erg_parser/debug", "erg_type/debug" ]
japanese = [ "erg_common/japanese", "erg_parser/japanese", "erg_type/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_chinese", "erg_type/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
[dependencies]
erg_common = { version = "0.2.8", path = "../erg_common" }
erg_parser = { version = "0.2.8", path = "../erg_parser" }
erg_type = { version = "0.2.8", path = "../erg_type" }
[lib]
path = "lib.rs"

View file

@ -5,25 +5,27 @@ use std::fmt;
use std::process;
use erg_common::cache::Cache;
use erg_common::codeobj::{CodeObj, CodeObjFlags};
use erg_common::color::{GREEN, RESET};
use erg_common::config::{ErgConfig, Input};
use erg_common::error::{Location, MultiErrorDisplay};
use erg_common::opcode::Opcode;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{TypeCode, TypePair};
use erg_common::value::ValueObj;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{
debug_power_assert, enum_unwrap, fn_name_full, impl_stream_for_wrapper, log, switch_unreachable,
};
use erg_type::codeobj::{CodeObj, CodeObjFlags};
use Opcode::*;
use erg_parser::ast::{Identifier, ParamPattern, Params, VarName, VarPattern};
use erg_parser::token::{Token, TokenCategory, TokenKind};
use erg_type::value::ValueObj;
use erg_type::{HasType, TypeCode, TypePair};
use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::eval::eval_lit;
use crate::hir::{
Accessor, Args, Array, Block, DefBody, Expr, Signature, SubrSignature, VarSignature, HIR,
};
@ -850,7 +852,7 @@ impl CodeGenerator {
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
self.emit_load_const(ValueObj::from(&lit));
self.emit_load_const(eval_lit(&lit));
self.write_instr(Opcode::COMPARE_OP);
self.write_arg(2); // ==
self.stack_dec();

View file

@ -3,13 +3,13 @@
//! コンパイラーを定義する
use std::path::Path;
use erg_common::codeobj::CodeObj;
use erg_common::color::{GREEN, RESET};
use erg_common::config::{ErgConfig, Input};
use erg_common::error::MultiErrorDisplay;
use erg_common::log;
use erg_common::traits::{Runnable, Stream};
use erg_common::Str;
use erg_type::codeobj::CodeObj;
use erg_parser::ParserRunner;

View file

@ -2,13 +2,13 @@
use std::cmp::Ordering;
use std::option::Option; // conflicting to Type::Option
use erg_common::free::{Constraint, FreeKind, FreeTyVar};
use erg_common::ty::{Predicate, RefinementType, SubrKind, SubrType, Type};
use erg_common::typaram::{TyParam, TyParamOrdering};
use erg_type::free::fresh_varname;
use erg_type::free::{Constraint, FreeKind, FreeTyVar};
use erg_type::typaram::{TyParam, TyParamOrdering};
use erg_type::value::ValueObj::Inf;
use erg_type::{Predicate, RefinementType, SubrKind, SubrType, Type};
use Predicate as Pred;
use erg_common::free::fresh_varname;
use erg_common::value::ValueObj::Inf;
use erg_common::Str;
use erg_common::{assume_unreachable, enum_unwrap, log, set};
use TyParamOrdering::*;

View file

@ -5,13 +5,10 @@ use std::option::Option; // conflicting to Type::Option
use erg_common::color::{GREEN, RED};
use erg_common::dict::Dict;
use erg_common::error::ErrorCore;
use erg_common::free::Constraint;
use erg_common::levenshtein::levenshtein;
use erg_common::set::Set;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ParamTy, SubrKind, SubrType, TyBound, Type};
use erg_common::typaram::TyParam;
use erg_common::value::{Field, ValueObj, Visibility};
use erg_common::traits::{Locational, Stream};
use erg_common::vis::{Field, Visibility};
use erg_common::Str;
use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
use Type::*;
@ -20,6 +17,11 @@ use ast::VarName;
use erg_parser::ast;
use erg_parser::token::Token;
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type};
use crate::context::instantiate::{ConstTemplate, TyVarContext};
use crate::context::{Context, ContextKind, RegistrationMode, TraitInstancePair, Variance};
use crate::error::readable_name;

View file

@ -3,26 +3,28 @@ use std::mem;
use std::option::Option; // conflicting to Type::Option
use erg_common::dict::Dict;
use erg_common::free::Constraint;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::ty::{ParamTy, Predicate, SubrKind, TyBound, Type};
use erg_common::typaram::{IntervalOp, TyParam, TyParamOrdering};
use erg_common::value::ValueObj;
use erg_common::Str;
use erg_common::{assume_unreachable, set, try_map};
use erg_type::free::Constraint;
use TyParamOrdering::*;
use Type::*;
use ast::{
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec, TypeBoundSpecs,
TypeSpec,
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, SubrKindSpec, TypeBoundSpec,
TypeBoundSpecs, TypeSpec,
};
use erg_parser::ast;
use erg_parser::token::TokenKind;
use erg_type::typaram::{IntervalOp, TyParam, TyParamOrdering};
use erg_type::value::ValueObj;
use erg_type::{ParamTy, Predicate, SubrKind, TyBound, Type};
use crate::context::{Context, RegistrationMode};
use crate::error::TyCheckResult;
use crate::eval::eval_lit;
use crate::hir;
use RegistrationMode::*;
@ -434,7 +436,7 @@ impl Context {
self.instantiate_typespec(spec, mode)?
} else {
match &sig.pat {
ast::ParamPattern::Lit(lit) => Type::enum_t(set![self.eval.eval_const_lit(lit)]),
ast::ParamPattern::Lit(lit) => Type::enum_t(set![eval_lit(lit)]),
// TODO: Array<Lit>
_ => {
let level = if mode == PreRegister {
@ -493,7 +495,7 @@ impl Context {
other => {
// FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(ValueObj::from(lit)),
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)),
_ => {
todo!()
}
@ -505,7 +507,7 @@ impl Context {
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyParam {
match expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(ValueObj::from(&lit.token)),
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(&lit)),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
TyParam::Mono(name.inspect().clone())
}
@ -569,7 +571,7 @@ impl Context {
set.pos_args()
.map(|arg| {
if let ast::ConstExpr::Lit(lit) = &arg.expr {
ValueObj::from(lit)
eval_lit(lit)
} else {
todo!()
}
@ -602,7 +604,7 @@ impl Context {
})?;
let return_t = self.instantiate_typespec(&subr.return_t, mode)?;
Ok(Type::subr(
subr.kind.clone(),
self.instantiate_subr_kind(&subr.kind)?,
non_defaults,
defaults,
return_t,
@ -611,6 +613,23 @@ impl Context {
}
}
fn instantiate_subr_kind(&self, kind: &SubrKindSpec) -> TyCheckResult<SubrKind> {
match kind {
SubrKindSpec::Func => Ok(SubrKind::Func),
SubrKindSpec::Proc => Ok(SubrKind::Proc),
SubrKindSpec::FuncMethod(spec) => {
Ok(SubrKind::fn_met(self.instantiate_typespec(spec, Normal)?))
}
SubrKindSpec::ProcMethod { before, after } => Ok(SubrKind::pr_met(
self.instantiate_typespec(before, Normal)?,
after
.as_ref()
.map(|after| self.instantiate_typespec(after, Normal))
.transpose()?,
)),
}
}
pub(crate) fn instantiate_ty_bound(
&self,
bound: &TypeBoundSpec,

View file

@ -15,11 +15,13 @@ use erg_common::dict::Dict;
use erg_common::error::Location;
use erg_common::impl_display_from_debug;
use erg_common::traits::{Locational, Stream};
use erg_common::ty::{Predicate, TyBound, Type};
use erg_common::typaram::TyParam;
use erg_common::value::{ValueObj, Visibility};
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_common::{fn_name, get_hash, log};
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{Predicate, TyBound, Type};
use Type::*;
use ast::{DefId, VarName};

View file

@ -1,16 +1,18 @@
use std::option::Option; // conflicting to Type::Option
use erg_common::free::HasLevel;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ParamTy, SubrType, TyBound, Type};
use erg_common::value::{ValueObj, Visibility};
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, log, set};
use Type::*;
use erg_type::free::HasLevel;
use ast::{DefId, VarName};
use erg_parser::ast;
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
use Type::*;
use crate::context::{Context, DefaultInfo, RegistrationMode};
use crate::error::readable_name;
use crate::error::{TyCheckError, TyCheckResult};

View file

@ -1,8 +1,8 @@
//! test module for `Context`
use erg_common::ty::{Predicate, TyBound, Type};
use erg_common::typaram::TyParam;
use erg_common::Str;
use erg_common::{enum_unwrap, set};
use erg_type::typaram::TyParam;
use erg_type::{Predicate, TyBound, Type};
use Type::*;
use crate::context::instantiate::TyVarContext;

View file

@ -3,14 +3,14 @@ use std::mem;
use std::option::Option;
use erg_common::error::Location;
use erg_common::free::{Constraint, FreeKind, HasLevel};
use erg_common::set::Set;
use erg_common::traits::{HasType, Stream};
use erg_common::ty::{Predicate, SubrKind, TyBound, Type};
use erg_common::typaram::TyParam;
use erg_common::value::ValueObj;
use erg_common::traits::Stream;
use erg_common::Str;
use erg_common::{assume_unreachable, fn_name, log, set};
use erg_type::free::{Constraint, FreeKind, HasLevel};
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, Predicate, SubrKind, TyBound, Type};
use crate::context::instantiate::TyVarContext;
use crate::context::{Context, TraitInstancePair, Variance};

View file

@ -5,14 +5,13 @@
use erg_common::color::{GREEN, RESET};
use erg_common::log;
use erg_common::traits::Stream;
use erg_common::value::Visibility;
use erg_common::vis::Visibility;
use erg_common::Str;
use Visibility::*;
use crate::error::{EffectError, EffectErrors, EffectResult};
use crate::hir::{Accessor, Def, Expr, Signature, HIR};
use Visibility::*;
#[derive(Debug)]
pub struct SideEffectChecker {
path_stack: Vec<(Str, Visibility)>,

View file

@ -5,13 +5,13 @@ use erg_common::color::{GREEN, RED, RESET, YELLOW};
use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
use erg_common::traits::{Locational, Stream};
use erg_common::ty::{Predicate, Type};
use erg_common::value::Visibility;
use erg_common::{fmt_iter, Str};
use erg_common::{impl_stream_for_wrapper, switch_lang};
use erg_common::vis::Visibility;
use erg_common::{fmt_iter, impl_stream_for_wrapper, switch_lang, Str};
use erg_parser::error::{ParserRunnerError, ParserRunnerErrors};
use erg_type::{Predicate, Type};
use crate::hir::Expr;
/// dname is for "double under name"

View file

@ -4,20 +4,72 @@ use erg_common::dict::Dict;
use erg_common::rccell::RcCell;
use erg_common::set::Set;
use erg_common::traits::Stream;
use erg_common::ty::{Predicate, SubrKind, TyBound, Type};
use erg_common::typaram::{OpKind, TyParam};
use erg_common::value::{Field, ValueObj};
use erg_common::vis::Field;
use erg_common::{fn_name, set};
use erg_common::{RcArray, Str};
use OpKind::*;
use erg_parser::ast::*;
use erg_parser::token::Token;
use erg_parser::token::{Token, TokenKind};
use erg_type::typaram::{OpKind, TyParam};
use erg_type::value::ValueObj;
use erg_type::{Predicate, SubrKind, TyBound, Type};
use crate::context::instantiate::TyVarContext;
use crate::context::Context;
use crate::error::{EvalError, EvalResult, TyCheckResult};
#[inline]
pub fn type_from_token_kind(kind: TokenKind) -> Type {
use TokenKind::*;
match kind {
NatLit => Type::Nat,
IntLit => Type::Int,
RatioLit => Type::Ratio,
StrLit => Type::Str,
BoolLit => Type::Bool,
NoneLit => Type::NoneType,
NoImplLit => Type::NotImplemented,
EllipsisLit => Type::Ellipsis,
InfLit => Type::Inf,
other => panic!("this has not type: {other}"),
}
}
fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
match kind {
TokenKind::Plus => Ok(OpKind::Add),
TokenKind::Minus => Ok(OpKind::Sub),
TokenKind::Star => Ok(OpKind::Mul),
TokenKind::Slash => Ok(OpKind::Div),
TokenKind::Pow => Ok(OpKind::Pow),
TokenKind::Mod => Ok(OpKind::Mod),
TokenKind::DblEq => Ok(OpKind::Eq),
TokenKind::NotEq => Ok(OpKind::Ne),
TokenKind::Less => Ok(OpKind::Lt),
TokenKind::Gre => Ok(OpKind::Gt),
TokenKind::LessEq => Ok(OpKind::Le),
TokenKind::GreEq => Ok(OpKind::Ge),
TokenKind::AndOp => Ok(OpKind::And),
TokenKind::OrOp => Ok(OpKind::Or),
TokenKind::BitAnd => Ok(OpKind::BitAnd),
TokenKind::BitXor => Ok(OpKind::BitXor),
TokenKind::BitOr => Ok(OpKind::BitOr),
TokenKind::Shl => Ok(OpKind::Shl),
TokenKind::Shr => Ok(OpKind::Shr),
TokenKind::Mutate => Ok(OpKind::Mutate),
_other => Err(()),
}
}
#[inline]
pub(crate) fn eval_lit(lit: &Literal) -> ValueObj {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone())
}
/// SubstContext::new([?T; 0], Context(Array(T, N))) => SubstContext{ params: { T: ?T; N: 0 } }
/// SubstContext::substitute([T; !N], Context(Array(T, N))): [?T; !0]
#[derive(Debug)]
@ -119,11 +171,6 @@ impl Evaluator {
Self::default()
}
#[inline]
pub(crate) fn eval_const_lit(&self, lit: &Literal) -> ValueObj {
ValueObj::from(lit)
}
fn eval_const_acc(&self, _acc: &Accessor, ctx: &Context) -> Option<ValueObj> {
match _acc {
Accessor::Local(local) => {
@ -144,9 +191,8 @@ impl Evaluator {
fn eval_const_bin(&self, bin: &BinOp) -> Option<ValueObj> {
match (bin.args[0].as_ref(), bin.args[1].as_ref()) {
(Expr::Lit(l), Expr::Lit(r)) => {
let op = OpKind::try_from(&bin.op).ok()?;
self.eval_bin_lit(op, ValueObj::from(l), ValueObj::from(r))
.ok()
let op = try_get_op_kind_from_token(bin.op.kind).ok()?;
self.eval_bin_lit(op, eval_lit(l), eval_lit(r)).ok()
}
_ => None,
}
@ -155,8 +201,8 @@ impl Evaluator {
fn eval_const_unary(&self, unary: &UnaryOp) -> Option<ValueObj> {
match unary.args[0].as_ref() {
Expr::Lit(lit) => {
let op = OpKind::try_from(&unary.op).ok()?;
self.eval_unary_lit(op, ValueObj::from(lit)).ok()
let op = try_get_op_kind_from_token(unary.op.kind).ok()?;
self.eval_unary_lit(op, eval_lit(lit)).ok()
}
_ => None,
}
@ -240,7 +286,7 @@ impl Evaluator {
// コンパイル時評価できないならNoneを返す
pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> {
match expr {
Expr::Lit(lit) => Some(self.eval_const_lit(lit)),
Expr::Lit(lit) => Some(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc, ctx),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),

View file

@ -2,21 +2,23 @@
use std::fmt;
use erg_common::error::Location;
use erg_common::traits::{HasType, Locational, NestedDisplay, Stream};
use erg_common::ty::Type;
use erg_common::typaram::TyParam;
use erg_common::value::{Field, ValueObj, Visibility};
use erg_common::traits::{Locational, NestedDisplay, Stream};
use erg_common::vis::{Field, Visibility};
use erg_common::Str;
use erg_common::{
enum_unwrap, impl_display_for_enum, impl_display_from_nested, impl_locational,
impl_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
impl_stream_for_wrapper, impl_t, impl_t_for_enum,
impl_stream_for_wrapper,
};
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{impl_t, impl_t_for_enum, HasType, Type};
use erg_parser::ast::{fmt_lines, DefId, Identifier, Params, VarPattern};
use erg_parser::token::{Token, TokenKind};
use crate::error::readable_name;
use crate::eval::type_from_token_kind;
#[derive(Debug, Clone)]
pub struct Literal {
@ -44,7 +46,7 @@ impl Locational for Literal {
impl From<Token> for Literal {
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.kind), token.content.clone());
Self {
t: data.t(),
data,
@ -54,16 +56,6 @@ impl From<Token> for Literal {
}
impl Literal {
pub fn new(c: ValueObj, lineno: usize, col: usize) -> Self {
let kind = TokenKind::from(&c);
let token = Token::new(kind, c.to_string(), lineno, col);
Self {
t: c.t(),
data: c,
token,
}
}
#[inline]
pub fn is(&self, kind: TokenKind) -> bool {
self.token.is(kind)

View file

@ -1,12 +1,13 @@
//! defines type information for builtin objects (in `Context`)
//!
//! 組み込みオブジェクトの型情報を(Contextに)定義
use erg_common::ty::type_constrs::*;
use erg_common::ty::Type;
use erg_common::typaram::TyParam;
use erg_common::value::{ValueObj, Visibility};
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_common::{debug_power_assert, set};
use erg_type::constructors::*;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::Type;
use ParamSpec as PS;
use Type::*;

View file

@ -4,15 +4,17 @@
use erg_common::color::{GREEN, RED, RESET};
use erg_common::error::Location;
use erg_common::get_hash;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ParamTy, Type};
use erg_common::typaram::TyParam;
use erg_common::value::{ValueObj, Visibility};
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::{fn_name, log, switch_lang};
use erg_parser::ast;
use erg_parser::ast::AST;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, Type};
use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir;

View file

@ -5,7 +5,6 @@ extern crate erg_parser;
use std::process;
use erg_common::config::ErgConfig;
use erg_common::deserialize::Deserializer;
use erg_common::traits::Runnable;
use erg_compiler::Compiler;
@ -13,6 +12,8 @@ use erg_compiler::Compiler;
use erg_parser::lex::LexerRunner;
use erg_parser::ParserRunner;
use erg_type::deserialize::Deserializer;
fn main() {
let cfg = ErgConfig::parse();
match cfg.mode {

View file

@ -3,14 +3,15 @@ use erg_common::dict::Dict;
use erg_common::error::Location;
use erg_common::log;
use erg_common::set::Set;
use erg_common::traits::{HasType, Locational, Stream};
use erg_common::ty::{ArgsOwnership, Ownership};
use erg_common::value::Visibility;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
use Visibility::*;
use erg_type::{ArgsOwnership, HasType, Ownership};
use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult};
use crate::hir::{self, Accessor, Array, Block, Def, Expr, Signature, HIR};
use Visibility::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WrapperKind {

View file

@ -1,12 +1,12 @@
use std::fmt;
use erg_common::traits::HasType;
use erg_common::ty::Type;
use erg_common::value::Visibility;
use erg_common::vis::Visibility;
use Visibility::*;
use erg_parser::ast::DefId;
use erg_type::{HasType, Type};
use crate::context::DefaultInfo;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -5,8 +5,9 @@ use std::fmt;
use erg_common::error::Location;
use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, NestedDisplay, Stream};
use erg_common::ty::SubrKind;
use erg_common::value::{Field, ValueObj, Visibility};
use erg_common::vis::{Field, Visibility};
// use erg_common::ty::SubrKind;
// use erg_common::value::{Field, ValueObj, Visibility};
use erg_common::Str;
use erg_common::{
fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct,
@ -61,13 +62,6 @@ impl From<Token> for Literal {
}
}
impl From<&Literal> for ValueObj {
#[inline]
fn from(lit: &Literal) -> ValueObj {
ValueObj::from(&lit.token)
}
}
impl Literal {
#[inline]
pub fn is(&self, kind: TokenKind) -> bool {
@ -1321,9 +1315,29 @@ impl ParamTySpec {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SubrKindSpec {
Func,
Proc,
FuncMethod(Box<TypeSpec>),
ProcMethod {
before: Box<TypeSpec>,
after: Option<Box<TypeSpec>>,
},
}
impl SubrKindSpec {
pub const fn arrow(&self) -> Str {
match self {
Self::Func | Self::FuncMethod(_) => Str::ever("->"),
Self::Proc | Self::ProcMethod { .. } => Str::ever("=>"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SubrTySpec {
pub kind: SubrKind,
pub kind: SubrKindSpec,
pub lparen: Option<Token>,
pub non_defaults: Vec<ParamTySpec>,
pub defaults: Vec<ParamTySpec>,
@ -1356,7 +1370,7 @@ impl Locational for SubrTySpec {
impl SubrTySpec {
pub fn new(
kind: SubrKind,
kind: SubrKindSpec,
lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>,
defaults: Vec<ParamTySpec>,
@ -1463,7 +1477,7 @@ impl TypeSpec {
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTySpec::new(
SubrKind::Func,
SubrKindSpec::Func,
lparen,
non_defaults,
defaults,
@ -1478,7 +1492,7 @@ impl TypeSpec {
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTySpec::new(
SubrKind::Proc,
SubrKindSpec::Proc,
lparen,
non_defaults,
defaults,

View file

@ -8,9 +8,9 @@ use erg_common::error::Location;
use erg_common::impl_displayable_stream_for_wrapper;
use erg_common::str::Str;
use erg_common::traits::{Locational, Stream};
use erg_common::ty::Type;
use erg_common::typaram::OpKind;
use erg_common::value::ValueObj;
// use erg_common::ty::Type;
// use erg_common::typaram::OpKind;
// use erg_common::value::ValueObj;
/// 意味論的名前と記号自体の名前が混在しているが、Pythonの名残である
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -163,40 +163,6 @@ pub enum TokenKind {
use TokenKind::*;
impl From<TokenKind> for Type {
#[inline]
fn from(tok: TokenKind) -> Type {
match tok {
NatLit => Type::Nat,
IntLit => Type::Int,
RatioLit => Type::Ratio,
StrLit => Type::Str,
BoolLit => Type::Bool,
NoneLit => Type::NoneType,
NoImplLit => Type::NotImplemented,
EllipsisLit => Type::Ellipsis,
InfLit => Type::Inf,
other => panic!("this has not type: {other}"),
}
}
}
impl From<&ValueObj> for TokenKind {
fn from(c: &ValueObj) -> TokenKind {
match c {
ValueObj::Int(_) => TokenKind::IntLit,
ValueObj::Nat(_) => TokenKind::NatLit,
ValueObj::Float(_) => TokenKind::RatioLit,
ValueObj::Str(_) => TokenKind::StrLit,
ValueObj::Bool(_) => TokenKind::BoolLit,
ValueObj::None => TokenKind::NoneLit,
ValueObj::Ellipsis => TokenKind::EllipsisLit,
ValueObj::Inf => TokenKind::InfLit,
_ => TokenKind::Illegal,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TokenCategory {
Symbol,
@ -318,50 +284,6 @@ pub struct Token {
pub col_begin: usize,
}
impl From<Token> for ValueObj {
#[inline]
fn from(tok: Token) -> ValueObj {
ValueObj::from_str(Type::from(tok.kind), tok.content)
}
}
impl From<&Token> for ValueObj {
#[inline]
fn from(tok: &Token) -> ValueObj {
ValueObj::from_str(Type::from(tok.kind), tok.content.clone())
}
}
impl TryFrom<&Token> for OpKind {
type Error = ();
#[inline]
fn try_from(tok: &Token) -> Result<Self, Self::Error> {
match tok.kind {
TokenKind::Plus => Ok(OpKind::Add),
TokenKind::Minus => Ok(OpKind::Sub),
TokenKind::Star => Ok(OpKind::Mul),
TokenKind::Slash => Ok(OpKind::Div),
TokenKind::Pow => Ok(OpKind::Pow),
TokenKind::Mod => Ok(OpKind::Mod),
TokenKind::DblEq => Ok(OpKind::Eq),
TokenKind::NotEq => Ok(OpKind::Ne),
TokenKind::Less => Ok(OpKind::Lt),
TokenKind::Gre => Ok(OpKind::Gt),
TokenKind::LessEq => Ok(OpKind::Le),
TokenKind::GreEq => Ok(OpKind::Ge),
TokenKind::AndOp => Ok(OpKind::And),
TokenKind::OrOp => Ok(OpKind::Or),
TokenKind::BitAnd => Ok(OpKind::BitAnd),
TokenKind::BitXor => Ok(OpKind::BitXor),
TokenKind::BitOr => Ok(OpKind::BitOr),
TokenKind::Shl => Ok(OpKind::Shl),
TokenKind::Shr => Ok(OpKind::Shr),
TokenKind::Mutate => Ok(OpKind::Mutate),
_other => Err(()),
}
}
}
impl fmt::Debug for Token {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Token")

View file

@ -12,7 +12,14 @@ homepage = "https://erg-lang.github.io/"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
debug = []
japanese = []
simplified_chinese = []
traditional_chinese = []
debug = [ "erg_common/debug" ]
japanese = [ "erg_common/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies]
erg_common = { version = "0.2.8", path = "../erg_common" }
[lib]
path = "lib.rs"

View file

@ -3,15 +3,15 @@ use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;
use erg_common::impl_display_from_debug;
use erg_common::opcode::Opcode;
use erg_common::python_util::detect_magic_number;
use erg_common::serialize::*;
use erg_common::Str;
use crate::deserialize::{DeserializeResult, Deserializer};
use crate::impl_display_from_debug;
use crate::opcode::Opcode;
use crate::python_util::detect_magic_number;
use crate::serialize::*;
use crate::traits::HasType;
use crate::ty::{Type, TypePair};
use crate::value::ValueObj;
use crate::Str;
use crate::{HasType, Type, TypePair};
pub fn consts_into_bytes(consts: Vec<ValueObj>) -> Vec<u8> {
let mut tuple = vec![];

View file

@ -0,0 +1,107 @@
use crate::*;
#[inline]
pub const fn param_t(name: &'static str, ty: Type) -> ParamTy {
ParamTy::new(Some(Str::ever(name)), ty)
}
#[inline]
pub const fn anon(ty: Type) -> ParamTy {
ParamTy::anonymous(ty)
}
#[inline]
pub fn mono<S: Into<Str>>(name: S) -> Type {
Type::mono(name)
}
#[inline]
pub fn mono_q<S: Into<Str>>(name: S) -> Type {
Type::mono_q(name)
}
#[inline]
pub fn mono_proj<S: Into<Str>>(lhs: Type, rhs: S) -> Type {
Type::mono_proj(lhs, rhs)
}
#[inline]
pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::poly(name, params)
}
#[inline]
pub fn poly_q<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::poly_q(name, params)
}
#[inline]
pub fn func(non_default_params: Vec<ParamTy>, default_params: Vec<ParamTy>, ret: Type) -> Type {
Type::func(non_default_params, default_params, ret)
}
#[inline]
pub fn proc(non_default_params: Vec<ParamTy>, default_params: Vec<ParamTy>, ret: Type) -> Type {
Type::proc(non_default_params, default_params, ret)
}
#[inline]
pub fn nd_func(params: Vec<ParamTy>, ret: Type) -> Type {
Type::nd_func(params, ret)
}
#[inline]
pub fn nd_proc(params: Vec<ParamTy>, ret: Type) -> Type {
Type::nd_proc(params, ret)
}
#[inline]
pub fn fn0_met(self_t: Type, return_t: Type) -> Type {
Type::fn0_met(self_t, return_t)
}
#[inline]
pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Type {
Type::fn1_met(self_t, input_t, return_t)
}
#[inline]
pub fn quant(unbound_t: Type, bounds: Set<TyBound>) -> Type {
Type::quantified(unbound_t, bounds)
}
#[inline]
pub fn instance(name: Str, t: Type) -> TyBound {
TyBound::instance(name, t)
}
#[inline]
pub fn static_instance(name: &'static str, t: Type) -> TyBound {
TyBound::static_instance(name, t)
}
/// Sub <: Sup
#[inline]
pub fn subtypeof(sub: Type, sup: Type) -> TyBound {
TyBound::sandwiched(Type::Never, sub, sup)
}
#[inline]
pub fn mono_q_tp<S: Into<Str>>(name: S) -> TyParam {
TyParam::mono_q(name)
}
#[inline]
pub fn mono_tp<S: Into<Str>>(name: S) -> TyParam {
TyParam::mono(name)
}
#[inline]
pub fn ty_tp(t: Type) -> TyParam {
TyParam::t(t)
}
#[inline]
pub fn value<V: Into<ValueObj>>(v: V) -> TyParam {
TyParam::value(v)
}

View file

@ -2,17 +2,17 @@
use std::process;
use std::string::FromUtf8Error;
use crate::cache::Cache;
use erg_common::cache::Cache;
use erg_common::config::{ErgConfig, Input};
use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_common::serialize::DataTypePrefix;
use erg_common::{fn_name, switch_lang};
use erg_common::{RcArray, Str};
use crate::codeobj::CodeObj;
use crate::config::{ErgConfig, Input};
use crate::error::{ErrorCore, ErrorKind, Location};
use crate::serialize::DataTypePrefix;
use crate::traits::HasType;
use crate::ty::Type;
use crate::typaram::TyParam;
use crate::value::ValueObj;
use crate::{fn_name, switch_lang};
use crate::{RcArray, Str};
use crate::{HasType, Type};
#[derive(Debug)]
pub struct DeserializeError {

View file

@ -2,11 +2,11 @@ use std::cell::{Ref, RefMut};
use std::fmt;
use std::mem;
use crate::rccell::RcCell;
use crate::traits::LimitedDisplay;
use crate::ty::Type;
use crate::typaram::TyParam;
use crate::Str;
use crate::Type;
use erg_common::rccell::RcCell;
use erg_common::traits::LimitedDisplay;
pub type Level = usize;
pub type Id = usize;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,11 +2,12 @@ use std::cmp::Ordering;
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub};
use erg_common::traits::LimitedDisplay;
use crate::free::{Constraint, FreeKind, FreeTyParam, HasLevel, Level};
use crate::traits::LimitedDisplay;
use crate::ty::Type;
use crate::value::ValueObj;
use crate::Str;
use crate::Type;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]

View file

@ -1,7 +1,6 @@
//! defines `ValueObj` (used in the compiler, VM).
//!
//! コンパイラ、VM等で使われる(データも保持した)値オブジェクトを定義する
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
@ -9,70 +8,18 @@ use std::mem;
use std::ops::Neg;
use std::rc::Rc;
use erg_common::dict::Dict;
use erg_common::rccell::RcCell;
use erg_common::serialize::*;
use erg_common::set;
use erg_common::vis::Field;
use erg_common::{fmt_iter, impl_display_from_debug, switch_lang};
use erg_common::{RcArray, Str};
use crate::codeobj::CodeObj;
use crate::dict::Dict;
// use crate::free::fresh_varname;
use crate::rccell::RcCell;
use crate::serialize::*;
use crate::set;
use crate::traits::HasType;
// use crate::ty::{ConstSubr, Predicate, Type};
// use crate::typaram::TyParam;
use crate::{fmt_iter, impl_display_from_debug, switch_lang};
use crate::{RcArray, Str};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
Private,
Public,
}
impl Visibility {
pub const fn is_public(&self) -> bool {
matches!(self, Self::Public)
}
pub const fn is_private(&self) -> bool {
matches!(self, Self::Private)
}
}
/// same structure as `Identifier`, but only for Record fields.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field {
vis: Visibility,
symbol: Str,
}
impl fmt::Display for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.vis == Visibility::Public {
write!(f, ".{}", self.symbol)
} else {
write!(f, "{}", self.symbol)
}
}
}
impl Borrow<str> for Field {
#[inline]
fn borrow(&self) -> &str {
&self.symbol[..]
}
}
impl Borrow<Str> for Field {
#[inline]
fn borrow(&self) -> &Str {
&self.symbol
}
}
impl Field {
pub const fn new(vis: Visibility, symbol: Str) -> Self {
Field { vis, symbol }
}
}
use crate::free::fresh_varname;
use crate::typaram::TyParam;
use crate::{ConstSubr, HasType, Predicate, Type};
/// 値オブジェクト
/// コンパイル時評価ができ、シリアライズも可能
@ -681,3 +628,36 @@ impl ValueObj {
}
}
}
pub mod value_set {
use crate::{Type, ValueObj};
use erg_common::set::Set;
// false -> SyntaxError
pub fn is_homogeneous(set: &Set<ValueObj>) -> bool {
let l_first = set.iter().next().unwrap().class();
set.iter().all(|c| c.class() == l_first)
}
pub fn inner_class(set: &Set<ValueObj>) -> Type {
set.iter().next().unwrap().class()
}
pub fn max(set: &Set<ValueObj>) -> Option<ValueObj> {
if !is_homogeneous(set) {
return None;
}
set.iter()
.max_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone)
}
pub fn min(set: &Set<ValueObj>) -> Option<ValueObj> {
if !is_homogeneous(set) {
return None;
}
set.iter()
.min_by(|x, y| x.try_cmp(y).unwrap())
.map(Clone::clone)
}
}

View file

@ -5,7 +5,6 @@ extern crate erg_parser;
use std::process;
use erg_common::config::ErgConfig;
use erg_common::deserialize::Deserializer;
use erg_common::traits::Runnable;
use erg_parser::lex::LexerRunner;
@ -13,6 +12,8 @@ use erg_parser::ParserRunner;
use erg_compiler::Compiler;
use erg_type::deserialize::Deserializer;
use erg::dummy::DummyVM;
fn main() {