mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 10:23:20 +00:00
Create erg_type
crate
This commit is contained in:
parent
e4e89f38f9
commit
5b5234f477
43 changed files with 2995 additions and 8238 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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>;
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
57
compiler/erg_common/vis.rs
Normal file
57
compiler/erg_common/vis.rs
Normal 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 }
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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)>,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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::*;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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![];
|
||||
|
|
107
compiler/erg_type/constructors.rs
Normal file
107
compiler/erg_type/constructors.rs
Normal 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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
@ -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)]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue