mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
Refactor
Add `ASTBuilder`, `Checker`
This commit is contained in:
parent
f12c2ba723
commit
d8799f0895
14 changed files with 254 additions and 104 deletions
72
compiler/erg_compiler/checker.rs
Normal file
72
compiler/erg_compiler/checker.rs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
use erg_common::config::ErgConfig;
|
||||||
|
use erg_common::error::MultiErrorDisplay;
|
||||||
|
use erg_common::traits::Runnable;
|
||||||
|
|
||||||
|
use erg_parser::ast::AST;
|
||||||
|
use erg_parser::builder::ASTBuilder;
|
||||||
|
|
||||||
|
use crate::effectcheck::SideEffectChecker;
|
||||||
|
use crate::error::{TyCheckError, TyCheckErrors};
|
||||||
|
use crate::hir::HIR;
|
||||||
|
use crate::lower::ASTLowerer;
|
||||||
|
use crate::ownercheck::OwnershipChecker;
|
||||||
|
|
||||||
|
/// Summarize lowering, side-effect checking, and ownership checking
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Checker {
|
||||||
|
cfg: ErgConfig,
|
||||||
|
lowerer: ASTLowerer,
|
||||||
|
ownership_checker: OwnershipChecker,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runnable for Checker {
|
||||||
|
type Err = TyCheckError;
|
||||||
|
type Errs = TyCheckErrors;
|
||||||
|
const NAME: &'static str = "Erg type-checker";
|
||||||
|
|
||||||
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
ownership_checker: OwnershipChecker::new(),
|
||||||
|
lowerer: ASTLowerer::new(),
|
||||||
|
cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn cfg(&self) -> &ErgConfig {
|
||||||
|
&self.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn finish(&mut self) {}
|
||||||
|
|
||||||
|
fn clear(&mut self) {}
|
||||||
|
|
||||||
|
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||||
|
let mut builder = ASTBuilder::new(self.cfg.copy());
|
||||||
|
let ast = builder.build()?;
|
||||||
|
let hir = self.check(ast, "exec")?;
|
||||||
|
println!("{hir}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval(&mut self, src: String) -> Result<String, TyCheckErrors> {
|
||||||
|
let mut builder = ASTBuilder::new(self.cfg.copy());
|
||||||
|
let ast = builder.build_with_input(src)?;
|
||||||
|
let hir = self.check(ast, "eval")?;
|
||||||
|
Ok(hir.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Checker {
|
||||||
|
pub fn check(&mut self, ast: AST, mode: &str) -> Result<HIR, TyCheckErrors> {
|
||||||
|
let (hir, 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,19 +4,15 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::error::MultiErrorDisplay;
|
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::traits::{Runnable, Stream};
|
use erg_common::traits::{Runnable, Stream};
|
||||||
use erg_type::codeobj::CodeObj;
|
use erg_type::codeobj::CodeObj;
|
||||||
|
|
||||||
use erg_parser::ParserRunner;
|
use erg_parser::builder::ASTBuilder;
|
||||||
|
|
||||||
|
use crate::checker::Checker;
|
||||||
use crate::codegen::CodeGenerator;
|
use crate::codegen::CodeGenerator;
|
||||||
use crate::effectcheck::SideEffectChecker;
|
|
||||||
use crate::error::{CompileError, CompileErrors, TyCheckErrors};
|
use crate::error::{CompileError, CompileErrors, TyCheckErrors};
|
||||||
use crate::lower::ASTLowerer;
|
|
||||||
use crate::ownercheck::OwnershipChecker;
|
|
||||||
use crate::reorder::Reorderer;
|
|
||||||
|
|
||||||
/// * registered as global -> Global
|
/// * registered as global -> Global
|
||||||
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
/// * defined in the toplevel scope (and called in the inner scope) -> Global
|
||||||
|
@ -91,13 +87,11 @@ impl AccessKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a `CodeObj` from an `AST`.
|
/// Generates a `CodeObj` from an String or other File inputs.
|
||||||
/// The input AST is not typed, so it's typed by `ASTLowerer` according to the cfg.opt_level.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
cfg: ErgConfig,
|
cfg: ErgConfig,
|
||||||
lowerer: ASTLowerer,
|
checker: Checker,
|
||||||
ownership_checker: OwnershipChecker,
|
|
||||||
code_generator: CodeGenerator,
|
code_generator: CodeGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,9 +102,8 @@ impl Runnable for Compiler {
|
||||||
|
|
||||||
fn new(cfg: ErgConfig) -> Self {
|
fn new(cfg: ErgConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
checker: Checker::new(cfg.copy()),
|
||||||
code_generator: CodeGenerator::new(cfg.copy()),
|
code_generator: CodeGenerator::new(cfg.copy()),
|
||||||
ownership_checker: OwnershipChecker::new(),
|
|
||||||
lowerer: ASTLowerer::new(),
|
|
||||||
cfg,
|
cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,25 +156,11 @@ impl Compiler {
|
||||||
log!(info "the compiling process has started.");
|
log!(info "the compiling process has started.");
|
||||||
let mut cfg = self.cfg.copy();
|
let mut cfg = self.cfg.copy();
|
||||||
cfg.input = Input::Str(src);
|
cfg.input = Input::Str(src);
|
||||||
let mut parser = ParserRunner::new(cfg);
|
let mut ast_builder = ASTBuilder::new(cfg);
|
||||||
let ast = parser.parse()?;
|
let ast = ast_builder.build()?;
|
||||||
let linker = Reorderer::new();
|
|
||||||
let ast = linker.link(ast).map_err(|errs| self.convert(errs))?;
|
|
||||||
let (hir, warns) = self
|
|
||||||
.lowerer
|
|
||||||
.lower(ast, mode)
|
|
||||||
.map_err(|errs| self.convert(errs))?;
|
|
||||||
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 hir = self
|
let hir = self
|
||||||
.ownership_checker
|
.checker
|
||||||
.check(hir)
|
.check(ast, mode)
|
||||||
.map_err(|errs| self.convert(errs))?;
|
.map_err(|errs| self.convert(errs))?;
|
||||||
let codeobj = self.code_generator.codegen(hir);
|
let codeobj = self.code_generator.codegen(hir);
|
||||||
log!(info "code object:\n{}", codeobj.code_info());
|
log!(info "code object:\n{}", codeobj.code_info());
|
||||||
|
|
|
@ -559,10 +559,15 @@ impl Context {
|
||||||
if sub == Type::Never {
|
if sub == Type::Never {
|
||||||
return Ok(mono_proj(*lhs, rhs));
|
return Ok(mono_proj(*lhs, rhs));
|
||||||
}
|
}
|
||||||
for (_ty, ty_ctx) in self
|
for (_ty, ty_ctx) in self.get_nominal_super_type_ctxs(&sub).ok_or_else(|| {
|
||||||
.get_nominal_super_type_ctxs(&sub)
|
EvalError::no_var_error(
|
||||||
.ok_or_else(|| todo!("{sub}"))?
|
line!() as usize,
|
||||||
{
|
t_loc,
|
||||||
|
self.caused_by(),
|
||||||
|
&rhs,
|
||||||
|
None, // TODO:
|
||||||
|
)
|
||||||
|
})? {
|
||||||
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) {
|
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) {
|
||||||
if let ValueObj::Type(quant_t) = obj {
|
if let ValueObj::Type(quant_t) = obj {
|
||||||
let subst_ctx = SubstContext::new(&sub, ty_ctx);
|
let subst_ctx = SubstContext::new(&sub, ty_ctx);
|
||||||
|
|
|
@ -246,10 +246,15 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, ctx) in self
|
for (_, ctx) in self.get_nominal_super_type_ctxs(&self_t).ok_or_else(|| {
|
||||||
.get_nominal_super_type_ctxs(&self_t)
|
TyCheckError::no_var_error(
|
||||||
.ok_or_else(|| todo!())?
|
line!() as usize,
|
||||||
{
|
obj.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
&self_t.to_string(),
|
||||||
|
None, // TODO:
|
||||||
|
)
|
||||||
|
})? {
|
||||||
match ctx.rec_get_var_t(ident, namespace) {
|
match ctx.rec_get_var_t(ident, namespace) {
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
return Ok(t);
|
return Ok(t);
|
||||||
|
@ -348,7 +353,15 @@ impl Context {
|
||||||
if let Some(method_name) = method_name.as_ref() {
|
if let Some(method_name) = method_name.as_ref() {
|
||||||
for (_, ctx) in self
|
for (_, ctx) in self
|
||||||
.get_nominal_super_type_ctxs(obj.ref_t())
|
.get_nominal_super_type_ctxs(obj.ref_t())
|
||||||
.ok_or_else(|| todo!())?
|
.ok_or_else(|| {
|
||||||
|
TyCheckError::no_var_error(
|
||||||
|
line!() as usize,
|
||||||
|
obj.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
&obj.to_string(),
|
||||||
|
None, // TODO:
|
||||||
|
)
|
||||||
|
})?
|
||||||
{
|
{
|
||||||
if let Some(vi) = ctx
|
if let Some(vi) = ctx
|
||||||
.locals
|
.locals
|
||||||
|
@ -856,10 +869,15 @@ impl Context {
|
||||||
namespace: &Str,
|
namespace: &Str,
|
||||||
) -> TyCheckResult<ValueObj> {
|
) -> TyCheckResult<ValueObj> {
|
||||||
let self_t = obj.ref_t();
|
let self_t = obj.ref_t();
|
||||||
for (_, ctx) in self
|
for (_, ctx) in self.get_nominal_super_type_ctxs(self_t).ok_or_else(|| {
|
||||||
.get_nominal_super_type_ctxs(self_t)
|
TyCheckError::no_var_error(
|
||||||
.ok_or_else(|| todo!())?
|
line!() as usize,
|
||||||
{
|
obj.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
&self_t.to_string(),
|
||||||
|
None, // TODO:
|
||||||
|
)
|
||||||
|
})? {
|
||||||
if let Ok(t) = ctx.get_const_local(name, namespace) {
|
if let Ok(t) = ctx.get_const_local(name, namespace) {
|
||||||
return Ok(t);
|
return Ok(t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,15 @@ pub struct TyCheckError {
|
||||||
pub caused_by: AtomicStr,
|
pub caused_by: AtomicStr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParserRunnerError> for TyCheckError {
|
||||||
|
fn from(err: ParserRunnerError) -> Self {
|
||||||
|
Self {
|
||||||
|
core: err.core,
|
||||||
|
caused_by: "".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ErrorDisplay for TyCheckError {
|
impl ErrorDisplay for TyCheckError {
|
||||||
fn core(&self) -> &ErrorCore {
|
fn core(&self) -> &ErrorCore {
|
||||||
&self.core
|
&self.core
|
||||||
|
@ -1169,6 +1178,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
|
||||||
pub struct TyCheckErrors(Vec<TyCheckError>);
|
pub struct TyCheckErrors(Vec<TyCheckError>);
|
||||||
|
|
||||||
impl_stream_for_wrapper!(TyCheckErrors, TyCheckError);
|
impl_stream_for_wrapper!(TyCheckErrors, TyCheckError);
|
||||||
|
impl MultiErrorDisplay<TyCheckError> for TyCheckErrors {}
|
||||||
|
|
||||||
impl From<Vec<TyCheckError>> for TyCheckErrors {
|
impl From<Vec<TyCheckError>> for TyCheckErrors {
|
||||||
fn from(errs: Vec<TyCheckError>) -> Self {
|
fn from(errs: Vec<TyCheckError>) -> Self {
|
||||||
|
@ -1189,6 +1199,12 @@ impl From<TyCheckError> for TyCheckErrors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ParserRunnerErrors> for TyCheckErrors {
|
||||||
|
fn from(err: ParserRunnerErrors) -> Self {
|
||||||
|
Self(err.into_iter().map(TyCheckError::from).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type TyCheckResult<T> = Result<T, TyCheckError>;
|
pub type TyCheckResult<T> = Result<T, TyCheckError>;
|
||||||
pub type TyCheckWarning = TyCheckError;
|
pub type TyCheckWarning = TyCheckError;
|
||||||
pub type TyCheckWarnings = TyCheckErrors;
|
pub type TyCheckWarnings = TyCheckErrors;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
extern crate erg_common;
|
extern crate erg_common;
|
||||||
pub extern crate erg_parser;
|
pub extern crate erg_parser;
|
||||||
|
|
||||||
|
mod checker;
|
||||||
mod compile;
|
mod compile;
|
||||||
pub use compile::*;
|
pub use compile::*;
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
@ -14,5 +15,4 @@ pub mod lower;
|
||||||
pub mod mod_cache;
|
pub mod mod_cache;
|
||||||
pub mod optimize;
|
pub mod optimize;
|
||||||
pub mod ownercheck;
|
pub mod ownercheck;
|
||||||
pub mod reorder;
|
|
||||||
pub mod varinfo;
|
pub mod varinfo;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! ASTLowerer(ASTからHIRへの変換器)を実装
|
//! ASTLowerer(ASTからHIRへの変換器)を実装
|
||||||
use erg_common::astr::AtomicStr;
|
use erg_common::astr::AtomicStr;
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::ErgConfig;
|
||||||
use erg_common::error::{Location, MultiErrorDisplay};
|
use erg_common::error::{Location, MultiErrorDisplay};
|
||||||
use erg_common::traits::{Locational, Runnable, Stream};
|
use erg_common::traits::{Locational, Runnable, Stream};
|
||||||
use erg_common::vis::Visibility;
|
use erg_common::vis::Visibility;
|
||||||
|
@ -10,10 +10,8 @@ use erg_common::{enum_unwrap, fmt_option, fn_name, get_hash, log, switch_lang, S
|
||||||
|
|
||||||
use erg_parser::ast;
|
use erg_parser::ast;
|
||||||
use erg_parser::ast::AST;
|
use erg_parser::ast::AST;
|
||||||
use erg_parser::error::ParserRunnerErrors;
|
use erg_parser::builder::ASTBuilder;
|
||||||
use erg_parser::lex::Lexer;
|
|
||||||
use erg_parser::token::{Token, TokenKind};
|
use erg_parser::token::{Token, TokenKind};
|
||||||
use erg_parser::Parser;
|
|
||||||
|
|
||||||
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
|
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
|
||||||
use erg_type::free::Constraint;
|
use erg_type::free::Constraint;
|
||||||
|
@ -27,7 +25,6 @@ use crate::error::{
|
||||||
};
|
};
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::hir::HIR;
|
use crate::hir::HIR;
|
||||||
use crate::reorder::Reorderer;
|
|
||||||
use crate::varinfo::VarKind;
|
use crate::varinfo::VarKind;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
|
@ -62,14 +59,8 @@ impl Runnable for ASTLowererRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(&mut self) -> Result<(), Self::Errs> {
|
fn exec(&mut self) -> Result<(), Self::Errs> {
|
||||||
let ts = Lexer::new(self.input().clone())
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
.lex()
|
let ast = ast_builder.build()?;
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
|
||||||
let ast = Parser::new(ts)
|
|
||||||
.parse(Str::ever(self.cfg.module))
|
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
|
||||||
let linker = Reorderer::new();
|
|
||||||
let ast = linker.link(ast).map_err(|errs| self.convert(errs))?;
|
|
||||||
let (hir, warns) = self
|
let (hir, warns) = self
|
||||||
.lowerer
|
.lowerer
|
||||||
.lower(ast, "exec")
|
.lower(ast, "exec")
|
||||||
|
@ -83,14 +74,8 @@ impl Runnable for ASTLowererRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
|
||||||
let ts = Lexer::new(Input::Str(src))
|
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
|
||||||
.lex()
|
let ast = ast_builder.build_with_input(src)?;
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
|
||||||
let ast = Parser::new(ts)
|
|
||||||
.parse(Str::ever(self.cfg.module))
|
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
|
||||||
let linker = Reorderer::new();
|
|
||||||
let ast = linker.link(ast).map_err(|errs| self.convert(errs))?;
|
|
||||||
let (hir, _) = self
|
let (hir, _) = self
|
||||||
.lowerer
|
.lowerer
|
||||||
.lower(ast, "eval")
|
.lower(ast, "eval")
|
||||||
|
|
|
@ -27,24 +27,24 @@ impl ModId {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ModuleEntry {
|
pub struct ModuleEntry {
|
||||||
id: ModId, // builtin == 0, __main__ == 1
|
_id: ModId, // builtin == 0, __main__ == 1
|
||||||
hir: Option<HIR>,
|
_hir: Option<HIR>,
|
||||||
ctx: Rc<Context>,
|
ctx: Rc<Context>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleEntry {
|
impl ModuleEntry {
|
||||||
pub fn new(id: ModId, hir: Option<HIR>, ctx: Context) -> Self {
|
pub fn new(id: ModId, hir: Option<HIR>, ctx: Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
_id: id,
|
||||||
hir,
|
_hir: hir,
|
||||||
ctx: Rc::new(ctx),
|
ctx: Rc::new(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builtin(ctx: Context) -> Self {
|
pub fn builtin(ctx: Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: ModId::builtin(),
|
_id: ModId::builtin(),
|
||||||
hir: None,
|
_hir: None,
|
||||||
ctx: Rc::new(ctx),
|
ctx: Rc::new(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
50
compiler/erg_parser/builder.rs
Normal file
50
compiler/erg_parser/builder.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use erg_common::config::ErgConfig;
|
||||||
|
use erg_common::traits::Runnable;
|
||||||
|
use erg_common::Str;
|
||||||
|
|
||||||
|
use crate::ast::AST;
|
||||||
|
use crate::desugar::Desugarer;
|
||||||
|
use crate::error::ParserRunnerErrors;
|
||||||
|
use crate::parse::ParserRunner;
|
||||||
|
use crate::reorder::Reorderer;
|
||||||
|
|
||||||
|
/// Summarize parsing, desugaring, and reordering
|
||||||
|
pub struct ASTBuilder {
|
||||||
|
runner: ParserRunner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ASTBuilder {
|
||||||
|
pub fn new(cfg: ErgConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
runner: ParserRunner::new(cfg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(&mut self) -> Result<AST, ParserRunnerErrors> {
|
||||||
|
let module = self.runner.parse()?;
|
||||||
|
let mut desugarer = Desugarer::new();
|
||||||
|
let module = desugarer.desugar(module);
|
||||||
|
let mut desugarer = Desugarer::new();
|
||||||
|
let module = desugarer.desugar(module);
|
||||||
|
let ast = AST::new(Str::ever(self.runner.cfg().module), module);
|
||||||
|
let reorderer = Reorderer::new();
|
||||||
|
let ast = reorderer
|
||||||
|
.reorder(ast)
|
||||||
|
.map_err(|errs| ParserRunnerErrors::convert(self.runner.input(), errs))?;
|
||||||
|
Ok(ast)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_with_input(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||||
|
let module = self.runner.parse_with_input(src)?;
|
||||||
|
let mut desugarer = Desugarer::new();
|
||||||
|
let module = desugarer.desugar(module);
|
||||||
|
let mut desugarer = Desugarer::new();
|
||||||
|
let module = desugarer.desugar(module);
|
||||||
|
let ast = AST::new(Str::ever(self.runner.cfg().module), module);
|
||||||
|
let reorderer = Reorderer::new();
|
||||||
|
let ast = reorderer
|
||||||
|
.reorder(ast)
|
||||||
|
.map_err(|errs| ParserRunnerErrors::convert(self.runner.input(), errs))?;
|
||||||
|
Ok(ast)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{enum_unwrap, get_hash, set};
|
use erg_common::{enum_unwrap, get_hash, log, set};
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
Accessor, Args, Array, ArrayComprehension, ArrayWithLength, BinOp, Block, Call, DataPack, Def,
|
Accessor, Args, Array, ArrayComprehension, ArrayWithLength, BinOp, Block, Call, DataPack, Def,
|
||||||
|
@ -48,10 +48,12 @@ impl Desugarer {
|
||||||
|
|
||||||
#[allow(clippy::let_and_return)]
|
#[allow(clippy::let_and_return)]
|
||||||
pub fn desugar(&mut self, module: Module) -> Module {
|
pub fn desugar(&mut self, module: Module) -> Module {
|
||||||
|
log!(info "the desugaring process has started.");
|
||||||
let module = self.desugar_multiple_pattern_def(module);
|
let module = self.desugar_multiple_pattern_def(module);
|
||||||
let module = self.desugar_pattern(module);
|
let module = self.desugar_pattern(module);
|
||||||
let module = self.desugar_shortened_record(module);
|
let module = self.desugar_shortened_record(module);
|
||||||
// let module = self.desugar_self(module);
|
log!(info "AST (desugared):\n{module}");
|
||||||
|
log!(info "the desugaring process has completed.");
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! パーサーが出すエラーを定義
|
//! パーサーが出すエラーを定義
|
||||||
use erg_common::astr::AtomicStr;
|
use erg_common::astr::AtomicStr;
|
||||||
|
use erg_common::color::{RED, RESET};
|
||||||
use erg_common::config::Input;
|
use erg_common::config::Input;
|
||||||
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
||||||
use erg_common::traits::Stream;
|
use erg_common::traits::Stream;
|
||||||
|
@ -82,6 +83,35 @@ impl LexError {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint))
|
Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_var_error(
|
||||||
|
errno: usize,
|
||||||
|
loc: Location,
|
||||||
|
name: &str,
|
||||||
|
similar_name: Option<String>,
|
||||||
|
) -> Self {
|
||||||
|
let hint = similar_name.map(|n| {
|
||||||
|
switch_lang!(
|
||||||
|
"japanese" => format!("似た名前の変数があります: {n}"),
|
||||||
|
"simplified_chinese" => format!("存在相同名称变量:{n}"),
|
||||||
|
"traditional_chinese" => format!("存在相同名稱變量:{n}"),
|
||||||
|
"english" => format!("exists a similar name variable: {n}"),
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
});
|
||||||
|
Self::new(ErrorCore::new(
|
||||||
|
errno,
|
||||||
|
NameError,
|
||||||
|
loc,
|
||||||
|
switch_lang!(
|
||||||
|
"japanese" => format!("{RED}{name}{RESET}という変数は定義されていません"),
|
||||||
|
"simplified_chinese" => format!("{RED}{name}{RESET}未定义"),
|
||||||
|
"traditional_chinese" => format!("{RED}{name}{RESET}未定義"),
|
||||||
|
"english" => format!("{RED}{name}{RESET} is not defined"),
|
||||||
|
),
|
||||||
|
hint,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type LexResult<T> = Result<T, LexError>;
|
pub type LexResult<T> = Result<T, LexError>;
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
extern crate erg_common;
|
extern crate erg_common;
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
|
pub mod builder;
|
||||||
pub mod desugar;
|
pub mod desugar;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
pub mod reorder;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|
||||||
pub use parse::{Parser, ParserRunner};
|
pub use parse::{Parser, ParserRunner};
|
||||||
|
|
|
@ -12,13 +12,11 @@ use erg_common::option_enum_unwrap;
|
||||||
use erg_common::set::Set as HashSet;
|
use erg_common::set::Set as HashSet;
|
||||||
use erg_common::traits::Runnable;
|
use erg_common::traits::Runnable;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::Str;
|
|
||||||
use erg_common::{
|
use erg_common::{
|
||||||
caused_by, debug_power_assert, enum_unwrap, fn_name, log, set, switch_lang, switch_unreachable,
|
caused_by, debug_power_assert, enum_unwrap, fn_name, log, set, switch_lang, switch_unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::desugar::Desugarer;
|
|
||||||
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
||||||
use crate::lex::Lexer;
|
use crate::lex::Lexer;
|
||||||
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
||||||
|
@ -201,13 +199,13 @@ impl Runnable for ParserRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParserRunner {
|
impl ParserRunner {
|
||||||
pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result<AST, ParserRunnerErrors> {
|
pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result<Module, ParserRunnerErrors> {
|
||||||
Parser::new(ts)
|
Parser::new(ts)
|
||||||
.parse(Str::ever(self.cfg.module))
|
.parse()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<AST, ParserRunnerErrors> {
|
pub fn parse(&mut self) -> Result<Module, ParserRunnerErrors> {
|
||||||
let ts = Lexer::new(self.input().clone())
|
let ts = Lexer::new(self.input().clone())
|
||||||
.lex()
|
.lex()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||||
|
@ -215,7 +213,7 @@ impl ParserRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses with default configuration
|
/// Parses with default configuration
|
||||||
pub fn parse_with_default_config(input: Input) -> Result<AST, ParserRunnerErrors> {
|
pub fn parse_with_default_config(input: Input) -> Result<Module, ParserRunnerErrors> {
|
||||||
let cfg = ErgConfig {
|
let cfg = ErgConfig {
|
||||||
input,
|
input,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -224,20 +222,20 @@ impl ParserRunner {
|
||||||
self_.parse()
|
self_.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_with_input(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
pub fn parse_with_input(&mut self, src: String) -> Result<Module, ParserRunnerErrors> {
|
||||||
let ts = Lexer::new(Input::Str(src))
|
let ts = Lexer::new(Input::Str(src))
|
||||||
.lex()
|
.lex()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||||
Parser::new(ts)
|
Parser::new(ts)
|
||||||
.parse(Str::ever(self.cfg.module))
|
.parse()
|
||||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn parse(&mut self, mod_name: Str) -> Result<AST, ParseErrors> {
|
pub fn parse(&mut self) -> Result<Module, ParseErrors> {
|
||||||
if self.tokens.is_empty() {
|
if self.tokens.is_empty() {
|
||||||
return Ok(AST::new(mod_name, Module::empty()));
|
return Ok(Module::empty());
|
||||||
}
|
}
|
||||||
log!(info "the parsing process has started.");
|
log!(info "the parsing process has started.");
|
||||||
log!(info "token stream: {}", self.tokens);
|
log!(info "token stream: {}", self.tokens);
|
||||||
|
@ -255,13 +253,8 @@ impl Parser {
|
||||||
}
|
}
|
||||||
log!(info "the parsing process has completed.");
|
log!(info "the parsing process has completed.");
|
||||||
log!(info "AST:\n{module}");
|
log!(info "AST:\n{module}");
|
||||||
log!(info "the desugaring process has started.");
|
|
||||||
let mut desugarer = Desugarer::new();
|
|
||||||
let module = desugarer.desugar(module);
|
|
||||||
log!(info "AST (desugared):\n{module}");
|
|
||||||
log!(info "the desugaring process has completed.{RESET}");
|
|
||||||
if self.errs.is_empty() {
|
if self.errs.is_empty() {
|
||||||
Ok(AST::new(mod_name, module))
|
Ok(module)
|
||||||
} else {
|
} else {
|
||||||
Err(mem::take(&mut self.errs))
|
Err(mem::take(&mut self.errs))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ use erg_common::log;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
|
||||||
use erg_parser::ast::{ClassDef, Expr, Module, PreDeclTypeSpec, TypeSpec, AST};
|
use crate::ast::{ClassDef, Expr, Module, PreDeclTypeSpec, TypeSpec, AST};
|
||||||
|
|
||||||
use crate::error::{TyCheckError, TyCheckErrors};
|
use crate::error::{ParseError, ParseErrors};
|
||||||
|
|
||||||
/// Combine method definitions across multiple modules, specialized class contexts, etc.
|
/// Combine method definitions across multiple modules, specialized class contexts, etc.
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -13,7 +13,7 @@ pub struct Reorderer {
|
||||||
// TODO: inner scope types
|
// TODO: inner scope types
|
||||||
pub def_root_pos_map: Dict<Str, usize>,
|
pub def_root_pos_map: Dict<Str, usize>,
|
||||||
pub deps: Dict<Str, Vec<Str>>,
|
pub deps: Dict<Str, Vec<Str>>,
|
||||||
pub errs: TyCheckErrors,
|
pub errs: ParseErrors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reorderer {
|
impl Reorderer {
|
||||||
|
@ -21,12 +21,12 @@ impl Reorderer {
|
||||||
Self {
|
Self {
|
||||||
def_root_pos_map: Dict::new(),
|
def_root_pos_map: Dict::new(),
|
||||||
deps: Dict::new(),
|
deps: Dict::new(),
|
||||||
errs: TyCheckErrors::empty(),
|
errs: ParseErrors::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn link(mut self, mut ast: AST) -> Result<AST, TyCheckErrors> {
|
pub fn reorder(mut self, mut ast: AST) -> Result<AST, ParseErrors> {
|
||||||
log!(info "the linking process has started.");
|
log!(info "the reordering process has started.");
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
while let Some(chunk) = ast.module.lpop() {
|
while let Some(chunk) = ast.module.lpop() {
|
||||||
match chunk {
|
match chunk {
|
||||||
|
@ -63,17 +63,15 @@ impl Reorderer {
|
||||||
class_def.methods_list.push(methods);
|
class_def.methods_list.push(methods);
|
||||||
new.insert(*pos, Expr::ClassDef(class_def));
|
new.insert(*pos, Expr::ClassDef(class_def));
|
||||||
} else {
|
} else {
|
||||||
let similar_name = Str::from(
|
let similar_name = self
|
||||||
self.def_root_pos_map
|
.def_root_pos_map
|
||||||
.keys()
|
.keys()
|
||||||
.fold("".to_string(), |acc, key| acc + &key[..] + ","),
|
.fold("".to_string(), |acc, key| acc + &key[..] + ",");
|
||||||
);
|
self.errs.push(ParseError::no_var_error(
|
||||||
self.errs.push(TyCheckError::no_var_error(
|
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
methods.class.loc(),
|
methods.class.loc(),
|
||||||
"".into(),
|
|
||||||
simple.name.inspect(),
|
simple.name.inspect(),
|
||||||
Some(&similar_name),
|
Some(similar_name),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +83,7 @@ impl Reorderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ast = AST::new(ast.name, Module::new(new));
|
let ast = AST::new(ast.name, Module::new(new));
|
||||||
log!(info "the linking process has completed:\n{}", ast);
|
log!(info "the reordering process has completed:\n{}", ast);
|
||||||
if self.errs.is_empty() {
|
if self.errs.is_empty() {
|
||||||
Ok(ast)
|
Ok(ast)
|
||||||
} else {
|
} else {
|
Loading…
Add table
Add a link
Reference in a new issue