cl-parser: Implement a module inlining pass
This commit is contained in:
parent
02323ae6f2
commit
9c3c2e8674
102
compiler/cl-parser/src/inliner.rs
Normal file
102
compiler/cl-parser/src/inliner.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
//! The [ModuleInliner] reads files described in the module structure of the
|
||||||
|
|
||||||
|
use crate::Parser;
|
||||||
|
use cl_ast::{ast_visitor::Fold, *};
|
||||||
|
use cl_lexer::Lexer;
|
||||||
|
use std::{
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
type IoErrs = Vec<(PathBuf, std::io::Error)>;
|
||||||
|
type ParseErrs = Vec<(PathBuf, crate::error::Error)>;
|
||||||
|
|
||||||
|
pub struct ModuleInliner {
|
||||||
|
path: PathBuf,
|
||||||
|
io_errs: IoErrs,
|
||||||
|
parse_errs: ParseErrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleInliner {
|
||||||
|
/// Creates a new [ModuleInliner]
|
||||||
|
pub fn new(root: impl AsRef<Path>) -> Self {
|
||||||
|
Self {
|
||||||
|
path: root.as_ref().to_path_buf(),
|
||||||
|
io_errs: Default::default(),
|
||||||
|
parse_errs: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn inline(mut self, file: File) -> Result<File, (File, IoErrs, ParseErrs)> {
|
||||||
|
let file = self.fold_file(file);
|
||||||
|
|
||||||
|
if self.io_errs.is_empty() && self.parse_errs.is_empty() {
|
||||||
|
Ok(file)
|
||||||
|
} else {
|
||||||
|
Err((file, self.io_errs, self.parse_errs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Records an [I/O error](std::io::Error), and rebuilds the outline [Module]
|
||||||
|
fn io_oops(&mut self, name: Identifier, error: std::io::Error) -> Module {
|
||||||
|
self.io_errs.push((self.path.clone(), error));
|
||||||
|
Module { name, kind: ModuleKind::Outline }
|
||||||
|
}
|
||||||
|
/// Records a [parse error](crate::error::Error), and rebuilds the outline [Module]
|
||||||
|
fn parse_oops(&mut self, name: Identifier, error: crate::error::Error) -> Module {
|
||||||
|
self.parse_errs.push((self.path.clone(), error));
|
||||||
|
Module { name, kind: ModuleKind::Outline }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fold for ModuleInliner {
|
||||||
|
fn fold_module(&mut self, m: Module) -> cl_ast::Module {
|
||||||
|
let Module { name, kind } = m;
|
||||||
|
let mut inliner = PathMiser::new(self, &name.0);
|
||||||
|
|
||||||
|
let kind = inliner.fold_module_kind(kind);
|
||||||
|
|
||||||
|
let ModuleKind::Outline = kind else {
|
||||||
|
return Module { name, kind };
|
||||||
|
};
|
||||||
|
|
||||||
|
inliner.path.set_extension("cl");
|
||||||
|
let file = match std::fs::read_to_string(&inliner.path) {
|
||||||
|
Err(e) => return inliner.io_oops(name, e),
|
||||||
|
Ok(s) => s,
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = match Parser::new(Lexer::new(&file)).file() {
|
||||||
|
Err(e) => return inliner.parse_oops(name, e),
|
||||||
|
Ok(file) => ModuleKind::Inline(file),
|
||||||
|
};
|
||||||
|
|
||||||
|
inliner.path.set_extension("");
|
||||||
|
Module { name, kind: inliner.fold_module_kind(kind) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// I am the [Path] miser. Whatever I touch turns to [Path] in my clutch.
|
||||||
|
pub struct PathMiser<'mi> {
|
||||||
|
mi: &'mi mut ModuleInliner,
|
||||||
|
}
|
||||||
|
impl<'mi> PathMiser<'mi> {
|
||||||
|
pub fn new(mi: &'mi mut ModuleInliner, name: &str) -> Self {
|
||||||
|
mi.path.push(name);
|
||||||
|
Self { mi }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'mi> Deref for PathMiser<'mi> {
|
||||||
|
type Target = ModuleInliner;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.mi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'mi> DerefMut for PathMiser<'mi> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.mi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'mi> Drop for PathMiser<'mi> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.mi.path.pop();
|
||||||
|
}
|
||||||
|
}
|
@ -14,3 +14,5 @@ use cl_token::*;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
|
pub mod inliner;
|
||||||
|
@ -3,12 +3,12 @@ use cl_ast::{
|
|||||||
desugar::{squash_groups::SquashGroups, while_else::WhileElseDesugar},
|
desugar::{squash_groups::SquashGroups, while_else::WhileElseDesugar},
|
||||||
};
|
};
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use cl_parser::Parser;
|
use cl_parser::{inliner::ModuleInliner, Parser};
|
||||||
use cl_typeck::{
|
use cl_typeck::{
|
||||||
definition::Def, name_collector::NameCollectable, project::Project, type_resolver::resolve,
|
definition::Def, name_collector::NameCollectable, project::Project, type_resolver::resolve,
|
||||||
};
|
};
|
||||||
use repline::{error::Error as RlError, prebaked::*};
|
use repline::{error::Error as RlError, prebaked::*};
|
||||||
use std::error::Error;
|
use std::{error::Error, path};
|
||||||
|
|
||||||
// Path to display in standard library errors
|
// Path to display in standard library errors
|
||||||
const STDLIB_DISPLAY_PATH: &str = "stdlib/lib.cl";
|
const STDLIB_DISPLAY_PATH: &str = "stdlib/lib.cl";
|
||||||
@ -37,6 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Err(e)?
|
Err(e)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let code = inline_modules(code, concat!(env!("PWD"), "/stdlib"));
|
||||||
|
|
||||||
unsafe { TREES.push(code) }.collect_in_root(&mut prj)?;
|
unsafe { TREES.push(code) }.collect_in_root(&mut prj)?;
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ fn enter_code(prj: &mut Project) -> Result<(), RlError> {
|
|||||||
return Ok(Response::Break);
|
return Ok(Response::Break);
|
||||||
}
|
}
|
||||||
let code = Parser::new(Lexer::new(line)).file()?;
|
let code = Parser::new(Lexer::new(line)).file()?;
|
||||||
|
let code = inline_modules(code, "");
|
||||||
let code = WhileElseDesugar.fold_file(code);
|
let code = WhileElseDesugar.fold_file(code);
|
||||||
// Safety: this is totally unsafe
|
// Safety: this is totally unsafe
|
||||||
unsafe { TREES.push(code) }.collect_in_root(prj)?;
|
unsafe { TREES.push(code) }.collect_in_root(prj)?;
|
||||||
@ -117,6 +119,7 @@ fn query_type_expression(prj: &mut Project) -> Result<(), RlError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_all(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
fn resolve_all(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
||||||
|
prj.resolve_imports()?;
|
||||||
for id in prj.pool.key_iter() {
|
for id in prj.pool.key_iter() {
|
||||||
resolve(prj, id)?;
|
resolve(prj, id)?;
|
||||||
}
|
}
|
||||||
@ -148,6 +151,21 @@ fn pretty_def(def: &Def, id: impl Into<usize>) {
|
|||||||
println!("\x1b[90m{module}\x1b[0m");
|
println!("\x1b[90m{module}\x1b[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inline_modules(code: cl_ast::File, path: impl AsRef<path::Path>) -> cl_ast::File {
|
||||||
|
match ModuleInliner::new(path).inline(code) {
|
||||||
|
Err((code, io, parse)) => {
|
||||||
|
for (file, error) in io {
|
||||||
|
eprintln!("{}:{error}", file.display());
|
||||||
|
}
|
||||||
|
for (file, error) in parse {
|
||||||
|
eprintln!("{}:{error}", file.display());
|
||||||
|
}
|
||||||
|
code
|
||||||
|
}
|
||||||
|
Ok(code) => code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn clear() -> Result<(), Box<dyn Error>> {
|
fn clear() -> Result<(), Box<dyn Error>> {
|
||||||
println!("\x1b[H\x1b[2J");
|
println!("\x1b[H\x1b[2J");
|
||||||
banner();
|
banner();
|
||||||
|
105
stdlib/lib.cl
105
stdlib/lib.cl
@ -1,107 +1,10 @@
|
|||||||
//! # The Conlang Standard Library
|
//! # The Conlang Standard Library
|
||||||
|
|
||||||
#[intrinsic = "bool"]
|
pub mod preamble {
|
||||||
pub type bool;
|
pub use super::num::*;
|
||||||
|
|
||||||
#[intrinsic = "char"]
|
|
||||||
pub type char;
|
|
||||||
|
|
||||||
#[intrinsic = "i8"]
|
|
||||||
pub type i8;
|
|
||||||
|
|
||||||
#[intrinsic = "i16"]
|
|
||||||
pub type i16;
|
|
||||||
|
|
||||||
#[intrinsic = "i32"]
|
|
||||||
pub type i32;
|
|
||||||
|
|
||||||
#[intrinsic = "i64"]
|
|
||||||
pub type i64;
|
|
||||||
|
|
||||||
#[intrinsic = "u8"]
|
|
||||||
pub type u8;
|
|
||||||
|
|
||||||
#[intrinsic = "u16"]
|
|
||||||
pub type u16;
|
|
||||||
|
|
||||||
#[intrinsic = "u32"]
|
|
||||||
pub type u32;
|
|
||||||
|
|
||||||
#[intrinsic = "u64"]
|
|
||||||
pub type u64;
|
|
||||||
|
|
||||||
impl bool {
|
|
||||||
const MIN: Self = false;
|
|
||||||
const MAX: Self = {
|
|
||||||
fn ret_true() -> Self {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
ret_true()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn if_else() -> i32 {
|
pub mod num;
|
||||||
// block 1
|
|
||||||
let x = 10;
|
|
||||||
let y = x + 2;
|
|
||||||
|
|
||||||
if x > 10
|
|
||||||
// compare x and 10
|
|
||||||
// end block 1, goto block 2 else goto block 3
|
|
||||||
{
|
|
||||||
// block 2
|
|
||||||
4
|
|
||||||
// end block 2, goto block 4
|
|
||||||
} else {
|
|
||||||
// block 3
|
|
||||||
5
|
|
||||||
// end block 3, goto block 4
|
|
||||||
}
|
|
||||||
// block 4
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg("test")]
|
#[cfg("test")]
|
||||||
mod test {
|
mod test;
|
||||||
//! Tests for funky behavior
|
|
||||||
|
|
||||||
struct UnitLike;
|
|
||||||
|
|
||||||
struct TupleLike(super::i32, super::self::test::super::char)
|
|
||||||
|
|
||||||
struct StructLike {
|
|
||||||
pub member1: UnitLike,
|
|
||||||
member2: TupleLike,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum NeverLike;
|
|
||||||
|
|
||||||
enum EmptyLike {
|
|
||||||
Empty,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Hodgepodge {
|
|
||||||
Empty,
|
|
||||||
UnitLike (),
|
|
||||||
Tuple (TupleLike),
|
|
||||||
StructEmpty {},
|
|
||||||
StructLike { member1: UnitLike, member2: TupleLike },
|
|
||||||
}
|
|
||||||
|
|
||||||
fn noop () -> bool {
|
|
||||||
loop if false {
|
|
||||||
|
|
||||||
} else break loop if false {
|
|
||||||
|
|
||||||
} else break loop if false {
|
|
||||||
|
|
||||||
} else break true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn while_else() -> i32 {
|
|
||||||
while conditional {
|
|
||||||
pass
|
|
||||||
} else {
|
|
||||||
fail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
41
stdlib/num.cl
Normal file
41
stdlib/num.cl
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//! The primitive numeric types
|
||||||
|
|
||||||
|
#[intrinsic = "bool"]
|
||||||
|
pub type bool;
|
||||||
|
|
||||||
|
#[intrinsic = "char"]
|
||||||
|
pub type char;
|
||||||
|
|
||||||
|
#[intrinsic = "i8"]
|
||||||
|
pub type i8;
|
||||||
|
|
||||||
|
#[intrinsic = "i16"]
|
||||||
|
pub type i16;
|
||||||
|
|
||||||
|
#[intrinsic = "i32"]
|
||||||
|
pub type i32;
|
||||||
|
|
||||||
|
#[intrinsic = "i64"]
|
||||||
|
pub type i64;
|
||||||
|
|
||||||
|
#[intrinsic = "u8"]
|
||||||
|
pub type u8;
|
||||||
|
|
||||||
|
#[intrinsic = "u16"]
|
||||||
|
pub type u16;
|
||||||
|
|
||||||
|
#[intrinsic = "u32"]
|
||||||
|
pub type u32;
|
||||||
|
|
||||||
|
#[intrinsic = "u64"]
|
||||||
|
pub type u64;
|
||||||
|
|
||||||
|
impl bool {
|
||||||
|
const MIN: Self = false;
|
||||||
|
const MAX: Self = {
|
||||||
|
fn ret_true() -> Self {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ret_true()
|
||||||
|
};
|
||||||
|
}
|
66
stdlib/test.cl
Normal file
66
stdlib/test.cl
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
//! Tests for funky behavior
|
||||||
|
use super::preamble::*;
|
||||||
|
|
||||||
|
struct UnitLike;
|
||||||
|
|
||||||
|
struct TupleLike(super::i32, super::self::test::char)
|
||||||
|
|
||||||
|
struct StructLike {
|
||||||
|
pub member1: UnitLike,
|
||||||
|
member2: TupleLike,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NeverLike;
|
||||||
|
|
||||||
|
enum EmptyLike {
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Hodgepodge {
|
||||||
|
Empty,
|
||||||
|
UnitLike (),
|
||||||
|
Tuple (TupleLike),
|
||||||
|
StructEmpty {},
|
||||||
|
StructLike { member1: UnitLike, member2: TupleLike },
|
||||||
|
}
|
||||||
|
|
||||||
|
fn noop () -> bool {
|
||||||
|
loop if false {
|
||||||
|
|
||||||
|
} else break loop if false {
|
||||||
|
|
||||||
|
} else break loop if false {
|
||||||
|
|
||||||
|
} else break true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_else() -> i32 {
|
||||||
|
while conditional {
|
||||||
|
pass
|
||||||
|
} else {
|
||||||
|
fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_else() -> i32 {
|
||||||
|
// block 1
|
||||||
|
let x = 10;
|
||||||
|
let y = x + 2;
|
||||||
|
|
||||||
|
if x > 10
|
||||||
|
// compare x and 10
|
||||||
|
// end block 1, goto block 2 else goto block 3
|
||||||
|
{
|
||||||
|
// block 2
|
||||||
|
4
|
||||||
|
// end block 2, goto block 4
|
||||||
|
} else {
|
||||||
|
// block 3
|
||||||
|
5
|
||||||
|
// end block 3, goto block 4
|
||||||
|
}
|
||||||
|
// block 4
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = 0;
|
Loading…
Reference in New Issue
Block a user