Implement module loading and imports
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
use std::{env, fs, process::ExitCode};
|
||||
use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
use decodal_core::{Data, Diagnostic, Engine, parse_source};
|
||||
use decodal_core::{Data, Diagnostic, DiagnosticKind, Engine, LoadedSource, SourceLoader, Span};
|
||||
|
||||
fn main() -> ExitCode {
|
||||
match run() {
|
||||
@@ -26,34 +30,36 @@ fn run() -> Result<(), Diagnostic> {
|
||||
}
|
||||
"check" => {
|
||||
let path = args.next().unwrap_or_else(|| String::from("-"));
|
||||
let source = read_source(&path)?;
|
||||
let parsed = parse_source(&source)?;
|
||||
let mut engine = Engine::from_parse(parsed.ast, parsed.root);
|
||||
let value = engine.eval_root()?;
|
||||
engine.materialize(&value)?;
|
||||
let data = materialize_path(&path)?;
|
||||
drop(data);
|
||||
println!("ok");
|
||||
Ok(())
|
||||
}
|
||||
"eval" | "materialize" => {
|
||||
let path = args.next().unwrap_or_else(|| String::from("-"));
|
||||
materialize_file(&path)
|
||||
let data = materialize_path(&path)?;
|
||||
print_data(&data, 0);
|
||||
println!();
|
||||
Ok(())
|
||||
}
|
||||
path => {
|
||||
let data = materialize_path(path)?;
|
||||
print_data(&data, 0);
|
||||
println!();
|
||||
Ok(())
|
||||
}
|
||||
path => materialize_file(path),
|
||||
}
|
||||
}
|
||||
|
||||
fn materialize_file(path: &str) -> Result<(), Diagnostic> {
|
||||
let source = read_source(path)?;
|
||||
let parsed = parse_source(&source)?;
|
||||
let mut engine = Engine::from_parse(parsed.ast, parsed.root);
|
||||
let value = engine.eval_root()?;
|
||||
let data = engine.materialize(&value)?;
|
||||
print_data(&data, 0);
|
||||
println!();
|
||||
Ok(())
|
||||
fn materialize_path(path: &str) -> Result<Data, Diagnostic> {
|
||||
let root = read_root_source(path)?;
|
||||
let mut engine = Engine::new(FsLoader);
|
||||
let module = engine.add_root_source(root.key, root.name, &root.source)?;
|
||||
let value = engine.eval_module(module)?;
|
||||
engine.materialize(&value)
|
||||
}
|
||||
|
||||
fn read_source(path: &str) -> Result<String, Diagnostic> {
|
||||
fn read_root_source(path: &str) -> Result<LoadedSource, Diagnostic> {
|
||||
if path == "-" {
|
||||
use std::io::Read;
|
||||
let mut source = String::new();
|
||||
@@ -61,23 +67,68 @@ fn read_source(path: &str) -> Result<String, Diagnostic> {
|
||||
.read_to_string(&mut source)
|
||||
.map_err(|error| {
|
||||
Diagnostic::new(
|
||||
decodal_core::DiagnosticKind::Import,
|
||||
decodal_core::Span::default(),
|
||||
DiagnosticKind::Import,
|
||||
Span::default(),
|
||||
format!("failed to read stdin: {error}"),
|
||||
)
|
||||
})?;
|
||||
Ok(source)
|
||||
} else {
|
||||
fs::read_to_string(path).map_err(|error| {
|
||||
Diagnostic::new(
|
||||
decodal_core::DiagnosticKind::Import,
|
||||
decodal_core::Span::default(),
|
||||
format!("failed to read `{path}`: {error}"),
|
||||
)
|
||||
Ok(LoadedSource {
|
||||
key: String::from("<stdin>"),
|
||||
name: String::from("<stdin>"),
|
||||
source,
|
||||
})
|
||||
} else {
|
||||
load_path(Path::new(path))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct FsLoader;
|
||||
|
||||
impl SourceLoader for FsLoader {
|
||||
fn load(
|
||||
&mut self,
|
||||
current_key: Option<&str>,
|
||||
specifier: &str,
|
||||
) -> Result<LoadedSource, Diagnostic> {
|
||||
let path = Path::new(specifier);
|
||||
let path = if path.is_absolute() {
|
||||
PathBuf::from(path)
|
||||
} else if let Some(current_key) = current_key.filter(|key| *key != "<stdin>") {
|
||||
Path::new(current_key)
|
||||
.parent()
|
||||
.unwrap_or_else(|| Path::new("."))
|
||||
.join(path)
|
||||
} else {
|
||||
PathBuf::from(path)
|
||||
};
|
||||
load_path(&path)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_path(path: &Path) -> Result<LoadedSource, Diagnostic> {
|
||||
let canonical = path.canonicalize().map_err(|error| {
|
||||
Diagnostic::new(
|
||||
DiagnosticKind::Import,
|
||||
Span::default(),
|
||||
format!("failed to resolve `{}`: {error}", path.display()),
|
||||
)
|
||||
})?;
|
||||
let source = fs::read_to_string(&canonical).map_err(|error| {
|
||||
Diagnostic::new(
|
||||
DiagnosticKind::Import,
|
||||
Span::default(),
|
||||
format!("failed to read `{}`: {error}", canonical.display()),
|
||||
)
|
||||
})?;
|
||||
let key = canonical.to_string_lossy().into_owned();
|
||||
Ok(LoadedSource {
|
||||
name: key.clone(),
|
||||
key,
|
||||
source,
|
||||
})
|
||||
}
|
||||
|
||||
fn print_help() {
|
||||
println!("Decodal - Deferred Constraint Data Language");
|
||||
println!();
|
||||
@@ -90,8 +141,9 @@ fn print_help() {
|
||||
|
||||
fn print_diagnostic(error: &Diagnostic) {
|
||||
eprintln!(
|
||||
"error[{kind:?}] {start}..{end}: {message}",
|
||||
"error[{kind:?}] {source}:{start}..{end}: {message}",
|
||||
kind = error.kind,
|
||||
source = error.span.source.0,
|
||||
start = error.span.start,
|
||||
end = error.span.end,
|
||||
message = error.message,
|
||||
|
||||
Reference in New Issue
Block a user