mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-02 21:44:34 +00:00
Refactor
Add `ASTBuilder`, `Checker`
This commit is contained in:
parent
f12c2ba723
commit
d8799f0895
14 changed files with 254 additions and 104 deletions
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::traits::{Locational, Stream};
|
||||
use erg_common::Str;
|
||||
use erg_common::{enum_unwrap, get_hash, set};
|
||||
use erg_common::{enum_unwrap, get_hash, log, set};
|
||||
|
||||
use crate::ast::{
|
||||
Accessor, Args, Array, ArrayComprehension, ArrayWithLength, BinOp, Block, Call, DataPack, Def,
|
||||
|
@ -48,10 +48,12 @@ impl Desugarer {
|
|||
|
||||
#[allow(clippy::let_and_return)]
|
||||
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_pattern(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
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//!
|
||||
//! パーサーが出すエラーを定義
|
||||
use erg_common::astr::AtomicStr;
|
||||
use erg_common::color::{RED, RESET};
|
||||
use erg_common::config::Input;
|
||||
use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay};
|
||||
use erg_common::traits::Stream;
|
||||
|
@ -82,6 +83,35 @@ impl LexError {
|
|||
) -> Self {
|
||||
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>;
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
extern crate erg_common;
|
||||
|
||||
pub mod ast;
|
||||
pub mod builder;
|
||||
pub mod desugar;
|
||||
pub mod error;
|
||||
pub mod lex;
|
||||
pub mod parse;
|
||||
pub mod reorder;
|
||||
pub mod token;
|
||||
|
||||
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::traits::Runnable;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_common::Str;
|
||||
use erg_common::{
|
||||
caused_by, debug_power_assert, enum_unwrap, fn_name, log, set, switch_lang, switch_unreachable,
|
||||
};
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::desugar::Desugarer;
|
||||
use crate::error::{ParseError, ParseErrors, ParseResult, ParserRunnerError, ParserRunnerErrors};
|
||||
use crate::lex::Lexer;
|
||||
use crate::token::{Token, TokenCategory, TokenKind, TokenStream};
|
||||
|
@ -201,13 +199,13 @@ impl Runnable for 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)
|
||||
.parse(Str::ever(self.cfg.module))
|
||||
.parse()
|
||||
.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())
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||
|
@ -215,7 +213,7 @@ impl ParserRunner {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
input,
|
||||
..Default::default()
|
||||
|
@ -224,20 +222,20 @@ impl ParserRunner {
|
|||
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))
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||
Parser::new(ts)
|
||||
.parse(Str::ever(self.cfg.module))
|
||||
.parse()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
return Ok(AST::new(mod_name, Module::empty()));
|
||||
return Ok(Module::empty());
|
||||
}
|
||||
log!(info "the parsing process has started.");
|
||||
log!(info "token stream: {}", self.tokens);
|
||||
|
@ -255,13 +253,8 @@ impl Parser {
|
|||
}
|
||||
log!(info "the parsing process has completed.");
|
||||
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() {
|
||||
Ok(AST::new(mod_name, module))
|
||||
Ok(module)
|
||||
} else {
|
||||
Err(mem::take(&mut self.errs))
|
||||
}
|
||||
|
|
93
compiler/erg_parser/reorder.rs
Normal file
93
compiler/erg_parser/reorder.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use erg_common::dict::Dict;
|
||||
use erg_common::log;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_common::Str;
|
||||
|
||||
use crate::ast::{ClassDef, Expr, Module, PreDeclTypeSpec, TypeSpec, AST};
|
||||
|
||||
use crate::error::{ParseError, ParseErrors};
|
||||
|
||||
/// Combine method definitions across multiple modules, specialized class contexts, etc.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Reorderer {
|
||||
// TODO: inner scope types
|
||||
pub def_root_pos_map: Dict<Str, usize>,
|
||||
pub deps: Dict<Str, Vec<Str>>,
|
||||
pub errs: ParseErrors,
|
||||
}
|
||||
|
||||
impl Reorderer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
def_root_pos_map: Dict::new(),
|
||||
deps: Dict::new(),
|
||||
errs: ParseErrors::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reorder(mut self, mut ast: AST) -> Result<AST, ParseErrors> {
|
||||
log!(info "the reordering process has started.");
|
||||
let mut new = vec![];
|
||||
while let Some(chunk) = ast.module.lpop() {
|
||||
match chunk {
|
||||
Expr::Def(def) => {
|
||||
match def.body.block.first().unwrap() {
|
||||
Expr::Call(call) => {
|
||||
match call.obj.get_name().map(|s| &s[..]) {
|
||||
// TODO: decorator
|
||||
Some("Class" | "Inherit" | "Inheritable") => {
|
||||
self.def_root_pos_map.insert(
|
||||
def.sig.ident().unwrap().inspect().clone(),
|
||||
new.len(),
|
||||
);
|
||||
let type_def = ClassDef::new(def, vec![]);
|
||||
new.push(Expr::ClassDef(type_def));
|
||||
}
|
||||
_ => {
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
new.push(Expr::Def(def));
|
||||
}
|
||||
}
|
||||
}
|
||||
Expr::Methods(methods) => match &methods.class {
|
||||
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
|
||||
if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) {
|
||||
let mut class_def = match new.remove(*pos) {
|
||||
Expr::ClassDef(class_def) => class_def,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
class_def.methods_list.push(methods);
|
||||
new.insert(*pos, Expr::ClassDef(class_def));
|
||||
} else {
|
||||
let similar_name = self
|
||||
.def_root_pos_map
|
||||
.keys()
|
||||
.fold("".to_string(), |acc, key| acc + &key[..] + ",");
|
||||
self.errs.push(ParseError::no_var_error(
|
||||
line!() as usize,
|
||||
methods.class.loc(),
|
||||
simple.name.inspect(),
|
||||
Some(similar_name),
|
||||
));
|
||||
}
|
||||
}
|
||||
other => todo!("{other}"),
|
||||
},
|
||||
other => {
|
||||
new.push(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
let ast = AST::new(ast.name, Module::new(new));
|
||||
log!(info "the reordering process has completed:\n{}", ast);
|
||||
if self.errs.is_empty() {
|
||||
Ok(ast)
|
||||
} else {
|
||||
Err(self.errs)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue