mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54:33 +00:00
Merge branch 'main' into codegen-bug
This commit is contained in:
commit
4053e1646f
38 changed files with 901 additions and 221 deletions
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
|
@ -54,7 +54,7 @@ jobs:
|
||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
- run: rustup update stable
|
- run: rustup update stable
|
||||||
- run: cargo build --all --all-targets --verbose
|
- run: cargo build --all --all-targets --verbose
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
use erg_common::pathutil::NormalizedPathBuf;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_compiler::artifact::IncompleteArtifact;
|
use erg_compiler::artifact::IncompleteArtifact;
|
||||||
use erg_compiler::erg_parser::parse::Parsable;
|
use erg_compiler::erg_parser::parse::Parsable;
|
||||||
|
@ -146,26 +147,26 @@ impl<Checker: BuildRunnable, Parser: Parsable> Server<Checker, Parser> {
|
||||||
/// self is __included__
|
/// self is __included__
|
||||||
pub fn dependencies_of(&self, uri: &NormalizedUrl) -> Vec<NormalizedUrl> {
|
pub fn dependencies_of(&self, uri: &NormalizedUrl) -> Vec<NormalizedUrl> {
|
||||||
let graph = self.get_graph().unwrap();
|
let graph = self.get_graph().unwrap();
|
||||||
let path = util::uri_to_path(uri);
|
let path = NormalizedPathBuf::from(util::uri_to_path(uri));
|
||||||
graph.sort().unwrap();
|
graph.sort().unwrap();
|
||||||
let self_node = graph.get_node(&path).unwrap();
|
let self_node = graph.get_node(&path).unwrap();
|
||||||
graph
|
graph
|
||||||
.ref_inner()
|
.ref_inner()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|node| node.id == path || self_node.depends_on(&node.id))
|
.filter(|node| node.id == path || self_node.depends_on(&node.id))
|
||||||
.map(|node| NormalizedUrl::new(Url::from_file_path(&node.id).unwrap()))
|
.map(|node| NormalizedUrl::new(Url::from_file_path(node.id.to_path_buf()).unwrap()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// self is __not included__
|
/// self is __not included__
|
||||||
pub fn dependents_of(&self, uri: &NormalizedUrl) -> Vec<NormalizedUrl> {
|
pub fn dependents_of(&self, uri: &NormalizedUrl) -> Vec<NormalizedUrl> {
|
||||||
let graph = self.get_graph().unwrap();
|
let graph = self.get_graph().unwrap();
|
||||||
let path = util::uri_to_path(uri);
|
let path = NormalizedPathBuf::from(util::uri_to_path(uri));
|
||||||
graph
|
graph
|
||||||
.ref_inner()
|
.ref_inner()
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|node| node.depends_on(&path))
|
.filter(|node| node.depends_on(&path))
|
||||||
.map(|node| NormalizedUrl::new(Url::from_file_path(&node.id).unwrap()))
|
.map(|node| NormalizedUrl::new(Url::from_file_path(node.id.to_path_buf()).unwrap()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,7 +216,11 @@ impl Input {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
InputKind::File(filename) => format!(
|
InputKind::File(filename) => format!(
|
||||||
"{}_{}",
|
"{}_{}",
|
||||||
filename.file_stem().and_then(|f| f.to_str()).unwrap_or("_"),
|
filename
|
||||||
|
.file_stem()
|
||||||
|
.and_then(|f| f.to_str())
|
||||||
|
.unwrap_or("_")
|
||||||
|
.trim_end_matches(".d"),
|
||||||
self.id
|
self.id
|
||||||
),
|
),
|
||||||
InputKind::REPL | InputKind::Pipe(_) => format!("stdin_{}", self.id),
|
InputKind::REPL | InputKind::Pipe(_) => format!("stdin_{}", self.id),
|
||||||
|
@ -248,9 +252,11 @@ impl Input {
|
||||||
|
|
||||||
pub fn unescaped_file_stem(&self) -> &str {
|
pub fn unescaped_file_stem(&self) -> &str {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
InputKind::File(filename) => {
|
InputKind::File(filename) => filename
|
||||||
filename.file_stem().and_then(|f| f.to_str()).unwrap_or("_")
|
.file_stem()
|
||||||
}
|
.and_then(|f| f.to_str())
|
||||||
|
.unwrap_or("_")
|
||||||
|
.trim_end_matches(".d"),
|
||||||
InputKind::REPL | InputKind::Pipe(_) => "stdin",
|
InputKind::REPL | InputKind::Pipe(_) => "stdin",
|
||||||
InputKind::DummyREPL(_stdin) => "stdin",
|
InputKind::DummyREPL(_stdin) => "stdin",
|
||||||
InputKind::Str(_) => "string",
|
InputKind::Str(_) => "string",
|
||||||
|
@ -260,9 +266,11 @@ impl Input {
|
||||||
|
|
||||||
pub fn unescaped_filename(&self) -> &str {
|
pub fn unescaped_filename(&self) -> &str {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
InputKind::File(filename) => {
|
InputKind::File(filename) => filename
|
||||||
filename.file_name().and_then(|f| f.to_str()).unwrap_or("_")
|
.file_name()
|
||||||
}
|
.and_then(|f| f.to_str())
|
||||||
|
.unwrap_or("_")
|
||||||
|
.trim_end_matches(".d"),
|
||||||
InputKind::REPL | InputKind::Pipe(_) => "stdin",
|
InputKind::REPL | InputKind::Pipe(_) => "stdin",
|
||||||
InputKind::DummyREPL(_stdin) => "stdin",
|
InputKind::DummyREPL(_stdin) => "stdin",
|
||||||
InputKind::Str(_) => "string",
|
InputKind::Str(_) => "string",
|
||||||
|
@ -283,7 +291,9 @@ impl Input {
|
||||||
pub fn module_name(&self) -> String {
|
pub fn module_name(&self) -> String {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
InputKind::File(filename) => {
|
InputKind::File(filename) => {
|
||||||
let file_stem = if filename.file_stem() == Some(OsStr::new("__init__")) {
|
let file_stem = if filename.file_stem() == Some(OsStr::new("__init__"))
|
||||||
|
|| filename.file_stem() == Some(OsStr::new("__init__.d"))
|
||||||
|
{
|
||||||
filename.parent().and_then(|p| p.file_stem())
|
filename.parent().and_then(|p| p.file_stem())
|
||||||
} else {
|
} else {
|
||||||
filename.file_stem()
|
filename.file_stem()
|
||||||
|
@ -291,6 +301,7 @@ impl Input {
|
||||||
file_stem
|
file_stem
|
||||||
.and_then(|f| f.to_str())
|
.and_then(|f| f.to_str())
|
||||||
.unwrap_or("_")
|
.unwrap_or("_")
|
||||||
|
.trim_end_matches(".d")
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
InputKind::REPL | InputKind::Pipe(_) => "<stdin>".to_string(),
|
InputKind::REPL | InputKind::Pipe(_) => "<stdin>".to_string(),
|
||||||
|
@ -748,11 +759,11 @@ impl Output {
|
||||||
pub fn lsp_log(file: &str, line: u32, msg: &str) {
|
pub fn lsp_log(file: &str, line: u32, msg: &str) {
|
||||||
let file_path = erg_path().join("els.log");
|
let file_path = erg_path().join("els.log");
|
||||||
let mut f = if file_path.exists() {
|
let mut f = if file_path.exists() {
|
||||||
File::options().write(true).open(file_path).unwrap()
|
File::options().append(true).open(file_path).unwrap()
|
||||||
} else {
|
} else {
|
||||||
File::create(file_path).unwrap()
|
File::create(file_path).unwrap()
|
||||||
};
|
};
|
||||||
f.write_all(format!("{file}@{line}: {msg}").as_bytes())
|
f.write_all(format!("{file}@{line}: {msg}\n").as_bytes())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub mod levenshtein;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod opcode;
|
pub mod opcode;
|
||||||
pub mod opcode308;
|
pub mod opcode308;
|
||||||
|
pub mod opcode309;
|
||||||
pub mod opcode310;
|
pub mod opcode310;
|
||||||
pub mod opcode311;
|
pub mod opcode311;
|
||||||
pub mod pathutil;
|
pub mod pathutil;
|
||||||
|
|
|
@ -31,14 +31,14 @@ impl_u8_enum! {Opcode308;
|
||||||
BINARY_TRUE_DIVIDE = 27,
|
BINARY_TRUE_DIVIDE = 27,
|
||||||
INPLACE_FLOOR_DIVIDE = 28,
|
INPLACE_FLOOR_DIVIDE = 28,
|
||||||
INPLACE_TRUE_DIVIDE = 29,
|
INPLACE_TRUE_DIVIDE = 29,
|
||||||
GET_LEN = 30,
|
// GET_LEN = 30,
|
||||||
MATCH_MAPPING = 31,
|
// MATCH_MAPPING = 31,
|
||||||
MATCH_SEQUENCE = 32,
|
// MATCH_SEQUENCE = 32,
|
||||||
MATCH_KEYS = 33,
|
// MATCH_KEYS = 33,
|
||||||
PUSH_EXC_INFO = 35,
|
// PUSH_EXC_INFO = 35,
|
||||||
CHECK_EXC_MATCH = 36,
|
// CHECK_EXC_MATCH = 36,
|
||||||
CHECK_EG_MATCH = 37,
|
// CHECK_EG_MATCH = 37,
|
||||||
WITH_EXCEPT_START = 49,
|
// WITH_EXCEPT_START = 49,
|
||||||
GET_AITER = 50,
|
GET_AITER = 50,
|
||||||
GET_ANEXT = 51,
|
GET_ANEXT = 51,
|
||||||
BEFORE_ASYNC_WITH = 52,
|
BEFORE_ASYNC_WITH = 52,
|
||||||
|
@ -92,9 +92,10 @@ impl_u8_enum! {Opcode308;
|
||||||
POP_JUMP_IF_FALSE = 114,
|
POP_JUMP_IF_FALSE = 114,
|
||||||
POP_JUMP_IF_TRUE = 115,
|
POP_JUMP_IF_TRUE = 115,
|
||||||
LOAD_GLOBAL = 116,
|
LOAD_GLOBAL = 116,
|
||||||
IS_OP = 117,
|
// IS_OP = 117,
|
||||||
CONTAINS_OP = 118,
|
// CONTAINS_OP = 118,
|
||||||
RERAISE = 119,
|
// RERAISE = 119,
|
||||||
|
SETUP_FINALLY = 122,
|
||||||
LOAD_FAST = 124,
|
LOAD_FAST = 124,
|
||||||
STORE_FAST = 125,
|
STORE_FAST = 125,
|
||||||
DELETE_FAST = 126,
|
DELETE_FAST = 126,
|
||||||
|
|
163
crates/erg_common/opcode309.rs
Normal file
163
crates/erg_common/opcode309.rs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
//! defines `Opcode` (represents Python bytecode opcodes).
|
||||||
|
//!
|
||||||
|
//! Opcode(Pythonバイトコードオペコードを表す)を定義する
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
use crate::impl_u8_enum;
|
||||||
|
|
||||||
|
impl_u8_enum! {Opcode309;
|
||||||
|
POP_TOP = 1,
|
||||||
|
ROT_TWO = 2,
|
||||||
|
ROT_THREE = 3,
|
||||||
|
DUP_TOP = 4,
|
||||||
|
DUP_TOP2 = 5,
|
||||||
|
ROT_FOUR = 6,
|
||||||
|
NOP = 9,
|
||||||
|
UNARY_POSITIVE = 10,
|
||||||
|
UNARY_NEGATIVE = 11,
|
||||||
|
UNARY_NOT = 12,
|
||||||
|
UNARY_INVERT = 15,
|
||||||
|
BINARY_MATRIX_MULTIPLY = 16,
|
||||||
|
INPLACE_MATRIX_MULTIPLY = 17,
|
||||||
|
BINARY_POWER = 19,
|
||||||
|
BINARY_MULTIPLY = 20,
|
||||||
|
BINARY_MODULO = 22,
|
||||||
|
BINARY_ADD = 23,
|
||||||
|
BINARY_SUBTRACT = 24,
|
||||||
|
BINARY_SUBSCR = 25,
|
||||||
|
BINARY_FLOOR_DIVIDE = 26,
|
||||||
|
BINARY_TRUE_DIVIDE = 27,
|
||||||
|
INPLACE_FLOOR_DIVIDE = 28,
|
||||||
|
INPLACE_TRUE_DIVIDE = 29,
|
||||||
|
// GET_LEN = 30,
|
||||||
|
// MATCH_MAPPING = 31,
|
||||||
|
// MATCH_SEQUENCE = 32,
|
||||||
|
// MATCH_KEYS = 33,
|
||||||
|
// PUSH_EXC_INFO = 35,
|
||||||
|
// CHECK_EXC_MATCH = 36,
|
||||||
|
// CHECK_EG_MATCH = 37,
|
||||||
|
RERAISE = 48,
|
||||||
|
WITH_EXCEPT_START = 49,
|
||||||
|
GET_AITER = 50,
|
||||||
|
GET_ANEXT = 51,
|
||||||
|
BEFORE_ASYNC_WITH = 52,
|
||||||
|
// BEGIN_FINALLY = 53,
|
||||||
|
END_ASYNC_FOR = 54,
|
||||||
|
// TODO:
|
||||||
|
INPLACE_ADD = 55,
|
||||||
|
INPLACE_SUBTRACT = 56,
|
||||||
|
INPLACE_MULTIPLY = 57,
|
||||||
|
INPLACE_MODULO = 59,
|
||||||
|
STORE_SUBSCR = 60,
|
||||||
|
BINARY_AND = 64,
|
||||||
|
BINARY_XOR = 65,
|
||||||
|
BINARY_OR = 66,
|
||||||
|
GET_ITER = 68,
|
||||||
|
GET_YIELD_FROM_ITER = 69,
|
||||||
|
PRINT_EXPR = 70,
|
||||||
|
LOAD_BUILD_CLASS = 71,
|
||||||
|
// LOAD_ASSERTION_ERROR = 74,
|
||||||
|
// WITH_CLEANUP_START = 81,
|
||||||
|
WITH_CLEANUP_FINISH = 82,
|
||||||
|
RETURN_VALUE = 83,
|
||||||
|
IMPORT_STAR = 84,
|
||||||
|
SETUP_ANNOTATIONS = 85,
|
||||||
|
YIELD_VALUE = 86,
|
||||||
|
POP_BLOCK = 87,
|
||||||
|
// END_FINALLY = 88,
|
||||||
|
POP_EXCEPT = 89,
|
||||||
|
/* ↓ These opcodes take an arg */
|
||||||
|
STORE_NAME = 90,
|
||||||
|
DELETE_NAME = 91,
|
||||||
|
UNPACK_SEQUENCE = 92,
|
||||||
|
FOR_ITER = 93,
|
||||||
|
UNPACK_EX = 94,
|
||||||
|
STORE_ATTR = 95,
|
||||||
|
STORE_GLOBAL = 97,
|
||||||
|
LOAD_CONST = 100,
|
||||||
|
LOAD_NAME = 101,
|
||||||
|
BUILD_TUPLE = 102,
|
||||||
|
BUILD_LIST = 103,
|
||||||
|
BUILD_SET = 104,
|
||||||
|
BUILD_MAP = 105, // build a Dict object
|
||||||
|
LOAD_ATTR = 106,
|
||||||
|
COMPARE_OP = 107,
|
||||||
|
IMPORT_NAME = 108,
|
||||||
|
IMPORT_FROM = 109,
|
||||||
|
JUMP_FORWARD = 110,
|
||||||
|
JUMP_IF_FALSE_OR_POP = 111,
|
||||||
|
JUMP_IF_TRUE_OR_POP = 112,
|
||||||
|
JUMP_ABSOLUTE = 113,
|
||||||
|
POP_JUMP_IF_FALSE = 114,
|
||||||
|
POP_JUMP_IF_TRUE = 115,
|
||||||
|
LOAD_GLOBAL = 116,
|
||||||
|
IS_OP = 117,
|
||||||
|
CONTAINS_OP = 118,
|
||||||
|
LOAD_FAST = 124,
|
||||||
|
STORE_FAST = 125,
|
||||||
|
DELETE_FAST = 126,
|
||||||
|
RAISE_VARARGS = 130,
|
||||||
|
CALL_FUNCTION = 131,
|
||||||
|
MAKE_FUNCTION = 132,
|
||||||
|
LOAD_CLOSURE = 135,
|
||||||
|
LOAD_DEREF = 136,
|
||||||
|
STORE_DEREF = 137,
|
||||||
|
CALL_FUNCTION_KW = 141,
|
||||||
|
CALL_FUNCTION_EX = 142,
|
||||||
|
SETUP_WITH = 143,
|
||||||
|
EXTENDED_ARG = 144,
|
||||||
|
BUILD_TUPLE_UNPACK_WITH_CALL = 158,
|
||||||
|
LOAD_METHOD = 160,
|
||||||
|
CALL_METHOD = 161,
|
||||||
|
CALL_FINALLY = 162,
|
||||||
|
POP_FINALLY = 163,
|
||||||
|
// Erg-specific opcodes (must have a unary `ERG_`)
|
||||||
|
// Define in descending order from 219, 255
|
||||||
|
ERG_POP_NTH = 196,
|
||||||
|
ERG_PEEK_NTH = 197, // get ref to the arg-th element from TOS
|
||||||
|
ERG_INC = 198, // name += 1; arg: typecode
|
||||||
|
ERG_DEC = 199, // name -= 1
|
||||||
|
ERG_LOAD_FAST_IMMUT = 200,
|
||||||
|
ERG_STORE_FAST_IMMUT = 201,
|
||||||
|
ERG_MOVE_FAST = 202,
|
||||||
|
ERG_CLONE_FAST = 203,
|
||||||
|
ERG_COPY_FAST = 204,
|
||||||
|
ERG_REF_FAST = 205,
|
||||||
|
ERG_REF_MUT_FAST = 206,
|
||||||
|
ERG_MOVE_OUTER = 207,
|
||||||
|
ERG_CLONE_OUTER = 208,
|
||||||
|
ERG_COPY_OUTER = 209,
|
||||||
|
ERG_REF_OUTER = 210,
|
||||||
|
ERG_REF_MUT_OUTER = 211,
|
||||||
|
ERG_LESS_THAN = 212,
|
||||||
|
ERG_LESS_EQUAL = 213,
|
||||||
|
ERG_EQUAL = 214,
|
||||||
|
ERG_NOT_EQUAL = 215,
|
||||||
|
ERG_MAKE_SLOT = 216,
|
||||||
|
ERG_MAKE_TYPE = 217,
|
||||||
|
ERG_MAKE_PURE_FUNCTION = 218,
|
||||||
|
ERG_CALL_PURE_FUNCTION = 219,
|
||||||
|
/* ↑ These opcodes take an arg ↑ */
|
||||||
|
/* ↓ These opcodes take no arg ↓ */
|
||||||
|
// ... = 220,
|
||||||
|
ERG_LOAD_EMPTY_SLOT = 242,
|
||||||
|
ERG_LOAD_EMPTY_STR = 243,
|
||||||
|
ERG_LOAD_1_NAT = 244,
|
||||||
|
ERG_LOAD_1_INT = 245,
|
||||||
|
ERG_LOAD_1_REAL = 246,
|
||||||
|
ERG_LOAD_NONE = 247,
|
||||||
|
ERG_MUTATE = 248, // !x
|
||||||
|
// `[] =` (it doesn't cause any exceptions)
|
||||||
|
ERG_STORE_SUBSCR = 249,
|
||||||
|
// ... = 250,
|
||||||
|
// `= []` (it doesn't cause any exceptions)
|
||||||
|
ERG_BINARY_SUBSCR = 251,
|
||||||
|
ERG_BINARY_RANGE = 252,
|
||||||
|
// `/?` (rhs may be 0, it may cause a runtime panic)
|
||||||
|
ERG_TRY_BINARY_DIVIDE = 253,
|
||||||
|
// `/` (rhs could not be 0, it doesn't cause any exceptions)
|
||||||
|
ERG_BINARY_TRUE_DIVIDE = 254,
|
||||||
|
NOT_IMPLEMENTED = 255,
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ use crate::normalize_path;
|
||||||
/// `PathBuf` may give false equivalence decisions in non-case-sensitive file systems.
|
/// `PathBuf` may give false equivalence decisions in non-case-sensitive file systems.
|
||||||
/// Use this for dictionary keys, etc.
|
/// Use this for dictionary keys, etc.
|
||||||
/// See also: `els::util::NormalizedUrl`
|
/// See also: `els::util::NormalizedUrl`
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct NormalizedPathBuf(PathBuf);
|
pub struct NormalizedPathBuf(PathBuf);
|
||||||
|
|
||||||
impl<P: Into<PathBuf>> From<P> for NormalizedPathBuf {
|
impl<P: Into<PathBuf>> From<P> for NormalizedPathBuf {
|
||||||
|
@ -41,7 +41,7 @@ impl Deref for NormalizedPathBuf {
|
||||||
|
|
||||||
impl NormalizedPathBuf {
|
impl NormalizedPathBuf {
|
||||||
pub fn new(path: PathBuf) -> Self {
|
pub fn new(path: PathBuf) -> Self {
|
||||||
NormalizedPathBuf(normalize_path(path))
|
NormalizedPathBuf(normalize_path(path.canonicalize().unwrap_or(path)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ use erg_common::fresh::SharedFreshNameGenerator;
|
||||||
use erg_common::io::Input;
|
use erg_common::io::Input;
|
||||||
use erg_common::opcode::{CommonOpcode, CompareOp};
|
use erg_common::opcode::{CommonOpcode, CompareOp};
|
||||||
use erg_common::opcode308::Opcode308;
|
use erg_common::opcode308::Opcode308;
|
||||||
|
use erg_common::opcode309::Opcode309;
|
||||||
use erg_common::opcode310::Opcode310;
|
use erg_common::opcode310::Opcode310;
|
||||||
use erg_common::opcode311::{BinOpCode, Opcode311};
|
use erg_common::opcode311::{BinOpCode, Opcode311};
|
||||||
use erg_common::option_enum_unwrap;
|
use erg_common::option_enum_unwrap;
|
||||||
|
@ -1783,10 +1784,10 @@ impl PyCodeGenerator {
|
||||||
self.write_instr(Opcode308::JUMP_FORWARD); // jump to end
|
self.write_instr(Opcode308::JUMP_FORWARD); // jump to end
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
// else block
|
// else block
|
||||||
let idx_else_begin = if self.py_version.minor >= Some(11) {
|
let idx_else_begin = match self.py_version.minor {
|
||||||
self.lasti() - idx_pop_jump_if_false - 2
|
Some(11) => self.lasti() - idx_pop_jump_if_false - 2,
|
||||||
} else {
|
Some(10) => self.lasti(),
|
||||||
self.lasti()
|
_ => self.lasti(),
|
||||||
};
|
};
|
||||||
self.fill_jump(idx_pop_jump_if_false + 1, idx_else_begin - 2);
|
self.fill_jump(idx_pop_jump_if_false + 1, idx_else_begin - 2);
|
||||||
match args.remove(0) {
|
match args.remove(0) {
|
||||||
|
@ -1805,8 +1806,12 @@ impl PyCodeGenerator {
|
||||||
self.stack_dec();
|
self.stack_dec();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.write_instr(Opcode308::JUMP_FORWARD);
|
self.write_instr(Opcode311::JUMP_FORWARD);
|
||||||
self.write_arg(1);
|
let jump_to = match self.py_version.minor {
|
||||||
|
Some(11 | 10) => 1,
|
||||||
|
_ => 2,
|
||||||
|
};
|
||||||
|
self.write_arg(jump_to);
|
||||||
// no else block
|
// no else block
|
||||||
let idx_end = if self.py_version.minor >= Some(11) {
|
let idx_end = if self.py_version.minor >= Some(11) {
|
||||||
self.lasti() - idx_pop_jump_if_false - 1
|
self.lasti() - idx_pop_jump_if_false - 1
|
||||||
|
@ -1861,7 +1866,7 @@ impl PyCodeGenerator {
|
||||||
self.write_arg(idx_for_iter / 2);
|
self.write_arg(idx_for_iter / 2);
|
||||||
}
|
}
|
||||||
Some(9 | 8 | 7) => {
|
Some(9 | 8 | 7) => {
|
||||||
self.write_instr(Opcode308::JUMP_ABSOLUTE);
|
self.write_instr(Opcode309::JUMP_ABSOLUTE);
|
||||||
self.write_arg(idx_for_iter);
|
self.write_arg(idx_for_iter);
|
||||||
}
|
}
|
||||||
_ => todo!("not supported Python version"),
|
_ => todo!("not supported Python version"),
|
||||||
|
@ -2077,7 +2082,7 @@ impl PyCodeGenerator {
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.write_instr(Opcode311::PUSH_EXC_INFO);
|
self.write_instr(Opcode311::PUSH_EXC_INFO);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.write_instr(Opcode308::WITH_EXCEPT_START);
|
self.write_instr(Opcode309::WITH_EXCEPT_START);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.write_instr(Opcode311::POP_JUMP_FORWARD_IF_TRUE);
|
self.write_instr(Opcode311::POP_JUMP_FORWARD_IF_TRUE);
|
||||||
self.write_arg(4);
|
self.write_arg(4);
|
||||||
|
@ -2151,6 +2156,59 @@ impl PyCodeGenerator {
|
||||||
self.emit_load_name_instr(stash);
|
self.emit_load_name_instr(stash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_with_instr_309(&mut self, mut args: Args) {
|
||||||
|
log!(info "entered {}", fn_name!());
|
||||||
|
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
|
||||||
|
return self.deopt_instr(ControlKind::With, args);
|
||||||
|
}
|
||||||
|
let expr = args.remove(0);
|
||||||
|
let Expr::Lambda(lambda) = args.remove(0) else { unreachable!() };
|
||||||
|
let params = self.gen_param_names(&lambda.params);
|
||||||
|
self.emit_expr(expr);
|
||||||
|
let idx_setup_with = self.lasti();
|
||||||
|
self.write_instr(Opcode310::SETUP_WITH);
|
||||||
|
self.write_arg(0);
|
||||||
|
// push __exit__, __enter__() to the stack
|
||||||
|
self.stack_inc_n(2);
|
||||||
|
let lambda_line = lambda.body.last().unwrap().ln_begin().unwrap_or(0);
|
||||||
|
self.emit_with_block(lambda.body, params);
|
||||||
|
let stash = Identifier::private_with_line(self.fresh_gen.fresh_varname(), lambda_line);
|
||||||
|
self.emit_store_instr(stash.clone(), Name);
|
||||||
|
self.write_instr(POP_BLOCK);
|
||||||
|
self.write_arg(0);
|
||||||
|
self.emit_load_const(ValueObj::None);
|
||||||
|
self.write_instr(Opcode310::DUP_TOP);
|
||||||
|
self.write_arg(0);
|
||||||
|
self.stack_inc();
|
||||||
|
self.write_instr(Opcode310::DUP_TOP);
|
||||||
|
self.write_arg(0);
|
||||||
|
self.stack_inc();
|
||||||
|
self.write_instr(Opcode310::CALL_FUNCTION);
|
||||||
|
self.write_arg(3);
|
||||||
|
self.stack_dec_n((1 + 3) - 1);
|
||||||
|
self.emit_pop_top();
|
||||||
|
let idx_jump_forward = self.lasti();
|
||||||
|
self.write_instr(Opcode311::JUMP_FORWARD);
|
||||||
|
self.write_arg(0);
|
||||||
|
self.edit_code(idx_setup_with + 1, self.lasti() - idx_setup_with - 2);
|
||||||
|
self.write_instr(Opcode310::WITH_EXCEPT_START);
|
||||||
|
self.write_arg(0);
|
||||||
|
let idx_pop_jump_if_true = self.lasti();
|
||||||
|
self.write_instr(Opcode310::POP_JUMP_IF_TRUE);
|
||||||
|
self.write_arg(0);
|
||||||
|
self.write_instr(Opcode309::RERAISE);
|
||||||
|
self.write_arg(1);
|
||||||
|
self.edit_code(idx_pop_jump_if_true + 1, self.lasti());
|
||||||
|
// self.emit_pop_top();
|
||||||
|
// self.emit_pop_top();
|
||||||
|
self.emit_pop_top();
|
||||||
|
self.write_instr(Opcode310::POP_EXCEPT);
|
||||||
|
self.write_arg(0);
|
||||||
|
let idx_end = self.lasti();
|
||||||
|
self.edit_code(idx_jump_forward + 1, idx_end - idx_jump_forward - 2);
|
||||||
|
self.emit_load_name_instr(stash);
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_with_instr_308(&mut self, mut args: Args) {
|
fn emit_with_instr_308(&mut self, mut args: Args) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
|
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
|
||||||
|
@ -2161,7 +2219,7 @@ impl PyCodeGenerator {
|
||||||
let params = self.gen_param_names(&lambda.params);
|
let params = self.gen_param_names(&lambda.params);
|
||||||
self.emit_expr(expr);
|
self.emit_expr(expr);
|
||||||
let idx_setup_with = self.lasti();
|
let idx_setup_with = self.lasti();
|
||||||
self.write_instr(Opcode308::SETUP_WITH);
|
self.write_instr(Opcode309::SETUP_WITH);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
// push __exit__, __enter__() to the stack
|
// push __exit__, __enter__() to the stack
|
||||||
// self.stack_inc_n(2);
|
// self.stack_inc_n(2);
|
||||||
|
@ -2219,7 +2277,8 @@ impl PyCodeGenerator {
|
||||||
"with!" => match self.py_version.minor {
|
"with!" => match self.py_version.minor {
|
||||||
Some(11) => self.emit_with_instr_311(args),
|
Some(11) => self.emit_with_instr_311(args),
|
||||||
Some(10) => self.emit_with_instr_310(args),
|
Some(10) => self.emit_with_instr_310(args),
|
||||||
Some(9 | 8 | 7) => self.emit_with_instr_308(args),
|
Some(9) => self.emit_with_instr_309(args),
|
||||||
|
Some(8) => self.emit_with_instr_308(args),
|
||||||
_ => todo!("not supported Python version"),
|
_ => todo!("not supported Python version"),
|
||||||
},
|
},
|
||||||
// "pyimport" | "py" are here
|
// "pyimport" | "py" are here
|
||||||
|
@ -2281,7 +2340,7 @@ impl PyCodeGenerator {
|
||||||
}
|
}
|
||||||
self.emit_expr(var_args.expr.clone());
|
self.emit_expr(var_args.expr.clone());
|
||||||
if pos_len > 0 {
|
if pos_len > 0 {
|
||||||
self.write_instr(Opcode308::BUILD_TUPLE_UNPACK_WITH_CALL);
|
self.write_instr(Opcode309::BUILD_TUPLE_UNPACK_WITH_CALL);
|
||||||
self.write_arg(2);
|
self.write_arg(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2752,6 +2811,10 @@ impl PyCodeGenerator {
|
||||||
self.emit_load_name_instr(Identifier::public("Str"));
|
self.emit_load_name_instr(Identifier::public("Str"));
|
||||||
}
|
}
|
||||||
other => match &other.qual_name()[..] {
|
other => match &other.qual_name()[..] {
|
||||||
|
"Bytes" => {
|
||||||
|
self.emit_push_null();
|
||||||
|
self.emit_load_name_instr(Identifier::public("Bytes"));
|
||||||
|
}
|
||||||
"Array" => {
|
"Array" => {
|
||||||
self.emit_push_null();
|
self.emit_push_null();
|
||||||
self.emit_load_name_instr(Identifier::public("Array"));
|
self.emit_load_name_instr(Identifier::public("Array"));
|
||||||
|
|
|
@ -14,6 +14,7 @@ use OpKind::*;
|
||||||
use erg_parser::ast::Dict as AstDict;
|
use erg_parser::ast::Dict as AstDict;
|
||||||
use erg_parser::ast::Set as AstSet;
|
use erg_parser::ast::Set as AstSet;
|
||||||
use erg_parser::ast::*;
|
use erg_parser::ast::*;
|
||||||
|
use erg_parser::desugar::Desugarer;
|
||||||
use erg_parser::token::{Token, TokenKind};
|
use erg_parser::token::{Token, TokenKind};
|
||||||
|
|
||||||
use crate::ty::constructors::{
|
use crate::ty::constructors::{
|
||||||
|
@ -303,8 +304,28 @@ impl Context {
|
||||||
|
|
||||||
fn call(&self, subr: ConstSubr, args: ValueArgs, loc: Location) -> EvalResult<ValueObj> {
|
fn call(&self, subr: ConstSubr, args: ValueArgs, loc: Location) -> EvalResult<ValueObj> {
|
||||||
match subr {
|
match subr {
|
||||||
ConstSubr::User(_user) => {
|
ConstSubr::User(user) => {
|
||||||
feature_error!(self, loc, "calling user-defined subroutines").map_err(Into::into)
|
// HACK: should avoid cloning
|
||||||
|
let mut subr_ctx = Context::instant(
|
||||||
|
user.name.clone(),
|
||||||
|
self.cfg.clone(),
|
||||||
|
2,
|
||||||
|
self.shared.clone(),
|
||||||
|
self.clone(),
|
||||||
|
);
|
||||||
|
// TODO: var_args
|
||||||
|
for (arg, sig) in args
|
||||||
|
.pos_args
|
||||||
|
.into_iter()
|
||||||
|
.zip(user.params.non_defaults.iter())
|
||||||
|
{
|
||||||
|
let name = VarName::from_str(sig.inspect().unwrap().clone());
|
||||||
|
subr_ctx.consts.insert(name, arg);
|
||||||
|
}
|
||||||
|
for (name, arg) in args.kw_args.into_iter() {
|
||||||
|
subr_ctx.consts.insert(VarName::from_str(name), arg);
|
||||||
|
}
|
||||||
|
subr_ctx.eval_const_block(&user.block())
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| {
|
ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| {
|
||||||
if e.0.loc.is_unknown() {
|
if e.0.loc.is_unknown() {
|
||||||
|
@ -316,6 +337,16 @@ impl Context {
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
))
|
))
|
||||||
}),
|
}),
|
||||||
|
ConstSubr::Gen(gen) => gen.call(args, self).map_err(|mut e| {
|
||||||
|
if e.0.loc.is_unknown() {
|
||||||
|
e.0.loc = loc;
|
||||||
|
}
|
||||||
|
EvalErrors::from(EvalError::new(
|
||||||
|
*e.0,
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
self.caused_by(),
|
||||||
|
))
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +460,9 @@ impl Context {
|
||||||
fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
|
fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
|
||||||
match record {
|
match record {
|
||||||
Record::Normal(rec) => self.eval_const_normal_record(rec),
|
Record::Normal(rec) => self.eval_const_normal_record(rec),
|
||||||
Record::Mixed(_rec) => unreachable_error!(self), // should be desugared
|
Record::Mixed(mixed) => self.eval_const_normal_record(
|
||||||
|
&Desugarer::desugar_shortened_record_inner(mixed.clone()),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1478,24 +1511,29 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, ()> {
|
fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, Type> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::Poly { name, params } if &name[..] == "Array" || &name[..] == "Array!" => {
|
Type::Poly { name, params } if &name[..] == "Array" || &name[..] == "Array!" => {
|
||||||
let t = self
|
let Ok(t) = self.convert_tp_into_type(params[0].clone()) else {
|
||||||
.convert_tp_into_type(params[0].clone())
|
return Err(poly(name, params));
|
||||||
.map_err(|_| ())?;
|
};
|
||||||
let TyParam::Value(ValueObj::Nat(len)) = params[1] else { unreachable!() };
|
let TyParam::Value(ValueObj::Nat(len)) = params[1] else { unreachable!() };
|
||||||
Ok(vec![ValueObj::builtin_type(t); len as usize])
|
Ok(vec![ValueObj::builtin_type(t); len as usize])
|
||||||
}
|
}
|
||||||
_ => Err(()),
|
_ => Err(ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn convert_value_into_array(&self, val: ValueObj) -> Result<Vec<ValueObj>, ()> {
|
pub(crate) fn convert_value_into_array(
|
||||||
|
&self,
|
||||||
|
val: ValueObj,
|
||||||
|
) -> Result<Vec<ValueObj>, ValueObj> {
|
||||||
match val {
|
match val {
|
||||||
ValueObj::Array(arr) => Ok(arr.to_vec()),
|
ValueObj::Array(arr) => Ok(arr.to_vec()),
|
||||||
ValueObj::Type(t) => self.convert_type_to_array(t.into_typ()),
|
ValueObj::Type(t) => self
|
||||||
_ => Err(()),
|
.convert_type_to_array(t.into_typ())
|
||||||
|
.map_err(ValueObj::builtin_type),
|
||||||
|
_ => Err(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1784,9 +1822,8 @@ impl Context {
|
||||||
})? {
|
})? {
|
||||||
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&attr_name), &self.name) {
|
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&attr_name), &self.name) {
|
||||||
if let ValueObj::Subr(subr) = obj {
|
if let ValueObj::Subr(subr) = obj {
|
||||||
let is_method = subr.sig_t().self_t().is_some();
|
|
||||||
let mut pos_args = vec![];
|
let mut pos_args = vec![];
|
||||||
if is_method {
|
if subr.sig_t().is_method() {
|
||||||
match ValueObj::try_from(lhs) {
|
match ValueObj::try_from(lhs) {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
pos_args.push(value);
|
pos_args.push(value);
|
||||||
|
|
|
@ -41,6 +41,9 @@ impl Generalizer {
|
||||||
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
|
||||||
match free {
|
match free {
|
||||||
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
|
||||||
|
TyParam::Value(ValueObj::Type(t)) => {
|
||||||
|
TyParam::t(self.generalize_t(t.into_typ(), uninit))
|
||||||
|
}
|
||||||
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
|
||||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||||
self.generalize_tp(fv.crack().clone(), uninit)
|
self.generalize_tp(fv.crack().clone(), uninit)
|
||||||
|
@ -122,7 +125,7 @@ impl Generalizer {
|
||||||
TyParam::unary(op, val)
|
TyParam::unary(op, val)
|
||||||
}
|
}
|
||||||
other if other.has_no_unbound_var() => other,
|
other if other.has_no_unbound_var() => other,
|
||||||
other => todo!("{other}"),
|
other => todo!("{other:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -897,7 +897,7 @@ impl Context {
|
||||||
Immutable,
|
Immutable,
|
||||||
Visibility::BUILTIN_PUBLIC,
|
Visibility::BUILTIN_PUBLIC,
|
||||||
);
|
);
|
||||||
let str_getitem_t = fn1_kw_met(Str, kw(KW_IDX, Nat), Str);
|
let str_getitem_t = fn1_kw_met(Str, kw(KW_IDX, Nat | poly(RANGE, vec![ty_tp(Int)])), Str);
|
||||||
str_.register_builtin_erg_impl(
|
str_.register_builtin_erg_impl(
|
||||||
FUNDAMENTAL_GETITEM,
|
FUNDAMENTAL_GETITEM,
|
||||||
str_getitem_t,
|
str_getitem_t,
|
||||||
|
@ -1181,7 +1181,7 @@ impl Context {
|
||||||
);
|
);
|
||||||
/* Array */
|
/* Array */
|
||||||
let mut array_ =
|
let mut array_ =
|
||||||
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::named_nd(TY_N, Nat)], 10);
|
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::default(TY_N, Nat)], 10);
|
||||||
array_.register_superclass(mono(GENERIC_ARRAY), &generic_array);
|
array_.register_superclass(mono(GENERIC_ARRAY), &generic_array);
|
||||||
array_
|
array_
|
||||||
.register_marker_trait(self, poly(OUTPUT, vec![ty_tp(T.clone())]))
|
.register_marker_trait(self, poly(OUTPUT, vec![ty_tp(T.clone())]))
|
||||||
|
@ -1240,11 +1240,16 @@ impl Context {
|
||||||
Predicate::le(var, N.clone() - value(1usize)),
|
Predicate::le(var, N.clone() - value(1usize)),
|
||||||
);
|
);
|
||||||
// __getitem__: |T, N|(self: [T; N], _: {I: Nat | I <= N}) -> T
|
// __getitem__: |T, N|(self: [T; N], _: {I: Nat | I <= N}) -> T
|
||||||
let array_getitem_t = fn1_kw_met(
|
// and (self: [T; N], _: Range(Int)) -> [T; _]
|
||||||
|
let array_getitem_t = (fn1_kw_met(
|
||||||
array_t(T.clone(), N.clone()),
|
array_t(T.clone(), N.clone()),
|
||||||
anon(input.clone()),
|
anon(input.clone()),
|
||||||
T.clone(),
|
T.clone(),
|
||||||
)
|
) & fn1_kw_met(
|
||||||
|
array_t(T.clone(), N.clone()),
|
||||||
|
anon(poly(RANGE, vec![ty_tp(Int)])),
|
||||||
|
unknown_len_array_t(T.clone()),
|
||||||
|
))
|
||||||
.quantify();
|
.quantify();
|
||||||
let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
|
let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
|
||||||
FUNDAMENTAL_GETITEM,
|
FUNDAMENTAL_GETITEM,
|
||||||
|
@ -1330,6 +1335,12 @@ impl Context {
|
||||||
array_t(T.clone(), TyParam::erased(Nat)),
|
array_t(T.clone(), TyParam::erased(Nat)),
|
||||||
);
|
);
|
||||||
array_.register_py_builtin(FUNC_DEDUP, t.quantify(), Some(FUNC_DEDUP), 28);
|
array_.register_py_builtin(FUNC_DEDUP, t.quantify(), Some(FUNC_DEDUP), 28);
|
||||||
|
/* Slice */
|
||||||
|
let mut slice = Self::builtin_mono_class(SLICE, 3);
|
||||||
|
slice.register_superclass(Obj, &obj);
|
||||||
|
slice.register_builtin_erg_impl(KW_START, Int, Immutable, Visibility::BUILTIN_PUBLIC);
|
||||||
|
slice.register_builtin_erg_impl(KW_STOP, Int, Immutable, Visibility::BUILTIN_PUBLIC);
|
||||||
|
slice.register_builtin_erg_impl(KW_STEP, Int, Immutable, Visibility::BUILTIN_PUBLIC);
|
||||||
/* GenericSet */
|
/* GenericSet */
|
||||||
let mut generic_set = Self::builtin_mono_class(GENERIC_SET, 1);
|
let mut generic_set = Self::builtin_mono_class(GENERIC_SET, 1);
|
||||||
generic_set.register_superclass(Obj, &obj);
|
generic_set.register_superclass(Obj, &obj);
|
||||||
|
@ -1534,6 +1545,29 @@ impl Context {
|
||||||
Str,
|
Str,
|
||||||
);
|
);
|
||||||
bytes.register_py_builtin(FUNC_DECODE, decode_t, Some(FUNC_DECODE), 6);
|
bytes.register_py_builtin(FUNC_DECODE, decode_t, Some(FUNC_DECODE), 6);
|
||||||
|
let bytes_getitem_t = fn1_kw_met(mono(BYTES), kw(KW_IDX, Nat), Int)
|
||||||
|
& fn1_kw_met(
|
||||||
|
mono(BYTES),
|
||||||
|
kw(KW_IDX, poly(RANGE, vec![ty_tp(Int)])),
|
||||||
|
mono(BYTES),
|
||||||
|
);
|
||||||
|
bytes.register_builtin_erg_impl(
|
||||||
|
FUNDAMENTAL_GETITEM,
|
||||||
|
bytes_getitem_t,
|
||||||
|
Immutable,
|
||||||
|
Visibility::BUILTIN_PUBLIC,
|
||||||
|
);
|
||||||
|
bytes
|
||||||
|
.register_marker_trait(self, poly(INDEXABLE, vec![ty_tp(Nat), ty_tp(Int)]))
|
||||||
|
.unwrap();
|
||||||
|
let mut bytes_eq = Self::builtin_methods(Some(mono(EQ)), 2);
|
||||||
|
bytes_eq.register_builtin_erg_impl(
|
||||||
|
OP_EQ,
|
||||||
|
fn1_met(mono(BYTES), mono(BYTES), Bool),
|
||||||
|
Const,
|
||||||
|
Visibility::BUILTIN_PUBLIC,
|
||||||
|
);
|
||||||
|
bytes.register_trait(mono(BYTES), bytes_eq);
|
||||||
/* GenericTuple */
|
/* GenericTuple */
|
||||||
let mut generic_tuple = Self::builtin_mono_class(GENERIC_TUPLE, 1);
|
let mut generic_tuple = Self::builtin_mono_class(GENERIC_TUPLE, 1);
|
||||||
generic_tuple.register_superclass(Obj, &obj);
|
generic_tuple.register_superclass(Obj, &obj);
|
||||||
|
@ -2370,6 +2404,7 @@ impl Context {
|
||||||
Some(ARRAY),
|
Some(ARRAY),
|
||||||
);
|
);
|
||||||
self.register_builtin_type(arr_t, array_, vis.clone(), Const, Some(ARRAY));
|
self.register_builtin_type(arr_t, array_, vis.clone(), Const, Some(ARRAY));
|
||||||
|
self.register_builtin_type(mono(SLICE), slice, vis.clone(), Const, Some(FUNC_SLICE));
|
||||||
self.register_builtin_type(
|
self.register_builtin_type(
|
||||||
mono(GENERIC_SET),
|
mono(GENERIC_SET),
|
||||||
generic_set,
|
generic_set,
|
||||||
|
|
|
@ -242,7 +242,7 @@ pub(crate) fn structural_func(mut args: ValueArgs, ctx: &Context) -> EvalValueRe
|
||||||
pub(crate) fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
pub(crate) fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
let slf = ctx
|
let slf = ctx
|
||||||
.convert_value_into_array(args.remove_left_or_key("Self").unwrap())
|
.convert_value_into_array(args.remove_left_or_key("Self").unwrap())
|
||||||
.unwrap();
|
.unwrap_or_else(|err| panic!("{err}, {args}"));
|
||||||
let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat);
|
let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat);
|
||||||
if let Some(v) = slf.get(index as usize) {
|
if let Some(v) = slf.get(index as usize) {
|
||||||
Ok(v.clone())
|
Ok(v.clone())
|
||||||
|
|
|
@ -220,6 +220,12 @@ impl Context {
|
||||||
)
|
)
|
||||||
.quantify();
|
.quantify();
|
||||||
let t_round = nd_func(vec![kw(KW_NUMBER, Float)], None, Int);
|
let t_round = nd_func(vec![kw(KW_NUMBER, Float)], None, Int);
|
||||||
|
let t_slice = func(
|
||||||
|
vec![kw(KW_START, Int)],
|
||||||
|
None,
|
||||||
|
vec![kw(KW_STOP, Int), kw(KW_STEP, Int)],
|
||||||
|
mono(SLICE),
|
||||||
|
);
|
||||||
let t_sorted = nd_func(
|
let t_sorted = nd_func(
|
||||||
vec![kw(KW_ITERABLE, poly(ITERABLE, vec![ty_tp(T.clone())]))],
|
vec![kw(KW_ITERABLE, poly(ITERABLE, vec![ty_tp(T.clone())]))],
|
||||||
None,
|
None,
|
||||||
|
@ -393,6 +399,13 @@ impl Context {
|
||||||
vis.clone(),
|
vis.clone(),
|
||||||
Some(FUNC_ROUND),
|
Some(FUNC_ROUND),
|
||||||
);
|
);
|
||||||
|
self.register_builtin_py_impl(
|
||||||
|
FUNC_SLICE,
|
||||||
|
t_slice,
|
||||||
|
Immutable,
|
||||||
|
vis.clone(),
|
||||||
|
Some(FUNC_SLICE),
|
||||||
|
);
|
||||||
self.register_builtin_py_impl(
|
self.register_builtin_py_impl(
|
||||||
FUNC_SORTED,
|
FUNC_SORTED,
|
||||||
t_sorted,
|
t_sorted,
|
||||||
|
|
|
@ -33,7 +33,10 @@ use crate::module::SharedCompilerResource;
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::Constraint;
|
use crate::ty::free::Constraint;
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::{BuiltinConstSubr, ConstSubr, ParamTy, Predicate, TyParam, Type, Visibility};
|
use crate::ty::{
|
||||||
|
BuiltinConstSubr, ClosureData, ConstSubr, GenConstSubr, ParamTy, Predicate, TyParam, Type,
|
||||||
|
Visibility,
|
||||||
|
};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use Mutability::*;
|
use Mutability::*;
|
||||||
use ParamSpec as PS;
|
use ParamSpec as PS;
|
||||||
|
@ -281,6 +284,7 @@ const NAMED_FUNC: &str = "NamedFunc";
|
||||||
const FUNC: &str = "Func";
|
const FUNC: &str = "Func";
|
||||||
const QUANTIFIED: &str = "Quantified";
|
const QUANTIFIED: &str = "Quantified";
|
||||||
const QUANTIFIED_FUNC: &str = "QuantifiedFunc";
|
const QUANTIFIED_FUNC: &str = "QuantifiedFunc";
|
||||||
|
const SLICE: &str = "Slice";
|
||||||
const FUNC_OBJECT: &str = "object";
|
const FUNC_OBJECT: &str = "object";
|
||||||
const FUNC_INT: &str = "int";
|
const FUNC_INT: &str = "int";
|
||||||
const FUNC_INT__: &str = "int__";
|
const FUNC_INT__: &str = "int__";
|
||||||
|
@ -332,6 +336,7 @@ const FUNC_POW: &str = "pow";
|
||||||
const FUNC_QUIT: &str = "quit";
|
const FUNC_QUIT: &str = "quit";
|
||||||
const FUNC_REPR: &str = "repr";
|
const FUNC_REPR: &str = "repr";
|
||||||
const FUNC_ROUND: &str = "round";
|
const FUNC_ROUND: &str = "round";
|
||||||
|
const FUNC_SLICE: &str = "slice";
|
||||||
const FUNC_SORTED: &str = "sorted";
|
const FUNC_SORTED: &str = "sorted";
|
||||||
const FUNC_SUM: &str = "sum";
|
const FUNC_SUM: &str = "sum";
|
||||||
const FUNC_IF: &str = "if";
|
const FUNC_IF: &str = "if";
|
||||||
|
@ -780,23 +785,53 @@ impl Context {
|
||||||
muty: Mutability,
|
muty: Mutability,
|
||||||
py_name: Option<&'static str>,
|
py_name: Option<&'static str>,
|
||||||
) {
|
) {
|
||||||
// FIXME: panic
|
|
||||||
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.local_name()) {
|
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.local_name()) {
|
||||||
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
|
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
|
||||||
} else {
|
} else {
|
||||||
let val = match ctx.kind {
|
let ret_val = match ctx.kind {
|
||||||
ContextKind::Class => ValueObj::builtin_class(t.clone()),
|
ContextKind::Class => ValueObj::builtin_class(t.clone()),
|
||||||
ContextKind::Trait => ValueObj::builtin_trait(t.clone()),
|
ContextKind::Trait => ValueObj::builtin_trait(t.clone()),
|
||||||
_ => ValueObj::builtin_type(t.clone()),
|
_ => ValueObj::builtin_type(t.clone()),
|
||||||
};
|
};
|
||||||
|
let qual_name = t.qual_name();
|
||||||
let name = VarName::from_str(t.local_name());
|
let name = VarName::from_str(t.local_name());
|
||||||
// e.g Array!: |T, N|(_: {T}, _: {N}) -> {Array!(T, N)}
|
// e.g Array!: |T, N|(_: {T}, _:= {N}) -> {Array!(T, N)}
|
||||||
let params = t
|
let nd_params = ctx
|
||||||
.typarams()
|
.params_spec
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ps| (!ps.has_default()).then_some(ParamTy::from(ps)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let d_params = ctx
|
||||||
|
.params_spec
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ps| ps.has_default().then_some(ParamTy::from(ps)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let meta_t = func(
|
||||||
|
nd_params.clone(),
|
||||||
|
None,
|
||||||
|
d_params.clone(),
|
||||||
|
v_enum(set! { ret_val }),
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
let subr = move |data: ClosureData, args, _ctx: &Context| {
|
||||||
|
let passed = Vec::<TyParam>::from(args);
|
||||||
|
let lack = data.nd_params.len() + data.d_params.len() - passed.len();
|
||||||
|
let erased = data
|
||||||
|
.d_params
|
||||||
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tp| ParamTy::Pos(tp_enum(self.get_tp_t(&tp).unwrap_or(Obj), set! { tp })))
|
.take(lack)
|
||||||
.collect();
|
.map(|pt| TyParam::erased(pt.typ().clone()));
|
||||||
let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify();
|
let params = passed.into_iter().chain(erased).collect::<Vec<_>>();
|
||||||
|
Ok(ValueObj::builtin_type(poly(data.qual_name, params)))
|
||||||
|
};
|
||||||
|
let subr = ConstSubr::Gen(GenConstSubr::new(
|
||||||
|
t.local_name(),
|
||||||
|
ClosureData::new(nd_params, d_params, qual_name),
|
||||||
|
subr,
|
||||||
|
meta_t.clone(),
|
||||||
|
Some(t.clone()),
|
||||||
|
));
|
||||||
if ERG_MODE {
|
if ERG_MODE {
|
||||||
self.locals.insert(
|
self.locals.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
|
@ -812,7 +847,7 @@ impl Context {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.consts.insert(name.clone(), val);
|
self.consts.insert(name.clone(), ValueObj::Subr(subr));
|
||||||
self.register_methods(&t, &ctx);
|
self.register_methods(&t, &ctx);
|
||||||
self.poly_types.insert(name, (t, ctx));
|
self.poly_types.insert(name, (t, ctx));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ use Type::*;
|
||||||
use crate::context::instantiate_spec::ConstTemplate;
|
use crate::context::instantiate_spec::ConstTemplate;
|
||||||
use crate::context::{Context, RegistrationMode, TraitImpl, TyVarCache, Variance};
|
use crate::context::{Context, RegistrationMode, TraitImpl, TyVarCache, Variance};
|
||||||
use crate::error::{
|
use crate::error::{
|
||||||
binop_to_dname, readable_name, unaryop_to_dname, SingleTyCheckResult, TyCheckError,
|
binop_to_dname, ordinal_num, readable_name, unaryop_to_dname, SingleTyCheckResult,
|
||||||
TyCheckErrors, TyCheckResult,
|
TyCheckError, TyCheckErrors, TyCheckResult,
|
||||||
};
|
};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use crate::{feature_error, hir};
|
use crate::{feature_error, hir};
|
||||||
|
@ -831,10 +831,10 @@ impl Context {
|
||||||
if let Some(attr_name) = attr_name.as_ref() {
|
if let Some(attr_name) = attr_name.as_ref() {
|
||||||
let mut vi =
|
let mut vi =
|
||||||
self.search_method_info(obj, attr_name, pos_args, kw_args, input, namespace)?;
|
self.search_method_info(obj, attr_name, pos_args, kw_args, input, namespace)?;
|
||||||
vi.t = self.resolve_overload(vi.t, pos_args, kw_args, attr_name)?;
|
vi.t = self.resolve_overload(obj, vi.t, pos_args, kw_args, attr_name)?;
|
||||||
Ok(vi)
|
Ok(vi)
|
||||||
} else {
|
} else {
|
||||||
let t = self.resolve_overload(obj.t(), pos_args, kw_args, obj)?;
|
let t = self.resolve_overload(obj, obj.t(), pos_args, kw_args, obj)?;
|
||||||
Ok(VarInfo {
|
Ok(VarInfo {
|
||||||
t,
|
t,
|
||||||
..VarInfo::default()
|
..VarInfo::default()
|
||||||
|
@ -844,6 +844,7 @@ impl Context {
|
||||||
|
|
||||||
fn resolve_overload(
|
fn resolve_overload(
|
||||||
&self,
|
&self,
|
||||||
|
obj: &hir::Expr,
|
||||||
instance: Type,
|
instance: Type,
|
||||||
pos_args: &[hir::PosArg],
|
pos_args: &[hir::PosArg],
|
||||||
kw_args: &[hir::KwArg],
|
kw_args: &[hir::KwArg],
|
||||||
|
@ -853,7 +854,7 @@ impl Context {
|
||||||
if intersecs.len() == 1 {
|
if intersecs.len() == 1 {
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
} else {
|
} else {
|
||||||
let input_t = subr_t(
|
let mut input_t = subr_t(
|
||||||
SubrKind::Proc,
|
SubrKind::Proc,
|
||||||
pos_args
|
pos_args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -867,6 +868,18 @@ impl Context {
|
||||||
Obj,
|
Obj,
|
||||||
);
|
);
|
||||||
for ty in intersecs.iter() {
|
for ty in intersecs.iter() {
|
||||||
|
match (ty.is_method(), input_t.is_method()) {
|
||||||
|
(true, false) => {
|
||||||
|
let Type::Subr(sub) = &mut input_t else { unreachable!() };
|
||||||
|
sub.non_default_params
|
||||||
|
.insert(0, ParamTy::kw(Str::ever("self"), obj.t()));
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
let Type::Subr(sub) = &mut input_t else { unreachable!() };
|
||||||
|
sub.non_default_params.remove(0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
if self.subtype_of(ty, &input_t) {
|
if self.subtype_of(ty, &input_t) {
|
||||||
return Ok(ty.clone());
|
return Ok(ty.clone());
|
||||||
}
|
}
|
||||||
|
@ -1486,7 +1499,12 @@ impl Context {
|
||||||
let missing_params = subr
|
let missing_params = subr
|
||||||
.non_default_params
|
.non_default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("_")))
|
.enumerate()
|
||||||
|
.map(|(i, pt)| {
|
||||||
|
pt.name().cloned().unwrap_or_else(|| {
|
||||||
|
Str::from(format!("({} param)", ordinal_num(i + 1)))
|
||||||
|
})
|
||||||
|
})
|
||||||
.filter(|pt| !passed_params.contains(pt))
|
.filter(|pt| !passed_params.contains(pt))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if !missing_params.is_empty() {
|
if !missing_params.is_empty() {
|
||||||
|
@ -1666,6 +1684,8 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
passed_params.insert(name.clone());
|
passed_params.insert(name.clone());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
passed_params.insert(Str::from(format!("({} param)", ordinal_num(nth))));
|
||||||
}
|
}
|
||||||
self.sub_unify(arg_t, param_t, arg, param.name())
|
self.sub_unify(arg_t, param_t, arg, param.name())
|
||||||
.map_err(|errs| {
|
.map_err(|errs| {
|
||||||
|
|
|
@ -602,7 +602,25 @@ impl Context {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
Type::And(l, r) => {
|
||||||
|
if let Some(self_t) = l.self_t() {
|
||||||
|
self.sub_unify(
|
||||||
|
callee.ref_t(),
|
||||||
|
self_t,
|
||||||
|
callee,
|
||||||
|
Some(&Str::ever("self")),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
if let Some(self_t) = r.self_t() {
|
||||||
|
self.sub_unify(
|
||||||
|
callee.ref_t(),
|
||||||
|
self_t,
|
||||||
|
callee,
|
||||||
|
Some(&Str::ever("self")),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => unreachable!("{other}"),
|
||||||
}
|
}
|
||||||
Ok(t)
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ use crate::module::{
|
||||||
};
|
};
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::GuardType;
|
use crate::ty::GuardType;
|
||||||
|
use crate::ty::ParamTy;
|
||||||
use crate::ty::{Predicate, Type, Visibility, VisibilityModifier};
|
use crate::ty::{Predicate, Type, Visibility, VisibilityModifier};
|
||||||
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
@ -233,6 +234,16 @@ impl ParamSpec {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default<S: Into<Str>>(name: S, t: Type) -> Self {
|
||||||
|
Self::new(
|
||||||
|
Some(name),
|
||||||
|
t,
|
||||||
|
false,
|
||||||
|
DefaultInfo::WithDefault,
|
||||||
|
AbsLocation::unknown(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn t<S: Into<Str>>(name: S, is_var_params: bool, default: DefaultInfo) -> Self {
|
pub fn t<S: Into<Str>>(name: S, is_var_params: bool, default: DefaultInfo) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
Some(name),
|
Some(name),
|
||||||
|
@ -252,6 +263,20 @@ impl ParamSpec {
|
||||||
AbsLocation::unknown(),
|
AbsLocation::unknown(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_default(&self) -> bool {
|
||||||
|
self.default_info.has_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ParamSpec> for ParamTy {
|
||||||
|
fn from(param: &ParamSpec) -> Self {
|
||||||
|
if let Some(name) = ¶m.name {
|
||||||
|
ParamTy::kw(name.clone(), param.t.clone())
|
||||||
|
} else {
|
||||||
|
ParamTy::Pos(param.t.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -434,6 +459,7 @@ pub struct Context {
|
||||||
/// => locals: {"x": T, "y": T}
|
/// => locals: {"x": T, "y": T}
|
||||||
/// TODO: impl params desugaring and replace to `Dict`
|
/// TODO: impl params desugaring and replace to `Dict`
|
||||||
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
|
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
|
||||||
|
pub(crate) params_spec: Vec<ParamSpec>,
|
||||||
pub(crate) locals: Dict<VarName, VarInfo>,
|
pub(crate) locals: Dict<VarName, VarInfo>,
|
||||||
pub(crate) consts: Dict<VarName, ValueObj>,
|
pub(crate) consts: Dict<VarName, ValueObj>,
|
||||||
// {"Nat": ctx, "Int": ctx, ...}
|
// {"Nat": ctx, "Int": ctx, ...}
|
||||||
|
@ -589,7 +615,7 @@ impl Context {
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut params_ = Vec::new();
|
let mut params_ = Vec::new();
|
||||||
for param in params.into_iter() {
|
for param in params.clone().into_iter() {
|
||||||
let id = DefId(get_hash(&(&name, ¶m)));
|
let id = DefId(get_hash(&(&name, ¶m)));
|
||||||
if let Some(name) = param.name {
|
if let Some(name) = param.name {
|
||||||
let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
|
let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
|
||||||
|
@ -635,6 +661,7 @@ impl Context {
|
||||||
method_to_classes: Dict::default(),
|
method_to_classes: Dict::default(),
|
||||||
method_impl_patches: Dict::default(),
|
method_impl_patches: Dict::default(),
|
||||||
params: params_,
|
params: params_,
|
||||||
|
params_spec: params,
|
||||||
decls: Dict::default(),
|
decls: Dict::default(),
|
||||||
future_defined_locals: Dict::default(),
|
future_defined_locals: Dict::default(),
|
||||||
deleted_locals: Dict::default(),
|
deleted_locals: Dict::default(),
|
||||||
|
|
|
@ -5,6 +5,7 @@ use erg_common::traits::{Locational, Runnable, Stream};
|
||||||
use erg_common::{enum_unwrap, fn_name, log, set, Str, Triple};
|
use erg_common::{enum_unwrap, fn_name, log, set, Str, Triple};
|
||||||
|
|
||||||
use erg_parser::ast::{self, AscriptionKind, Identifier, VarName, AST};
|
use erg_parser::ast::{self, AscriptionKind, Identifier, VarName, AST};
|
||||||
|
use erg_parser::desugar::Desugarer;
|
||||||
|
|
||||||
use crate::context::instantiate::TyVarCache;
|
use crate::context::instantiate::TyVarCache;
|
||||||
use crate::lower::ASTLowerer;
|
use crate::lower::ASTLowerer;
|
||||||
|
@ -332,7 +333,7 @@ impl ASTLowerer {
|
||||||
fn fake_lower_record(&self, rec: ast::Record) -> LowerResult<hir::Record> {
|
fn fake_lower_record(&self, rec: ast::Record) -> LowerResult<hir::Record> {
|
||||||
let rec = match rec {
|
let rec = match rec {
|
||||||
ast::Record::Normal(rec) => rec,
|
ast::Record::Normal(rec) => rec,
|
||||||
ast::Record::Mixed(_mixed) => unreachable!(),
|
ast::Record::Mixed(mixed) => Desugarer::desugar_shortened_record_inner(mixed),
|
||||||
};
|
};
|
||||||
let mut elems = Vec::new();
|
let mut elems = Vec::new();
|
||||||
for elem in rec.attrs.into_iter() {
|
for elem in rec.attrs.into_iter() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ The name of the operating system dependent module imported. The following names
|
||||||
.chdir!: (path: PathLike, ) => NoneType
|
.chdir!: (path: PathLike, ) => NoneType
|
||||||
.chmod!: (path: PathLike, mode: Nat) => NoneType
|
.chmod!: (path: PathLike, mode: Nat) => NoneType
|
||||||
.getcwd!: () => Str
|
.getcwd!: () => Str
|
||||||
.getenv!: (key: Str, default: Str or NoneType := NoneType) => Str
|
.getenv!: |D <: Str or NoneType|(key: Str, default: D := NoneType) => Str or D
|
||||||
.listdir!: (path := PathLike,) => [Str; _]
|
.listdir!: (path := PathLike,) => [Str; _]
|
||||||
.mkdir!: (path: PathLike, mode := Nat) => NoneType
|
.mkdir!: (path: PathLike, mode := Nat) => NoneType
|
||||||
.putenv!: (key: Str, value: Str) => NoneType
|
.putenv!: (key: Str, value: Str) => NoneType
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from _erg_control import then__
|
from _erg_control import then__
|
||||||
|
from _erg_range import Range
|
||||||
|
|
||||||
class Array(list):
|
class Array(list):
|
||||||
def dedup(self, same_bucket=None):
|
def dedup(self, same_bucket=None):
|
||||||
|
@ -24,3 +25,11 @@ class Array(list):
|
||||||
|
|
||||||
def __mul__(self, n):
|
def __mul__(self, n):
|
||||||
return then__(list.__mul__(self, n), Array)
|
return then__(list.__mul__(self, n), Array)
|
||||||
|
|
||||||
|
def __getitem__(self, index_or_slice):
|
||||||
|
if isinstance(index_or_slice, slice):
|
||||||
|
return Array(list.__getitem__(self, index_or_slice))
|
||||||
|
elif isinstance(index_or_slice, Range):
|
||||||
|
return Array(list.__getitem__(self, index_or_slice.into_slice()))
|
||||||
|
else:
|
||||||
|
return list.__getitem__(self, index_or_slice)
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
class Bytes(bytes):
|
class Bytes(bytes):
|
||||||
def try_new(*b): # -> Result[Nat]
|
def try_new(*b): # -> Result[Nat]
|
||||||
return Bytes(bytes(*b))
|
return Bytes(bytes(*b))
|
||||||
|
|
||||||
|
def __getitem__(self, index_or_slice):
|
||||||
|
from _erg_range import Range
|
||||||
|
if isinstance(index_or_slice, slice):
|
||||||
|
return Bytes(bytes.__getitem__(self, index_or_slice))
|
||||||
|
elif isinstance(index_or_slice, Range):
|
||||||
|
return Bytes(bytes.__getitem__(self, index_or_slice.into_slice()))
|
||||||
|
else:
|
||||||
|
return bytes.__getitem__(self, index_or_slice)
|
||||||
|
|
|
@ -12,6 +12,13 @@ class Range:
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_slice(slice):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def into_slice(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
res = self.start + item
|
res = self.start + item
|
||||||
if res in self:
|
if res in self:
|
||||||
|
@ -56,6 +63,13 @@ class RightOpenRange(Range):
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
return self.start <= item < self.end
|
return self.start <= item < self.end
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_slice(slice):
|
||||||
|
return Range(slice.start, slice.stop)
|
||||||
|
|
||||||
|
def into_slice(self):
|
||||||
|
return slice(self.start, self.end)
|
||||||
|
|
||||||
|
|
||||||
# represents `start<..<end`
|
# represents `start<..<end`
|
||||||
class OpenRange(Range):
|
class OpenRange(Range):
|
||||||
|
@ -68,6 +82,13 @@ class ClosedRange(Range):
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
return self.start <= item <= self.end
|
return self.start <= item <= self.end
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_slice(slice):
|
||||||
|
return Range(slice.start, slice.stop - 1)
|
||||||
|
|
||||||
|
def into_slice(self):
|
||||||
|
return slice(self.start, self.end + 1)
|
||||||
|
|
||||||
|
|
||||||
class RangeIterator:
|
class RangeIterator:
|
||||||
def __init__(self, rng):
|
def __init__(self, rng):
|
||||||
|
|
|
@ -2,7 +2,6 @@ from _erg_result import Error
|
||||||
from _erg_int import Int
|
from _erg_int import Int
|
||||||
from _erg_control import then__
|
from _erg_control import then__
|
||||||
|
|
||||||
|
|
||||||
class Str(str):
|
class Str(str):
|
||||||
def __instancecheck__(cls, obj):
|
def __instancecheck__(cls, obj):
|
||||||
return isinstance(obj, str)
|
return isinstance(obj, str)
|
||||||
|
@ -40,6 +39,15 @@ class Str(str):
|
||||||
def __mod__(self, other):
|
def __mod__(self, other):
|
||||||
return then__(str.__mod__(other, self), Str)
|
return then__(str.__mod__(other, self), Str)
|
||||||
|
|
||||||
|
def __getitem__(self, index_or_slice):
|
||||||
|
from _erg_range import Range
|
||||||
|
if isinstance(index_or_slice, slice):
|
||||||
|
return Str(str.__getitem__(self, index_or_slice))
|
||||||
|
elif isinstance(index_or_slice, Range):
|
||||||
|
return Str(str.__getitem__(self, index_or_slice.into_slice()))
|
||||||
|
else:
|
||||||
|
return str.__getitem__(self, index_or_slice)
|
||||||
|
|
||||||
|
|
||||||
class StrMut: # Inherits Str
|
class StrMut: # Inherits Str
|
||||||
value: Str
|
value: Str
|
||||||
|
|
|
@ -18,6 +18,7 @@ use erg_common::{fmt_option, fn_name, log, switch_lang, Str};
|
||||||
use erg_parser::ast::{self, AscriptionKind, VisModifierSpec};
|
use erg_parser::ast::{self, AscriptionKind, VisModifierSpec};
|
||||||
use erg_parser::ast::{OperationKind, TypeSpecWithOp, VarName, AST};
|
use erg_parser::ast::{OperationKind, TypeSpecWithOp, VarName, AST};
|
||||||
use erg_parser::build_ast::ASTBuilder;
|
use erg_parser::build_ast::ASTBuilder;
|
||||||
|
use erg_parser::desugar::Desugarer;
|
||||||
use erg_parser::token::{Token, TokenKind};
|
use erg_parser::token::{Token, TokenKind};
|
||||||
use erg_parser::Parser;
|
use erg_parser::Parser;
|
||||||
|
|
||||||
|
@ -381,7 +382,9 @@ impl ASTLowerer {
|
||||||
log!(info "entered {}({record})", fn_name!());
|
log!(info "entered {}({record})", fn_name!());
|
||||||
match record {
|
match record {
|
||||||
ast::Record::Normal(rec) => self.lower_normal_record(rec),
|
ast::Record::Normal(rec) => self.lower_normal_record(rec),
|
||||||
ast::Record::Mixed(_rec) => unreachable!(), // should be desugared
|
ast::Record::Mixed(mixed) => {
|
||||||
|
self.lower_normal_record(Desugarer::desugar_shortened_record_inner(mixed))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl SharedCompilerResource {
|
||||||
|
|
||||||
pub fn inherit(&self, path: PathBuf) -> Self {
|
pub fn inherit(&self, path: PathBuf) -> Self {
|
||||||
let mut _self = self.clone();
|
let mut _self = self.clone();
|
||||||
_self.promises.path = path;
|
_self.promises.path = path.into();
|
||||||
_self
|
_self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use erg_common::pathutil::NormalizedPathBuf;
|
||||||
|
use erg_common::set;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::shared::{MappedRwLockReadGuard, RwLockReadGuard, Shared};
|
use erg_common::shared::{MappedRwLockReadGuard, RwLockReadGuard, Shared};
|
||||||
use erg_common::tsort::{tsort, Graph, Node, TopoSortError};
|
use erg_common::tsort::{tsort, Graph, Node, TopoSortError};
|
||||||
use erg_common::{normalize_path, set};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum IncRefError {
|
pub enum IncRefError {
|
||||||
|
@ -18,7 +19,7 @@ impl IncRefError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct ModuleGraph(Graph<PathBuf, ()>);
|
pub struct ModuleGraph(Graph<NormalizedPathBuf, ()>);
|
||||||
|
|
||||||
impl fmt::Display for ModuleGraph {
|
impl fmt::Display for ModuleGraph {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
@ -35,7 +36,7 @@ impl fmt::Display for ModuleGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for ModuleGraph {
|
impl IntoIterator for ModuleGraph {
|
||||||
type Item = Node<PathBuf, ()>;
|
type Item = Node<NormalizedPathBuf, ()>;
|
||||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
@ -48,20 +49,45 @@ impl ModuleGraph {
|
||||||
Self(Graph::new())
|
Self(Graph::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_node(&self, path: &Path) -> Option<&Node<PathBuf, ()>> {
|
pub fn get_node(&self, path: &Path) -> Option<&Node<NormalizedPathBuf, ()>> {
|
||||||
let path = normalize_path(path.to_path_buf());
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
self.0.iter().find(|n| n.id == path)
|
self.0.iter().find(|n| n.id == path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parents(&self, path: &Path) -> Option<&Set<PathBuf>> {
|
/// if `path` depends on `target`, returns `true`, else `false`.
|
||||||
let path = normalize_path(path.to_path_buf());
|
/// if `path` not found, returns `false`
|
||||||
|
pub fn depends_on(&self, path: &Path, target: &Path) -> bool {
|
||||||
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
|
let target = NormalizedPathBuf::new(target.to_path_buf());
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.find(|n| n.id == path)
|
||||||
|
.map(|n| n.depends_on.contains(&target))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self, path: &Path) -> Set<NormalizedPathBuf> {
|
||||||
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.filter(|n| n.depends_on.contains(&path))
|
||||||
|
.map(|n| n.id.clone())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parents(&self, path: &Path) -> Option<&Set<NormalizedPathBuf>> {
|
||||||
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
self.0.iter().find(|n| n.id == path).map(|n| &n.depends_on)
|
self.0.iter().find(|n| n.id == path).map(|n| &n.depends_on)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ancestors(&self, path: &Path) -> Set<PathBuf> {
|
/// ```erg
|
||||||
let path = normalize_path(path.to_path_buf());
|
/// # a.er
|
||||||
|
/// b = import "b"
|
||||||
|
/// ```
|
||||||
|
/// -> a: child, b: parent
|
||||||
|
pub fn ancestors(&self, path: &Path) -> Set<NormalizedPathBuf> {
|
||||||
let mut ancestors = set! {};
|
let mut ancestors = set! {};
|
||||||
if let Some(parents) = self.parents(&path) {
|
if let Some(parents) = self.parents(path) {
|
||||||
for parent in parents.iter() {
|
for parent in parents.iter() {
|
||||||
ancestors.insert(parent.clone());
|
ancestors.insert(parent.clone());
|
||||||
ancestors.extend(self.ancestors(parent));
|
ancestors.extend(self.ancestors(parent));
|
||||||
|
@ -71,7 +97,7 @@ impl ModuleGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node_if_none(&mut self, path: &Path) {
|
pub fn add_node_if_none(&mut self, path: &Path) {
|
||||||
let path = normalize_path(path.to_path_buf());
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
if self.0.iter().all(|n| n.id != path) {
|
if self.0.iter().all(|n| n.id != path) {
|
||||||
let node = Node::new(path, (), set! {});
|
let node = Node::new(path, (), set! {});
|
||||||
self.0.push(node);
|
self.0.push(node);
|
||||||
|
@ -80,8 +106,8 @@ impl ModuleGraph {
|
||||||
|
|
||||||
/// returns Err (and do nothing) if this operation makes a cycle
|
/// returns Err (and do nothing) if this operation makes a cycle
|
||||||
pub fn inc_ref(&mut self, referrer: &Path, depends_on: PathBuf) -> Result<(), IncRefError> {
|
pub fn inc_ref(&mut self, referrer: &Path, depends_on: PathBuf) -> Result<(), IncRefError> {
|
||||||
let referrer = normalize_path(referrer.to_path_buf());
|
let referrer = NormalizedPathBuf::new(referrer.to_path_buf());
|
||||||
let depends_on = normalize_path(depends_on);
|
let depends_on = NormalizedPathBuf::new(depends_on);
|
||||||
if self.ancestors(&depends_on).contains(&referrer) && referrer != depends_on {
|
if self.ancestors(&depends_on).contains(&referrer) && referrer != depends_on {
|
||||||
return Err(IncRefError::CycleDetected);
|
return Err(IncRefError::CycleDetected);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +122,7 @@ impl ModuleGraph {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Node<PathBuf, ()>> {
|
pub fn iter(&self) -> impl Iterator<Item = &Node<NormalizedPathBuf, ()>> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,13 +138,13 @@ impl ModuleGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&mut self, path: &Path) {
|
pub fn remove(&mut self, path: &Path) {
|
||||||
let path = normalize_path(path.to_path_buf());
|
let path = NormalizedPathBuf::new(path.to_path_buf());
|
||||||
self.0.retain(|n| n.id != path);
|
self.0.retain(|n| n.id != path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename_path(&mut self, old: &Path, new: PathBuf) {
|
pub fn rename_path(&mut self, old: &Path, new: PathBuf) {
|
||||||
let old = normalize_path(old.to_path_buf());
|
let old = NormalizedPathBuf::new(old.to_path_buf());
|
||||||
let new = normalize_path(new);
|
let new = NormalizedPathBuf::new(new);
|
||||||
for node in self.0.iter_mut() {
|
for node in self.0.iter_mut() {
|
||||||
if node.id == old {
|
if node.id == old {
|
||||||
node.id = new.clone();
|
node.id = new.clone();
|
||||||
|
@ -145,7 +171,7 @@ impl fmt::Display for SharedModuleGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for SharedModuleGraph {
|
impl IntoIterator for SharedModuleGraph {
|
||||||
type Item = Node<PathBuf, ()>;
|
type Item = Node<NormalizedPathBuf, ()>;
|
||||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
@ -158,7 +184,10 @@ impl SharedModuleGraph {
|
||||||
Self(Shared::new(ModuleGraph::new()))
|
Self(Shared::new(ModuleGraph::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_node(&self, path: &Path) -> Option<MappedRwLockReadGuard<Node<PathBuf, ()>>> {
|
pub fn get_node(
|
||||||
|
&self,
|
||||||
|
path: &Path,
|
||||||
|
) -> Option<MappedRwLockReadGuard<Node<NormalizedPathBuf, ()>>> {
|
||||||
if self.0.borrow().get_node(path).is_some() {
|
if self.0.borrow().get_node(path).is_some() {
|
||||||
Some(RwLockReadGuard::map(self.0.borrow(), |graph| {
|
Some(RwLockReadGuard::map(self.0.borrow(), |graph| {
|
||||||
graph.get_node(path).unwrap()
|
graph.get_node(path).unwrap()
|
||||||
|
@ -168,7 +197,15 @@ impl SharedModuleGraph {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ancestors(&self, path: &Path) -> Set<PathBuf> {
|
pub fn depends_on(&self, path: &Path, target: &Path) -> bool {
|
||||||
|
self.0.borrow().depends_on(path, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn children(&self, path: &Path) -> Set<NormalizedPathBuf> {
|
||||||
|
self.0.borrow().children(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ancestors(&self, path: &Path) -> Set<NormalizedPathBuf> {
|
||||||
self.0.borrow().ancestors(path)
|
self.0.borrow().ancestors(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ impl Promise {
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct SharedPromises {
|
pub struct SharedPromises {
|
||||||
graph: SharedModuleGraph,
|
graph: SharedModuleGraph,
|
||||||
pub(crate) path: PathBuf,
|
pub(crate) path: NormalizedPathBuf,
|
||||||
promises: Shared<Dict<NormalizedPathBuf, Promise>>,
|
promises: Shared<Dict<NormalizedPathBuf, Promise>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ impl SharedPromises {
|
||||||
pub fn new(graph: SharedModuleGraph, path: PathBuf) -> Self {
|
pub fn new(graph: SharedModuleGraph, path: PathBuf) -> Self {
|
||||||
Self {
|
Self {
|
||||||
graph,
|
graph,
|
||||||
path,
|
path: NormalizedPathBuf::new(path),
|
||||||
promises: Shared::new(Dict::new()),
|
promises: Shared::new(Dict::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,26 @@ impl SharedPromises {
|
||||||
Promise::Running { parent, handle };
|
Promise::Running { parent, handle };
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
// Suppose A depends on B and C, and B depends on C.
|
||||||
|
// In this case, B must join C before A joins C. Otherwise, a deadlock will occur.
|
||||||
|
let children = self.graph.children(path);
|
||||||
|
for child in children.iter() {
|
||||||
|
if child == &self.path {
|
||||||
|
continue;
|
||||||
|
} else if self.graph.depends_on(&self.path, child) {
|
||||||
|
*self.promises.borrow_mut().get_mut(path).unwrap() =
|
||||||
|
Promise::Running { parent, handle };
|
||||||
|
while self
|
||||||
|
.promises
|
||||||
|
.borrow()
|
||||||
|
.get(path)
|
||||||
|
.is_some_and(|p| !p.is_finished())
|
||||||
|
{
|
||||||
|
std::thread::yield_now();
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
let res = handle.join();
|
let res = handle.join();
|
||||||
*self.promises.borrow_mut().get_mut(path).unwrap() = Promise::Finished;
|
*self.promises.borrow_mut().get_mut(path).unwrap() = Promise::Finished;
|
||||||
res
|
res
|
||||||
|
|
|
@ -8,7 +8,7 @@ use erg_common::impl_display_from_debug;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::opcode::CommonOpcode;
|
use erg_common::opcode::CommonOpcode;
|
||||||
use erg_common::opcode308::Opcode308;
|
use erg_common::opcode309::Opcode309;
|
||||||
use erg_common::opcode310::Opcode310;
|
use erg_common::opcode310::Opcode310;
|
||||||
use erg_common::opcode311::{BinOpCode, Opcode311};
|
use erg_common::opcode311::{BinOpCode, Opcode311};
|
||||||
use erg_common::python_util::{env_magic_number, PythonVersion};
|
use erg_common::python_util::{env_magic_number, PythonVersion};
|
||||||
|
@ -36,20 +36,20 @@ pub fn consts_into_bytes(consts: Vec<ValueObj>, python_ver: PythonVersion) -> Ve
|
||||||
|
|
||||||
pub fn jump_abs_addr(minor_ver: u8, op: u8, idx: usize, arg: usize) -> usize {
|
pub fn jump_abs_addr(minor_ver: u8, op: u8, idx: usize, arg: usize) -> usize {
|
||||||
match minor_ver {
|
match minor_ver {
|
||||||
7 | 8 => jump_abs_addr_308(Opcode308::from(op), idx, arg),
|
7 | 8 | 9 => jump_abs_addr_309(Opcode309::from(op), idx, arg),
|
||||||
9 | 10 => jump_abs_addr_310(Opcode310::from(op), idx, arg),
|
10 => jump_abs_addr_310(Opcode310::from(op), idx, arg),
|
||||||
11 => jump_abs_addr_311(Opcode311::from(op), idx, arg),
|
11 => jump_abs_addr_311(Opcode311::from(op), idx, arg),
|
||||||
n => todo!("unsupported version: {n}"),
|
n => todo!("unsupported version: {n}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jump_abs_addr_308(op: Opcode308, idx: usize, arg: usize) -> usize {
|
fn jump_abs_addr_309(op: Opcode309, idx: usize, arg: usize) -> usize {
|
||||||
match op {
|
match op {
|
||||||
Opcode308::FOR_ITER | Opcode308::JUMP_FORWARD => idx + arg * 2 + 2,
|
Opcode309::FOR_ITER | Opcode309::JUMP_FORWARD => idx + arg + 2,
|
||||||
Opcode308::JUMP_ABSOLUTE | Opcode308::POP_JUMP_IF_FALSE | Opcode308::POP_JUMP_IF_TRUE => {
|
Opcode309::JUMP_ABSOLUTE | Opcode309::POP_JUMP_IF_FALSE | Opcode309::POP_JUMP_IF_TRUE => {
|
||||||
arg * 2
|
arg
|
||||||
}
|
}
|
||||||
Opcode308::SETUP_WITH => idx + arg * 2 + 2,
|
Opcode309::SETUP_WITH => idx + arg + 2,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,10 +541,8 @@ impl CodeObj {
|
||||||
arg
|
arg
|
||||||
};
|
};
|
||||||
match py_ver.and_then(|pv| pv.minor) {
|
match py_ver.and_then(|pv| pv.minor) {
|
||||||
Some(7) => self.read_instr_307(op, arg, idx, &mut instrs),
|
Some(7 | 8 | 9) => self.read_instr_309(op, arg, idx, &mut instrs),
|
||||||
Some(8) => self.read_instr_308(op, arg, idx, &mut instrs),
|
Some(10) => self.read_instr_310(op, arg, idx, &mut instrs),
|
||||||
// Some(9) => self.read_instr_309(op, arg, idx, &mut instrs),
|
|
||||||
Some(9 | 10) => self.read_instr_310(op, arg, idx, &mut instrs),
|
|
||||||
Some(11) => self.read_instr_311(op, arg, idx, &mut instrs),
|
Some(11) => self.read_instr_311(op, arg, idx, &mut instrs),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -557,78 +555,34 @@ impl CodeObj {
|
||||||
instrs
|
instrs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_instr_307(&self, op: &u8, arg: usize, idx: usize, instrs: &mut String) {
|
fn read_instr_309(&self, op: &u8, arg: usize, idx: usize, instrs: &mut String) {
|
||||||
let op307 = Opcode308::from(*op);
|
let op309 = Opcode309::from(*op);
|
||||||
let s_op = op307.to_string();
|
let s_op = op309.to_string();
|
||||||
write!(instrs, "{idx:>15} {s_op:<25}").unwrap();
|
write!(instrs, "{idx:>15} {s_op:<25}").unwrap();
|
||||||
if let Ok(op) = CommonOpcode::try_from(*op) {
|
if let Ok(op) = CommonOpcode::try_from(*op) {
|
||||||
self.dump_additional_info(op, arg, idx, instrs);
|
self.dump_additional_info(op, arg, idx, instrs);
|
||||||
}
|
}
|
||||||
match op307 {
|
match op309 {
|
||||||
Opcode308::STORE_DEREF | Opcode308::LOAD_DEREF => {
|
Opcode309::STORE_DEREF | Opcode309::LOAD_DEREF => {
|
||||||
write!(instrs, "{arg} ({})", self.freevars.get(arg).unwrap()).unwrap();
|
write!(instrs, "{arg} ({})", self.freevars.get(arg).unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
Opcode308::LOAD_CLOSURE => {
|
Opcode309::LOAD_CLOSURE => {
|
||||||
write!(instrs, "{arg} ({})", self.cellvars.get(arg).unwrap()).unwrap();
|
write!(instrs, "{arg} ({})", self.cellvars.get(arg).unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
Opcode308::JUMP_ABSOLUTE => {
|
Opcode309::JUMP_ABSOLUTE => {
|
||||||
write!(instrs, "{arg} (to {})", arg).unwrap();
|
write!(instrs, "{arg} (to {})", arg).unwrap();
|
||||||
}
|
}
|
||||||
Opcode308::JUMP_FORWARD => {
|
Opcode309::JUMP_FORWARD => {
|
||||||
write!(instrs, "{arg} (to {})", idx + arg + 2).unwrap();
|
write!(instrs, "{arg} (to {})", idx + arg + 2).unwrap();
|
||||||
}
|
}
|
||||||
Opcode308::POP_JUMP_IF_FALSE | Opcode308::POP_JUMP_IF_TRUE => {
|
// REVIEW: *2?
|
||||||
|
Opcode309::POP_JUMP_IF_FALSE | Opcode309::POP_JUMP_IF_TRUE => {
|
||||||
write!(instrs, "{arg} (to {})", arg).unwrap();
|
write!(instrs, "{arg} (to {})", arg).unwrap();
|
||||||
}
|
}
|
||||||
Opcode308::CALL_FUNCTION
|
Opcode309::BINARY_ADD
|
||||||
| Opcode308::CALL_FUNCTION_EX
|
| Opcode309::BINARY_SUBTRACT
|
||||||
| Opcode308::CALL_FUNCTION_KW => {
|
| Opcode309::BINARY_MULTIPLY
|
||||||
write!(instrs, "{arg}").unwrap();
|
| Opcode309::BINARY_TRUE_DIVIDE => {
|
||||||
}
|
|
||||||
Opcode308::BINARY_ADD
|
|
||||||
| Opcode308::BINARY_SUBTRACT
|
|
||||||
| Opcode308::BINARY_MULTIPLY
|
|
||||||
| Opcode308::BINARY_TRUE_DIVIDE => {
|
|
||||||
write!(instrs, "{arg} ({:?})", TypePair::from(arg as u8)).unwrap();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
instrs.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_instr_308(&self, op: &u8, arg: usize, idx: usize, instrs: &mut String) {
|
|
||||||
let op308 = Opcode308::from(*op);
|
|
||||||
let s_op = op308.to_string();
|
|
||||||
write!(instrs, "{idx:>15} {s_op:<25}").unwrap();
|
|
||||||
if let Ok(op) = CommonOpcode::try_from(*op) {
|
|
||||||
self.dump_additional_info(op, arg, idx, instrs);
|
|
||||||
}
|
|
||||||
match op308 {
|
|
||||||
Opcode308::STORE_DEREF | Opcode308::LOAD_DEREF => {
|
|
||||||
write!(instrs, "{arg} ({})", self.freevars.get(arg).unwrap()).unwrap();
|
|
||||||
}
|
|
||||||
Opcode308::LOAD_CLOSURE => {
|
|
||||||
write!(instrs, "{arg} ({})", self.cellvars.get(arg).unwrap()).unwrap();
|
|
||||||
}
|
|
||||||
Opcode308::JUMP_ABSOLUTE => {
|
|
||||||
write!(instrs, "{arg} (to {})", arg * 2).unwrap();
|
|
||||||
}
|
|
||||||
Opcode308::JUMP_FORWARD => {
|
|
||||||
write!(instrs, "{arg} (to {})", idx + arg * 2 + 2).unwrap();
|
|
||||||
}
|
|
||||||
// REVIEW: *2?
|
|
||||||
Opcode308::POP_JUMP_IF_FALSE | Opcode308::POP_JUMP_IF_TRUE => {
|
|
||||||
write!(instrs, "{arg} (to {})", arg * 2).unwrap();
|
|
||||||
}
|
|
||||||
Opcode308::CALL_FUNCTION
|
|
||||||
| Opcode308::CALL_FUNCTION_EX
|
|
||||||
| Opcode308::CALL_FUNCTION_KW => {
|
|
||||||
write!(instrs, "{arg}").unwrap();
|
|
||||||
}
|
|
||||||
Opcode308::BINARY_ADD
|
|
||||||
| Opcode308::BINARY_SUBTRACT
|
|
||||||
| Opcode308::BINARY_MULTIPLY
|
|
||||||
| Opcode308::BINARY_TRUE_DIVIDE => {
|
|
||||||
write!(instrs, "{arg} ({:?})", TypePair::from(arg as u8)).unwrap();
|
write!(instrs, "{arg} ({:?})", TypePair::from(arg as u8)).unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -5,20 +5,20 @@ use erg_common::dict::Dict;
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
|
||||||
use erg_parser::ast::{ConstBlock, Params};
|
use erg_parser::ast::{Block, ConstBlock, Params};
|
||||||
|
|
||||||
use super::constructors::subr_t;
|
use super::constructors::subr_t;
|
||||||
use super::value::{EvalValueResult, ValueObj};
|
use super::value::{EvalValueResult, ValueObj};
|
||||||
use super::{Predicate, Type};
|
use super::{ParamTy, Predicate, TyParam, Type};
|
||||||
|
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct UserConstSubr {
|
pub struct UserConstSubr {
|
||||||
name: Str,
|
pub name: Str,
|
||||||
params: Params,
|
pub(crate) params: Params,
|
||||||
block: ConstBlock,
|
pub(crate) block: ConstBlock,
|
||||||
sig_t: Type,
|
pub(crate) sig_t: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UserConstSubr {
|
impl UserConstSubr {
|
||||||
|
@ -30,6 +30,10 @@ impl UserConstSubr {
|
||||||
sig_t,
|
sig_t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block(self) -> Block {
|
||||||
|
self.block.downgrade()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -38,6 +42,26 @@ pub struct ValueArgs {
|
||||||
pub kw_args: Dict<Str, ValueObj>,
|
pub kw_args: Dict<Str, ValueObj>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ValueArgs {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for arg in &self.pos_args {
|
||||||
|
args.push(arg.to_string());
|
||||||
|
}
|
||||||
|
for (key, arg) in self.kw_args.iter() {
|
||||||
|
args.push(format!("{key} := {arg}"));
|
||||||
|
}
|
||||||
|
write!(f, "({})", args.join(", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ValueArgs> for Vec<TyParam> {
|
||||||
|
fn from(args: ValueArgs) -> Self {
|
||||||
|
// TODO: kw_args
|
||||||
|
args.pos_args.into_iter().map(TyParam::Value).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ValueArgs {
|
impl ValueArgs {
|
||||||
pub const fn new(pos_args: Vec<ValueObj>, kw_args: Dict<Str, ValueObj>) -> Self {
|
pub const fn new(pos_args: Vec<ValueObj>, kw_args: Dict<Str, ValueObj>) -> Self {
|
||||||
ValueArgs { pos_args, kw_args }
|
ValueArgs { pos_args, kw_args }
|
||||||
|
@ -54,7 +78,7 @@ impl ValueArgs {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BuiltinConstSubr {
|
pub struct BuiltinConstSubr {
|
||||||
name: &'static str,
|
name: Str,
|
||||||
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
sig_t: Type,
|
sig_t: Type,
|
||||||
as_type: Option<Type>,
|
as_type: Option<Type>,
|
||||||
|
@ -91,14 +115,14 @@ impl fmt::Display for BuiltinConstSubr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltinConstSubr {
|
impl BuiltinConstSubr {
|
||||||
pub const fn new(
|
pub fn new<S: Into<Str>>(
|
||||||
name: &'static str,
|
name: S,
|
||||||
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
subr: fn(ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
sig_t: Type,
|
sig_t: Type,
|
||||||
as_type: Option<Type>,
|
as_type: Option<Type>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name: name.into(),
|
||||||
subr,
|
subr,
|
||||||
sig_t,
|
sig_t,
|
||||||
as_type,
|
as_type,
|
||||||
|
@ -110,10 +134,90 @@ impl BuiltinConstSubr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ClosureData {
|
||||||
|
pub(crate) nd_params: Vec<ParamTy>,
|
||||||
|
pub(crate) d_params: Vec<ParamTy>,
|
||||||
|
pub(crate) qual_name: Str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClosureData {
|
||||||
|
pub const fn new(nd_params: Vec<ParamTy>, d_params: Vec<ParamTy>, qual_name: Str) -> Self {
|
||||||
|
Self {
|
||||||
|
nd_params,
|
||||||
|
d_params,
|
||||||
|
qual_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GenConstSubr {
|
||||||
|
name: Str,
|
||||||
|
data: ClosureData,
|
||||||
|
subr: fn(ClosureData, ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
|
sig_t: Type,
|
||||||
|
as_type: Option<Type>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for GenConstSubr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("BuiltinConstSubr")
|
||||||
|
.field("name", &self.name)
|
||||||
|
.field("sig_t", &self.sig_t)
|
||||||
|
.field("as_type", &self.as_type)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for GenConstSubr {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for GenConstSubr {}
|
||||||
|
|
||||||
|
impl std::hash::Hash for GenConstSubr {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.name.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GenConstSubr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "<const subroutine '{}'>", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenConstSubr {
|
||||||
|
pub fn new<S: Into<Str>>(
|
||||||
|
name: S,
|
||||||
|
data: ClosureData,
|
||||||
|
subr: fn(ClosureData, ValueArgs, &Context) -> EvalValueResult<ValueObj>,
|
||||||
|
sig_t: Type,
|
||||||
|
as_type: Option<Type>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
data,
|
||||||
|
subr,
|
||||||
|
sig_t,
|
||||||
|
as_type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
|
(self.subr)(self.data.clone(), args, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum ConstSubr {
|
pub enum ConstSubr {
|
||||||
User(UserConstSubr),
|
User(UserConstSubr),
|
||||||
Builtin(BuiltinConstSubr),
|
Builtin(BuiltinConstSubr),
|
||||||
|
Gen(GenConstSubr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConstSubr {
|
impl fmt::Display for ConstSubr {
|
||||||
|
@ -123,6 +227,7 @@ impl fmt::Display for ConstSubr {
|
||||||
write!(f, "<user-defined const subroutine '{}'>", subr.name)
|
write!(f, "<user-defined const subroutine '{}'>", subr.name)
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(subr) => write!(f, "{subr}"),
|
ConstSubr::Builtin(subr) => write!(f, "{subr}"),
|
||||||
|
ConstSubr::Gen(subr) => write!(f, "{subr}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,10 +237,10 @@ impl ConstSubr {
|
||||||
match self {
|
match self {
|
||||||
ConstSubr::User(user) => &user.sig_t,
|
ConstSubr::User(user) => &user.sig_t,
|
||||||
ConstSubr::Builtin(builtin) => &builtin.sig_t,
|
ConstSubr::Builtin(builtin) => &builtin.sig_t,
|
||||||
|
ConstSubr::Gen(gen) => &gen.sig_t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ConstSubr{sig_t: Int -> {Int}, ..}.as_type() == Int -> Int
|
|
||||||
pub fn as_type(&self, ctx: &Context) -> Option<Type> {
|
pub fn as_type(&self, ctx: &Context) -> Option<Type> {
|
||||||
match self {
|
match self {
|
||||||
ConstSubr::User(user) => {
|
ConstSubr::User(user) => {
|
||||||
|
@ -170,6 +275,7 @@ impl ConstSubr {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
ConstSubr::Builtin(builtin) => builtin.as_type.clone(),
|
ConstSubr::Builtin(builtin) => builtin.as_type.clone(),
|
||||||
|
ConstSubr::Gen(gen) => gen.as_type.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@ use self::constructors::subr_t;
|
||||||
|
|
||||||
pub const STR_OMIT_THRESHOLD: usize = 16;
|
pub const STR_OMIT_THRESHOLD: usize = 16;
|
||||||
pub const CONTAINER_OMIT_THRESHOLD: usize = 8;
|
pub const CONTAINER_OMIT_THRESHOLD: usize = 8;
|
||||||
|
pub const DEFAULT_PARAMS_THRESHOLD: usize = 5;
|
||||||
|
|
||||||
/// cloneのコストがあるためなるべく.ref_tを使うようにすること
|
/// cloneのコストがあるためなるべく.ref_tを使うようにすること
|
||||||
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
|
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
|
||||||
|
@ -315,6 +316,10 @@ impl LimitedDisplay for SubrType {
|
||||||
var_params.typ().limited_fmt(f, limit - 1)?;
|
var_params.typ().limited_fmt(f, limit - 1)?;
|
||||||
}
|
}
|
||||||
for (i, pt) in self.default_params.iter().enumerate() {
|
for (i, pt) in self.default_params.iter().enumerate() {
|
||||||
|
if limit.is_positive() && i >= DEFAULT_PARAMS_THRESHOLD {
|
||||||
|
write!(f, ", ...")?;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if i > 0 || !self.non_default_params.is_empty() || self.var_params.is_some() {
|
if i > 0 || !self.non_default_params.is_empty() || self.var_params.is_some() {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
@ -1712,6 +1717,7 @@ impl Type {
|
||||||
Self::Quantified(t) => t.is_procedure(),
|
Self::Quantified(t) => t.is_procedure(),
|
||||||
Self::Subr(subr) if subr.kind == SubrKind::Proc => true,
|
Self::Subr(subr) if subr.kind == SubrKind::Proc => true,
|
||||||
Self::Refinement(refine) => refine.t.is_procedure(),
|
Self::Refinement(refine) => refine.t.is_procedure(),
|
||||||
|
Self::And(lhs, rhs) => lhs.is_procedure() && rhs.is_procedure(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1814,6 +1820,7 @@ impl Type {
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_refinement(),
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_refinement(),
|
||||||
Self::Refinement(_) => true,
|
Self::Refinement(_) => true,
|
||||||
|
Self::And(l, r) => l.is_refinement() && r.is_refinement(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1855,6 +1862,7 @@ impl Type {
|
||||||
Self::Refinement(refine) => refine.t.is_method(),
|
Self::Refinement(refine) => refine.t.is_method(),
|
||||||
Self::Subr(subr) => subr.is_method(),
|
Self::Subr(subr) => subr.is_method(),
|
||||||
Self::Quantified(quant) => quant.is_method(),
|
Self::Quantified(quant) => quant.is_method(),
|
||||||
|
Self::And(l, r) => l.is_method() && r.is_method(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2266,6 +2274,11 @@ impl Type {
|
||||||
match self {
|
match self {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().intersection_types(),
|
Type::FreeVar(fv) if fv.is_linked() => fv.crack().intersection_types(),
|
||||||
Type::Refinement(refine) => refine.t.intersection_types(),
|
Type::Refinement(refine) => refine.t.intersection_types(),
|
||||||
|
Type::Quantified(tys) => tys
|
||||||
|
.intersection_types()
|
||||||
|
.into_iter()
|
||||||
|
.map(|t| t.quantify())
|
||||||
|
.collect(),
|
||||||
Type::And(t1, t2) => {
|
Type::And(t1, t2) => {
|
||||||
let mut types = t1.intersection_types();
|
let mut types = t1.intersection_types();
|
||||||
types.extend(t2.intersection_types());
|
types.extend(t2.intersection_types());
|
||||||
|
|
|
@ -375,22 +375,7 @@ impl Hash for TypeObj {
|
||||||
|
|
||||||
impl fmt::Display for TypeObj {
|
impl fmt::Display for TypeObj {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
self.limited_fmt(f, 10)
|
||||||
TypeObj::Builtin { t, .. } => {
|
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
write!(f, "<type {t}>")
|
|
||||||
} else {
|
|
||||||
write!(f, "{t}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeObj::Generated(t) => {
|
|
||||||
if cfg!(feature = "debug") {
|
|
||||||
write!(f, "<user type {t}>")
|
|
||||||
} else {
|
|
||||||
write!(f, "{t}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +386,7 @@ impl LimitedDisplay for TypeObj {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
write!(f, "<type ")?;
|
write!(f, "<type ")?;
|
||||||
t.limited_fmt(f, limit - 1)?;
|
t.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "{t}>")
|
write!(f, ">")
|
||||||
} else {
|
} else {
|
||||||
t.limited_fmt(f, limit - 1)
|
t.limited_fmt(f, limit - 1)
|
||||||
}
|
}
|
||||||
|
@ -410,7 +395,7 @@ impl LimitedDisplay for TypeObj {
|
||||||
if cfg!(feature = "debug") {
|
if cfg!(feature = "debug") {
|
||||||
write!(f, "<user type ")?;
|
write!(f, "<user type ")?;
|
||||||
t.limited_fmt(f, limit - 1)?;
|
t.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "{t}>")
|
write!(f, ">")
|
||||||
} else {
|
} else {
|
||||||
t.limited_fmt(f, limit - 1)
|
t.limited_fmt(f, limit - 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,24 @@ impl VarInfo {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn d_parameter(t: Type, def_loc: AbsLocation, namespace: Str) -> Self {
|
||||||
|
let kind = VarKind::Parameter {
|
||||||
|
def_id: DefId(0),
|
||||||
|
var: false,
|
||||||
|
default: DefaultInfo::WithDefault,
|
||||||
|
};
|
||||||
|
Self::new(
|
||||||
|
t,
|
||||||
|
Immutable,
|
||||||
|
Visibility::private(namespace),
|
||||||
|
kind,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
def_loc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn instance_attr(field: Field, t: Type, impl_of: Option<Type>, namespace: Str) -> Self {
|
pub fn instance_attr(field: Field, t: Type, impl_of: Option<Type>, namespace: Str) -> Self {
|
||||||
let muty = if field.is_const() {
|
let muty = if field.is_const() {
|
||||||
Mutability::Const
|
Mutability::Const
|
||||||
|
|
|
@ -4159,6 +4159,13 @@ impl Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn t_spec_op_mut(&mut self) -> Option<&mut TypeSpecWithOp> {
|
||||||
|
match self {
|
||||||
|
Self::Var(v) => v.t_spec.as_mut(),
|
||||||
|
Self::Subr(c) => c.return_t_spec.as_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_const(&self) -> bool {
|
pub fn is_const(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Var(var) => var.is_const(),
|
Self::Var(var) => var.is_const(),
|
||||||
|
|
|
@ -261,16 +261,11 @@ impl Desugarer {
|
||||||
for chunk in def.body.block.into_iter() {
|
for chunk in def.body.block.into_iter() {
|
||||||
chunks.push(desugar(chunk));
|
chunks.push(desugar(chunk));
|
||||||
}
|
}
|
||||||
if let Signature::Subr(mut subr) = def.sig {
|
if let Some(t_op) = def.sig.t_spec_op_mut() {
|
||||||
let mut defaults = vec![];
|
*t_op.t_spec_as_expr = desugar(*t_op.t_spec_as_expr.clone());
|
||||||
for default in subr.params.defaults.into_iter() {
|
|
||||||
let default_val = desugar(default.default_val);
|
|
||||||
defaults.push(DefaultParamSignature {
|
|
||||||
default_val,
|
|
||||||
..default
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
subr.params.defaults = defaults;
|
if let Signature::Subr(mut subr) = def.sig {
|
||||||
|
subr.params = Self::perform_desugar_params(desugar, subr.params);
|
||||||
def.sig = Signature::Subr(subr);
|
def.sig = Signature::Subr(subr);
|
||||||
}
|
}
|
||||||
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
|
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
|
||||||
|
@ -304,15 +299,10 @@ impl Desugarer {
|
||||||
for chunk in lambda.body.into_iter() {
|
for chunk in lambda.body.into_iter() {
|
||||||
chunks.push(desugar(chunk));
|
chunks.push(desugar(chunk));
|
||||||
}
|
}
|
||||||
let mut defaults = vec![];
|
if let Some(t_op) = &mut lambda.sig.return_t_spec {
|
||||||
for default in lambda.sig.params.defaults.into_iter() {
|
*t_op.t_spec_as_expr = desugar(*t_op.t_spec_as_expr.clone());
|
||||||
let default_val = desugar(default.default_val);
|
|
||||||
defaults.push(DefaultParamSignature {
|
|
||||||
default_val,
|
|
||||||
..default
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
lambda.sig.params.defaults = defaults;
|
lambda.sig.params = Self::perform_desugar_params(desugar, lambda.sig.params);
|
||||||
let body = Block::new(chunks);
|
let body = Block::new(chunks);
|
||||||
Expr::Lambda(Lambda::new(lambda.sig, lambda.op, body, lambda.id))
|
Expr::Lambda(Lambda::new(lambda.sig, lambda.op, body, lambda.id))
|
||||||
}
|
}
|
||||||
|
@ -370,6 +360,36 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn perform_desugar_params(mut desugar: impl FnMut(Expr) -> Expr, mut params: Params) -> Params {
|
||||||
|
let mut non_defaults = vec![];
|
||||||
|
for mut non_default in params.non_defaults.into_iter() {
|
||||||
|
non_default.t_spec = non_default.t_spec.map(|t_spec| {
|
||||||
|
TypeSpecWithOp::new(t_spec.op, t_spec.t_spec, desugar(*t_spec.t_spec_as_expr))
|
||||||
|
});
|
||||||
|
non_defaults.push(non_default);
|
||||||
|
}
|
||||||
|
params.var_params = params.var_params.map(|mut var_params| {
|
||||||
|
var_params.t_spec = var_params.t_spec.map(|t_spec| {
|
||||||
|
TypeSpecWithOp::new(t_spec.op, t_spec.t_spec, desugar(*t_spec.t_spec_as_expr))
|
||||||
|
});
|
||||||
|
var_params
|
||||||
|
});
|
||||||
|
let mut defaults = vec![];
|
||||||
|
for mut default in params.defaults.into_iter() {
|
||||||
|
let default_val = desugar(default.default_val);
|
||||||
|
default.sig.t_spec = default.sig.t_spec.map(|t_spec| {
|
||||||
|
TypeSpecWithOp::new(t_spec.op, t_spec.t_spec, desugar(*t_spec.t_spec_as_expr))
|
||||||
|
});
|
||||||
|
defaults.push(DefaultParamSignature {
|
||||||
|
default_val,
|
||||||
|
..default
|
||||||
|
});
|
||||||
|
}
|
||||||
|
params.non_defaults = non_defaults;
|
||||||
|
params.defaults = defaults;
|
||||||
|
params
|
||||||
|
}
|
||||||
|
|
||||||
/// `fib 0 = 0; fib 1 = 1; fib n = fib(n-1) + fib(n-2)`
|
/// `fib 0 = 0; fib 1 = 1; fib n = fib(n-1) + fib(n-2)`
|
||||||
/// -> `fib n = match n, (0 -> 0), (1 -> 1), n -> fib(n-1) + fib(n-2)`
|
/// -> `fib n = match n, (0 -> 0), (1 -> 1), n -> fib(n-1) + fib(n-2)`
|
||||||
fn desugar_multiple_pattern_def(&self, module: Module) -> Module {
|
fn desugar_multiple_pattern_def(&self, module: Module) -> Module {
|
||||||
|
@ -856,7 +876,7 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn desugar_shortened_record_inner(record: MixedRecord) -> NormalRecord {
|
pub fn desugar_shortened_record_inner(record: MixedRecord) -> NormalRecord {
|
||||||
let attrs = record
|
let attrs = record
|
||||||
.attrs
|
.attrs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
12
tests/should_err/array_member.er
Normal file
12
tests/should_err/array_member.er
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
C = Class { .a = Array(Int) }
|
||||||
|
_ = C.new { .a = [1] } # OK
|
||||||
|
_ = C.new { .a = ["a"] } # ERR
|
||||||
|
|
||||||
|
D = Class { .a = Array(Int, 1) }
|
||||||
|
_ = D.new { .a = [1] } # OK
|
||||||
|
d = D.new { .a = [1, 2] } # OK
|
||||||
|
assert d.a[0] == "a" # ERR
|
||||||
|
|
||||||
|
E = Class { .a = Array(Int, 2) }
|
||||||
|
_ = E.new { .a = [1, 2] } # OK
|
||||||
|
_ = E.new { .a = [1] } # ERR
|
3
tests/should_ok/array_member.er
Normal file
3
tests/should_ok/array_member.er
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
D = Class { .a = Array(Int, 1) }
|
||||||
|
d = D.new { .a = [1] }
|
||||||
|
assert d.a[0] == 1
|
11
tests/should_ok/index.er
Normal file
11
tests/should_ok/index.er
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
a = [1, 2, 3]
|
||||||
|
assert a[0] == 1
|
||||||
|
assert a[1..2] == [2, 3]
|
||||||
|
|
||||||
|
s = "abcd"
|
||||||
|
assert s[0] == "a"
|
||||||
|
assert s[1..2] == "bc"
|
||||||
|
|
||||||
|
b = bytes("abcd", "utf-8")
|
||||||
|
assert b[0] == 97
|
||||||
|
assert b[1..2] == bytes("bc", "utf-8")
|
|
@ -17,6 +17,11 @@ fn exec_array() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/array.er", 0)
|
expect_success("tests/should_ok/array.er", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_array_member() -> Result<(), ()> {
|
||||||
|
expect_success("tests/should_ok/array_member.er", 0)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_class() -> Result<(), ()> {
|
fn exec_class() -> Result<(), ()> {
|
||||||
expect_success("examples/class.er", 0)
|
expect_success("examples/class.er", 0)
|
||||||
|
@ -118,6 +123,11 @@ fn exec_import_cyclic() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/cyclic/import.er", 0)
|
expect_success("tests/should_ok/cyclic/import.er", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_index() -> Result<(), ()> {
|
||||||
|
expect_success("tests/should_ok/index.er", 0)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_inherit() -> Result<(), ()> {
|
fn exec_inherit() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/inherit.er", 0)
|
expect_success("tests/should_ok/inherit.er", 0)
|
||||||
|
@ -308,6 +318,11 @@ fn exec_array_err() -> Result<(), ()> {
|
||||||
expect_failure("examples/array.er", 0, 1)
|
expect_failure("examples/array.er", 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_array_member_err() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/array_member.er", 0, 3)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_as() -> Result<(), ()> {
|
fn exec_as() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/as.er", 0, 6)
|
expect_failure("tests/should_err/as.er", 0, 6)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue