mirror of
https://github.com/exoticorn/curlywas.git
synced 2026-01-20 19:56:42 +01:00
add include support
This commit is contained in:
20
src/ast.rs
20
src/ast.rs
@@ -2,12 +2,23 @@ use std::{fmt, path::PathBuf};
|
|||||||
|
|
||||||
use crate::parser::Span;
|
use crate::parser::Span;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Script {
|
pub struct Script {
|
||||||
pub imports: Vec<Import>,
|
pub imports: Vec<Import>,
|
||||||
pub global_vars: Vec<GlobalVar>,
|
pub global_vars: Vec<GlobalVar>,
|
||||||
pub functions: Vec<Function>,
|
pub functions: Vec<Function>,
|
||||||
pub data: Vec<Data>,
|
pub data: Vec<Data>,
|
||||||
|
pub includes: Vec<Include>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
pub fn merge(&mut self, mut other: Script) {
|
||||||
|
self.imports.append(&mut other.imports);
|
||||||
|
self.global_vars.append(&mut other.global_vars);
|
||||||
|
self.functions.append(&mut other.functions);
|
||||||
|
self.data.append(&mut other.data);
|
||||||
|
assert!(other.includes.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -16,6 +27,13 @@ pub enum TopLevelItem {
|
|||||||
GlobalVar(GlobalVar),
|
GlobalVar(GlobalVar),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Data(Data),
|
Data(Data),
|
||||||
|
Include(Include)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Include {
|
||||||
|
pub span: Span,
|
||||||
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
31
src/lib.rs
31
src/lib.rs
@@ -24,16 +24,41 @@ impl Options {
|
|||||||
|
|
||||||
pub fn compile_file<P: AsRef<Path>>(path: P, options: Options) -> Result<Vec<u8>> {
|
pub fn compile_file<P: AsRef<Path>>(path: P, options: Options) -> Result<Vec<u8>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
let mut script = ast::Script::default();
|
||||||
|
|
||||||
let mut sources = Sources::new();
|
let mut sources = Sources::new();
|
||||||
let id = sources.add(path)?;
|
|
||||||
|
|
||||||
let mut script = match parser::parse(&sources, id) {
|
let mut pending_files = vec![(path.to_path_buf(), None)];
|
||||||
|
while let Some((path, span)) = pending_files.pop() {
|
||||||
|
match sources.add(&path) {
|
||||||
|
Ok((id, true)) => {
|
||||||
|
let mut new_script = match parser::parse(&sources, id) {
|
||||||
Ok(script) => script,
|
Ok(script) => script,
|
||||||
Err(_) => bail!("Parse failed"),
|
Err(_) => bail!("Parse failed"),
|
||||||
};
|
};
|
||||||
|
|
||||||
includes::resolve_includes(&mut script, path)?;
|
includes::resolve_includes(&mut new_script, &path)?;
|
||||||
|
|
||||||
|
for include in std::mem::take(&mut new_script.includes) {
|
||||||
|
let mut path = path.parent().expect("Script path has no parent").to_path_buf();
|
||||||
|
path.push(include.path);
|
||||||
|
pending_files.push((path, Some(include.span)));
|
||||||
|
}
|
||||||
|
|
||||||
|
script.merge(new_script);
|
||||||
|
}
|
||||||
|
Ok((_, false)) => (), // already parsed this include
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(span) = span {
|
||||||
|
let _ = typecheck::report_error(&err.to_string(), &span, &sources);
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to load script {}: {}", path.display(), err);
|
||||||
|
}
|
||||||
|
bail!("Parse failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
constfold::fold_script(&mut script);
|
constfold::fold_script(&mut script);
|
||||||
if typecheck::tc_script(&mut script, &sources).is_err() {
|
if typecheck::tc_script(&mut script, &sources).is_err() {
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ impl Sources {
|
|||||||
Sources(Vec::new())
|
Sources(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, path: &Path) -> Result<usize> {
|
pub fn add(&mut self, path: &Path) -> Result<(usize, bool)> {
|
||||||
let canonical = path.canonicalize()?;
|
let canonical = path.canonicalize()?;
|
||||||
for (index, source) in self.0.iter().enumerate() {
|
for (index, source) in self.0.iter().enumerate() {
|
||||||
if source.path.canonicalize()? == canonical {
|
if source.path.canonicalize()? == canonical {
|
||||||
return Ok(index);
|
return Ok((index, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut source = String::new();
|
let mut source = String::new();
|
||||||
@@ -37,7 +37,7 @@ impl Sources {
|
|||||||
source: ariadne::Source::from(source),
|
source: ariadne::Source::from(source),
|
||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
});
|
});
|
||||||
Ok(self.0.len() - 1)
|
Ok((self.0.len() - 1, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,7 +970,12 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
|
|||||||
})
|
})
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
import.or(function).or(global).or(data).boxed()
|
let include =
|
||||||
|
just(Token::Ident("include".to_string())).ignore_then(string.clone().map_with_span(
|
||||||
|
|path, span| ast::TopLevelItem::Include(ast::Include { span, path }),
|
||||||
|
));
|
||||||
|
|
||||||
|
import.or(function).or(global).or(data).or(include).boxed()
|
||||||
};
|
};
|
||||||
|
|
||||||
top_level_item.repeated().then_ignore(end()).map(|items| {
|
top_level_item.repeated().then_ignore(end()).map(|items| {
|
||||||
@@ -979,6 +984,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
|
|||||||
global_vars: Vec::new(),
|
global_vars: Vec::new(),
|
||||||
functions: Vec::new(),
|
functions: Vec::new(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
|
includes: Vec::new(),
|
||||||
};
|
};
|
||||||
for item in items {
|
for item in items {
|
||||||
match item {
|
match item {
|
||||||
@@ -986,6 +992,7 @@ fn script_parser() -> impl Parser<Token, ast::Script, Error = ScriptError> + Clo
|
|||||||
ast::TopLevelItem::GlobalVar(v) => script.global_vars.push(v),
|
ast::TopLevelItem::GlobalVar(v) => script.global_vars.push(v),
|
||||||
ast::TopLevelItem::Function(f) => script.functions.push(f),
|
ast::TopLevelItem::Function(f) => script.functions.push(f),
|
||||||
ast::TopLevelItem::Data(d) => script.data.push(d),
|
ast::TopLevelItem::Data(d) => script.data.push(d),
|
||||||
|
ast::TopLevelItem::Include(i) => script.includes.push(i),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
script
|
script
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ fn type_mismatch(
|
|||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_error(msg: &str, span: &Span, sources: &Sources) -> Result<()> {
|
pub fn report_error(msg: &str, span: &Span, sources: &Sources) -> Result<()> {
|
||||||
Report::build(ReportKind::Error, span.0, span.1.start)
|
Report::build(ReportKind::Error, span.0, span.1.start)
|
||||||
.with_message(msg)
|
.with_message(msg)
|
||||||
.with_label(
|
.with_label(
|
||||||
|
|||||||
Reference in New Issue
Block a user