mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
Add "check" mode
Input::File(String) -> Input::file(PathBuf)
This commit is contained in:
parent
c1d92bc0f4
commit
9b0d66a63a
16 changed files with 200 additions and 184 deletions
|
@ -4,7 +4,9 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, BufRead, BufReader, Read};
|
use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::stdin::GLOBAL_STDIN;
|
use crate::stdin::GLOBAL_STDIN;
|
||||||
use crate::{power_assert, read_file};
|
use crate::{power_assert, read_file};
|
||||||
|
@ -17,8 +19,7 @@ pub const BUILD_DATE: &str = env!("BUILD_DATE");
|
||||||
/// Inputで操作を一本化する
|
/// Inputで操作を一本化する
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
/// filename
|
File(PathBuf),
|
||||||
File(String),
|
|
||||||
REPL,
|
REPL,
|
||||||
/// same content as cfg.command
|
/// same content as cfg.command
|
||||||
Pipe(String),
|
Pipe(String),
|
||||||
|
@ -34,7 +35,7 @@ impl Input {
|
||||||
|
|
||||||
pub fn enclosed_name(&self) -> &str {
|
pub fn enclosed_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => &filename[..],
|
Self::File(filename) => filename.as_os_str().to_str().unwrap_or("???"),
|
||||||
Self::REPL | Self::Pipe(_) => "<stdin>",
|
Self::REPL | Self::Pipe(_) => "<stdin>",
|
||||||
Self::Str(_) => "<string>",
|
Self::Str(_) => "<string>",
|
||||||
Self::Dummy => "<dummy>",
|
Self::Dummy => "<dummy>",
|
||||||
|
@ -44,7 +45,7 @@ impl Input {
|
||||||
/// ファイルに書き出すとき使う
|
/// ファイルに書き出すとき使う
|
||||||
pub fn filename(&self) -> &str {
|
pub fn filename(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => &filename[..],
|
Self::File(filename) => filename.as_os_str().to_str().unwrap_or("???"),
|
||||||
Self::REPL | Self::Pipe(_) => "stdin",
|
Self::REPL | Self::Pipe(_) => "stdin",
|
||||||
Self::Str(_) => "string",
|
Self::Str(_) => "string",
|
||||||
Self::Dummy => "dummy",
|
Self::Dummy => "dummy",
|
||||||
|
@ -54,11 +55,14 @@ impl Input {
|
||||||
pub fn read(&self) -> String {
|
pub fn read(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => {
|
Self::File(filename) => {
|
||||||
let file = match File::open(&filename[..]) {
|
let file = match File::open(filename) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let code = e.raw_os_error().unwrap_or(1);
|
let code = e.raw_os_error().unwrap_or(1);
|
||||||
println!("cannot open '{filename}': [Errno {code}] {e}");
|
println!(
|
||||||
|
"cannot open '{}': [Errno {code}] {e}",
|
||||||
|
filename.to_string_lossy()
|
||||||
|
);
|
||||||
process::exit(code);
|
process::exit(code);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -66,7 +70,10 @@ impl Input {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let code = e.raw_os_error().unwrap_or(1);
|
let code = e.raw_os_error().unwrap_or(1);
|
||||||
println!("cannot read '{filename}': [Errno {code}] {e}");
|
println!(
|
||||||
|
"cannot read '{}': [Errno {code}] {e}",
|
||||||
|
filename.to_string_lossy()
|
||||||
|
);
|
||||||
process::exit(code);
|
process::exit(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +87,7 @@ impl Input {
|
||||||
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> {
|
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> {
|
||||||
power_assert!(ln_begin, >=, 1);
|
power_assert!(ln_begin, >=, 1);
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => match File::open(&filename[..]) {
|
Self::File(filename) => match File::open(filename) {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
let mut codes = vec![];
|
let mut codes = vec![];
|
||||||
let mut lines = BufReader::new(file).lines().skip(ln_begin - 1);
|
let mut lines = BufReader::new(file).lines().skip(ln_begin - 1);
|
||||||
|
@ -238,7 +245,10 @@ impl ErgConfig {
|
||||||
panic!("invalid option: {other}");
|
panic!("invalid option: {other}");
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cfg.input = Input::File(arg);
|
cfg.input = Input::File(
|
||||||
|
PathBuf::from_str(&arg[..])
|
||||||
|
.unwrap_or_else(|_| panic!("invalid file path: {}", arg)),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,12 @@ macro_rules! impl_stream_for_wrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<$Strc> for Vec<$Inner> {
|
||||||
|
fn from(item: $Strc) -> Vec<$Inner> {
|
||||||
|
item.payload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl $crate::traits::Stream<$Inner> for $Strc {
|
impl $crate::traits::Stream<$Inner> for $Strc {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn payload(self) -> Vec<$Inner> {
|
fn payload(self) -> Vec<$Inner> {
|
||||||
|
@ -259,6 +265,12 @@ macro_rules! impl_stream {
|
||||||
erg_common::traits::Stream::get(self, idx).unwrap()
|
erg_common::traits::Stream::get(self, idx).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<$Strc> for Vec<$Inner> {
|
||||||
|
fn from(item: $Strc) -> Vec<$Inner> {
|
||||||
|
item.payload()
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::traits::Stream;
|
use erg_common::traits::{Runnable, Stream};
|
||||||
|
|
||||||
use erg_parser::ast::VarName;
|
use erg_parser::ast::VarName;
|
||||||
use erg_parser::builder::ASTBuilder;
|
use erg_parser::builder::ASTBuilder;
|
||||||
|
@ -19,20 +19,20 @@ pub struct HIRBuilder {
|
||||||
impl HIRBuilder {
|
impl HIRBuilder {
|
||||||
fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
|
fn convert(&self, errs: TyCheckErrors) -> CompileErrors {
|
||||||
errs.into_iter()
|
errs.into_iter()
|
||||||
.map(|e| CompileError::new(e.core, self.checker.cfg.input.clone(), e.caused_by))
|
.map(|e| CompileError::new(e.core, self.checker.input().clone(), e.caused_by))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
pub fn new(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
||||||
Self {
|
Self {
|
||||||
checker: Checker::new(cfg, mod_cache.clone()),
|
checker: Checker::new_with_cache(cfg, mod_cache.clone()),
|
||||||
mod_cache,
|
mod_cache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_and_cache(&mut self, var_name: VarName) -> Result<(), CompileErrors> {
|
pub fn build_and_cache(&mut self, var_name: VarName) -> Result<(), CompileErrors> {
|
||||||
let mut ast_builder = ASTBuilder::new(self.checker.cfg.copy());
|
let mut ast_builder = ASTBuilder::new(self.checker.cfg().copy());
|
||||||
let ast = ast_builder.build()?;
|
let ast = ast_builder.build()?;
|
||||||
let ast = Reorderer::new()
|
let ast = Reorderer::new()
|
||||||
.reorder(ast)
|
.reorder(ast)
|
||||||
|
@ -46,7 +46,7 @@ impl HIRBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_and_cache_main(&mut self, src: String, mode: &str) -> Result<(), CompileErrors> {
|
pub fn build_and_cache_main(&mut self, src: String, mode: &str) -> Result<(), CompileErrors> {
|
||||||
let mut cfg = self.checker.cfg.copy();
|
let mut cfg = self.checker.cfg().copy();
|
||||||
cfg.input = Input::Str(src);
|
cfg.input = Input::Str(src);
|
||||||
let mut ast_builder = ASTBuilder::new(cfg);
|
let mut ast_builder = ASTBuilder::new(cfg);
|
||||||
let ast = ast_builder.build()?;
|
let ast = ast_builder.build()?;
|
||||||
|
|
|
@ -16,50 +16,22 @@ use crate::ownercheck::OwnershipChecker;
|
||||||
/// Summarize lowering, side-effect checking, and ownership checking
|
/// Summarize lowering, side-effect checking, and ownership checking
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Checker {
|
pub struct Checker {
|
||||||
pub cfg: ErgConfig,
|
|
||||||
lowerer: ASTLowerer,
|
lowerer: ASTLowerer,
|
||||||
ownership_checker: OwnershipChecker,
|
ownership_checker: OwnershipChecker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Checker {
|
impl Runnable for Checker {
|
||||||
pub fn new(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
|
||||||
Self {
|
|
||||||
cfg,
|
|
||||||
lowerer: ASTLowerer::new(mod_cache),
|
|
||||||
ownership_checker: OwnershipChecker::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check(&mut self, ast: AST, mode: &str) -> Result<(HIR, Context), TyCheckErrors> {
|
|
||||||
let (hir, ctx, warns) = self.lowerer.lower(ast, mode)?;
|
|
||||||
if self.cfg.verbose >= 2 {
|
|
||||||
warns.fmt_all_stderr();
|
|
||||||
}
|
|
||||||
let effect_checker = SideEffectChecker::new();
|
|
||||||
let hir = effect_checker.check(hir)?;
|
|
||||||
let hir = self.ownership_checker.check(hir)?;
|
|
||||||
Ok((hir, ctx))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CheckerRunner {
|
|
||||||
checker: Checker,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Runnable for CheckerRunner {
|
|
||||||
type Err = TyCheckError;
|
type Err = TyCheckError;
|
||||||
type Errs = TyCheckErrors;
|
type Errs = TyCheckErrors;
|
||||||
const NAME: &'static str = "Erg type-checker";
|
const NAME: &'static str = "Erg type-checker";
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
Self {
|
Checker::new_with_cache(cfg, SharedModuleCache::new())
|
||||||
checker: Checker::new(cfg, SharedModuleCache::new()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cfg(&self) -> &ErgConfig {
|
fn cfg(&self) -> &ErgConfig {
|
||||||
&self.checker.cfg
|
self.lowerer.cfg()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -70,7 +42,7 @@ impl Runnable for CheckerRunner {
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||||
let mut builder = ASTBuilder::new(self.cfg().copy());
|
let mut builder = ASTBuilder::new(self.cfg().copy());
|
||||||
let ast = builder.build()?;
|
let ast = builder.build()?;
|
||||||
let (hir, _) = self.checker.check(ast, "exec")?;
|
let (hir, _) = self.check(ast, "exec")?;
|
||||||
println!("{hir}");
|
println!("{hir}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -78,7 +50,27 @@ impl Runnable for CheckerRunner {
|
||||||
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
||||||
let mut builder = ASTBuilder::new(self.cfg().copy());
|
let mut builder = ASTBuilder::new(self.cfg().copy());
|
||||||
let ast = builder.build_with_str(src)?;
|
let ast = builder.build_with_str(src)?;
|
||||||
let (hir, _) = self.checker.check(ast, "eval")?;
|
let (hir, _) = self.check(ast, "eval")?;
|
||||||
Ok(hir.to_string())
|
Ok(hir.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Checker {
|
||||||
|
pub fn new_with_cache(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
||||||
|
Self {
|
||||||
|
lowerer: ASTLowerer::new_with_cache(cfg, mod_cache),
|
||||||
|
ownership_checker: OwnershipChecker::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(&mut self, ast: AST, mode: &str) -> Result<(HIR, Context), TyCheckErrors> {
|
||||||
|
let (hir, ctx, warns) = self.lowerer.lower(ast, mode)?;
|
||||||
|
if self.cfg().verbose >= 2 {
|
||||||
|
warns.fmt_all_stderr();
|
||||||
|
}
|
||||||
|
let effect_checker = SideEffectChecker::new();
|
||||||
|
let hir = effect_checker.check(hir)?;
|
||||||
|
let hir = self.ownership_checker.check(hir)?;
|
||||||
|
Ok((hir, ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -996,7 +996,7 @@ impl CodeGenerator {
|
||||||
self.write_instr(Opcode::LOAD_BUILD_CLASS);
|
self.write_instr(Opcode::LOAD_BUILD_CLASS);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.stack_inc();
|
self.stack_inc();
|
||||||
let code = self.emit_typedef_block(class_def);
|
let code = self.emit_class_block(class_def);
|
||||||
self.emit_load_const(code);
|
self.emit_load_const(code);
|
||||||
self.emit_load_const(ident.inspect().clone());
|
self.emit_load_const(ident.inspect().clone());
|
||||||
self.write_instr(Opcode::MAKE_FUNCTION);
|
self.write_instr(Opcode::MAKE_FUNCTION);
|
||||||
|
@ -1014,6 +1014,7 @@ impl CodeGenerator {
|
||||||
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
||||||
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
|
/// Y = Inherit X => class Y(X): ...
|
||||||
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
|
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
|
||||||
log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
|
log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -1638,17 +1639,13 @@ impl CodeGenerator {
|
||||||
self.cancel_pop_top();
|
self.cancel_pop_top();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_typedef_block(&mut self, class: ClassDef) -> CodeObj {
|
fn emit_class_block(&mut self, class: ClassDef) -> CodeObj {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
let name = class.sig.ident().inspect().clone();
|
let name = class.sig.ident().inspect().clone();
|
||||||
self.unit_size += 1;
|
self.unit_size += 1;
|
||||||
let firstlineno = match (
|
let firstlineno = match class.methods.get(0).and_then(|def| def.ln_begin()) {
|
||||||
class.private_methods.get(0).and_then(|def| def.ln_begin()),
|
Some(l) => l,
|
||||||
class.public_methods.get(0).and_then(|def| def.ln_begin()),
|
None => class.sig.ln_begin().unwrap(),
|
||||||
) {
|
|
||||||
(Some(l), Some(r)) => l.min(r),
|
|
||||||
(Some(line), None) | (None, Some(line)) => line,
|
|
||||||
(None, None) => class.sig.ln_begin().unwrap(),
|
|
||||||
};
|
};
|
||||||
self.units.push(CodeGenUnit::new(
|
self.units.push(CodeGenUnit::new(
|
||||||
self.unit_size,
|
self.unit_size,
|
||||||
|
@ -1660,33 +1657,13 @@ impl CodeGenerator {
|
||||||
let mod_name = self.toplevel_block_codeobj().name.clone();
|
let mod_name = self.toplevel_block_codeobj().name.clone();
|
||||||
self.emit_load_const(mod_name);
|
self.emit_load_const(mod_name);
|
||||||
self.emit_store_instr(Identifier::public("__module__"), Name);
|
self.emit_store_instr(Identifier::public("__module__"), Name);
|
||||||
self.emit_load_const(name.clone());
|
self.emit_load_const(name);
|
||||||
self.emit_store_instr(Identifier::public("__qualname__"), Name);
|
self.emit_store_instr(Identifier::public("__qualname__"), Name);
|
||||||
self.emit_init_method(&class.sig, class.__new__.clone());
|
self.emit_init_method(&class.sig, class.__new__.clone());
|
||||||
if class.need_to_gen_new {
|
if class.need_to_gen_new {
|
||||||
self.emit_new_func(&class.sig, class.__new__);
|
self.emit_new_func(&class.sig, class.__new__);
|
||||||
}
|
}
|
||||||
for def in class.private_methods.into_iter() {
|
self.emit_frameless_block(class.methods, vec![]);
|
||||||
match def.sig {
|
|
||||||
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
|
|
||||||
Signature::Var(sig) => self.emit_var_def(sig, def.body),
|
|
||||||
}
|
|
||||||
// TODO: discard
|
|
||||||
if self.cur_block().stack_len == 1 {
|
|
||||||
self.emit_pop_top();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for mut def in class.public_methods.into_iter() {
|
|
||||||
def.sig.ident_mut().dot = Some(Token::dummy());
|
|
||||||
match def.sig {
|
|
||||||
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
|
|
||||||
Signature::Var(sig) => self.emit_var_def(sig, def.body),
|
|
||||||
}
|
|
||||||
// TODO: discard
|
|
||||||
if self.cur_block().stack_len == 1 {
|
|
||||||
self.emit_pop_top();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.emit_load_const(ValueObj::None);
|
self.emit_load_const(ValueObj::None);
|
||||||
self.write_instr(RETURN_VALUE);
|
self.write_instr(RETURN_VALUE);
|
||||||
self.write_arg(0u8);
|
self.write_arg(0u8);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::option::Option; // conflicting to Type::Option
|
use std::option::Option;
|
||||||
|
use std::path::PathBuf; // conflicting to Type::Option
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::MultiErrorDisplay;
|
use erg_common::error::MultiErrorDisplay;
|
||||||
|
@ -762,6 +763,7 @@ impl Context {
|
||||||
|
|
||||||
pub(crate) fn import_mod(
|
pub(crate) fn import_mod(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
current_input: Input,
|
||||||
var_name: &VarName,
|
var_name: &VarName,
|
||||||
mod_name: &hir::Expr,
|
mod_name: &hir::Expr,
|
||||||
) -> TyCheckResult<()> {
|
) -> TyCheckResult<()> {
|
||||||
|
@ -812,7 +814,12 @@ impl Context {
|
||||||
Self::init_py_time_mod(),
|
Self::init_py_time_mod(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => self.import_user_module(var_name, __name__, mod_cache),
|
_ => self.import_user_module(
|
||||||
|
current_input,
|
||||||
|
var_name,
|
||||||
|
__name__,
|
||||||
|
mod_cache,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// maybe unreachable
|
// maybe unreachable
|
||||||
|
@ -843,9 +850,16 @@ impl Context {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_user_module(&self, var_name: &VarName, __name__: Str, mod_cache: &SharedModuleCache) {
|
fn import_user_module(
|
||||||
|
&self,
|
||||||
|
_current_input: Input,
|
||||||
|
var_name: &VarName,
|
||||||
|
__name__: Str,
|
||||||
|
mod_cache: &SharedModuleCache,
|
||||||
|
) {
|
||||||
|
let path = PathBuf::from(format!("{__name__}.er"));
|
||||||
let cfg = ErgConfig {
|
let cfg = ErgConfig {
|
||||||
input: Input::File(format!("{__name__}.er")),
|
input: Input::File(path),
|
||||||
..ErgConfig::default()
|
..ErgConfig::default()
|
||||||
};
|
};
|
||||||
let mut hir_builder = HIRBuilder::new(cfg, mod_cache.clone());
|
let mut hir_builder = HIRBuilder::new(cfg, mod_cache.clone());
|
||||||
|
|
|
@ -476,19 +476,9 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
hir::Expr::ClassDef(type_def) => {
|
hir::Expr::ClassDef(class_def) => {
|
||||||
for def in type_def.public_methods.iter_mut() {
|
for def in class_def.methods.iter_mut() {
|
||||||
match &mut def.sig {
|
self.resolve_expr_t(def)?;
|
||||||
hir::Signature::Var(var) => {
|
|
||||||
var.t = self.deref_tyvar(mem::take(&mut var.t), var.loc())?;
|
|
||||||
}
|
|
||||||
hir::Signature::Subr(subr) => {
|
|
||||||
subr.t = self.deref_tyvar(mem::take(&mut subr.t), subr.loc())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for chunk in def.body.block.iter_mut() {
|
|
||||||
self.resolve_expr_t(chunk)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,10 +84,10 @@ impl SideEffectChecker {
|
||||||
Expr::Def(def) => {
|
Expr::Def(def) => {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(type_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
// TODO: grow
|
// TODO: grow
|
||||||
for def in type_def.public_methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_def(def);
|
self.check_expr(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
|
@ -211,9 +211,9 @@ impl SideEffectChecker {
|
||||||
Expr::Def(def) => {
|
Expr::Def(def) => {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(type_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
for def in type_def.public_methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_def(def);
|
self.check_expr(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Array(array) => match array {
|
Expr::Array(array) => match array {
|
||||||
|
|
|
@ -1390,16 +1390,14 @@ pub struct ClassDef {
|
||||||
/// The type of `new` that is automatically defined if not defined
|
/// The type of `new` that is automatically defined if not defined
|
||||||
pub need_to_gen_new: bool,
|
pub need_to_gen_new: bool,
|
||||||
pub __new__: Type,
|
pub __new__: Type,
|
||||||
pub private_methods: RecordAttrs,
|
pub methods: Block,
|
||||||
pub public_methods: RecordAttrs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for ClassDef {
|
impl NestedDisplay for ClassDef {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
self.sig.fmt_nest(f, level)?;
|
self.sig.fmt_nest(f, level)?;
|
||||||
writeln!(f, ":")?;
|
writeln!(f, ":")?;
|
||||||
self.private_methods.fmt_nest(f, level + 1)?;
|
self.methods.fmt_nest(f, level + 1)
|
||||||
self.public_methods.fmt_nest(f, level + 1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1432,8 +1430,7 @@ impl ClassDef {
|
||||||
require_or_sup: Expr,
|
require_or_sup: Expr,
|
||||||
need_to_gen_new: bool,
|
need_to_gen_new: bool,
|
||||||
__new__: Type,
|
__new__: Type,
|
||||||
private_methods: RecordAttrs,
|
methods: Block,
|
||||||
public_methods: RecordAttrs,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind,
|
kind,
|
||||||
|
@ -1441,8 +1438,7 @@ impl ClassDef {
|
||||||
require_or_sup: Box::new(require_or_sup),
|
require_or_sup: Box::new(require_or_sup),
|
||||||
need_to_gen_new,
|
need_to_gen_new,
|
||||||
__new__,
|
__new__,
|
||||||
private_methods,
|
methods,
|
||||||
public_methods,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
extern crate erg_common;
|
extern crate erg_common;
|
||||||
pub extern crate erg_parser;
|
pub extern crate erg_parser;
|
||||||
|
|
||||||
mod builder;
|
pub mod builder;
|
||||||
mod check;
|
pub mod check;
|
||||||
mod compile;
|
mod compile;
|
||||||
pub use compile::*;
|
pub use compile::*;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
|
|
@ -1,19 +1,58 @@
|
||||||
|
use erg_common::log;
|
||||||
use erg_common::traits::Stream;
|
use erg_common::traits::Stream;
|
||||||
|
|
||||||
use crate::hir::{Expr, HIR};
|
use erg_parser::token::Token;
|
||||||
use crate::mod_cache::SharedModuleCache;
|
|
||||||
|
use erg_type::value::TypeKind;
|
||||||
|
use erg_type::{SubrKind, SubrType, Type};
|
||||||
|
|
||||||
|
use crate::hir::{Block, ClassDef, Expr, Record, RecordAttrs, HIR};
|
||||||
|
use crate::mod_cache::{ModuleEntry, SharedModuleCache};
|
||||||
|
|
||||||
pub struct Linker {}
|
pub struct Linker {}
|
||||||
|
|
||||||
impl Linker {
|
impl Linker {
|
||||||
pub fn link(mod_cache: SharedModuleCache) -> HIR {
|
pub fn link(mod_cache: SharedModuleCache) -> HIR {
|
||||||
|
log!(info "the linking process has started.");
|
||||||
let mut main_mod_hir = mod_cache.remove("<module>").unwrap().hir.unwrap();
|
let mut main_mod_hir = mod_cache.remove("<module>").unwrap().hir.unwrap();
|
||||||
for chunk in main_mod_hir.module.iter_mut() {
|
for chunk in main_mod_hir.module.iter_mut() {
|
||||||
match chunk {
|
match chunk {
|
||||||
Expr::Def(def) if def.def_kind().is_module() => {}
|
// x = import "mod"
|
||||||
|
// ↓
|
||||||
|
// class x:
|
||||||
|
// ...
|
||||||
|
Expr::Def(ref def) if def.def_kind().is_module() => {
|
||||||
|
// let sig = option_enum_unwrap!(&def.sig, Signature::Var)
|
||||||
|
// .unwrap_or_else(|| todo!("module subroutines are not allowed"));
|
||||||
|
if let Some(ModuleEntry { hir: Some(hir), .. }) =
|
||||||
|
mod_cache.remove(def.sig.ident().inspect())
|
||||||
|
{
|
||||||
|
let block = Block::new(Vec::from(hir.module));
|
||||||
|
let def = ClassDef::new(
|
||||||
|
TypeKind::Class,
|
||||||
|
def.sig.clone(),
|
||||||
|
Expr::Record(Record::new(
|
||||||
|
Token::dummy(),
|
||||||
|
Token::dummy(),
|
||||||
|
RecordAttrs::empty(),
|
||||||
|
)),
|
||||||
|
false,
|
||||||
|
Type::Subr(SubrType::new(
|
||||||
|
SubrKind::Func,
|
||||||
|
vec![],
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
Type::Failure,
|
||||||
|
)),
|
||||||
|
block,
|
||||||
|
);
|
||||||
|
*chunk = Expr::ClassDef(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log!(info "linked: {main_mod_hir}");
|
||||||
main_mod_hir
|
main_mod_hir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,22 @@ use crate::mod_cache::SharedModuleCache;
|
||||||
use crate::varinfo::VarKind;
|
use crate::varinfo::VarKind;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
pub struct ASTLowererRunner {
|
/// Singleton that checks types of an AST, and convert (lower) it into a HIR
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ASTLowerer {
|
||||||
cfg: ErgConfig,
|
cfg: ErgConfig,
|
||||||
lowerer: ASTLowerer,
|
pub(crate) ctx: Context,
|
||||||
|
errs: LowerErrors,
|
||||||
|
warns: LowerWarnings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runnable for ASTLowererRunner {
|
impl Default for ASTLowerer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new_with_cache(ErgConfig::default(), SharedModuleCache::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runnable for ASTLowerer {
|
||||||
type Err = CompileError;
|
type Err = CompileError;
|
||||||
type Errs = CompileErrors;
|
type Errs = CompileErrors;
|
||||||
const NAME: &'static str = "Erg lowerer";
|
const NAME: &'static str = "Erg lowerer";
|
||||||
|
@ -47,27 +57,21 @@ impl Runnable for ASTLowererRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
Self {
|
Self::new_with_cache(cfg, SharedModuleCache::new())
|
||||||
cfg,
|
|
||||||
lowerer: ASTLowerer::new(SharedModuleCache::new()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn finish(&mut self) {}
|
fn finish(&mut self) {}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
self.lowerer.errs.clear();
|
self.errs.clear();
|
||||||
self.lowerer.warns.clear();
|
self.warns.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
let ast = ast_builder.build()?;
|
let ast = ast_builder.build()?;
|
||||||
let (hir, _, warns) = self
|
let (hir, _, warns) = self.lower(ast, "exec").map_err(|errs| self.convert(errs))?;
|
||||||
.lowerer
|
|
||||||
.lower(ast, "exec")
|
|
||||||
.map_err(|errs| self.convert(errs))?;
|
|
||||||
if self.cfg.verbose >= 2 {
|
if self.cfg.verbose >= 2 {
|
||||||
let warns = self.convert(warns);
|
let warns = self.convert(warns);
|
||||||
warns.fmt_all_stderr();
|
warns.fmt_all_stderr();
|
||||||
|
@ -79,45 +83,27 @@ impl Runnable for ASTLowererRunner {
|
||||||
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||||
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
let ast = ast_builder.build_with_str(src)?;
|
let ast = ast_builder.build_with_str(src)?;
|
||||||
let (hir, ..) = self
|
let (hir, ..) = self.lower(ast, "eval").map_err(|errs| self.convert(errs))?;
|
||||||
.lowerer
|
|
||||||
.lower(ast, "eval")
|
|
||||||
.map_err(|errs| self.convert(errs))?;
|
|
||||||
Ok(format!("{hir}"))
|
Ok(format!("{hir}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ASTLowererRunner {
|
impl ASTLowerer {
|
||||||
|
pub fn new_with_cache(cfg: ErgConfig, mod_cache: SharedModuleCache) -> Self {
|
||||||
|
Self {
|
||||||
|
cfg,
|
||||||
|
ctx: Context::new_main_module(mod_cache),
|
||||||
|
errs: LowerErrors::empty(),
|
||||||
|
warns: LowerWarnings::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn convert(&self, errs: LowerErrors) -> CompileErrors {
|
fn convert(&self, errs: LowerErrors) -> CompileErrors {
|
||||||
errs.into_iter()
|
errs.into_iter()
|
||||||
.map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by))
|
.map(|e| CompileError::new(e.core, self.input().clone(), e.caused_by))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Singleton that checks types of an AST, and convert (lower) it into a HIR
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ASTLowerer {
|
|
||||||
pub(crate) ctx: Context,
|
|
||||||
errs: LowerErrors,
|
|
||||||
warns: LowerWarnings,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ASTLowerer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(SharedModuleCache::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ASTLowerer {
|
|
||||||
pub fn new(mod_cache: SharedModuleCache) -> Self {
|
|
||||||
Self {
|
|
||||||
ctx: Context::new_main_module(mod_cache),
|
|
||||||
errs: LowerErrors::empty(),
|
|
||||||
warns: LowerWarnings::empty(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn return_t_check(
|
fn return_t_check(
|
||||||
&self,
|
&self,
|
||||||
|
@ -601,11 +587,12 @@ impl ASTLowerer {
|
||||||
match block.first().unwrap() {
|
match block.first().unwrap() {
|
||||||
hir::Expr::Call(call) => {
|
hir::Expr::Call(call) => {
|
||||||
if call.is_import_call() {
|
if call.is_import_call() {
|
||||||
self.ctx
|
let current_input = self.input().clone();
|
||||||
.outer
|
self.ctx.outer.as_mut().unwrap().import_mod(
|
||||||
.as_mut()
|
current_input,
|
||||||
.unwrap()
|
&ident.name,
|
||||||
.import_mod(&ident.name, &call.args.pos_args.first().unwrap().expr)?;
|
&call.args.pos_args.first().unwrap().expr,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_other => {}
|
_other => {}
|
||||||
|
@ -660,8 +647,7 @@ impl ASTLowerer {
|
||||||
fn lower_class_def(&mut self, class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {
|
fn lower_class_def(&mut self, class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {
|
||||||
log!(info "entered {}({class_def})", fn_name!());
|
log!(info "entered {}({class_def})", fn_name!());
|
||||||
let mut hir_def = self.lower_def(class_def.def)?;
|
let mut hir_def = self.lower_def(class_def.def)?;
|
||||||
let mut private_methods = hir::RecordAttrs::empty();
|
let mut hir_methods = hir::Block::empty();
|
||||||
let mut public_methods = hir::RecordAttrs::empty();
|
|
||||||
for mut methods in class_def.methods_list.into_iter() {
|
for mut methods in class_def.methods_list.into_iter() {
|
||||||
let (class, impl_trait) = match &methods.class {
|
let (class, impl_trait) = match &methods.class {
|
||||||
ast::TypeSpec::TypeApp { spec, args } => {
|
ast::TypeSpec::TypeApp { spec, args } => {
|
||||||
|
@ -731,19 +717,11 @@ impl ASTLowerer {
|
||||||
self.ctx.preregister_def(def)?;
|
self.ctx.preregister_def(def)?;
|
||||||
}
|
}
|
||||||
for def in methods.defs.into_iter() {
|
for def in methods.defs.into_iter() {
|
||||||
if methods.vis.is(TokenKind::Dot) {
|
let def = self.lower_def(def).map_err(|e| {
|
||||||
let def = self.lower_def(def).map_err(|e| {
|
self.pop_append_errs();
|
||||||
self.pop_append_errs();
|
e
|
||||||
e
|
})?;
|
||||||
})?;
|
hir_methods.push(hir::Expr::Def(def));
|
||||||
public_methods.push(def);
|
|
||||||
} else {
|
|
||||||
let def = self.lower_def(def).map_err(|e| {
|
|
||||||
self.pop_append_errs();
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
private_methods.push(def);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
match self.ctx.pop() {
|
match self.ctx.pop() {
|
||||||
Ok(methods) => {
|
Ok(methods) => {
|
||||||
|
@ -782,8 +760,7 @@ impl ASTLowerer {
|
||||||
require_or_sup,
|
require_or_sup,
|
||||||
need_to_gen_new,
|
need_to_gen_new,
|
||||||
__new__,
|
__new__,
|
||||||
private_methods,
|
hir_methods,
|
||||||
public_methods,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ use std::thread;
|
||||||
use erg_common::config::ErgConfig;
|
use erg_common::config::ErgConfig;
|
||||||
use erg_common::traits::Runnable;
|
use erg_common::traits::Runnable;
|
||||||
|
|
||||||
use erg_compiler::lower::ASTLowererRunner;
|
use erg_compiler::check::Checker;
|
||||||
|
use erg_compiler::lower::ASTLowerer;
|
||||||
use erg_compiler::Compiler;
|
use erg_compiler::Compiler;
|
||||||
|
|
||||||
use erg_parser::lex::LexerRunner;
|
use erg_parser::lex::LexerRunner;
|
||||||
|
@ -26,7 +27,10 @@ fn run() {
|
||||||
ParserRunner::run(cfg);
|
ParserRunner::run(cfg);
|
||||||
}
|
}
|
||||||
"lower" => {
|
"lower" => {
|
||||||
ASTLowererRunner::run(cfg);
|
ASTLowerer::run(cfg);
|
||||||
|
}
|
||||||
|
"check" => {
|
||||||
|
Checker::run(cfg);
|
||||||
}
|
}
|
||||||
"compile" | "exec" => {
|
"compile" | "exec" => {
|
||||||
Compiler::run(cfg);
|
Compiler::run(cfg);
|
||||||
|
|
|
@ -2916,6 +2916,7 @@ impl Def {
|
||||||
DefKind::Other
|
DefKind::Other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some("import") => DefKind::Module,
|
||||||
_ => DefKind::Other,
|
_ => DefKind::Other,
|
||||||
},
|
},
|
||||||
_ => DefKind::Other,
|
_ => DefKind::Other,
|
||||||
|
|
|
@ -124,8 +124,8 @@ impl Deserializer {
|
||||||
eprintln!("{:?} is not a filename", cfg.input);
|
eprintln!("{:?} is not a filename", cfg.input);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
};
|
};
|
||||||
let codeobj = CodeObj::from_pyc(&filename[..])
|
let codeobj = CodeObj::from_pyc(&filename)
|
||||||
.unwrap_or_else(|_| panic!("failed to deserialize {filename}"));
|
.unwrap_or_else(|_| panic!("failed to deserialize {}", filename.to_string_lossy()));
|
||||||
println!("{}", codeobj.code_info());
|
println!("{}", codeobj.code_info());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@ use erg_common::traits::Runnable;
|
||||||
use erg_parser::lex::LexerRunner;
|
use erg_parser::lex::LexerRunner;
|
||||||
use erg_parser::ParserRunner;
|
use erg_parser::ParserRunner;
|
||||||
|
|
||||||
use erg_compiler::lower::ASTLowererRunner;
|
use erg_compiler::check::Checker;
|
||||||
|
use erg_compiler::lower::ASTLowerer;
|
||||||
use erg_compiler::Compiler;
|
use erg_compiler::Compiler;
|
||||||
|
|
||||||
use erg_type::deserialize::Deserializer;
|
use erg_type::deserialize::Deserializer;
|
||||||
|
@ -28,7 +29,10 @@ fn run() {
|
||||||
ParserRunner::run(cfg);
|
ParserRunner::run(cfg);
|
||||||
}
|
}
|
||||||
"lower" => {
|
"lower" => {
|
||||||
ASTLowererRunner::run(cfg);
|
ASTLowerer::run(cfg);
|
||||||
|
}
|
||||||
|
"check" => {
|
||||||
|
Checker::run(cfg);
|
||||||
}
|
}
|
||||||
"compile" => {
|
"compile" => {
|
||||||
Compiler::run(cfg);
|
Compiler::run(cfg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue