mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
Organize crates
This commit is contained in:
parent
6ddef21fec
commit
f9d91aa38e
71 changed files with 6 additions and 14 deletions
18
compiler/erg_compiler/.gitignore
vendored
Normal file
18
compiler/erg_compiler/.gitignore
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
*.pyc
|
||||
/.vscode/
|
||||
/.VSCodeCounter/
|
||||
/.vs/
|
||||
/.DS_Store
|
||||
/*/.DS_Store
|
||||
/.idea/
|
||||
/timeit.dat
|
26
compiler/erg_compiler/Cargo.toml
Normal file
26
compiler/erg_compiler/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "erg_compiler"
|
||||
version = "0.2.0"
|
||||
description = "Centimetre: the Erg compiler"
|
||||
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler"
|
||||
documentation = "https://docs.rs/erg_compiler"
|
||||
homepage = "https://erg-lang.github.io/"
|
||||
|
||||
[features]
|
||||
# when "debug" feature is turned on, that of parser will also be turned on.
|
||||
debug = [ "erg_common/debug", "erg_parser/debug" ]
|
||||
japanese = [ "erg_common/japanese", "erg_parser/japanese" ]
|
||||
|
||||
[dependencies]
|
||||
erg_common = { version = "0.1.4", path = "../erg_common" }
|
||||
erg_parser = { version = "0.1.1", path = "../erg_parser" }
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "cm"
|
||||
path = "main.rs"
|
3
compiler/erg_compiler/README.md
Normal file
3
compiler/erg_compiler/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# The Erg compiler (codename: Centimetre)
|
||||
|
||||
The overall structure is described in detail in [architecture.md](../../doc/JA/compiler/architecture.md).
|
1202
compiler/erg_compiler/codegen.rs
Normal file
1202
compiler/erg_compiler/codegen.rs
Normal file
File diff suppressed because it is too large
Load diff
148
compiler/erg_compiler/compile.rs
Normal file
148
compiler/erg_compiler/compile.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
//! defines `Compiler`.
|
||||
//!
|
||||
//! コンパイラーを定義する
|
||||
use std::path::Path;
|
||||
|
||||
use erg_common::Str;
|
||||
use erg_common::{log};
|
||||
use erg_common::codeobj::{CodeObj, CodeObjFlags};
|
||||
use erg_common::color::{GREEN, RESET};
|
||||
use erg_common::config::{Input, ErgConfig, SEMVER, BUILD_INFO};
|
||||
use erg_common::error::MultiErrorDisplay;
|
||||
use erg_common::traits::{Runnable, Stream};
|
||||
|
||||
use erg_parser::ParserRunner;
|
||||
|
||||
use crate::codegen::CodeGenerator;
|
||||
use crate::effectcheck::SideEffectChecker;
|
||||
use crate::error::{TyCheckErrors, CompileError, CompileErrors};
|
||||
use crate::lower::ASTLowerer;
|
||||
use crate::ownercheck::OwnershipChecker;
|
||||
|
||||
/// * registered as global -> Global
|
||||
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
||||
/// * defined and called in the toplevel scope -> Local
|
||||
/// * not defined in the toplevel and called in the inner scope -> Deref
|
||||
/// * defined and called in the current scope (except the toplevel) -> Fast
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum StoreLoadKind {
|
||||
Local,
|
||||
LocalConst,
|
||||
Global,
|
||||
GlobalConst,
|
||||
Deref,
|
||||
DerefConst,
|
||||
Fast,
|
||||
FastConst,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Name {
|
||||
pub kind: StoreLoadKind,
|
||||
pub idx: usize,
|
||||
}
|
||||
|
||||
impl Name {
|
||||
pub const fn new(kind: StoreLoadKind, idx: usize) -> Self { Self{ kind, idx } }
|
||||
|
||||
pub const fn local(idx: usize) -> Self { Self{ kind: StoreLoadKind::Local, idx } }
|
||||
pub const fn global(idx: usize) -> Self { Self{ kind: StoreLoadKind::Global, idx } }
|
||||
pub const fn deref(idx: usize) -> Self { Self{ kind: StoreLoadKind::Deref, idx } }
|
||||
pub const fn fast(idx: usize) -> Self { Self{ kind: StoreLoadKind::Fast, idx } }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AccessKind {
|
||||
Name,
|
||||
Attr,
|
||||
Method,
|
||||
}
|
||||
|
||||
impl AccessKind {
|
||||
pub const fn is_local(&self) -> bool { matches!(self, Self::Name) }
|
||||
pub const fn is_attr(&self) -> bool { matches!(self, Self::Attr) }
|
||||
pub const fn is_method(&self) -> bool { matches!(self, Self::Method) }
|
||||
}
|
||||
|
||||
/// Generates a `CodeObj` from an `AST`.
|
||||
/// The input AST is not typed, so it's typed by `ASTLowerer` according to the cfg.opt_level.
|
||||
#[derive(Debug)]
|
||||
pub struct Compiler {
|
||||
cfg: ErgConfig,
|
||||
lowerer: ASTLowerer,
|
||||
code_generator: CodeGenerator,
|
||||
}
|
||||
|
||||
impl Runnable for Compiler {
|
||||
type Err = CompileError;
|
||||
type Errs = CompileErrors;
|
||||
|
||||
fn new(cfg: ErgConfig) -> Self {
|
||||
Self {
|
||||
code_generator: CodeGenerator::new(cfg.copy()),
|
||||
lowerer: ASTLowerer::new(),
|
||||
cfg,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn input(&self) -> &Input { &self.cfg.input }
|
||||
|
||||
#[inline]
|
||||
fn start_message(&self) -> String { format!("Erg compiler {} {}\n", SEMVER, &*BUILD_INFO) }
|
||||
|
||||
#[inline]
|
||||
fn finish(&mut self) {}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.code_generator.clear();
|
||||
}
|
||||
|
||||
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
|
||||
let codeobj = self.compile(src, "eval")?;
|
||||
Ok(codeobj.code_info())
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler {
|
||||
fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
|
||||
errs.into_iter().map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by)).collect::<Vec<_>>().into()
|
||||
}
|
||||
|
||||
pub fn compile_and_dump_as_pyc<P: AsRef<Path>>(&mut self, src: Str, path: P) -> Result<(), CompileErrors> {
|
||||
let code = self.compile(src, "exec")?;
|
||||
code.dump_as_pyc(path, self.cfg.python_ver).expect("failed to dump a .pyc file");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile(&mut self, src: Str, mode: &str) -> Result<CodeObj, CompileErrors> {
|
||||
log!("{GREEN}[DEBUG] the compiling process has started.{RESET}");
|
||||
let mut dynamic = true;
|
||||
let mut parser = ParserRunner::new(self.cfg.copy());
|
||||
let ast = parser.parse_from_str(src)?;
|
||||
if ast.is_empty() {
|
||||
return Ok(CodeObj::empty(vec![], Str::rc(self.input().enclosed_name()), "<module>", 1))
|
||||
}
|
||||
let (hir, warns) = self.lowerer.lower(ast, mode).map_err(|errs| self.convert(errs))?;
|
||||
if warns.is_empty() { dynamic = false; }
|
||||
if self.cfg.verbose >= 2 {
|
||||
let warns = self.convert(warns);
|
||||
warns.fmt_all_stderr();
|
||||
}
|
||||
let effect_checker = SideEffectChecker::new();
|
||||
let hir = effect_checker.check(hir).map_err(|errs| self.convert(errs))?;
|
||||
let ownership_checker = OwnershipChecker::new();
|
||||
let hir = ownership_checker.check(hir).map_err(|errs| self.convert(errs))?;
|
||||
let mut codeobj = self.code_generator.codegen(hir);
|
||||
if dynamic {
|
||||
codeobj.flags += CodeObjFlags::EvmDynamic as u32;
|
||||
}
|
||||
log!("{GREEN}code object:\n{}", codeobj.code_info());
|
||||
log!("[DEBUG] the compiling process has completed, found errors: {}{RESET}", self.code_generator.errs.len());
|
||||
if self.code_generator.errs.is_empty() {
|
||||
Ok(codeobj)
|
||||
} else {
|
||||
Err(self.code_generator.errs.flush())
|
||||
}
|
||||
}
|
||||
}
|
2746
compiler/erg_compiler/context.rs
Normal file
2746
compiler/erg_compiler/context.rs
Normal file
File diff suppressed because it is too large
Load diff
187
compiler/erg_compiler/effectcheck.rs
Normal file
187
compiler/erg_compiler/effectcheck.rs
Normal file
|
@ -0,0 +1,187 @@
|
|||
//! implements SideEffectChecker
|
||||
//! SideEffectCheckerを実装
|
||||
//! 関数や不変型に副作用がないかチェックする
|
||||
|
||||
use erg_common::Str;
|
||||
use erg_common::color::{GREEN, RESET};
|
||||
use erg_common::log;
|
||||
use erg_common::traits::Stream;
|
||||
|
||||
use crate::error::{EffectError, EffectErrors, EffectResult};
|
||||
use crate::hir::{HIR, Expr, Def, Accessor, Signature};
|
||||
use crate::varinfo::Visibility;
|
||||
use Visibility::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SideEffectChecker {
|
||||
path_stack: Vec<(Str, Visibility)>,
|
||||
errs: EffectErrors,
|
||||
}
|
||||
|
||||
impl SideEffectChecker {
|
||||
pub fn new() -> Self { Self { path_stack: vec![], errs: EffectErrors::empty() } }
|
||||
|
||||
fn full_path(&self) -> String {
|
||||
self.path_stack.iter().fold(String::new(), |acc, (path, vis)| {
|
||||
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn check(mut self, hir: HIR) -> EffectResult<HIR> {
|
||||
self.path_stack.push((hir.name.clone(), Private));
|
||||
log!("{GREEN}[DEBUG] the side-effect checking process has started.{RESET}");
|
||||
// トップレベルでは副作用があっても問題なく、純粋性違反がないかのみチェックする
|
||||
for expr in hir.module.iter() {
|
||||
match expr {
|
||||
Expr::Def(def) => { self.check_def(def, true); },
|
||||
Expr::Call(call) => {
|
||||
for parg in call.args.pos_args().iter() {
|
||||
self.check_expr(&parg.expr, true);
|
||||
}
|
||||
for kwarg in call.args.kw_args().iter() {
|
||||
self.check_expr(&kwarg.expr, true);
|
||||
}
|
||||
},
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
log!("{GREEN}[DEBUG] the side-effect checking process has completed, found errors: {}{RESET}", self.errs.len());
|
||||
if self.errs.is_empty() {
|
||||
Ok(hir)
|
||||
} else {
|
||||
Err(self.errs)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_def(&mut self, def: &Def, allow_inner_effect: bool) {
|
||||
let name_and_vis = match &def.sig {
|
||||
Signature::Var(var) =>
|
||||
// TODO: visibility
|
||||
if let Some(name) = var.inspect() { (name.clone(), Private) }
|
||||
else { (Str::ever("::<instant>"), Private) },
|
||||
Signature::Subr(subr) => (subr.name.inspect().clone(), Private),
|
||||
};
|
||||
self.path_stack.push(name_and_vis);
|
||||
// TODO: support raw identifier (``)
|
||||
let is_procedural = def.sig.is_procedural();
|
||||
let is_subr = def.sig.is_subr();
|
||||
let is_const = def.sig.is_const();
|
||||
let is_type = def.body.is_type();
|
||||
match (is_procedural, is_subr) {
|
||||
(true, _) => {
|
||||
if !allow_inner_effect {
|
||||
let expr = Expr::Def(def.clone());
|
||||
self.errs.push(
|
||||
EffectError::has_effect(&expr, self.full_path())
|
||||
);
|
||||
}
|
||||
for chunk in def.body.block.iter() {
|
||||
self.check_expr(chunk, allow_inner_effect);
|
||||
}
|
||||
},
|
||||
(false, false) => {
|
||||
for chunk in def.body.block.iter() {
|
||||
self.check_expr(chunk, allow_inner_effect);
|
||||
}
|
||||
},
|
||||
(false, true) => { self.check_func(def); },
|
||||
}
|
||||
if is_const { self.check_const(def); }
|
||||
if !is_procedural && is_type { self.check_immut_type(def); }
|
||||
self.path_stack.pop();
|
||||
}
|
||||
|
||||
fn check_func(&mut self, funcdef: &Def) {
|
||||
for chunk in funcdef.body.block.iter() {
|
||||
self.check_expr(chunk, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_immut_type(&mut self, _typedef: &Def) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn check_const(&mut self, _constdef: &Def) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// check if `expr` has side-effects / purity violations.
|
||||
///
|
||||
/// returns effects, purity violations will be appended to `self.errs`.
|
||||
///
|
||||
/// causes side-effects:
|
||||
/// ```
|
||||
/// p!() // 1 side-effect
|
||||
/// p!(q!()) // 2 side-effects
|
||||
/// x =
|
||||
/// y = r!()
|
||||
/// y + 1 // 1 side-effect
|
||||
/// ```
|
||||
/// causes no side-effects:
|
||||
/// ```
|
||||
/// q! = p!
|
||||
/// y = f(p!)
|
||||
/// ```
|
||||
/// purity violation:
|
||||
/// ```
|
||||
/// for iter, i -> print! i
|
||||
/// ```
|
||||
fn check_expr(&mut self, expr: &Expr, allow_self_effect: bool) {
|
||||
match expr {
|
||||
Expr::Def(def) => { self.check_def(def, allow_self_effect); },
|
||||
// 引数がproceduralでも関数呼び出しなら副作用なし
|
||||
Expr::Call(call) => {
|
||||
if self.is_procedural(&call.obj) && !allow_self_effect {
|
||||
self.errs.push(
|
||||
EffectError::has_effect(expr, self.full_path())
|
||||
);
|
||||
}
|
||||
call.args
|
||||
.pos_args()
|
||||
.iter()
|
||||
.for_each(|parg|self.check_expr(&parg.expr, allow_self_effect));
|
||||
call.args
|
||||
.kw_args()
|
||||
.iter()
|
||||
.for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect));
|
||||
},
|
||||
Expr::UnaryOp(unary) => {
|
||||
self.check_expr(&unary.expr, allow_self_effect);
|
||||
},
|
||||
Expr::BinOp(bin) => {
|
||||
self.check_expr(&bin.lhs, allow_self_effect);
|
||||
self.check_expr(&bin.rhs, allow_self_effect);
|
||||
},
|
||||
Expr::Lambda(lambda) => {
|
||||
let is_proc = lambda.is_procedural();
|
||||
if is_proc {
|
||||
self.path_stack.push((Str::ever("<lambda!>"), Private));
|
||||
} else {
|
||||
self.path_stack.push((Str::ever("<lambda>"), Private));
|
||||
}
|
||||
if !allow_self_effect && is_proc {
|
||||
self.errs.push(EffectError::has_effect(expr, self.full_path()));
|
||||
}
|
||||
lambda.body
|
||||
.iter()
|
||||
.for_each(|chunk| self.check_expr(chunk, allow_self_effect && is_proc));
|
||||
self.path_stack.pop();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
fn is_procedural(&self, expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Lambda(lambda) => lambda.is_procedural(),
|
||||
// 引数がproceduralでも関数呼び出しなら副作用なし
|
||||
Expr::Call(call) => self.is_procedural(&call.obj),
|
||||
Expr::Accessor(Accessor::Local(local)) => local.name.is_procedural(),
|
||||
// procedural: x.y! (e.g. Array.sample!)
|
||||
// !procedural: !x.y
|
||||
Expr::Accessor(Accessor::Attr(attr)) => attr.name.is_procedural(),
|
||||
Expr::Accessor(_) => todo!(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
501
compiler/erg_compiler/error.rs
Normal file
501
compiler/erg_compiler/error.rs
Normal file
|
@ -0,0 +1,501 @@
|
|||
use std::fmt::Display;
|
||||
use std::ops::Add;
|
||||
|
||||
use erg_common::color::{GREEN, RED, YELLOW, RESET};
|
||||
use erg_common::config::Input;
|
||||
use erg_common::error::{ErrorCore, ErrorKind::*, ErrorDisplay, MultiErrorDisplay, Location};
|
||||
use erg_common::traits::{Stream, Locational};
|
||||
use erg_common::ty::{Type, Predicate};
|
||||
use erg_common::{Str, fmt_iter};
|
||||
use erg_common::{impl_stream_for_wrapper, switch_lang};
|
||||
|
||||
use erg_parser::error::{ParserRunnerError, ParserRunnerErrors};
|
||||
|
||||
use crate::hir::Expr;
|
||||
|
||||
/// dname is for "double under name"
|
||||
pub fn binop_to_dname(op: &str) -> &str {
|
||||
match op {
|
||||
"+" => "__add__",
|
||||
"-" => "__sub__",
|
||||
"*" => "__mul__",
|
||||
"/" => "__div__",
|
||||
"**" => "__pow__",
|
||||
"%" => "__mod__",
|
||||
".." => "__rng__",
|
||||
"<.." => "__lorng__",
|
||||
"..<" => "__rorng__",
|
||||
"<..<" => "__orng__",
|
||||
"and" => "__and__",
|
||||
"or" => "__or__",
|
||||
"in" => "__in__",
|
||||
"contains" => "__contains__",
|
||||
"subof" => "__subof__",
|
||||
"supof" => "__supof__",
|
||||
"is" => "__is__",
|
||||
"isnot" => "__isnot__",
|
||||
"==" => "__eq__",
|
||||
"!=" => "__ne__",
|
||||
"<" => "__lt__",
|
||||
"<=" => "__le__",
|
||||
">" => "__gt__",
|
||||
">=" => "__ge__",
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unaryop_to_dname(op: &str) -> &str {
|
||||
match op {
|
||||
"+" => "__pos__",
|
||||
"-" => "__neg__",
|
||||
"~" => "__invert__",
|
||||
"!" => "__mutate__",
|
||||
"..." => "__spread__",
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readable_name(name: &str) -> &str {
|
||||
match name {
|
||||
"__add__" => "`+`",
|
||||
"__sub__" => "`-`",
|
||||
"__mul__" => "`*`",
|
||||
"__div__" => "`/`",
|
||||
"__pow__" => "`**`",
|
||||
"__mod__" => "`%`",
|
||||
"__rng__" => "`..`",
|
||||
"__lrng__" => "`<..`",
|
||||
"__rrng__" => "`..<`",
|
||||
"__lrrng__" => "`<..<`",
|
||||
"__and__" => "`and`",
|
||||
"__or__" => "`or`",
|
||||
"__in__" => "`in`",
|
||||
"__contains__" => "`contains`",
|
||||
"__subof__" => "`subof`",
|
||||
"__supof__" => "`supof`",
|
||||
"__is__" => "`is`",
|
||||
"__isnot__" => "`isnot`",
|
||||
"__eq__" => "`==`",
|
||||
"__ne__" => "`!=`",
|
||||
"__lt__" => "`<`",
|
||||
"__le__" => "`<=`",
|
||||
"__gt__" => "`>`",
|
||||
"__ge__" => "`>=`",
|
||||
"__pos__" => "`+`",
|
||||
"__neg__" => "`-`",
|
||||
"__invert__" => "`~`",
|
||||
"__mutate__" => "`!`",
|
||||
"__spread__" => "`...`",
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompileError {
|
||||
pub core: ErrorCore,
|
||||
pub input: Input,
|
||||
pub caused_by: Str,
|
||||
}
|
||||
|
||||
impl From<ParserRunnerError> for CompileError {
|
||||
fn from(err: ParserRunnerError) -> Self {
|
||||
Self { core: err.core, input: err.input, caused_by: "".into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorDisplay for CompileError {
|
||||
fn core(&self) -> &ErrorCore { &self.core }
|
||||
fn input(&self) -> &Input { &self.input }
|
||||
fn caused_by(&self) -> &str { &self.caused_by }
|
||||
fn ref_inner(&self) -> Option<&Box<Self>> { None }
|
||||
}
|
||||
|
||||
impl CompileError {
|
||||
pub const fn new(core: ErrorCore, input: Input, caused_by: Str) -> Self { Self{ core, input, caused_by } }
|
||||
|
||||
pub fn compiler_bug(errno: usize, input: Input, loc: Location, fn_name: &str, line: u32) -> Self {
|
||||
Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!(
|
||||
format!("this is a bug of the Erg compiler, please report it to https://github.com/...\ncaused from: {fn_name}:{line}"),
|
||||
format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/...)\n{fn_name}:{line}より発生")
|
||||
), None), input, "".into())
|
||||
}
|
||||
|
||||
pub fn stack_bug(input: Input, loc: Location, stack_len: u32, block_id: usize, fn_name: &str) -> Self {
|
||||
Self::new(ErrorCore::new(0, CompilerSystemError, loc, switch_lang!(
|
||||
format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\
|
||||
this is a bug of the Erg compiler, please report it (https://github.com/...)\n\
|
||||
caused from: {fn_name}"),
|
||||
format!("スタックの要素数が異常です (要素数: {stack_len}, ブロックID: {block_id})\n\
|
||||
これはコンパイラのバグです、開発者に報告して下さい (https://github.com/...)\n\
|
||||
{fn_name}より発生")
|
||||
), None), input, "".into())
|
||||
}
|
||||
|
||||
pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: Str) -> Self {
|
||||
Self::new(ErrorCore::new(0, FeatureError, loc, switch_lang!(
|
||||
format!("this feature({name}) is not implemented yet"),
|
||||
format!("この機能({name})はまだ正式に提供されていません")
|
||||
), None), input, caused_by)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TyCheckError {
|
||||
pub core: ErrorCore,
|
||||
pub caused_by: Str,
|
||||
}
|
||||
|
||||
impl TyCheckError {
|
||||
pub const fn new(core: ErrorCore, caused_by: Str) -> Self { Self{ core, caused_by } }
|
||||
|
||||
pub fn unreachable(fn_name: &str, line: u32) -> Self { Self::new(ErrorCore::unreachable(fn_name, line), "".into()) }
|
||||
|
||||
pub fn checker_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
|
||||
Self::new(ErrorCore::new(errno, CompilerSystemError, loc, switch_lang!(
|
||||
format!("this is a bug of the Erg compiler, please report it to https://github.com/...\ncaused from: {fn_name}:{line}"),
|
||||
format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/...)\n{fn_name}:{line}より発生")
|
||||
), None), "".into())
|
||||
}
|
||||
|
||||
pub fn feature_error(loc: Location, name: &str, caused_by: Str) -> Self {
|
||||
Self::new(ErrorCore::new(0, FeatureError, loc, switch_lang!(
|
||||
format!("this feature({name}) is not implemented yet"),
|
||||
format!("この機能({name})はまだ正式に提供されていません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn syntax_error<S: Into<Str>>(errno: usize, loc: Location, caused_by: Str, desc: S, hint: Option<Str>) -> Self {
|
||||
Self::new(ErrorCore::new(errno, SyntaxError, loc, desc, hint), caused_by)
|
||||
}
|
||||
|
||||
pub fn duplicate_decl_error(loc: Location, caused_by: Str, name: &str) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, NameError, loc,
|
||||
switch_lang!(
|
||||
format!("{name} is already declared"),
|
||||
format!("{name}は既に宣言されています")
|
||||
), Option::<Str>::None),
|
||||
caused_by
|
||||
)
|
||||
}
|
||||
|
||||
pub fn violate_decl_error(loc: Location, caused_by: Str, name: &str, spec_t: &Type, found_t: &Type) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc,
|
||||
switch_lang!(
|
||||
format!("{name} was declared as {GREEN}{spec_t}{RESET}, but an {RED}{found_t}{RESET} object is assigned"),
|
||||
format!("{name}は{GREEN}{spec_t}{RESET}型として宣言されましたが、{RED}{found_t}{RESET}型のオブジェクトが代入されています")
|
||||
), Option::<Str>::None),
|
||||
caused_by
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_type_spec_error(loc: Location, caused_by: Str, name: &str) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc,
|
||||
switch_lang!(
|
||||
format!("the type of {name} is not specified"),
|
||||
format!("{name}の型が指定されていません")
|
||||
), None),
|
||||
caused_by
|
||||
)
|
||||
}
|
||||
|
||||
pub fn no_var_error(loc: Location, caused_by: Str, name: &str, similar_name: Option<&Str>) -> Self {
|
||||
let name = readable_name(name);
|
||||
let hint = similar_name.map(|n| {
|
||||
let n = readable_name(n);
|
||||
switch_lang!(
|
||||
format!("exists a similar name variable: {n}"),
|
||||
format!("似た名前の変数があります: {n}")
|
||||
).into()
|
||||
});
|
||||
Self::new(ErrorCore::new(0, NameError, loc, switch_lang!(
|
||||
format!("{RED}{name}{RESET} is not defined"),
|
||||
format!("{RED}{name}{RESET}という変数は定義されていません")
|
||||
), hint), caused_by)
|
||||
}
|
||||
|
||||
pub fn no_attr_error(
|
||||
loc: Location,
|
||||
caused_by: Str,
|
||||
obj_t: &Type,
|
||||
name: &str,
|
||||
similar_name: Option<&Str>,
|
||||
) -> Self {
|
||||
let hint = similar_name.map(|n| {
|
||||
let n = readable_name(n);
|
||||
switch_lang!(
|
||||
format!("has a similar name attribute: {n}"),
|
||||
format!("似た名前の属性があります: {n}")
|
||||
).into()
|
||||
});
|
||||
Self::new(ErrorCore::new( 0, AttributeError, loc, switch_lang!(
|
||||
format!("{obj_t} object has no attribute {RED}{name}{RESET}"),
|
||||
format!("{obj_t}型オブジェクトに{RED}{name}{RESET}という属性はありません")
|
||||
), hint),
|
||||
caused_by,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn callable_impl_error<'a, C: Locational + Display>(callee: &C, param_ts: impl Iterator<Item=&'a Type>, caused_by: Str) -> Self {
|
||||
let param_ts = fmt_iter(param_ts);
|
||||
Self::new(ErrorCore::new(0, NotImplementedError, callee.loc(), switch_lang!(
|
||||
format!("{callee} is not a Callable object that takes {param_ts} as an argument"),
|
||||
format!("{callee}は{param_ts}を引数に取る呼び出し可能オブジェクトではありません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn type_mismatch_error(
|
||||
loc: Location,
|
||||
caused_by: Str,
|
||||
name: &str,
|
||||
expect: &Type,
|
||||
found: &Type,
|
||||
) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
|
||||
format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn return_type_error(
|
||||
loc: Location,
|
||||
caused_by: Str,
|
||||
name: &str,
|
||||
expect: &Type,
|
||||
found: &Type,
|
||||
) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("the return type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
|
||||
format!("{name}の戻り値の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, NameError, loc, switch_lang!(
|
||||
format!("{name}: {t} is not initialized"),
|
||||
format!("{name}: {t}は初期化されていません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn argument_error(loc: Location, caused_by: Str, expect: usize, found: usize) -> Self {
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("the number of positional arguments is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
|
||||
format!("ポジショナル引数の数が違います。\n予期した個数: {GREEN}{expect}{RESET}\n与えられた個数: {RED}{found}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn match_error(loc: Location, caused_by: Str, expr_t: &Type) -> Self {
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("not all patterns of type {expr_t} are covered"),
|
||||
format!("{expr_t}型の全パターンを網羅していません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn infer_error(loc: Location, caused_by: Str, expr: &str) -> Self {
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("failed to infer the type of {expr}"),
|
||||
format!("{expr}の型が推論できません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, AssignError, loc, switch_lang!(
|
||||
format!("cannot assign twice to the immutable variable {name}"),
|
||||
format!("定数{name}には再代入できません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn too_many_args_error(
|
||||
loc: Location,
|
||||
callee_name: &str,
|
||||
caused_by: Str,
|
||||
params_len: usize,
|
||||
pos_args_len: usize,
|
||||
kw_args_len: usize
|
||||
) -> Self {
|
||||
let name = readable_name(callee_name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("too many arguments for {name}:
|
||||
total expected params: {GREEN}{params_len}{RESET}
|
||||
passed positional args: {RED}{pos_args_len}{RESET}
|
||||
passed keyword args: {RED}{kw_args_len}{RESET}"),
|
||||
format!("{name}に渡された引数の数が多すぎます。
|
||||
必要な引数の合計数: {GREEN}{params_len}{RESET}個
|
||||
渡された引数の数: {RED}{pos_args_len}{RESET}個
|
||||
キーワード引数の数: {RED}{kw_args_len}{RESET}個")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn multiple_args_error(
|
||||
loc: Location,
|
||||
callee_name: &str,
|
||||
caused_by: Str,
|
||||
arg_name: &str,
|
||||
) -> Self {
|
||||
let name = readable_name(callee_name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("{name}'s argument {RED}{arg_name}{RESET} is passed multiple times"),
|
||||
format!("{name}の引数{RED}{arg_name}{RESET}が複数回渡されています")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn unexpected_kw_arg_error(
|
||||
loc: Location,
|
||||
callee_name: &str,
|
||||
caused_by: Str,
|
||||
param_name: &str,
|
||||
) -> Self {
|
||||
let name = readable_name(callee_name);
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("{name} got unexpected keyword argument {RED}{param_name}{RESET}"),
|
||||
format!("{name}には予期しないキーワード引数{RED}{param_name}{RESET}が渡されています")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn unused_warning(loc: Location, name: &str, caused_by: Str) -> Self {
|
||||
let name = readable_name(name);
|
||||
Self::new(ErrorCore::new(0, UnusedWarning, loc, switch_lang!(
|
||||
format!("{YELLOW}{name}{RESET} is not used"),
|
||||
format!("{YELLOW}{name}{RESET}は使用されていません")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn unification_error(lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>, caused_by: Str) -> Self {
|
||||
let loc = match (lhs_loc, rhs_loc) {
|
||||
(Some(l), Some(r)) => Location::pair(l, r),
|
||||
(Some(l), None) => l,
|
||||
(None, Some(r)) => r,
|
||||
(None, None) => Location::Unknown,
|
||||
};
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("unification failed:\nlhs: {YELLOW}{lhs_t}{RESET}\nrhs: {YELLOW}{rhs_t}{RESET}"),
|
||||
format!("型の単一化に失敗しました:\n左辺: {YELLOW}{lhs_t}{RESET}\n右辺: {YELLOW}{rhs_t}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn re_unification_error(lhs_t: &Type, rhs_t: &Type, lhs_loc: Option<Location>, rhs_loc: Option<Location>, caused_by: Str) -> Self {
|
||||
let loc = match (lhs_loc, rhs_loc) {
|
||||
(Some(l), Some(r)) => Location::pair(l, r),
|
||||
(Some(l), None) => l,
|
||||
(None, Some(r)) => r,
|
||||
(None, None) => Location::Unknown,
|
||||
};
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("re-unification failed:\nlhs: {YELLOW}{lhs_t}{RESET}\nrhs: {YELLOW}{rhs_t}{RESET}"),
|
||||
format!("型の再単一化に失敗しました:\n左辺: {YELLOW}{lhs_t}{RESET}\n右辺: {YELLOW}{rhs_t}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn subtyping_error(sub_t: &Type, sup_t: &Type, sub_loc: Option<Location>, sup_loc: Option<Location>, caused_by: Str) -> Self {
|
||||
let loc = match (sub_loc, sup_loc) {
|
||||
(Some(l), Some(r)) => Location::pair(l, r),
|
||||
(Some(l), None) => l,
|
||||
(None, Some(r)) => r,
|
||||
(None, None) => Location::Unknown,
|
||||
};
|
||||
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
|
||||
format!("subtype constraints cannot be satisfied:\nsubtype: {YELLOW}{sub_t}{RESET}\nsupertype: {YELLOW}{sup_t}{RESET}"),
|
||||
format!("部分型制約を満たせません:\nサブタイプ: {YELLOW}{sub_t}{RESET}\nスーパータイプ: {YELLOW}{sup_t}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn pred_unification_error(lhs: &Predicate, rhs: &Predicate, caused_by: Str) -> Self {
|
||||
Self::new(ErrorCore::new(0, TypeError, Location::Unknown, switch_lang!(
|
||||
format!("predicate unification failed:\nlhs: {YELLOW}{lhs}{RESET}\nrhs: {YELLOW}{rhs}{RESET}"),
|
||||
format!("述語式の単一化に失敗しました:\n左辺: {YELLOW}{lhs}{RESET}\n右辺: {YELLOW}{rhs}{RESET}")
|
||||
), None), caused_by)
|
||||
}
|
||||
|
||||
pub fn has_effect<S: Into<Str>>(expr: &Expr, caused_by: S) -> Self {
|
||||
Self::new(ErrorCore::new(0, HasEffect, expr.loc(), switch_lang!(
|
||||
format!("this expression causes a side-effect"),
|
||||
format!("この式には副作用があります")
|
||||
), None), caused_by.into())
|
||||
}
|
||||
|
||||
pub fn move_error<S: Into<Str>>(name: &str, name_loc: Location, moved_loc: Location, caused_by: S) -> Self {
|
||||
Self::new(ErrorCore::new(0, MoveError, name_loc, switch_lang!(
|
||||
format!("{RED}{name}{RESET} was moved in line {}", moved_loc.ln_begin().unwrap()),
|
||||
format!("{RED}{name}{RESET}は{}行目ですでに移動されています", moved_loc.ln_begin().unwrap())
|
||||
), None), caused_by.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TyCheckErrors(Vec<TyCheckError>);
|
||||
|
||||
impl_stream_for_wrapper!(TyCheckErrors, TyCheckError);
|
||||
|
||||
impl From<Vec<TyCheckError>> for TyCheckErrors {
|
||||
fn from(errs: Vec<TyCheckError>) -> Self { Self(errs) }
|
||||
}
|
||||
|
||||
impl Add for TyCheckErrors {
|
||||
type Output = Self;
|
||||
fn add(self, other: Self) -> Self {
|
||||
Self(self.0.into_iter().chain(other.0.into_iter()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TyCheckError> for TyCheckErrors {
|
||||
fn from(err: TyCheckError) -> Self { Self(vec![err]) }
|
||||
}
|
||||
|
||||
pub type TyCheckResult<T> = Result<T, TyCheckError>;
|
||||
pub type TyCheckWarning = TyCheckError;
|
||||
pub type TyCheckWarnings = TyCheckErrors;
|
||||
|
||||
pub type EvalError = TyCheckError;
|
||||
pub type EvalErrors = TyCheckErrors;
|
||||
pub type EvalResult<T> = TyCheckResult<T>;
|
||||
|
||||
pub type EffectError = TyCheckError;
|
||||
pub type EffectErrors = TyCheckErrors;
|
||||
pub type EffectResult<T> = Result<T, EffectErrors>;
|
||||
|
||||
pub type OwnershipError = TyCheckError;
|
||||
pub type OwnershipErrors = TyCheckErrors;
|
||||
pub type OwnershipResult<T> = Result<T, OwnershipErrors>;
|
||||
|
||||
pub type LowerError = TyCheckError;
|
||||
pub type LowerWarning = LowerError;
|
||||
pub type LowerErrors = TyCheckErrors;
|
||||
pub type LowerWarnings = LowerErrors;
|
||||
pub type LowerResult<T> = TyCheckResult<T>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CompileErrors(Vec<CompileError>);
|
||||
|
||||
impl_stream_for_wrapper!(CompileErrors, CompileError);
|
||||
|
||||
impl From<ParserRunnerErrors> for CompileErrors {
|
||||
fn from(err: ParserRunnerErrors) -> Self {
|
||||
Self(err.into_iter().map(CompileError::from).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<CompileError>> for CompileErrors {
|
||||
fn from(errs: Vec<CompileError>) -> Self { Self(errs) }
|
||||
}
|
||||
|
||||
impl From<CompileError> for CompileErrors {
|
||||
fn from(err: CompileError) -> Self { Self(vec![err]) }
|
||||
}
|
||||
|
||||
impl MultiErrorDisplay<CompileError> for CompileErrors {}
|
||||
|
||||
impl CompileErrors {
|
||||
pub fn flush(&mut self) -> Self {
|
||||
Self(self.0.drain(..).collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub type CompileResult<T> = Result<T, CompileError>;
|
||||
pub type CompileWarning = CompileError;
|
||||
pub type CompileWarnings = CompileErrors;
|
461
compiler/erg_compiler/eval.rs
Normal file
461
compiler/erg_compiler/eval.rs
Normal file
|
@ -0,0 +1,461 @@
|
|||
use std::mem;
|
||||
|
||||
use erg_common::Str;
|
||||
use erg_common::{fn_name, set};
|
||||
use erg_common::value::ValueObj;
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::rccell::RcCell;
|
||||
use erg_common::set::{Set};
|
||||
use erg_common::traits::Stream;
|
||||
use erg_common::ty::{OpKind, TyParam, Type, Predicate, TyBound, ConstObj, SubrKind};
|
||||
use OpKind::*;
|
||||
|
||||
use erg_parser::ast::*;
|
||||
use erg_parser::token::Token;
|
||||
|
||||
use crate::context::{Context, TyVarContext};
|
||||
use crate::error::{EvalError, EvalResult, TyCheckResult};
|
||||
|
||||
/// SubstContext::new([?T; 0], Context(Array(T, N))) => SubstContext{ params: { T: ?T; N: 0 } }
|
||||
/// SubstContext::substitute([T; !N], Context(Array(T, N))): [?T; !0]
|
||||
#[derive(Debug)]
|
||||
struct SubstContext {
|
||||
params: Dict<Str, TyParam>,
|
||||
}
|
||||
|
||||
impl SubstContext {
|
||||
pub fn new(substituted: &Type, ty_ctx: &Context) -> Self {
|
||||
let param_names = ty_ctx.impls.iter()
|
||||
.filter(|(_, vi)| vi.kind.is_parameter())
|
||||
.map(|(name, _)| name.inspect().clone());
|
||||
let self_ = SubstContext{
|
||||
params: param_names.zip(substituted.typarams().into_iter()).collect(),
|
||||
};
|
||||
// REVIEW: 順番は保証されるか? 引数がunnamed_paramsに入る可能性は?
|
||||
self_
|
||||
}
|
||||
|
||||
fn substitute(&self, quant_t: Type, ty_ctx: &Context, level: usize) -> TyCheckResult<Type> {
|
||||
let bounds = ty_ctx.bounds();
|
||||
let tv_ctx = TyVarContext::new(level, bounds);
|
||||
let (inst, _) = Context::instantiate_t(quant_t, tv_ctx);
|
||||
for param in inst.typarams() {
|
||||
self.substitute_tp(¶m, ty_ctx)?;
|
||||
}
|
||||
Ok(inst)
|
||||
}
|
||||
|
||||
fn substitute_tp(&self, param: &TyParam, ty_ctx: &Context) -> TyCheckResult<()> {
|
||||
match param {
|
||||
TyParam::FreeVar(fv) => {
|
||||
if let Some(name) = fv.unbound_name() {
|
||||
if let Some(v) = self.params.get(&name) {
|
||||
ty_ctx.unify_tp(param, v, None, false)?;
|
||||
}
|
||||
} else {
|
||||
if fv.is_unbound() { panic!() }
|
||||
}
|
||||
}
|
||||
TyParam::BinOp{ lhs, rhs, .. } => {
|
||||
self.substitute_tp(lhs, ty_ctx)?;
|
||||
self.substitute_tp(rhs, ty_ctx)?;
|
||||
}
|
||||
TyParam::UnaryOp{ val, .. } => {
|
||||
self.substitute_tp(val, ty_ctx)?;
|
||||
}
|
||||
TyParam::Array(args)
|
||||
| TyParam::Tuple(args)
|
||||
| TyParam::App{ args, .. }
|
||||
| TyParam::PolyQVar{ args, .. } => {
|
||||
for arg in args.iter() {
|
||||
self.substitute_tp(arg, ty_ctx)?;
|
||||
}
|
||||
}
|
||||
TyParam::Type(t) => { self.substitute_t(t, ty_ctx)?; },
|
||||
TyParam::MonoProj{ obj, attr } => todo!("{obj}.{attr}"),
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn substitute_t(&self, t: &Type, ty_ctx: &Context) -> TyCheckResult<()> {
|
||||
match t {
|
||||
Type::FreeVar(fv) => {
|
||||
if let Some(name) = fv.unbound_name() {
|
||||
if let Some(v) = self.params.get(&name) {
|
||||
if let TyParam::Type(v) = v {
|
||||
ty_ctx.unify(t, v, None, None)?;
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t => todo!("{t}"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Evaluator {
|
||||
}
|
||||
|
||||
impl Evaluator {
|
||||
#[inline]
|
||||
pub fn new() -> Self { Self::default() }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn eval_const_lit(&self, lit: &Literal) -> ValueObj { ValueObj::from(lit) }
|
||||
|
||||
fn eval_const_acc(&self, _acc: &Accessor) -> Option<ValueObj> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn eval_const_bin(&self, _bin: &BinOp) -> Option<ValueObj> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn eval_const_unary(&self, _unary: &UnaryOp) -> Option<ValueObj> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
// TODO: kw args
|
||||
fn eval_args(&self, _args: &Args) -> Option<Vec<ValueObj>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn eval_const_call(&self, call: &Call, ctx: &Context) -> Option<ValueObj> {
|
||||
if let Expr::Accessor(acc) = call.obj.as_ref() {
|
||||
match acc {
|
||||
Accessor::Local(name) if name.is_const() => {
|
||||
if let Some(ConstObj::Subr(subr)) = ctx.consts.get(name.inspect()) {
|
||||
let args = self.eval_args(&call.args)?;
|
||||
Some(subr.call(args))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Accessor::Local(_) => None,
|
||||
Accessor::Attr(_attr) => todo!(),
|
||||
Accessor::TupleAttr(_attr) => todo!(),
|
||||
Accessor::SelfDot(_name) => todo!(),
|
||||
Accessor::Subscr(_subscr) => todo!(),
|
||||
}
|
||||
} else { None }
|
||||
}
|
||||
|
||||
fn eval_const_def(&self, def: &Def) -> Option<ValueObj> {
|
||||
if def.is_const() {
|
||||
todo!()
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する
|
||||
// コンパイル時評価できないならNoneを返す
|
||||
pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> {
|
||||
match expr {
|
||||
Expr::Lit(lit) => Some(self.eval_const_lit(lit)),
|
||||
Expr::Accessor(acc) => self.eval_const_acc(acc),
|
||||
Expr::BinOp(bin) => self.eval_const_bin(bin),
|
||||
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
|
||||
Expr::Call(call) => self.eval_const_call(call, ctx),
|
||||
Expr::Def(def) => self.eval_const_def(def),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_const_block(&self, block: &Block, ctx: &Context) -> Option<ValueObj> {
|
||||
for chunk in block.iter().rev().skip(1).rev() {
|
||||
self.eval_const_expr(chunk, ctx)?;
|
||||
}
|
||||
self.eval_const_expr(block.last().unwrap(), ctx)
|
||||
}
|
||||
|
||||
fn eval_bin_lit(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
|
||||
match op {
|
||||
Add => lhs.try_add(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Sub => lhs.try_sub(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Mul => lhs.try_mul(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Div => lhs.try_div(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Gt => lhs.try_gt(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Ge => lhs.try_ge(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Eq => lhs.try_eq(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
Ne => lhs.try_ne(rhs).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_bin_tp(&self, op: OpKind, lhs: &TyParam, rhs: &TyParam) -> EvalResult<TyParam> {
|
||||
match (lhs, rhs) {
|
||||
(TyParam::ConstObj(ConstObj::Value(lhs)), TyParam::ConstObj(ConstObj::Value(rhs))) =>
|
||||
self.eval_bin_lit(op, lhs.clone(), rhs.clone())
|
||||
.map(|v| TyParam::value(v)),
|
||||
(TyParam::ConstObj(ConstObj::MutValue(lhs)), TyParam::ConstObj(ConstObj::Value(rhs))) =>
|
||||
self.eval_bin_lit(op, lhs.borrow().clone(), rhs.clone())
|
||||
.map(|v| TyParam::ConstObj(ConstObj::MutValue(RcCell::new(v)))),
|
||||
(TyParam::FreeVar(fv), r) => {
|
||||
if fv.is_linked() {
|
||||
self.eval_bin_tp(op, &*fv.crack(), r)
|
||||
} else {
|
||||
Err(EvalError::unreachable(fn_name!(), line!()))
|
||||
}
|
||||
},
|
||||
(l, TyParam::FreeVar(fv)) => {
|
||||
if fv.is_linked() {
|
||||
self.eval_bin_tp(op, l, &*fv.crack())
|
||||
} else {
|
||||
Err(EvalError::unreachable(fn_name!(), line!()))
|
||||
}
|
||||
},
|
||||
(e @ TyParam::Erased(_), _)
|
||||
| (_, e @ TyParam::Erased(_)) => Ok(e.clone()),
|
||||
(l, r) => todo!("{l} {op} {r}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_unary_lit(&self, op: OpKind, val: ConstObj) -> EvalResult<ConstObj> {
|
||||
match op {
|
||||
Pos => todo!(),
|
||||
Neg => todo!(),
|
||||
Invert => todo!(),
|
||||
Mutate => if let ConstObj::Value(v) = val {
|
||||
Ok(ConstObj::MutValue(RcCell::new(v)))
|
||||
} else { todo!() },
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> {
|
||||
match val {
|
||||
TyParam::ConstObj(c) =>
|
||||
self.eval_unary_lit(op, c.clone()).map(|c| TyParam::cons(c)),
|
||||
TyParam::FreeVar(fv) if fv.is_linked() => {
|
||||
self.eval_unary_tp(op, &*fv.crack())
|
||||
},
|
||||
e @ TyParam::Erased(_) => Ok(e.clone()),
|
||||
other => todo!("{op} {other}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_app(&self, _name: &Str, _args: &Vec<TyParam>) -> EvalResult<TyParam> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// 量化変数などはそのまま返す
|
||||
pub(crate) fn eval_tp(&self, p: &TyParam, ctx: &Context) -> EvalResult<TyParam> {
|
||||
match p {
|
||||
TyParam::FreeVar(fv) if fv.is_linked() =>
|
||||
self.eval_tp(&fv.crack(), ctx),
|
||||
TyParam::Mono(name) =>
|
||||
ctx.consts.get(name)
|
||||
.and_then(|c| match c {
|
||||
ConstObj::Value(v) => Some(TyParam::value(v.clone())),
|
||||
_ => None,
|
||||
}).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
TyParam::BinOp{ op, lhs, rhs } =>
|
||||
self.eval_bin_tp(*op, lhs, rhs),
|
||||
TyParam::UnaryOp{ op, val } =>
|
||||
self.eval_unary_tp(*op, val),
|
||||
TyParam::App{ name, args } =>
|
||||
self.eval_app(name, args),
|
||||
p @ (
|
||||
TyParam::Type(_) | TyParam::Erased(_) | TyParam::ConstObj(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_)
|
||||
) => Ok(p.clone()),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_t(&self, substituted: Type, ctx: &Context, level: usize) -> EvalResult<Type> {
|
||||
match substituted {
|
||||
Type::FreeVar(fv) if fv.is_linked() =>
|
||||
self.eval_t(fv.crack().clone(), ctx, level),
|
||||
Type::Subr(mut subr) => {
|
||||
let kind = match subr.kind {
|
||||
SubrKind::FuncMethod(self_t) => {
|
||||
SubrKind::fn_met(self.eval_t(*self_t, ctx, level)?)
|
||||
}
|
||||
SubrKind::ProcMethod{ before, after } => {
|
||||
let before = self.eval_t(*before, ctx, level)?;
|
||||
if let Some(after) = after {
|
||||
let after = self.eval_t(*after, ctx, level)?;
|
||||
SubrKind::pr_met(before, Some(after))
|
||||
} else {
|
||||
SubrKind::pr_met(before, None)
|
||||
}
|
||||
}
|
||||
other => other,
|
||||
};
|
||||
for p in subr.non_default_params.iter_mut() {
|
||||
p.ty = self.eval_t(mem::take(&mut p.ty), ctx, level)?;
|
||||
}
|
||||
for p in subr.default_params.iter_mut() {
|
||||
p.ty = self.eval_t(mem::take(&mut p.ty), ctx, level)?;
|
||||
}
|
||||
let return_t = self.eval_t(*subr.return_t, ctx, level)?;
|
||||
Ok(Type::subr(kind, subr.non_default_params, subr.default_params, return_t))
|
||||
},
|
||||
Type::Array{ t, len } => {
|
||||
let t = self.eval_t(*t, ctx, level)?;
|
||||
let len = self.eval_tp(&len, ctx)?;
|
||||
Ok(Type::array(t, len))
|
||||
},
|
||||
Type::Refinement(refine) => {
|
||||
let mut preds = Set::with_capacity(refine.preds.len());
|
||||
for pred in refine.preds.into_iter() {
|
||||
preds.insert(self.eval_pred(pred, ctx)?);
|
||||
}
|
||||
Ok(Type::refinement(refine.var, *refine.t, preds))
|
||||
},
|
||||
// [?T; 0].MutType! == [?T; !0]
|
||||
Type::MonoProj{ lhs, rhs } => {
|
||||
for ty_ctx in ctx.get_sorted_supertypes(&lhs) {
|
||||
if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) {
|
||||
if let ConstObj::Type(quant_t) = obj {
|
||||
let subst_ctx = SubstContext::new(&lhs, ty_ctx);
|
||||
let t = subst_ctx.substitute(*quant_t, ty_ctx, level)?;
|
||||
let t = self.eval_t(t, ctx, level)?;
|
||||
return Ok(t)
|
||||
} else { todo!() }
|
||||
}
|
||||
}
|
||||
todo!()
|
||||
},
|
||||
Type::Range(l) => Ok(Type::range(self.eval_t(*l, ctx, level)?)),
|
||||
Type::Iter(l) => Ok(Type::iter(self.eval_t(*l, ctx, level)?)),
|
||||
Type::Ref(l) => Ok(Type::refer(self.eval_t(*l, ctx, level)?)),
|
||||
Type::RefMut(l) => Ok(Type::ref_mut(self.eval_t(*l, ctx, level)?)),
|
||||
Type::Option(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)),
|
||||
Type::OptionMut(l) => Ok(Type::option_mut(self.eval_t(*l, ctx, level)?)),
|
||||
Type::VarArgs(l) => Ok(Type::var_args(self.eval_t(*l, ctx, level)?)),
|
||||
Type::Poly{ name, mut params } => {
|
||||
for p in params.iter_mut() {
|
||||
*p = self.eval_tp(&mem::take(p), ctx)?;
|
||||
}
|
||||
Ok(Type::poly(name, params))
|
||||
},
|
||||
other if other.is_monomorphic() => Ok(other),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn _eval_bound(&self, bound: TyBound, ctx: &Context, level: usize) -> EvalResult<TyBound> {
|
||||
match bound {
|
||||
TyBound::Subtype{ sub, sup } =>
|
||||
Ok(TyBound::subtype(
|
||||
self.eval_t(sub, ctx, level)?,
|
||||
self.eval_t(sup, ctx, level)?
|
||||
)),
|
||||
TyBound::Supertype{ sup, sub } =>
|
||||
Ok(TyBound::supertype(
|
||||
self.eval_t(sup, ctx, level)?,
|
||||
self.eval_t(sub, ctx, level)?
|
||||
)),
|
||||
TyBound::Sandwiched { sub, mid, sup } => {
|
||||
let sub = self.eval_t(sub, ctx, level)?;
|
||||
let mid = self.eval_t(mid, ctx, level)?;
|
||||
let sup = self.eval_t(sup, ctx, level)?;
|
||||
Ok(TyBound::sandwiched(sub, mid, sup))
|
||||
},
|
||||
TyBound::Instance{ name: inst, t } =>
|
||||
Ok(TyBound::instance(inst, self.eval_t(t, ctx, level)?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_pred(&self, p: Predicate, ctx: &Context) -> EvalResult<Predicate> {
|
||||
match p {
|
||||
Predicate::Value(_) | Predicate::Const(_) => Ok(p),
|
||||
Predicate::Equal{ lhs, rhs } =>
|
||||
Ok(Predicate::eq(lhs, self.eval_tp(&rhs, ctx)?)),
|
||||
Predicate::NotEqual{ lhs, rhs } =>
|
||||
Ok(Predicate::ne(lhs, self.eval_tp(&rhs, ctx)?)),
|
||||
Predicate::LessEqual{ lhs, rhs } =>
|
||||
Ok(Predicate::le(lhs, self.eval_tp(&rhs, ctx)?)),
|
||||
Predicate::GreaterEqual{ lhs, rhs } =>
|
||||
Ok(Predicate::ge(lhs, self.eval_tp(&rhs, ctx)?)),
|
||||
Predicate::And(l, r) =>
|
||||
Ok(Predicate::and(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)),
|
||||
Predicate::Or(l, r) =>
|
||||
Ok(Predicate::or(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)),
|
||||
Predicate::Not(l, r) =>
|
||||
Ok(Predicate::not(self.eval_pred(*l, ctx)?, self.eval_pred(*r, ctx)?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_tp_t(&self, p: &TyParam, bounds: Option<&Set<TyBound>>, ctx: &Context) -> EvalResult<Type> {
|
||||
let p = self.eval_tp(p, ctx)?;
|
||||
match p {
|
||||
TyParam::ConstObj(ConstObj::Value(v)) => Ok(Type::enum_t(set![v])),
|
||||
TyParam::ConstObj(ConstObj::MutValue(v)) => Ok(v.borrow().class().mutate()),
|
||||
TyParam::Erased(t) => Ok((&*t).clone()),
|
||||
TyParam::FreeVar(fv) =>
|
||||
if let Some(t) = fv.type_of() { Ok(t) } else { todo!() },
|
||||
TyParam::Type(_) => Ok(Type::Type),
|
||||
TyParam::Mono(name) =>
|
||||
ctx.consts.get(&name)
|
||||
.and_then(|c| match c {
|
||||
ConstObj::Value(v) => Some(Type::enum_t(set![v.clone()])),
|
||||
_ => None,
|
||||
}).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
TyParam::MonoQVar(name) => {
|
||||
if let Some(bs) = bounds {
|
||||
if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(&name)) {
|
||||
Ok(bound.t().clone())
|
||||
} else { todo!() }
|
||||
} else { todo!() }
|
||||
},
|
||||
TyParam::UnaryOp{ op, val } => {
|
||||
match op {
|
||||
OpKind::Mutate => Ok(self.get_tp_t(&val, bounds, ctx)?.mutate()),
|
||||
_ => todo!(),
|
||||
}
|
||||
},
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn _get_tp_class(&self, p: &TyParam, ctx: &Context) -> EvalResult<Type> {
|
||||
let p = self.eval_tp(p, ctx)?;
|
||||
match p {
|
||||
TyParam::ConstObj(ConstObj::Value(v)) => Ok(v.class()),
|
||||
TyParam::Erased(t) => Ok((&*t).clone()),
|
||||
| TyParam::FreeVar(fv) =>
|
||||
if let Some(t) = fv.type_of() { Ok(t) } else { todo!() },
|
||||
TyParam::Type(_) => Ok(Type::Type),
|
||||
TyParam::Mono(name) =>
|
||||
ctx.consts.get(&name)
|
||||
.and_then(|c| match c {
|
||||
ConstObj::Value(v) => Some(v.class()),
|
||||
_ => None,
|
||||
}).ok_or(EvalError::unreachable(fn_name!(), line!())),
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: lとrが型の場合はContextの方で判定する
|
||||
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam, ctx: &Context) -> bool {
|
||||
match (lhs, rhs) {
|
||||
(TyParam::Type(l), TyParam::Type(r)) => l == r,
|
||||
(TyParam::ConstObj(l), TyParam::ConstObj(r)) => l == r,
|
||||
(TyParam::Erased(l), TyParam::Erased(r)) => l == r,
|
||||
(TyParam::FreeVar{ .. }, TyParam::FreeVar{ .. }) => true,
|
||||
(TyParam::Mono(l), TyParam::Mono(r)) => {
|
||||
if l == r { true }
|
||||
else if let (Some(l), Some(r)) = (ctx.consts.get(l), ctx.consts.get(r)) { l == r }
|
||||
else {
|
||||
// lとrが型の場合は...
|
||||
false
|
||||
}
|
||||
},
|
||||
(TyParam::BinOp{ .. }, TyParam::BinOp{ .. }) => todo!(),
|
||||
(TyParam::UnaryOp{ .. }, TyParam::UnaryOp{ .. }) => todo!(),
|
||||
(TyParam::App{ .. }, TyParam::App{ .. }) => todo!(),
|
||||
(TyParam::Mono(m), TyParam::ConstObj(l))
|
||||
| (TyParam::ConstObj(l), TyParam::Mono(m)) =>
|
||||
if let Some(o) = ctx.consts.get(m) { o == l } else { true },
|
||||
(TyParam::MonoQVar(_), _) | (_, TyParam::MonoQVar(_)) => false,
|
||||
(l, r) => todo!("l: {l}, r: {r}"),
|
||||
}
|
||||
}
|
||||
}
|
876
compiler/erg_compiler/hir.rs
Normal file
876
compiler/erg_compiler/hir.rs
Normal file
|
@ -0,0 +1,876 @@
|
|||
/// defines High-level Intermediate Representation
|
||||
use std::fmt;
|
||||
|
||||
use erg_common::{Str};
|
||||
use erg_common::value::ValueObj;
|
||||
use erg_common::error::Location;
|
||||
use erg_common::traits::{HasType, Locational, Stream, NestedDisplay};
|
||||
use erg_common::ty::{Type, TyParam, Constraint};
|
||||
use erg_common::{
|
||||
impl_locational, impl_locational_for_enum,
|
||||
impl_stream_for_wrapper, impl_display_for_enum,
|
||||
impl_nested_display_for_enum, impl_display_from_nested,
|
||||
};
|
||||
|
||||
use erg_parser::token::{Token, TokenKind};
|
||||
use erg_parser::ast::{VarName, VarPattern, Params, DefId, fmt_lines};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Literal {
|
||||
pub data: ValueObj, // for constant folding
|
||||
pub token: Token, // for Locational
|
||||
t: Type,
|
||||
}
|
||||
|
||||
impl HasType for Literal {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl NestedDisplay for Literal {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{}", self.token)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Literal);
|
||||
|
||||
impl Locational for Literal {
|
||||
#[inline]
|
||||
fn loc(&self) -> Location { self.token.loc() }
|
||||
}
|
||||
|
||||
impl From<Token> for Literal {
|
||||
fn from(token: Token) -> Self {
|
||||
let data = ValueObj::from_str(Type::from(token.kind), token.content.clone());
|
||||
Self { t: data.t(), data, token }
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn new(c: ValueObj, lineno: usize, col: usize) -> Self {
|
||||
let kind = TokenKind::from(&c);
|
||||
let token = Token::new(kind, c.to_string(), lineno, col);
|
||||
Self { t: c.t(), data: c, token }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is(&self, kind: TokenKind) -> bool {
|
||||
self.token.is(kind)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PosArg {
|
||||
pub expr: Expr,
|
||||
}
|
||||
|
||||
impl NestedDisplay for PosArg {
|
||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||
self.expr.fmt_nest(f, level)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(PosArg);
|
||||
|
||||
impl Locational for PosArg {
|
||||
fn loc(&self) -> Location { self.expr.loc() }
|
||||
}
|
||||
|
||||
impl PosArg {
|
||||
pub const fn new(expr: Expr) -> Self { Self { expr } }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KwArg {
|
||||
pub keyword: Token,
|
||||
pub expr: Expr,
|
||||
}
|
||||
|
||||
impl NestedDisplay for KwArg {
|
||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||
write!(f, "{}:\n", self.keyword)?;
|
||||
self.expr.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(KwArg);
|
||||
|
||||
impl Locational for KwArg {
|
||||
fn loc(&self) -> Location {
|
||||
Location::concat(&self.keyword, &self.expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl KwArg {
|
||||
pub const fn new(keyword: Token, expr: Expr) -> Self { Self { keyword, expr } }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Args {
|
||||
pos_args: Vec<PosArg>,
|
||||
kw_args: Vec<KwArg>,
|
||||
paren: Option<(Token, Token)>,
|
||||
}
|
||||
|
||||
impl NestedDisplay for Args {
|
||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||
if !self.pos_args.is_empty() { fmt_lines(self.pos_args.iter(), f, level)?; }
|
||||
if !self.kw_args.is_empty() { fmt_lines(self.kw_args.iter(), f, level)?; }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Args);
|
||||
|
||||
impl Locational for Args {
|
||||
fn loc(&self) -> Location {
|
||||
if let Some((l, r)) = &self.paren {
|
||||
Location::concat(l, r)
|
||||
} else if !self.kw_args.is_empty() {
|
||||
Location::concat(self.kw_args.first().unwrap(), self.kw_args.last().unwrap())
|
||||
} else if !self.pos_args.is_empty() {
|
||||
Location::concat(self.pos_args.first().unwrap(), self.pos_args.last().unwrap())
|
||||
} else {
|
||||
Location::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl_stream!(Args, KwArg, kw_args);
|
||||
|
||||
impl Args {
|
||||
pub const fn new(pos_args: Vec<PosArg>, kw_args: Vec<KwArg>, paren: Option<(Token, Token)>) -> Self {
|
||||
Self { pos_args, kw_args, paren }
|
||||
}
|
||||
|
||||
pub const fn empty() -> Self {
|
||||
Self::new(vec![], vec![], None)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.pos_args.len() + self.kw_args.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn kw_len(&self) -> usize { self.kw_args.len() }
|
||||
|
||||
pub fn pos_args(&self) -> &[PosArg] { &self.pos_args[..] }
|
||||
|
||||
pub fn kw_args(&self) -> &[KwArg] { &self.kw_args[..] }
|
||||
|
||||
pub fn push_pos(&mut self, pos: PosArg) {
|
||||
self.pos_args.push(pos);
|
||||
}
|
||||
|
||||
pub fn push_kw(&mut self, kw: KwArg) {
|
||||
self.kw_args.push(kw);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, index: usize) -> Expr {
|
||||
if self.pos_args.get(index).is_some() {
|
||||
self.pos_args.remove(index).expr
|
||||
} else {
|
||||
self.kw_args.remove(index-self.pos_args.len()).expr
|
||||
}
|
||||
}
|
||||
|
||||
/// try_remove((1, 2, z: 3), 2) == Some(3)
|
||||
pub fn try_remove(&mut self, index: usize) -> Option<Expr> {
|
||||
if self.pos_args.get(index).is_some() {
|
||||
Some(self.pos_args.remove(index).expr)
|
||||
} else {
|
||||
self.kw_args.get(index-self.pos_args.len())?;
|
||||
Some(self.kw_args.remove(index-self.pos_args.len()).expr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_remove_pos(&mut self, index: usize) -> Option<PosArg> {
|
||||
self.pos_args.get(index)?;
|
||||
Some(self.pos_args.remove(index))
|
||||
}
|
||||
|
||||
pub fn try_remove_kw(&mut self, index: usize) -> Option<KwArg> {
|
||||
self.kw_args.get(index)?;
|
||||
Some(self.kw_args.remove(index))
|
||||
}
|
||||
|
||||
pub fn get(&self, index: usize) -> Option<&Expr> {
|
||||
if self.pos_args.get(index).is_some() {
|
||||
self.pos_args.get(index).map(|a| &a.expr)
|
||||
} else {
|
||||
self.kw_args.get(index-self.pos_args.len()).map(|a| &a.expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// represents local variables
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Local {
|
||||
pub name: Token,
|
||||
/// オブジェクト自身の名前
|
||||
__name__: Option<Str>,
|
||||
t: Type,
|
||||
}
|
||||
|
||||
impl fmt::Display for Local {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let __name__ = if let Some(__name__) = self.__name__() {
|
||||
format!("(__name__ = {__name__})")
|
||||
} else { "".to_string() };
|
||||
if self.t != Type::ASTOmitted {
|
||||
write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
|
||||
} else {
|
||||
write!(f, "{}{}", self.name.content, __name__)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasType for Local {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl Locational for Local {
|
||||
#[inline]
|
||||
fn loc(&self) -> Location { self.name.loc() }
|
||||
}
|
||||
|
||||
impl Local {
|
||||
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self { Self{ name, __name__, t } }
|
||||
|
||||
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
|
||||
#[inline]
|
||||
pub fn inspect(&self) -> &Str { &self.name.content }
|
||||
|
||||
pub const fn __name__(&self) -> Option<&Str> { self.__name__.as_ref() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Attribute {
|
||||
pub obj: Box<Expr>,
|
||||
pub name: Token,
|
||||
t: Type
|
||||
}
|
||||
|
||||
impl fmt::Display for Attribute {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({}).{}", self.obj, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl_locational!(Attribute, obj, name);
|
||||
|
||||
impl HasType for Attribute {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl Attribute {
|
||||
pub fn new(obj: Expr, name: Token, t: Type) -> Self {
|
||||
Self { obj: Box::new(obj), name, t }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Subscript {
|
||||
obj: Box<Expr>,
|
||||
index: Box<Expr>,
|
||||
t: Type
|
||||
}
|
||||
|
||||
impl fmt::Display for Subscript {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({})[{}]", self.obj, self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl_locational!(Subscript, obj, index);
|
||||
|
||||
impl HasType for Subscript {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl Subscript {
|
||||
pub fn new(obj: Expr, index: Expr, t: Type) -> Self {
|
||||
Self { obj: Box::new(obj), index: Box::new(index), t }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Accessor {
|
||||
Local(Local),
|
||||
SelfDot(Local),
|
||||
Attr(Attribute),
|
||||
Subscr(Subscript),
|
||||
}
|
||||
|
||||
impl NestedDisplay for Accessor {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
match self {
|
||||
Self::Local(name) => write!(f, "{}", name),
|
||||
Self::SelfDot(attr) => write!(f, ".{}", attr),
|
||||
Self::Attr(attr) => write!(f, "{}", attr),
|
||||
Self::Subscr(subscr) => write!(f, "{}", subscr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Accessor);
|
||||
impl_locational_for_enum!(Accessor; Local, SelfDot, Attr, Subscr);
|
||||
|
||||
impl HasType for Accessor {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type {
|
||||
match self {
|
||||
Self::Local(n) | Self::SelfDot(n) => n.ref_t(),
|
||||
Self::Attr(a) => a.ref_t(),
|
||||
Self::Subscr(s) => s.ref_t(),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl Accessor {
|
||||
pub const fn local(symbol: Token, t: Type) -> Self { Self::Local(Local::new(symbol, None, t)) }
|
||||
|
||||
pub const fn self_dot(name: Token, t: Type) -> Self { Self::SelfDot(Local::new(name, None, t)) }
|
||||
|
||||
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
|
||||
Self::Attr(Attribute::new(obj, name, t))
|
||||
}
|
||||
|
||||
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
|
||||
Self::Subscr(Subscript::new(obj, index, t))
|
||||
}
|
||||
|
||||
pub fn var_full_name(&self) -> Option<String> {
|
||||
match self {
|
||||
Self::Local(local) => Some(local.inspect().to_string()),
|
||||
Self::Attr(attr) =>
|
||||
attr.obj.var_full_name().map(|n| n + "." + attr.name.inspect()),
|
||||
Self::Subscr(_)
|
||||
| Self::SelfDot(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
// 参照するオブジェクト自体が持っている固有の名前
|
||||
pub fn __name__(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Local(local)
|
||||
| Self::SelfDot(local) => local.__name__().map(|s| &s[..]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Array {
|
||||
pub l_sqbr: Token,
|
||||
pub r_sqbr: Token,
|
||||
t: Type,
|
||||
pub elems: Args,
|
||||
pub guard: Option<Box<Expr>>,
|
||||
}
|
||||
|
||||
impl HasType for Array {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl NestedDisplay for Array {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
if let Some(guard) = &self.guard {
|
||||
write!(f, "[{} | {}]", self.elems, guard)
|
||||
} else {
|
||||
write!(f, "[{}]", self.elems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Array);
|
||||
impl_locational!(Array, l_sqbr, r_sqbr);
|
||||
|
||||
impl Array {
|
||||
pub fn new(l_sqbr: Token, r_sqbr: Token, level: usize, elems: Args, guard: Option<Expr>) -> Self {
|
||||
let elem_t = elems.pos_args().first()
|
||||
.map(|a| a.expr.t())
|
||||
.unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type)));
|
||||
let t = Type::array(elem_t, TyParam::value(elems.len()));
|
||||
Self { l_sqbr, r_sqbr, t, elems, guard: guard.map(Box::new) }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, elem: Expr) {
|
||||
self.elems.push_pos(PosArg::new(elem));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Dict {
|
||||
pub l_brace: Token,
|
||||
pub r_brace: Token,
|
||||
pub attrs: Args, // TODO: keyをTokenではなくExprにする
|
||||
}
|
||||
|
||||
impl HasType for Dict {
|
||||
fn ref_t(&self) -> &Type { todo!() }
|
||||
fn t(&self) -> Type { todo!() }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl NestedDisplay for Dict {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{{{}}}", self.attrs)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Dict);
|
||||
impl_locational!(Dict, l_brace, r_brace);
|
||||
|
||||
impl Dict {
|
||||
pub const fn new(l_brace: Token, r_brace: Token, attrs: Args) -> Self {
|
||||
Self { l_brace, r_brace, attrs }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BinOp {
|
||||
pub op: Token,
|
||||
pub lhs: Box<Expr>,
|
||||
pub rhs: Box<Expr>,
|
||||
pub sig_t: Type, // e.g. (Int, Int) -> Int
|
||||
}
|
||||
|
||||
impl NestedDisplay for BinOp {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
write!(f, "`{}`:\n", self.op.content)?;
|
||||
self.lhs.fmt_nest(f, level + 1)?;
|
||||
write!(f, "\n")?;
|
||||
self.rhs.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasType for BinOp {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() }
|
||||
#[inline]
|
||||
fn lhs_t(&self) -> &Type { &self.sig_t.lhs_t() }
|
||||
#[inline]
|
||||
fn rhs_t(&self) -> &Type { &self.sig_t.rhs_t() }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) }
|
||||
}
|
||||
|
||||
impl_display_from_nested!(BinOp);
|
||||
impl_locational!(BinOp, lhs, rhs);
|
||||
|
||||
impl BinOp {
|
||||
pub fn new(op: Token, lhs: Expr, rhs: Expr, sig_t: Type) -> Self {
|
||||
Self { op, lhs: Box::new(lhs), rhs: Box::new(rhs), sig_t }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UnaryOp {
|
||||
pub op: Token,
|
||||
pub expr: Box<Expr>,
|
||||
pub sig_t: Type, // e.g. Neg -> Nat
|
||||
}
|
||||
|
||||
impl HasType for UnaryOp {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() }
|
||||
#[inline]
|
||||
fn lhs_t(&self) -> &Type { self.expr.ref_t() }
|
||||
#[inline]
|
||||
fn rhs_t(&self) -> &Type { panic!("invalid operation") }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) }
|
||||
}
|
||||
|
||||
impl NestedDisplay for UnaryOp {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
write!(f, "`{}`: {}:\n", self.op, self.sig_t)?;
|
||||
self.expr.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(UnaryOp);
|
||||
impl_locational!(UnaryOp, op, expr);
|
||||
|
||||
impl UnaryOp {
|
||||
pub fn new(op: Token, expr: Expr, sig_t: Type) -> Self {
|
||||
Self { op, expr: Box::new(expr), sig_t }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Call {
|
||||
pub obj: Box<Expr>,
|
||||
pub args: Args,
|
||||
/// 全体の型、e.g. `abs(-1)` -> `Neg -> Nat`
|
||||
/// necessary for mangling
|
||||
pub sig_t: Type,
|
||||
}
|
||||
|
||||
impl NestedDisplay for Call {
|
||||
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
|
||||
write!(f, "({}): {}:\n", self.obj, self.sig_t)?;
|
||||
self.args.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Call);
|
||||
|
||||
impl HasType for Call {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.sig_t.return_t().unwrap() }
|
||||
#[inline]
|
||||
fn lhs_t(&self) -> &Type { self.sig_t.lhs_t() }
|
||||
#[inline]
|
||||
fn rhs_t(&self) -> &Type { self.sig_t.rhs_t() }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) }
|
||||
}
|
||||
|
||||
impl Locational for Call {
|
||||
fn loc(&self) -> Location {
|
||||
Location::concat(self.obj.as_ref(), &self.args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Call {
|
||||
pub fn new(obj: Expr, args: Args, sig_t: Type) -> Self {
|
||||
Self { obj: Box::new(obj), args, sig_t }
|
||||
}
|
||||
|
||||
pub fn is_import_call(&self) -> bool {
|
||||
self.obj.var_full_name()
|
||||
.map(|s| &s[..] == "import" || &s[..] == "pyimport")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Block(Vec<Expr>);
|
||||
|
||||
impl HasType for Block {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { self.last().unwrap().ref_t() }
|
||||
#[inline]
|
||||
fn t(&self) -> Type { self.last().unwrap().t() }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { self.last().unwrap().signature_t() }
|
||||
}
|
||||
|
||||
impl NestedDisplay for Block {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
fmt_lines(self.0.iter(), f, level)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Block);
|
||||
impl_stream_for_wrapper!(Block, Expr);
|
||||
|
||||
impl Locational for Block {
|
||||
fn loc(&self) -> Location {
|
||||
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct VarSignature {
|
||||
pub pat: VarPattern,
|
||||
pub t: Type,
|
||||
}
|
||||
|
||||
impl fmt::Display for VarSignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} (: {})", self.pat, self.t)
|
||||
}
|
||||
}
|
||||
|
||||
impl Locational for VarSignature {
|
||||
fn loc(&self) -> Location { self.pat.loc() }
|
||||
}
|
||||
|
||||
impl VarSignature {
|
||||
pub const fn new(pat: VarPattern, t: Type) -> Self { Self{ pat, t } }
|
||||
|
||||
pub fn inspect(&self) -> Option<&Str> { self.pat.inspect() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SubrSignature {
|
||||
pub name: VarName,
|
||||
pub params: Params,
|
||||
pub t: Type,
|
||||
}
|
||||
|
||||
impl fmt::Display for SubrSignature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{} (: {})", self.name, self.params, self.t)
|
||||
}
|
||||
}
|
||||
|
||||
impl Locational for SubrSignature {
|
||||
fn loc(&self) -> Location {
|
||||
Location::concat(&self.name, &self.params)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubrSignature {
|
||||
pub const fn new(name: VarName, params: Params, t: Type) -> Self {
|
||||
Self{ name, params, t }
|
||||
}
|
||||
|
||||
pub fn is_procedural(&self) -> bool { self.name.is_procedural() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lambda {
|
||||
pub params: Params,
|
||||
op: Token,
|
||||
pub body: Block,
|
||||
pub id: usize,
|
||||
t: Type
|
||||
}
|
||||
|
||||
impl HasType for Lambda {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl NestedDisplay for Lambda {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
write!(f, "{} {}\n", self.params, self.op.content)?;
|
||||
self.body.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Lambda);
|
||||
impl_locational!(Lambda, params, body);
|
||||
|
||||
impl Lambda {
|
||||
pub const fn new(id: usize, params: Params, op: Token, body: Block, t: Type) -> Self {
|
||||
Self { id, params, op, body, t }
|
||||
}
|
||||
|
||||
pub fn is_procedural(&self) -> bool { self.op.is(TokenKind::ProcArrow) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Signature {
|
||||
Var(VarSignature),
|
||||
Subr(SubrSignature),
|
||||
}
|
||||
|
||||
impl_display_for_enum!(Signature; Var, Subr,);
|
||||
impl_locational_for_enum!(Signature; Var, Subr,);
|
||||
|
||||
impl Signature {
|
||||
pub const fn is_subr(&self) -> bool { matches!(self, Self::Subr(_)) }
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
match self {
|
||||
Self::Var(v) => v.pat.is_const(),
|
||||
Self::Subr(s) => s.name.is_const(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_procedural(&self) -> bool {
|
||||
match self {
|
||||
Self::Var(v) => v.pat.is_procedural(),
|
||||
Self::Subr(s) => s.name.is_procedural(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// represents a declaration of a variable
|
||||
/// necessary for type field declaration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Decl {
|
||||
pub sig: Signature,
|
||||
t: Type,
|
||||
}
|
||||
|
||||
impl NestedDisplay for Decl {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{}: {}", self.sig, self.t)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Decl);
|
||||
|
||||
impl Locational for Decl {
|
||||
#[inline]
|
||||
fn loc(&self) -> Location { self.sig.loc() }
|
||||
}
|
||||
|
||||
impl Decl {
|
||||
pub const fn spec_t(&self) -> &Type { &self.t }
|
||||
|
||||
pub const fn is_sub(&self) -> bool { self.sig.is_subr() }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DefBody {
|
||||
pub op: Token,
|
||||
pub block: Block,
|
||||
pub id : DefId,
|
||||
}
|
||||
|
||||
impl_locational!(DefBody, op, block);
|
||||
|
||||
impl DefBody {
|
||||
pub const fn new(op: Token, block: Block, id: DefId) -> Self { Self { op, block, id } }
|
||||
|
||||
pub fn is_type(&self) -> bool {
|
||||
match self.block.first().unwrap() {
|
||||
Expr::Call(call) => {
|
||||
if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() {
|
||||
&local.inspect()[..] == "Type"
|
||||
} else { false }
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Def {
|
||||
pub sig: Signature,
|
||||
pub body: DefBody,
|
||||
}
|
||||
|
||||
impl NestedDisplay for Def {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||
write!(f, "{} {}\n", self.sig, self.body.op.content)?;
|
||||
self.body.block.fmt_nest(f, level + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(Def);
|
||||
impl_locational!(Def, sig, body);
|
||||
|
||||
impl Def {
|
||||
pub const fn new(sig: Signature, body: DefBody) -> Self { Self { sig, body } }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Expr {
|
||||
Lit(Literal),
|
||||
Accessor(Accessor),
|
||||
Array(Array),
|
||||
// Dict(Dict),
|
||||
// Set(Set),
|
||||
Dict(Dict),
|
||||
BinOp(BinOp),
|
||||
UnaryOp(UnaryOp),
|
||||
Call(Call),
|
||||
Lambda(Lambda),
|
||||
Decl(Decl),
|
||||
Def(Def),
|
||||
}
|
||||
|
||||
impl_nested_display_for_enum!(Expr; Lit, Accessor, Array, Dict, BinOp, UnaryOp, Call, Lambda, Decl, Def);
|
||||
impl_display_from_nested!(Expr);
|
||||
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Dict, BinOp, UnaryOp, Call, Lambda, Decl, Def);
|
||||
|
||||
impl HasType for Expr {
|
||||
fn ref_t(&self) -> &Type {
|
||||
match self {
|
||||
Expr::Lit(lit) => lit.ref_t(),
|
||||
Expr::Accessor(accessor) => accessor.ref_t(),
|
||||
Expr::Array(array) => array.ref_t(),
|
||||
Expr::Dict(dict) => dict.ref_t(),
|
||||
Expr::BinOp(bin) => bin.ref_t(),
|
||||
Expr::UnaryOp(unary) => unary.ref_t(),
|
||||
Expr::Call(call) => call.ref_t(),
|
||||
Expr::Lambda(lambda) => lambda.ref_t(),
|
||||
_ => &Type::NoneType,
|
||||
}
|
||||
}
|
||||
fn signature_t(&self) -> Option<&Type> {
|
||||
match self {
|
||||
Expr::BinOp(bin) => bin.signature_t(),
|
||||
Expr::UnaryOp(unary) => unary.signature_t(),
|
||||
Expr::Call(call) => call.signature_t(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn receiver_t(&self) -> Option<&Type> {
|
||||
match self {
|
||||
Self::Accessor(Accessor::Attr(attr)) => Some(attr.obj.ref_t()),
|
||||
_other => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_full_name(&self) -> Option<String> {
|
||||
match self {
|
||||
Expr::Accessor(acc) => acc.var_full_name(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 参照するオブジェクト自体が持っている名前(e.g. Int.__name__ == Some("int"))
|
||||
pub fn __name__(&self) -> Option<&str> {
|
||||
match self {
|
||||
Expr::Accessor(acc) => acc.__name__(),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Toplevel grammar unit
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Module(Vec<Expr>);
|
||||
|
||||
impl fmt::Display for Module {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt_lines(self.0.iter(), f, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Locational for Module {
|
||||
fn loc(&self) -> Location {
|
||||
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl_stream_for_wrapper!(Module, Expr);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HIR {
|
||||
pub name: Str,
|
||||
pub module: Module,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for HIR {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.module)
|
||||
}
|
||||
}
|
||||
|
||||
impl HIR {
|
||||
pub const fn new(name: Str, module: Module) -> Self { Self { name, module } }
|
||||
}
|
513
compiler/erg_compiler/initialize.rs
Normal file
513
compiler/erg_compiler/initialize.rs
Normal file
|
@ -0,0 +1,513 @@
|
|||
//! defines type information for builtin objects (in `Context`)
|
||||
//!
|
||||
//! 組み込みオブジェクトの型情報を(Contextに)定義
|
||||
use erg_common::{Str};
|
||||
use erg_common::{set, debug_power_assert};
|
||||
use erg_common::ty::{Type, TyParam, ConstObj};
|
||||
use Type::*;
|
||||
use erg_common::ty::type_constrs::*;
|
||||
use ParamSpec as PS;
|
||||
|
||||
use erg_parser::ast::{VarName};
|
||||
|
||||
use crate::varinfo::{Mutability, Visibility, VarInfo, VarKind};
|
||||
use crate::context::{Context, ParamSpec, DefaultInfo};
|
||||
use Visibility::*;
|
||||
use Mutability::*;
|
||||
use VarKind::*;
|
||||
use DefaultInfo::*;
|
||||
|
||||
// NOTE: TyParam::MonoQuantVarは生成時に型を指定する必要があるが、逆にそちらがあれば型境界を指定しなくてもよい
|
||||
impl Context {
|
||||
fn register_decl(&mut self, name: &'static str, t: Type, vis: Visibility) {
|
||||
let name = VarName::from_static(name);
|
||||
if self.decls.get(&name).is_some() {
|
||||
panic!("already registered: {name}");
|
||||
} else {
|
||||
self.decls.insert(name, VarInfo::new(t, Immutable, vis, Builtin));
|
||||
}
|
||||
}
|
||||
|
||||
fn register_impl(&mut self, name: &'static str, t: Type, muty: Mutability, vis: Visibility) {
|
||||
let name = VarName::from_static(name);
|
||||
if self.impls.get(&name).is_some() {
|
||||
panic!("already registered: {name}");
|
||||
} else {
|
||||
self.impls.insert(name, VarInfo::new(t, muty, vis, Builtin));
|
||||
}
|
||||
}
|
||||
|
||||
fn register_const(&mut self, name: &'static str, obj: ConstObj) {
|
||||
if self.consts.get(name).is_some() {
|
||||
panic!("already registered: {name}");
|
||||
} else {
|
||||
self.consts.insert(Str::ever(name), obj);
|
||||
}
|
||||
}
|
||||
|
||||
fn register_type(&mut self, t: Type, ctx: Self, muty: Mutability) {
|
||||
if self.types.contains_key(&t) {
|
||||
panic!("{} has already been registered", t.name());
|
||||
} else {
|
||||
let name = VarName::from_str(Str::rc(t.name()));
|
||||
self.impls.insert(name, VarInfo::new(Type, muty, Private, Builtin));
|
||||
self.types.insert(t, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn register_patch(&mut self, name: &'static str, ctx: Self, muty: Mutability) {
|
||||
if self.patches.contains_key(name) {
|
||||
panic!("{} has already been registered", name);
|
||||
} else {
|
||||
let name = VarName::from_static(name);
|
||||
self.impls.insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin));
|
||||
for method_name in ctx.impls.keys() {
|
||||
if let Some(patches) = self._method_impl_patches.get_mut(method_name) {
|
||||
patches.push(name.clone());
|
||||
} else {
|
||||
self._method_impl_patches.insert(method_name.clone(), vec![name.clone()]);
|
||||
}
|
||||
}
|
||||
debug_power_assert!(ctx.super_classes.len(), ==, 1);
|
||||
if let Some(target_type) = ctx.super_classes.first() {
|
||||
for impl_trait in ctx.super_traits.iter() {
|
||||
self.glue_patch_and_types.push(
|
||||
(VarName::from_str(ctx.name.clone()), target_type.clone(), impl_trait.clone())
|
||||
);
|
||||
}
|
||||
}
|
||||
self.patches.insert(name, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/// see std/prelude.er
|
||||
// 型境界はすべて各サブルーチンで定義する
|
||||
// push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する
|
||||
fn init_builtin_traits(&mut self) {
|
||||
let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL);
|
||||
// __eq__: |Self <: Eq; R <: Eq()| Self(R).(R) -> Bool
|
||||
let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool);
|
||||
let op_t = quant(op_t, set!{subtype(mono_q("Self"), mono("Eq")), subtype(mono_q("R"), poly("Eq", vec![]))});
|
||||
eq.register_decl("__eq__", op_t.clone(), Public);
|
||||
let mut ord = Self::poly_trait("Ord", vec![PS::t("R", WithDefault)], vec![mono("Eq")], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(poly("Self", vec![mono_q_tp("R")]), mono_q("R"), Bool);
|
||||
let op_t = quant(op_t, set!{subtype(mono_q("Self"), mono("Ord")), subtype(mono_q("R"), poly("Ord", vec![]))});
|
||||
ord.register_decl("__lt__", op_t.clone(), Public);
|
||||
let mut seq = Self::poly_trait("Seq", vec![PS::t("T", NonDefault)], vec![], Self::TOP_LEVEL);
|
||||
let self_t = poly_q("Self", vec![TyParam::t(mono_q("T"))]);
|
||||
let t = fn0_met(self_t.clone(), Nat);
|
||||
let t = quant(t, set!{subtype(self_t.clone(), mono("Seq"))});
|
||||
seq.register_decl("__len__", t, Public);
|
||||
let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T"));
|
||||
let t = quant(t, set!{subtype(self_t, mono("Seq")), static_instance("T", Type)});
|
||||
seq.register_decl("get", t, Public);
|
||||
let (r, o) = (mono_q("R"), mono_q("O"));
|
||||
let (r_bound, o_bound) = (static_instance("R", Type), static_instance("O", Type));
|
||||
let params = vec![PS::t("R", WithDefault), PS::t("O", WithDefault)];
|
||||
let ty_params = vec![mono_q_tp("R"), mono_q_tp("O")];
|
||||
let mut add_ro = Self::poly_trait("Add", params.clone(), vec![], Self::TOP_LEVEL);
|
||||
let self_bound = subtype(poly_q("Self", ty_params.clone()), poly("Add", ty_params.clone()));
|
||||
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{r_bound.clone(), o_bound.clone(), self_bound});
|
||||
add_ro.register_decl("__add__", op_t, Public);
|
||||
let mut sub_ro = Self::poly_trait("Sub", params.clone(), vec![], Self::TOP_LEVEL);
|
||||
let self_bound = subtype(poly_q("Self", ty_params.clone()), poly("Sub", ty_params.clone()));
|
||||
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{r_bound.clone(), o_bound.clone(), self_bound});
|
||||
sub_ro.register_decl("__sub__", op_t, Public);
|
||||
let mut mul_ro = Self::poly_trait("Mul", params.clone(), vec![], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), o.clone());
|
||||
mul_ro.register_decl("__mul__", op_t, Public);
|
||||
let mut div_ro = Self::poly_trait("Div", params.clone(), vec![], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(poly("Div", ty_params.clone()), r, o);
|
||||
div_ro.register_decl("__div__", op_t, Public);
|
||||
let sup = poly("Add", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "AddO")]);
|
||||
let mut add = Self::mono_trait("Add", vec![sup], Self::TOP_LEVEL);
|
||||
add.register_decl("AddO", Type, Public);
|
||||
let sup = poly("Sub", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "SubO")]);
|
||||
let mut sub = Self::mono_trait("Sub", vec![sup], Self::TOP_LEVEL);
|
||||
sub.register_decl("SubO", Type, Public);
|
||||
let sup = poly("Mul", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "MulO")]);
|
||||
let mut mul = Self::mono_trait("Mul", vec![sup], Self::TOP_LEVEL);
|
||||
mul.register_decl("MulO", Type, Public);
|
||||
let sup = Type::poly("Div", vec![mono_q_tp("Self"), TyParam::mono_proj(mono_q_tp("Self"), "DivO")]);
|
||||
let mut div = Self::mono_trait("Div", vec![sup], Self::TOP_LEVEL);
|
||||
div.register_decl("DivO", Type, Public);
|
||||
let num = Self::mono_trait("Num", vec![
|
||||
mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"),
|
||||
], Self::TOP_LEVEL);
|
||||
self.register_type(mono("Eq"), eq, Const);
|
||||
self.register_type(mono("Ord"), ord, Const);
|
||||
self.register_type(mono("Seq"), seq, Const);
|
||||
self.register_type(poly("Add", ty_params.clone()), add_ro, Const);
|
||||
self.register_type(poly("Sub", ty_params.clone()), sub_ro, Const);
|
||||
self.register_type(poly("Mul", ty_params.clone()), mul_ro, Const);
|
||||
self.register_type(poly("Div", ty_params), div_ro, Const);
|
||||
self.register_type(mono("Num"), num, Const);
|
||||
}
|
||||
|
||||
fn init_builtin_classes(&mut self) {
|
||||
let mut obj = Self::mono_class("Obj", vec![], vec![], Self::TOP_LEVEL);
|
||||
let t = fn0_met(mono_q("Self"), mono_q("Self"));
|
||||
let t = quant(t, set!{subtype(mono_q("Self"), mono("Obj"))});
|
||||
obj.register_impl("clone", t, Const, Public);
|
||||
obj.register_impl("__module__", Str, Const, Public);
|
||||
obj.register_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public);
|
||||
obj.register_impl("__repr__", fn0_met(Obj, Str), Immutable, Public);
|
||||
obj.register_impl("__str__", fn0_met(Obj, Str), Immutable, Public);
|
||||
obj.register_impl(
|
||||
"__dict__",
|
||||
fn0_met(Obj, Type::dict(Str, Obj)),
|
||||
Immutable,
|
||||
Public,
|
||||
);
|
||||
obj.register_impl(
|
||||
"__bytes__",
|
||||
fn0_met(Obj, Type::mono("Bytes")),
|
||||
Immutable,
|
||||
Public,
|
||||
);
|
||||
// let mut record = Self::mono_trait("Record", vec![Obj], Self::TOP_LEVEL);
|
||||
// let mut class = Self::mono_class("Class", vec![Type, Obj], Self::TOP_LEVEL);
|
||||
let mut float = Self::mono_class("Float", vec![Obj], vec![
|
||||
mono("Num"),
|
||||
mono("Ord"), mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"),
|
||||
mono("Mutate"),
|
||||
], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(Float, Float, Float);
|
||||
float.register_impl("__add__", op_t.clone(), Const, Public);
|
||||
float.register_impl("__sub__", op_t.clone(), Const, Public);
|
||||
float.register_impl("__mul__", op_t.clone(), Const, Public);
|
||||
float.register_impl("__div__", op_t , Const, Public);
|
||||
float.register_impl("Real", Float, Const, Public);
|
||||
float.register_impl("Imag", Float, Const, Public);
|
||||
let mut ratio = Self::mono_class("Ratio", vec![Obj], vec![
|
||||
mono("Num"),
|
||||
mono("Ord"), mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"),
|
||||
mono("Mutate"),
|
||||
], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(Ratio, Ratio, Ratio);
|
||||
ratio.register_impl("__add__", op_t.clone(), Const, Public);
|
||||
ratio.register_impl("__sub__", op_t.clone(), Const, Public);
|
||||
ratio.register_impl("__mul__", op_t.clone(), Const, Public);
|
||||
ratio.register_impl("__div__", op_t , Const, Public);
|
||||
ratio.register_impl("Real", Ratio, Const, Public);
|
||||
ratio.register_impl("Imag", Ratio, Const, Public);
|
||||
let mut int = Self::mono_class("Int", vec![Obj], vec![
|
||||
mono("Num"),
|
||||
mono("Rational"), mono("Integral"),
|
||||
mono("Ord"), mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"),
|
||||
mono("Mutate"),
|
||||
], Self::TOP_LEVEL);
|
||||
int.register_impl("abs", fn0_met(Int, Nat), Immutable, Public);
|
||||
// __div__ is not included in Int (cast to Float)
|
||||
let op_t = fn1_met(Int, Int, Int);
|
||||
int.register_impl("__add__", op_t.clone(), Const, Public);
|
||||
int.register_impl("__sub__", op_t.clone(), Const, Public);
|
||||
int.register_impl("__mul__", op_t, Const, Public);
|
||||
int.register_impl("Real", Int, Const, Public);
|
||||
int.register_impl("Imag", Int, Const, Public);
|
||||
int.super_traits.push(poly("Add", vec![ty_tp(Int), ty_tp(Int)]));
|
||||
int.super_traits.push(poly("Sub", vec![ty_tp(Int), ty_tp(Int)]));
|
||||
int.super_traits.push(poly("Mul", vec![ty_tp(Int), ty_tp(Int)]));
|
||||
int.super_traits.push(poly("Div", vec![ty_tp(Int), ty_tp(Ratio)]));
|
||||
let mut nat = Self::mono_class("Nat", vec![Int, Obj], vec![
|
||||
mono("Num"),
|
||||
mono("Rational"), mono("Integral"),
|
||||
mono("Ord"), mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"),
|
||||
mono("Mutate"),
|
||||
Obj,
|
||||
], Self::TOP_LEVEL);
|
||||
// __sub__, __div__ is not included in Nat (cast to Int)
|
||||
let op_t = fn1_met(Nat, Nat, Nat);
|
||||
nat.register_impl("__add__", op_t.clone(), Const, Public);
|
||||
nat.register_impl("__mul__", op_t, Const, Public);
|
||||
nat.register_impl(
|
||||
"times!",
|
||||
Type::pr_met(Nat, None, vec![param_t("p", nd_proc(vec![], NoneType))], vec![], NoneType),
|
||||
Immutable,
|
||||
Public
|
||||
);
|
||||
nat.register_impl("Real", Nat, Const, Public);
|
||||
nat.register_impl("Imag", Nat, Const, Public);
|
||||
nat.super_traits.push(poly("Add", vec![ty_tp(Nat), ty_tp(Nat)]));
|
||||
nat.super_traits.push(poly("Sub", vec![ty_tp(Nat), ty_tp(Nat)]));
|
||||
nat.super_traits.push(poly("Mul", vec![ty_tp(Nat), ty_tp(Nat)]));
|
||||
nat.super_traits.push(poly("Div", vec![ty_tp(Nat), ty_tp(Ratio)]));
|
||||
let mut bool_ = Self::mono_class("Bool", vec![Nat, Int, Obj], vec![
|
||||
mono("Num"),
|
||||
mono("Rational"), mono("Integral"),
|
||||
mono("Ord"), mono("Eq"),
|
||||
mono("Add"), mono("Sub"), mono("Mul"), mono("Div"),
|
||||
mono("Mutate"),
|
||||
Obj,
|
||||
], Self::TOP_LEVEL);
|
||||
bool_.register_impl("__and__", fn1_met(Bool, Bool, Bool), Const, Public);
|
||||
bool_.register_impl("__or__", fn1_met(Bool, Bool, Bool), Const, Public);
|
||||
let mut str_ = Self::mono_class("Str", vec![Obj], vec![
|
||||
mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(Str)]),
|
||||
], Self::TOP_LEVEL);
|
||||
str_.register_impl("__add__", fn1_met(Str, Str, Str), Const, Public);
|
||||
str_.register_impl("replace", Type::fn_met(
|
||||
Str,
|
||||
vec![param_t("pat", Str), param_t("into", Str)],
|
||||
vec![], Str),
|
||||
Immutable,
|
||||
Public
|
||||
);
|
||||
str_.super_traits.push(poly("Add", vec![ty_tp(Str), ty_tp(Str)]));
|
||||
let mut array = Self::poly_class("Array", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], vec![Obj], vec![
|
||||
mono("Eq"), mono("Mutate"),
|
||||
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))])
|
||||
], Self::TOP_LEVEL);
|
||||
let n = mono_q_tp("N");
|
||||
let m = mono_q_tp("M");
|
||||
let array_t = Type::array(mono_q("T"), n.clone());
|
||||
let t = Type::fn_met(
|
||||
array_t.clone(),
|
||||
vec![param_t("rhs", Type::array(mono_q("T"), m.clone()))],
|
||||
vec![],
|
||||
Type::array(mono_q("T"), n + m)
|
||||
);
|
||||
let t = quant(t, set!{static_instance("N", Nat), static_instance("M", Nat)});
|
||||
array.register_impl("concat", t, Immutable, Public);
|
||||
let mut_type = ConstObj::t(Type::poly("Array!", vec![
|
||||
TyParam::t(mono_q("T")),
|
||||
TyParam::mono_q("N").mutate(),
|
||||
]));
|
||||
// [T; N].MutType! = [T; !N] (neither [T!; N] nor [T; N]!)
|
||||
array.register_const("MutType!", mut_type);
|
||||
let mut type_ = Self::mono_class("Type", vec![Obj], vec![mono("Eq"), mono("Named")], Self::TOP_LEVEL);
|
||||
type_.register_impl("mro", Type::array(Type, TyParam::erased(Nat)), Immutable, Public);
|
||||
let module = Self::mono_class("Module", vec![Obj], vec![mono("Eq"), mono("Named")], Self::TOP_LEVEL);
|
||||
let array_mut_t = Type::poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N")]);
|
||||
let mut array_mut = Self::poly_class("Array!", vec![PS::t_nd("T"), PS::named_nd("N", NatMut)], vec![Obj], vec![
|
||||
mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(mono_q("T"))])
|
||||
], Self::TOP_LEVEL);
|
||||
let t = Type::pr_met(
|
||||
Type::ref_mut(array_mut_t.clone()),
|
||||
Some(Type::ref_mut(poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N") + value(1)]))),
|
||||
vec![param_t("elem", mono_q("T"))],
|
||||
vec![],
|
||||
Type::NoneType,
|
||||
);
|
||||
let t = quant(t, set!{static_instance("T", Type), static_instance("N", NatMut)});
|
||||
array_mut.register_impl("push!", t, Immutable, Public);
|
||||
let range_t = Type::poly("Range", vec![TyParam::t(mono_q("T"))]);
|
||||
let range = Self::poly_class("Range", vec![PS::t_nd("T")], vec![Obj], vec![
|
||||
mono("Eq"), mono("Mutate"),
|
||||
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))])
|
||||
], Self::TOP_LEVEL);
|
||||
self.register_type(Obj, obj, Const);
|
||||
// self.register_type(Type::mono("Record"), vec![], record, Const);
|
||||
// self.register_type(Type::mono("Class"), vec![], class, Const);
|
||||
self.register_type(Float, float, Const);
|
||||
self.register_type(Ratio, ratio, Const);
|
||||
self.register_type(Int, int, Const);
|
||||
self.register_type(Nat, nat, Const);
|
||||
self.register_type(Bool, bool_, Const);
|
||||
self.register_type(Str, str_, Const);
|
||||
self.register_type(Type, type_, Const);
|
||||
self.register_type(Module, module, Const);
|
||||
self.register_type(array_t, array, Const);
|
||||
self.register_type(range_t, range, Const);
|
||||
self.register_type(array_mut_t, array_mut, Const);
|
||||
}
|
||||
|
||||
fn init_builtin_funcs(&mut self) {
|
||||
let t_abs = nd_func(vec![param_t("n", mono("Num"))], Nat);
|
||||
let t_assert = func(vec![param_t("condition", Bool)], vec![param_t("err_message", Str)], NoneType);
|
||||
let t_classof = nd_func(vec![param_t("o", Obj)], Type::option(Class));
|
||||
let t_compile = nd_func(vec![param_t("src", Str)], Code);
|
||||
let t_cond = nd_func(
|
||||
vec![param_t("condition", Bool), param_t("then", mono_q("T")), param_t("else", mono_q("T"))],
|
||||
mono_q("T"),
|
||||
);
|
||||
let t_cond = quant(t_cond, set!{static_instance("T", Type)});
|
||||
let t_discard = nd_func(vec![param_t("o", Obj)], NoneType);
|
||||
let t_id = nd_func(vec![param_t("o", Obj)], Nat);
|
||||
// FIXME: quantify
|
||||
let t_if = func(
|
||||
vec![param_t("cond", Bool), param_t("then", nd_func(vec![], mono_q("T")))],
|
||||
vec![param_t("else", nd_func(vec![], mono_q("T")))],
|
||||
Type::option(mono_q("T")),
|
||||
);
|
||||
let t_if = quant(t_if, set!{static_instance("T", Type)});
|
||||
let t_import = nd_func(vec![param_t("path", Str)], Module);
|
||||
let t_log = nd_func(vec![param_t("objs", Type::var_args(Obj))], NoneType);
|
||||
let t_pyimport = nd_func(vec![param_t("path", Str)], Module);
|
||||
let t_quit = func(vec![], vec![param_t("code", Int)], NoneType);
|
||||
self.register_impl("abs", t_abs, Const, Private);
|
||||
self.register_impl("assert", t_assert, Const, Private);
|
||||
self.register_impl("classof", t_classof, Const, Private);
|
||||
self.register_impl("compile", t_compile, Const, Private);
|
||||
self.register_impl("cond", t_cond, Const, Private);
|
||||
self.register_impl("discard", t_discard, Const, Private);
|
||||
self.register_impl("id" , t_id, Const, Private);
|
||||
self.register_impl("if", t_if, Const, Private);
|
||||
self.register_impl("log", t_log, Const, Private);
|
||||
self.register_impl("import", t_import, Const, Private);
|
||||
self.register_impl("pyimport", t_pyimport, Const, Private);
|
||||
self.register_impl("quit", t_quit, Const, Private);
|
||||
}
|
||||
|
||||
fn init_builtin_procs(&mut self) {
|
||||
let t_print = nd_proc(vec![param_t("objs", Type::var_args(Type::refer(Obj)))], NoneType);
|
||||
let t_input = nd_proc(vec![param_t("msg", Str)], Str);
|
||||
let t_if = proc(
|
||||
vec![param_t("cond", Bool), param_t("then", nd_proc(vec![], mono_q("T")))],
|
||||
vec![param_t("else", nd_proc(vec![], mono_q("T")))],
|
||||
Type::option(mono_q("T"))
|
||||
);
|
||||
let t_if = quant(t_if, set!{static_instance("T", Type)});
|
||||
let t_for = nd_proc(vec![param_t("iter", Type::iter(mono_q("T"))), param_t("p", nd_proc(vec![anon(mono_q("T"))], NoneType))], NoneType);
|
||||
let t_for = quant(t_for, set!{static_instance("T", Type)});
|
||||
let t_while = nd_proc(vec![param_t("cond", BoolMut), param_t("p", nd_proc(vec![], NoneType))], NoneType);
|
||||
self.register_impl("print!", t_print, Const, Private);
|
||||
self.register_impl("input!", t_input, Const, Private);
|
||||
self.register_impl("if!", t_if, Const, Private);
|
||||
self.register_impl("for!", t_for, Const, Private);
|
||||
self.register_impl("while!", t_while, Const, Private);
|
||||
}
|
||||
|
||||
fn init_builtin_operators(&mut self) {
|
||||
/* binary */
|
||||
let l = mono_q("L");
|
||||
let r = mono_q("R");
|
||||
let o = mono_q("O");
|
||||
let params = vec![mono_q_tp("R"), mono_q_tp("O")];
|
||||
let op_t = Type::func2(l.clone(), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{
|
||||
static_instance("R", Type),
|
||||
static_instance("O", Type),
|
||||
subtype(l.clone(), poly("Add", params.clone()))
|
||||
});
|
||||
self.register_impl("__add__", op_t, Const, Private);
|
||||
let op_t = Type::func2(l.clone(), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{
|
||||
static_instance("R", Type),
|
||||
static_instance("O", Type),
|
||||
subtype(l.clone(), poly("Sub", params.clone()))
|
||||
});
|
||||
self.register_impl("__sub__", op_t, Const, Private);
|
||||
let op_t = Type::func2(l.clone(), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{subtype(l.clone(), poly("Mul", params.clone()))});
|
||||
self.register_impl("__mul__", op_t, Const, Private);
|
||||
let op_t = Type::func2(l.clone(), r.clone(), o.clone());
|
||||
let op_t = quant(op_t, set!{subtype(l, poly("Mul", params.clone()))});
|
||||
self.register_impl("__div__", op_t, Const, Private);
|
||||
let m = mono_q("M");
|
||||
let op_t = Type::func2(m.clone(), m.clone(), m.clone());
|
||||
let op_t = quant(op_t, set!{subtype(m, poly("Mul", vec![]))});
|
||||
self.register_impl("__pow__", op_t, Const, Private);
|
||||
let d = mono_q("D");
|
||||
let op_t = Type::func2(d.clone(), d.clone(), d.clone());
|
||||
let op_t = quant(op_t, set!{subtype(d, poly("Div", vec![]))});
|
||||
self.register_impl("__mod__", op_t, Const, Private);
|
||||
let e = mono_q("E");
|
||||
let op_t = Type::func2(e.clone(), e.clone(), Bool);
|
||||
let op_t = quant(op_t, set!{subtype(e, poly("Eq", vec![]))});
|
||||
self.register_impl("__eq__", op_t.clone(), Const, Private);
|
||||
self.register_impl("__ne__", op_t, Const, Private);
|
||||
let o = mono_q("O");
|
||||
let op_t = Type::func2(o.clone(), o.clone(), Bool);
|
||||
let op_t = quant(op_t, set!{subtype(o, poly("Ord", vec![]))});
|
||||
self.register_impl("__lt__", op_t.clone(), Const, Private);
|
||||
self.register_impl("__le__", op_t.clone(), Const, Private);
|
||||
self.register_impl("__gt__", op_t.clone(), Const, Private);
|
||||
self.register_impl("__ge__", op_t, Const, Private);
|
||||
self.register_impl("__and__", Type::func2(Bool, Bool, Bool), Const, Private);
|
||||
self.register_impl("__or__", Type::func2(Bool, Bool, Bool), Const, Private);
|
||||
/* unary */
|
||||
// TODO: Boolの+/-は警告を出したい
|
||||
let n = mono_q("N");
|
||||
let op_t = fn0_met(n.clone(), n.clone());
|
||||
let op_t = quant(op_t, set!{subtype(n, mono("Num"))});
|
||||
self.register_decl("__pos__", op_t.clone(), Private);
|
||||
self.register_decl("__neg__", op_t, Private);
|
||||
let t = mono_q("T");
|
||||
let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone()));
|
||||
let op_t = quant(op_t, set!{subtype(t, mono("Ord"))});
|
||||
self.register_decl("__rng__", op_t.clone(), Private);
|
||||
self.register_decl("__lorng__", op_t.clone(), Private);
|
||||
self.register_decl("__rorng__", op_t.clone(), Private);
|
||||
self.register_decl("__orng__", op_t, Private);
|
||||
let op_t = Type::func1(mono_q("T"), Type::mono_proj(mono_q("T"), "MutType!"));
|
||||
let op_t = quant(op_t, set!{subtype(mono_q("T"), mono("Mutate"))});
|
||||
self.register_impl("__mutate__", op_t, Const, Private);
|
||||
}
|
||||
|
||||
fn init_builtin_patches(&mut self) {
|
||||
let m = mono_q_tp("M");
|
||||
let n = mono_q_tp("N");
|
||||
let o = mono_q_tp("O");
|
||||
let p = mono_q_tp("P");
|
||||
let params = vec![
|
||||
PS::named_nd("M", Int), PS::named_nd("N", Int),
|
||||
PS::named_nd("O", Int), PS::named_nd("P", Int),
|
||||
];
|
||||
// Interval is a bounding patch connecting M..N and (Add(O..P, M+O..N..P), Sub(O..P, M-P..N-O))
|
||||
let mut interval = Self::poly_patch("Interval", params, vec![Type::from(&m..=&n)], vec![
|
||||
poly("Add", vec![TyParam::from(&o..=&p), TyParam::from(m.clone() + o.clone() ..= n.clone() + p.clone())]),
|
||||
poly("Sub", vec![TyParam::from(&o..=&p), TyParam::from(m.clone() - p.clone() ..= n.clone() - o.clone())]),
|
||||
], Self::TOP_LEVEL);
|
||||
let op_t = fn1_met(
|
||||
Type::from(&m..=&n),
|
||||
Type::from(&o..=&p),
|
||||
Type::from(m.clone() + o.clone() ..= n.clone() + p.clone()),
|
||||
);
|
||||
interval.register_impl("__add__", op_t, Const, Public);
|
||||
let op_t = fn1_met(
|
||||
Type::from(&m..=&n),
|
||||
Type::from(&o..=&p),
|
||||
Type::from(m - p ..= n - o),
|
||||
);
|
||||
interval.register_impl("__sub__", op_t, Const, Public);
|
||||
self.register_patch("Interval", interval, Const);
|
||||
// eq.register_impl("__ne__", op_t, Const, Public);
|
||||
// ord.register_impl("__le__", op_t.clone(), Const, Public);
|
||||
// ord.register_impl("__gt__", op_t.clone(), Const, Public);
|
||||
// ord.register_impl("__ge__", op_t, Const, Public);
|
||||
}
|
||||
|
||||
pub(crate) fn init_py_math_mod() -> Self {
|
||||
let mut math = Context::module("math".into(), 10);
|
||||
math.register_impl("pi", Type::Float, Immutable, Public);
|
||||
math.register_impl("tau", Type::Float, Immutable, Public);
|
||||
math.register_impl("e", Type::Float, Immutable, Public);
|
||||
math.register_impl("sin", Type::func1(Float, Float), Immutable, Public);
|
||||
math.register_impl("cos", Type::func1(Float, Float), Immutable, Public);
|
||||
math.register_impl("tan", Type::func1(Float, Float), Immutable, Public);
|
||||
math
|
||||
}
|
||||
|
||||
pub(crate) fn init_py_random_mod() -> Self {
|
||||
let mut random = Context::module("random".into(), 10);
|
||||
random.register_impl("seed!", Type::proc(vec![], vec![
|
||||
param_t("a", Type::mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
|
||||
param_t("version", Type::Int),
|
||||
], NoneType), Immutable, Public);
|
||||
random.register_impl("randint!", nd_proc(vec![param_t("a", Int), param_t("b", Int)], Int), Immutable, Public);
|
||||
let t = nd_proc(vec![param_t("seq", Type::poly("Seq", vec![ty_tp(mono_q("T"))]))], mono_q("T"));
|
||||
let t = quant(t, set!{static_instance("T", Type)});
|
||||
random.register_impl("choice!", t, Immutable, Public);
|
||||
random
|
||||
}
|
||||
|
||||
pub(crate) fn init_builtins() -> Self {
|
||||
// TODO: capacityを正確に把握する
|
||||
let mut ctx = Context::module("<builtins>".into(), 40);
|
||||
ctx.init_builtin_funcs();
|
||||
ctx.init_builtin_procs();
|
||||
ctx.init_builtin_operators();
|
||||
ctx.init_builtin_traits();
|
||||
ctx.init_builtin_classes();
|
||||
ctx.init_builtin_patches();
|
||||
ctx
|
||||
}
|
||||
}
|
18
compiler/erg_compiler/lib.rs
Normal file
18
compiler/erg_compiler/lib.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
//! defines the compiler for Erg (ergc).
|
||||
extern crate erg_common;
|
||||
pub extern crate erg_parser;
|
||||
|
||||
mod compile;
|
||||
pub use compile::*;
|
||||
mod codegen;
|
||||
pub mod effectcheck;
|
||||
pub mod error;
|
||||
pub mod eval;
|
||||
pub mod hir;
|
||||
pub mod initialize;
|
||||
pub mod lower;
|
||||
pub use lower::ASTLowerer;
|
||||
pub mod optimize;
|
||||
pub mod ownercheck;
|
||||
pub mod context;
|
||||
pub mod varinfo;
|
363
compiler/erg_compiler/lower.rs
Normal file
363
compiler/erg_compiler/lower.rs
Normal file
|
@ -0,0 +1,363 @@
|
|||
//! implements `ASTLowerer`.
|
||||
//!
|
||||
//! ASTLowerer(ASTからHIRへの変換器)を実装
|
||||
use erg_common::{switch_lang, log, fn_name};
|
||||
use erg_common::color::{GREEN, RED, RESET};
|
||||
use erg_common::error::Location;
|
||||
use erg_common::traits::{Locational, Stream, HasType};
|
||||
use erg_common::ty::{Type, ParamTy};
|
||||
use erg_common::get_hash;
|
||||
|
||||
use erg_parser::ast;
|
||||
use erg_parser::ast::{AST};
|
||||
|
||||
use crate::hir;
|
||||
use crate::hir::{HIR};
|
||||
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
|
||||
use crate::context::{Context, ContextKind, RegistrationMode};
|
||||
use crate::varinfo::{Visibility};
|
||||
use Visibility::*;
|
||||
|
||||
/// Singleton that checks types of an AST, and convert (lower) it into a HIR
|
||||
#[derive(Debug)]
|
||||
pub struct ASTLowerer {
|
||||
pub(crate) mod_ctx: Context,
|
||||
errs: LowerErrors,
|
||||
warns: LowerWarnings,
|
||||
}
|
||||
|
||||
impl ASTLowerer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mod_ctx: Context::new(
|
||||
"<module>".into(),
|
||||
ContextKind::Module,
|
||||
vec![],
|
||||
Some(Context::init_builtins()),
|
||||
vec![],
|
||||
vec![],
|
||||
0
|
||||
),
|
||||
errs: LowerErrors::empty(),
|
||||
warns: LowerWarnings::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn return_t_check(&self, loc: Location, name: &str, expect: &Type, found: &Type) -> LowerResult<()> {
|
||||
self.mod_ctx
|
||||
.unify(expect, found, Some(loc), None)
|
||||
.or_else(|_| Err(LowerError::type_mismatch_error(
|
||||
loc,
|
||||
self.mod_ctx.caused_by(),
|
||||
name,
|
||||
expect,
|
||||
found,
|
||||
)))
|
||||
}
|
||||
|
||||
fn use_check(&self, expr: hir::Expr, mode: &str) -> LowerResult<hir::Expr> {
|
||||
if mode != "eval" && !expr.ref_t().is_nonelike() {
|
||||
Err(LowerError::syntax_error(
|
||||
0,
|
||||
expr.loc(),
|
||||
self.mod_ctx.name.clone(),
|
||||
switch_lang!(
|
||||
"the evaluation result of the expression is not used",
|
||||
"式の評価結果が使われていません",
|
||||
),
|
||||
Some(switch_lang!(
|
||||
"if you don't use the value, use `discard` function",
|
||||
"値を使わない場合は、discard関数を使用してください",
|
||||
).into())
|
||||
))
|
||||
} else {
|
||||
Ok(expr)
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_append_errs(&mut self) {
|
||||
if let Err(mut errs) = self.mod_ctx.pop() {
|
||||
self.errs.append(&mut errs);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_array(&mut self, array: ast::Array, check: bool) -> LowerResult<hir::Array> {
|
||||
log!("[DEBUG] entered {}({array})", fn_name!());
|
||||
let mut hir_array = hir::Array::new(array.l_sqbr, array.r_sqbr, self.mod_ctx.level, hir::Args::empty(), None);
|
||||
for elem in array.elems.into_iters().0 {
|
||||
hir_array.push(self.lower_expr(elem.expr, check)?);
|
||||
}
|
||||
Ok(hir_array)
|
||||
}
|
||||
|
||||
/// call全体で推論できる場合があり、そのときはcheck: falseにする
|
||||
fn lower_acc(&mut self, acc: ast::Accessor, check: bool) -> LowerResult<hir::Accessor> {
|
||||
log!("[DEBUG] entered {}({acc})", fn_name!());
|
||||
match acc {
|
||||
ast::Accessor::Local(n) => {
|
||||
let (t, __name__) = if check {
|
||||
(
|
||||
self.mod_ctx.get_local_t(&n.symbol, &self.mod_ctx.name)?,
|
||||
self.mod_ctx.get_local_uniq_obj_name(&n.symbol),
|
||||
)
|
||||
} else { (Type::ASTOmitted, None) };
|
||||
let acc = hir::Accessor::Local(hir::Local::new(n.symbol, __name__, t));
|
||||
Ok(acc)
|
||||
}
|
||||
ast::Accessor::Attr(a) => {
|
||||
let obj = self.lower_expr(*a.obj, true)?;
|
||||
let t = if check {
|
||||
self.mod_ctx.get_attr_t(&obj, &a.name.symbol, &self.mod_ctx.name)?
|
||||
} else { Type::ASTOmitted };
|
||||
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, a.name.symbol, t));
|
||||
Ok(acc)
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_bin(&mut self, bin: ast::BinOp) -> LowerResult<hir::BinOp> {
|
||||
log!("[DEBUG] entered {}({bin})", fn_name!());
|
||||
let mut args = bin.args.into_iter();
|
||||
let lhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
|
||||
let rhs = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
|
||||
let args = [lhs, rhs];
|
||||
let t = self.mod_ctx.get_binop_t(&bin.op, &args, &self.mod_ctx.name)?;
|
||||
let mut args = args.into_iter();
|
||||
let lhs = args.next().unwrap().expr;
|
||||
let rhs = args.next().unwrap().expr;
|
||||
Ok(hir::BinOp::new(bin.op, lhs, rhs, t))
|
||||
}
|
||||
|
||||
fn lower_unary(&mut self, unary: ast::UnaryOp) -> LowerResult<hir::UnaryOp> {
|
||||
log!("[DEBUG] entered {}({unary})", fn_name!());
|
||||
let mut args = unary.args.into_iter();
|
||||
let arg = hir::PosArg::new(self.lower_expr(*args.next().unwrap(), true)?);
|
||||
let args = [arg];
|
||||
let t = self.mod_ctx.get_unaryop_t(&unary.op, &args, &self.mod_ctx.name)?;
|
||||
let mut args = args.into_iter();
|
||||
let expr = args.next().unwrap().expr;
|
||||
Ok(hir::UnaryOp::new(unary.op, expr, t))
|
||||
}
|
||||
|
||||
fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
|
||||
log!("[DEBUG] entered {}({}(...))", fn_name!(), call.obj);
|
||||
let (pos_args, kw_args, paren) = call.args.deconstruct();
|
||||
let mut hir_args = hir::Args::new(Vec::with_capacity(pos_args.len()), Vec::with_capacity(kw_args.len()), paren);
|
||||
for arg in pos_args.into_iter() {
|
||||
hir_args.push_pos(hir::PosArg::new(self.lower_expr(arg.expr, true)?));
|
||||
}
|
||||
for arg in kw_args.into_iter() {
|
||||
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr, true)?));
|
||||
}
|
||||
let mut obj = self.lower_expr(*call.obj, false)?;
|
||||
let t = self.mod_ctx.get_call_t(&mut obj, hir_args.pos_args(), hir_args.kw_args(), &self.mod_ctx.name)?;
|
||||
Ok(hir::Call::new(obj, hir_args, t))
|
||||
}
|
||||
|
||||
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
|
||||
log!("[DEBUG] entered {}({lambda})", fn_name!());
|
||||
let is_procedural = lambda.is_procedural();
|
||||
let id = get_hash(&lambda.sig);
|
||||
let name = format!("<lambda_{id}>");
|
||||
let kind = if is_procedural { ContextKind::Proc } else { ContextKind::Func };
|
||||
self.mod_ctx.grow(&name, kind, Private)?;
|
||||
self.mod_ctx.assign_params(&lambda.sig.params, None)
|
||||
.map_err(|e| { self.pop_append_errs(); e })?;
|
||||
self.mod_ctx.preregister(lambda.body.ref_payload())
|
||||
.map_err(|e| { self.pop_append_errs(); e })?;
|
||||
let body = self.lower_block(lambda.body)
|
||||
.map_err(|e| { self.pop_append_errs(); e })?;
|
||||
// impls => named non-default params + named default params + embedded params (will be discarded)
|
||||
// unnnamed_params => unnamed non-default params + unnamed default params
|
||||
// non default params = [unnamed non-default params + unnamed default params].sorted() // sort by pos
|
||||
// default params = [unnamed default params, named default params].sorted()
|
||||
let (named_non_default_params, named_default_params) = {
|
||||
let (named_default_params, named_non_default_params_and_embeddeds): (Vec<_>, Vec<_>) = self.mod_ctx.impls.iter()
|
||||
.filter(|(_, v)| v.kind.is_parameter())
|
||||
.partition(|(_, v)| v.kind.has_default());
|
||||
let (_, named_non_default_params): (Vec<_>, Vec<_>)= named_non_default_params_and_embeddeds.into_iter()
|
||||
.partition(|(_, v)| v.kind.is_embedded_param());
|
||||
(
|
||||
named_non_default_params.into_iter()
|
||||
.map(|(n, v)| (v.kind.pos_as_param().unwrap(), ParamTy::new(Some(n.inspect().clone()), v.t())))
|
||||
.collect::<Vec<_>>(),
|
||||
named_default_params.into_iter()
|
||||
.map(|(n, v)| (v.kind.pos_as_param().unwrap(), ParamTy::new(Some(n.inspect().clone()), v.t())))
|
||||
.collect::<Vec<_>>()
|
||||
)
|
||||
};
|
||||
let (unnamed_non_default_params, unnamed_default_params) = {
|
||||
let (unnamed_default_params, unnamed_non_default_params): (Vec<_>, Vec<_>) = self.mod_ctx.unnamed_params.iter()
|
||||
.map(|v| (v, ParamTy::anonymous(v.t())))
|
||||
.partition(|(v, _)| v.kind.has_default());
|
||||
(
|
||||
unnamed_non_default_params.into_iter()
|
||||
.map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt)).collect(),
|
||||
unnamed_default_params.into_iter()
|
||||
.map(|(v, pt)| (v.kind.pos_as_param().unwrap(), pt)).collect(),
|
||||
)
|
||||
};
|
||||
let non_default_params = {
|
||||
let mut a = [unnamed_non_default_params, named_non_default_params].concat();
|
||||
a.sort_by(|(l, _), (r, _)| l.cmp(r));
|
||||
a.into_iter().map(|(_, p)| p).collect::<Vec<_>>()
|
||||
};
|
||||
let default_params = {
|
||||
let mut a = [unnamed_default_params, named_default_params].concat();
|
||||
a.sort_by(|(l, _), (r, _)| l.cmp(r));
|
||||
a.into_iter().map(|(_, p)| p).collect::<Vec<_>>()
|
||||
};
|
||||
let bounds = self.mod_ctx.instantiate_ty_bounds(&lambda.sig.bounds, RegistrationMode::Normal)
|
||||
.map_err(|e| { self.pop_append_errs(); e })?;
|
||||
self.pop_append_errs();
|
||||
let t = if is_procedural {
|
||||
Type::proc(non_default_params, default_params, body.t())
|
||||
} else {
|
||||
Type::func(non_default_params, default_params, body.t())
|
||||
};
|
||||
let t = if bounds.is_empty() { t } else { Type::quantified(t, bounds) };
|
||||
Ok(hir::Lambda::new(id, lambda.sig.params, lambda.op, body, t))
|
||||
}
|
||||
|
||||
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
|
||||
log!("[DEBUG] entered {}({})", fn_name!(), def.sig);
|
||||
// FIXME: Instant
|
||||
self.mod_ctx.grow(def.sig.name_as_str(), ContextKind::Instant, Private)?;
|
||||
let res = match def.sig {
|
||||
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
|
||||
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
|
||||
};
|
||||
// TODO: Context上の関数に型境界情報を追加
|
||||
self.pop_append_errs();
|
||||
res
|
||||
}
|
||||
|
||||
fn lower_var_def(&mut self, sig: ast::VarSignature, body: ast::DefBody) -> LowerResult<hir::Def> {
|
||||
log!("[DEBUG] entered {}({sig})", fn_name!());
|
||||
self.mod_ctx.preregister(body.block.ref_payload())?;
|
||||
let block = self.lower_block(body.block)?;
|
||||
let found_body_t = block.ref_t();
|
||||
let opt_expect_body_t = self.mod_ctx
|
||||
.outer.as_ref().unwrap()
|
||||
.get_current_scope_local_var(sig.inspect().unwrap())
|
||||
.map(|vi| vi.t.clone());
|
||||
let name = sig.pat.inspect().unwrap();
|
||||
if let Some(expect_body_t) = opt_expect_body_t {
|
||||
if let Err(e) = self.return_t_check(sig.loc(), name, &expect_body_t, &found_body_t) {
|
||||
self.errs.push(e);
|
||||
}
|
||||
}
|
||||
let id = body.id;
|
||||
// TODO: cover all VarPatterns
|
||||
self.mod_ctx.outer.as_mut().unwrap().assign_var(&sig, id, found_body_t)?;
|
||||
match block.first().unwrap() {
|
||||
hir::Expr::Call(call) => {
|
||||
if let ast::VarPattern::VarName(name) = &sig.pat {
|
||||
if call.is_import_call() {
|
||||
self.mod_ctx.outer.as_mut()
|
||||
.unwrap()
|
||||
.import_mod(name, &call.args.pos_args().first().unwrap().expr)?;
|
||||
}
|
||||
} else { todo!() }
|
||||
},
|
||||
_other => {}
|
||||
}
|
||||
let sig = hir::VarSignature::new(sig.pat, found_body_t.clone());
|
||||
let body = hir::DefBody::new(body.op, block, body.id);
|
||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||
}
|
||||
|
||||
// NOTE: 呼ばれている間はinner scopeなので注意
|
||||
fn lower_subr_def(&mut self, sig: ast::SubrSignature, body: ast::DefBody) -> LowerResult<hir::Def> {
|
||||
log!("[DEBUG] entered {}({sig})", fn_name!());
|
||||
let t = self.mod_ctx
|
||||
.outer.as_ref().unwrap()
|
||||
.get_current_scope_local_var(sig.name.inspect())
|
||||
.unwrap_or_else(|| {
|
||||
log!("{}\n", sig.name.inspect());
|
||||
log!("{}\n", self.mod_ctx.outer.as_ref().unwrap());
|
||||
panic!()
|
||||
}) // FIXME: or instantiate
|
||||
.t.clone();
|
||||
self.mod_ctx.assign_params(&sig.params, None)?;
|
||||
self.mod_ctx.preregister(body.block.ref_payload())?;
|
||||
let block = self.lower_block(body.block)?;
|
||||
let found_body_t = block.ref_t();
|
||||
let expect_body_t = t.return_t().unwrap();
|
||||
if let Err(e) = self.return_t_check(sig.loc(), sig.name.inspect(), expect_body_t, found_body_t) {
|
||||
self.errs.push(e);
|
||||
}
|
||||
let id = body.id;
|
||||
self.mod_ctx.outer.as_mut().unwrap().assign_subr(&sig, id, found_body_t)?;
|
||||
let sig = hir::SubrSignature::new(sig.name, sig.params, t);
|
||||
let body = hir::DefBody::new(body.op, block, body.id);
|
||||
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
|
||||
}
|
||||
|
||||
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
|
||||
// so turn off type checking (check=false)
|
||||
fn lower_expr(&mut self, expr: ast::Expr, check: bool) -> LowerResult<hir::Expr> {
|
||||
log!("[DEBUG] entered {}", fn_name!());
|
||||
match expr {
|
||||
ast::Expr::Lit(lit) => {
|
||||
Ok(hir::Expr::Lit(hir::Literal::from(lit.token)))
|
||||
},
|
||||
ast::Expr::Array(arr) => {
|
||||
Ok(hir::Expr::Array(self.lower_array(arr, check)?))
|
||||
}
|
||||
ast::Expr::Accessor(acc) => {
|
||||
Ok(hir::Expr::Accessor(self.lower_acc(acc, check)?))
|
||||
}
|
||||
ast::Expr::BinOp(bin) => {
|
||||
Ok(hir::Expr::BinOp(self.lower_bin(bin)?))
|
||||
}
|
||||
ast::Expr::UnaryOp(unary) => {
|
||||
Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?))
|
||||
}
|
||||
ast::Expr::Call(call) => {
|
||||
Ok(hir::Expr::Call(self.lower_call(call)?))
|
||||
}
|
||||
ast::Expr::Lambda(lambda) => {
|
||||
Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?))
|
||||
}
|
||||
ast::Expr::Def(def) => {
|
||||
Ok(hir::Expr::Def(self.lower_def(def)?))
|
||||
}
|
||||
other => todo!("{other}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_block(&mut self, ast_block: ast::Block) -> LowerResult<hir::Block> {
|
||||
log!("[DEBUG] entered {}", fn_name!());
|
||||
let mut hir_block = Vec::with_capacity(ast_block.len());
|
||||
for expr in ast_block.into_iter() {
|
||||
let expr = self.lower_expr(expr, true)?;
|
||||
hir_block.push(expr);
|
||||
}
|
||||
Ok(hir::Block::new(hir_block))
|
||||
}
|
||||
|
||||
pub fn lower(&mut self, ast: AST, mode: &str) -> Result<(HIR, LowerWarnings), LowerErrors> {
|
||||
log!("{GREEN}[DEBUG] the type-checking process has started.");
|
||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||
self.mod_ctx.preregister(ast.module.ref_payload())?;
|
||||
for expr in ast.module.into_iter() {
|
||||
match self.lower_expr(expr, true)
|
||||
.and_then(|e| self.use_check(e, mode)) {
|
||||
Ok(expr) => { module.push(expr); }
|
||||
Err(e) => { self.errs.push(e); },
|
||||
}
|
||||
}
|
||||
let hir = HIR::new(ast.name, module);
|
||||
log!("[DEBUG] {}() has completed, found errors: {}", fn_name!(), self.errs.len());
|
||||
if self.errs.is_empty() {
|
||||
log!("HIR:\n{hir}");
|
||||
log!("[DEBUG] the type-checking process has completed.{RESET}");
|
||||
Ok((hir, LowerWarnings::from(self.warns.take_all())))
|
||||
} else {
|
||||
log!("{RED}[DEBUG] the type-checking process has failed.{RESET}");
|
||||
Err(LowerErrors::from(self.errs.take_all()))
|
||||
}
|
||||
}
|
||||
}
|
28
compiler/erg_compiler/main.rs
Normal file
28
compiler/erg_compiler/main.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
extern crate erg_common;
|
||||
extern crate erg_compiler;
|
||||
extern crate erg_parser;
|
||||
|
||||
use std::process;
|
||||
|
||||
use erg_common::deserialize::Deserializer;
|
||||
use erg_common::config::{ErgConfig};
|
||||
use erg_common::traits::Runnable;
|
||||
|
||||
use erg_compiler::Compiler;
|
||||
|
||||
use erg_parser::lex::LexerRunner;
|
||||
use erg_parser::ParserRunner;
|
||||
|
||||
fn main() {
|
||||
let cfg = ErgConfig::parse();
|
||||
match cfg.mode {
|
||||
"lex" => { LexerRunner::run(cfg); }
|
||||
"parse" => { ParserRunner::run(cfg); }
|
||||
"compile" | "exec" => { Compiler::run(cfg); }
|
||||
"read" => { Deserializer::run(cfg); }
|
||||
other => {
|
||||
println!("invalid mode: {other}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
17
compiler/erg_compiler/optimize.rs
Normal file
17
compiler/erg_compiler/optimize.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use crate::hir::HIR;
|
||||
use crate::error::{CompileWarnings};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HIROptimizer {
|
||||
|
||||
}
|
||||
|
||||
impl HIROptimizer {
|
||||
pub fn fold_constants(&mut self, mut _hir: HIR) -> HIR { todo!() }
|
||||
|
||||
pub fn eliminate_unused_variables(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) { todo!() }
|
||||
|
||||
pub fn eliminate_dead_code(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) {
|
||||
todo!()
|
||||
}
|
||||
}
|
213
compiler/erg_compiler/ownercheck.rs
Normal file
213
compiler/erg_compiler/ownercheck.rs
Normal file
|
@ -0,0 +1,213 @@
|
|||
use erg_common::Str;
|
||||
use erg_common::{log};
|
||||
use erg_common::color::{GREEN, RESET};
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::error::Location;
|
||||
use erg_common::set::Set;
|
||||
use erg_common::traits::{Stream, Locational, HasType};
|
||||
use erg_common::ty::{ArgsOwnership, Ownership};
|
||||
|
||||
use crate::error::{OwnershipError, OwnershipErrors, OwnershipResult};
|
||||
use crate::hir::{HIR, Def, Signature, Accessor, Block, Expr};
|
||||
use crate::varinfo::Visibility;
|
||||
use Visibility::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum WrapperKind {
|
||||
Ref,
|
||||
Rc,
|
||||
Box,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct LocalVars {
|
||||
alive_vars: Set<Str>,
|
||||
dropped_vars: Dict<Str, Location>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OwnershipChecker {
|
||||
path_stack: Vec<(Str, Visibility)>,
|
||||
dict: Dict<Str, LocalVars>,
|
||||
errs: OwnershipErrors,
|
||||
}
|
||||
|
||||
impl OwnershipChecker {
|
||||
pub fn new() -> Self {
|
||||
OwnershipChecker {
|
||||
path_stack: vec![],
|
||||
dict: Dict::new(),
|
||||
errs: OwnershipErrors::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn full_path(&self) -> String {
|
||||
self.path_stack.iter().fold(String::new(), |acc, (path, vis)| {
|
||||
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] }
|
||||
})
|
||||
}
|
||||
|
||||
// moveされた後の変数が使用されていないかチェックする
|
||||
// ProceduralでないメソッドでRefMutが使われているかはSideEffectCheckerでチェックする
|
||||
pub fn check(mut self, hir: HIR) -> OwnershipResult<HIR> {
|
||||
log!("{GREEN}[DEBUG] the ownership checking process has started.{RESET}");
|
||||
self.path_stack.push((hir.name.clone(), Private));
|
||||
self.dict.insert(Str::from(self.full_path()), LocalVars::default());
|
||||
for chunk in hir.module.iter() {
|
||||
self.check_expr(chunk, Ownership::Owned);
|
||||
}
|
||||
log!("{GREEN}[DEBUG] the ownership checking process has completed, found errors: {}{RESET}", self.errs.len());
|
||||
if self.errs.is_empty() {
|
||||
Ok(hir)
|
||||
} else {
|
||||
Err(self.errs)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_block(&mut self, block: &Block) {
|
||||
for chunk in block.iter() {
|
||||
self.check_expr(chunk, Ownership::Owned);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, expr: &Expr, ownership: Ownership) {
|
||||
match expr {
|
||||
Expr::Def(def) => {
|
||||
self.define(&def);
|
||||
let name_and_vis = match &def.sig {
|
||||
Signature::Var(var) =>
|
||||
// TODO: visibility
|
||||
if let Some(name) = var.inspect() { (name.clone(), Private) }
|
||||
else { (Str::ever("::<instant>"), Private) },
|
||||
Signature::Subr(subr) => (subr.name.inspect().clone(), Private),
|
||||
};
|
||||
self.path_stack.push(name_and_vis);
|
||||
self.dict.insert(Str::from(self.full_path()), LocalVars::default());
|
||||
self.check_block(&def.body.block);
|
||||
self.path_stack.pop();
|
||||
},
|
||||
Expr::Accessor(Accessor::Local(local)) => {
|
||||
for n in 0..self.path_stack.len() {
|
||||
if let Some(moved_loc) = self.nth_outer_scope(n).dropped_vars.get(local.inspect()) {
|
||||
let moved_loc = *moved_loc;
|
||||
self.errs.push(OwnershipError::move_error(
|
||||
local.inspect(),
|
||||
local.loc(),
|
||||
moved_loc,
|
||||
self.full_path(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if expr.ref_t().is_mut() && ownership.is_owned() {
|
||||
log!("dropped: {}", local.inspect());
|
||||
self.drop(local.inspect(), expr.loc());
|
||||
}
|
||||
},
|
||||
Expr::Accessor(Accessor::Attr(a)) => {
|
||||
if a.ref_t().is_mut() { todo!("ownership checking {a}") }
|
||||
},
|
||||
Expr::Accessor(_a) => todo!(),
|
||||
// TODO: referenced
|
||||
Expr::Call(call) => {
|
||||
self.check_expr(&call.obj, ownership);
|
||||
let args_ownership = call.signature_t().unwrap().args_ownership();
|
||||
match args_ownership {
|
||||
ArgsOwnership::Args{ self_, non_defaults, defaults } => {
|
||||
if let Some(ownership) = self_ {
|
||||
self.check_expr(&call.obj, ownership);
|
||||
}
|
||||
let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults.iter()
|
||||
.enumerate()
|
||||
.partition(|(i, _)| *i == call.args.pos_args().len());
|
||||
for (parg, (_, ownership)) in call.args.pos_args()
|
||||
.iter()
|
||||
.zip(nd_ownerships.into_iter()) {
|
||||
self.check_expr(&parg.expr, *ownership);
|
||||
}
|
||||
for (kwarg, (_, ownership)) in call.args.kw_args()
|
||||
.iter()
|
||||
.zip(d_ownerships.into_iter().chain(defaults.iter().enumerate())) {
|
||||
self.check_expr(&kwarg.expr, *ownership);
|
||||
}
|
||||
},
|
||||
ArgsOwnership::VarArgs(ownership) => {
|
||||
for parg in call.args.pos_args().iter() {
|
||||
self.check_expr(&parg.expr, ownership);
|
||||
}
|
||||
for kwarg in call.args.kw_args().iter() {
|
||||
self.check_expr(&kwarg.expr, ownership);
|
||||
}
|
||||
},
|
||||
other => todo!("{other:?}"),
|
||||
}
|
||||
},
|
||||
// TODO: referenced
|
||||
Expr::BinOp(binop) => {
|
||||
self.check_expr(&binop.lhs, ownership);
|
||||
self.check_expr(&binop.rhs, ownership);
|
||||
},
|
||||
Expr::UnaryOp(unary) => {
|
||||
self.check_expr(&unary.expr, ownership);
|
||||
},
|
||||
Expr::Array(arr) => {
|
||||
for a in arr.elems.pos_args().iter() {
|
||||
self.check_expr(&a.expr, ownership);
|
||||
}
|
||||
},
|
||||
Expr::Dict(dict) => {
|
||||
for a in dict.attrs.kw_args().iter() {
|
||||
// self.check_expr(&a.key);
|
||||
self.check_expr(&a.expr, ownership);
|
||||
}
|
||||
},
|
||||
// TODO: capturing
|
||||
Expr::Lambda(lambda) => {
|
||||
let name_and_vis = (Str::from(format!("<lambda_{}>", lambda.id)), Private);
|
||||
self.path_stack.push(name_and_vis);
|
||||
self.dict.insert(Str::from(self.full_path()), LocalVars::default());
|
||||
self.check_block(&lambda.body);
|
||||
self.path_stack.pop();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: このメソッドを呼ぶとき、スコープを再帰的に検索する
|
||||
#[inline]
|
||||
fn current_scope(&mut self) -> &mut LocalVars {
|
||||
self.dict.get_mut(&self.full_path()[..]).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_outer_scope(&mut self, n: usize) -> &mut LocalVars {
|
||||
let path = self.path_stack.iter()
|
||||
.take(self.path_stack.len() - n)
|
||||
.fold(String::new(), |acc, (path, vis)| {
|
||||
if vis.is_public() { acc + "." + &path[..] } else { acc + "::" + &path[..] }
|
||||
});
|
||||
self.dict.get_mut(&path[..]).unwrap()
|
||||
}
|
||||
|
||||
fn define(&mut self, def: &Def) {
|
||||
match &def.sig {
|
||||
Signature::Var(sig) => {
|
||||
for name in sig.pat.inspects() {
|
||||
self.current_scope().alive_vars.insert(name.clone());
|
||||
}
|
||||
},
|
||||
Signature::Subr(sig) => {
|
||||
self.current_scope().alive_vars.insert(sig.name.inspect().clone());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn drop(&mut self, name: &Str, moved_loc: Location) {
|
||||
for n in 0..self.path_stack.len() {
|
||||
if self.nth_outer_scope(n).alive_vars.remove(name) {
|
||||
self.nth_outer_scope(n).dropped_vars.insert(name.clone(), moved_loc);
|
||||
return
|
||||
}
|
||||
}
|
||||
panic!("variable not found: {name}");
|
||||
}
|
||||
}
|
4
compiler/erg_compiler/tests/dependent.er
Normal file
4
compiler/erg_compiler/tests/dependent.er
Normal file
|
@ -0,0 +1,4 @@
|
|||
concat|T: Type, M, N: Nat|(l: [T; M], r: [T; N]): [T; M + N] = l + r
|
||||
|
||||
l: [Nat; 6] = concat [1, 2, 3], [4, 5, 6]
|
||||
assert l == [1, 2, 3, 4, 5, 6]
|
6
compiler/erg_compiler/tests/fib.er
Normal file
6
compiler/erg_compiler/tests/fib.er
Normal file
|
@ -0,0 +1,6 @@
|
|||
fib 0 = 0
|
||||
fib 1 = 1
|
||||
fib(n: 2..<Inf): Nat = fib(n-1) + fib(n-2)
|
||||
|
||||
print! fib 10
|
||||
assert fib(10) == 55
|
6
compiler/erg_compiler/tests/infer_arr.er
Normal file
6
compiler/erg_compiler/tests/infer_arr.er
Normal file
|
@ -0,0 +1,6 @@
|
|||
v = ![]
|
||||
v.push! 1
|
||||
|
||||
w = v
|
||||
print! w
|
||||
print! v # this should cause a MoveError
|
9
compiler/erg_compiler/tests/side_effect.er
Normal file
9
compiler/erg_compiler/tests/side_effect.er
Normal file
|
@ -0,0 +1,9 @@
|
|||
if True, () -> log "hello"
|
||||
if! True, () => print! "hello"
|
||||
# if True, () => print! "hello" # this should cause a type error
|
||||
if True, () ->
|
||||
_x = "aaa" + input!() # this should cause an effect error
|
||||
print! "hello" # this should cause an effect error
|
||||
|
||||
f x: Int = log x
|
||||
g x: Int = print! x # this should cause an effect error
|
155
compiler/erg_compiler/varinfo.rs
Normal file
155
compiler/erg_compiler/varinfo.rs
Normal file
|
@ -0,0 +1,155 @@
|
|||
use std::fmt;
|
||||
|
||||
use erg_common::Str;
|
||||
use erg_common::ty::{Type};
|
||||
use erg_common::traits::HasType;
|
||||
|
||||
use erg_parser::ast::DefId;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Mutability {
|
||||
Immutable,
|
||||
Const,
|
||||
}
|
||||
|
||||
impl From<&str> for Mutability {
|
||||
fn from(item: &str) -> Self {
|
||||
if item.chars().next().unwrap().is_uppercase() {
|
||||
Self::Const
|
||||
} else { Self::Immutable }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mutability {
|
||||
pub const fn is_const(&self) -> bool { matches!(self, Self::Const) }
|
||||
}
|
||||
|
||||
use Mutability::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(u8)]
|
||||
pub enum Visibility {
|
||||
Private,
|
||||
Public,
|
||||
}
|
||||
|
||||
impl Visibility {
|
||||
pub const fn is_public(&self) -> bool { matches!(self, Self::Public) }
|
||||
pub const fn is_private(&self) -> bool { matches!(self, Self::Private) }
|
||||
}
|
||||
|
||||
use Visibility::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ParamId {
|
||||
/// 変数でないパターン
|
||||
/// e.g. `[x, y]` of `f [x, y], z = ...`
|
||||
PatNonDefault(usize),
|
||||
/// e.g. `[x, y]` of `f [x, y] |= [0, 1] = ...`
|
||||
PatWithDefault(usize),
|
||||
/// 変数パターン
|
||||
/// e.g. `z` of `f [x, y], z = ...`
|
||||
VarNonDefault{ keyword: Str, pos: usize },
|
||||
/// e.g. `z` of `f [x, y], z |= 0 = ...`
|
||||
VarWithDefault{ keyword: Str, pos: usize },
|
||||
/// パターンに埋め込まれた変数パターン
|
||||
/// この場合デフォルト値はない
|
||||
/// e.g. `x` or `y` of `f [x, y], z = ...`
|
||||
Embedded(Str),
|
||||
}
|
||||
|
||||
impl ParamId {
|
||||
pub const fn var_default(keyword: Str, pos: usize) -> Self { Self::VarWithDefault{ keyword, pos } }
|
||||
pub const fn var_non_default(keyword: Str, pos: usize) -> Self { Self::VarNonDefault{ keyword, pos } }
|
||||
|
||||
pub const fn pos(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::PatNonDefault(pos)
|
||||
| Self::PatWithDefault(pos)
|
||||
| Self::VarNonDefault{ pos, .. }
|
||||
| Self::VarWithDefault{ pos, .. } => Some(*pos),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn has_default(&self) -> bool {
|
||||
matches!(self, Self::PatWithDefault(_) | Self::VarWithDefault{ .. })
|
||||
}
|
||||
|
||||
pub const fn is_embedded(&self) -> bool { matches!(self, Self::Embedded(_)) }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum VarKind {
|
||||
Defined(DefId),
|
||||
Declared,
|
||||
Parameter{ def_id: DefId, param_id: ParamId },
|
||||
Generated,
|
||||
DoesNotExist,
|
||||
Builtin,
|
||||
}
|
||||
|
||||
impl VarKind {
|
||||
pub const fn parameter(def_id: DefId, param_id: ParamId) -> Self {
|
||||
Self::Parameter{ def_id, param_id }
|
||||
}
|
||||
|
||||
pub const fn pos_as_param(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::Parameter{ param_id, .. } => param_id.pos(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn has_default(&self) -> bool {
|
||||
match self {
|
||||
Self::Parameter{ param_id, .. } => param_id.has_default(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_parameter(&self) -> bool {
|
||||
matches!(self, Self::Parameter{ .. })
|
||||
}
|
||||
|
||||
pub const fn is_embedded_param(&self) -> bool {
|
||||
matches!(self, Self::Parameter{ param_id, .. } if param_id.is_embedded())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VarInfo {
|
||||
pub t: Type,
|
||||
pub muty: Mutability,
|
||||
pub vis: Visibility,
|
||||
pub kind: VarKind,
|
||||
}
|
||||
|
||||
impl fmt::Display for VarInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "VarInfo{{t: {}, muty: {:?}, vis: {:?} kind: {:?}}}", self.t, self.muty, self.vis, self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasType for VarInfo {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type { &self.t }
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> { None }
|
||||
}
|
||||
|
||||
impl VarInfo {
|
||||
pub const ILLEGAL: &'static Self = &VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist);
|
||||
|
||||
pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self {
|
||||
Self { t, muty, vis, kind }
|
||||
}
|
||||
|
||||
pub fn same_id_as(&self, id: DefId) -> bool {
|
||||
match self.kind {
|
||||
VarKind::Defined(i) | VarKind::Parameter{ def_id: i, .. } => id == i,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue