1#![doc = include_str!("../README.md")]
2
3use std::{fs::File, io::Read, path::Path, sync::Arc};
4
5use kdl::KdlDocument;
6use miette::{Diagnostic, NamedSource};
7use thiserror::Error;
8
9pub use parse::{KdlScriptParseError, ParsedProgram, PunEnv};
10pub use types::{Definition, DefinitionGraph, KdlScriptTypeError, TypedProgram};
11
12#[cfg(feature = "eval")]
13pub mod eval;
14pub mod parse;
15pub mod spanned;
16#[cfg(test)]
17mod tests;
18pub mod types;
19
20#[derive(Debug, Error, Diagnostic)]
21pub enum KdlScriptError {
22 #[error(transparent)]
23 Io(#[from] std::io::Error),
24
25 #[error(transparent)]
26 #[diagnostic(transparent)]
27 Kdl(#[from] kdl::KdlError),
28
29 #[error(transparent)]
30 #[diagnostic(transparent)]
31 Parse(#[from] KdlScriptParseError),
32
33 #[error(transparent)]
34 #[diagnostic(transparent)]
35 Type(#[from] KdlScriptTypeError),
36}
37
38pub struct ErrorHandler {
39 pub error_style: ErrorStyle,
40 pub error_mode: ErrorMode,
41}
42
43pub enum ErrorMode {
44 Gather(Vec<KdlScriptError>),
45 Scream,
46}
47
48pub enum ErrorStyle {
49 Human,
50 Json,
51}
52
53pub struct Compiler {
54 pub source: Option<Arc<NamedSource>>,
56 pub parsed: Option<Arc<ParsedProgram>>,
57 pub typed: Option<Arc<TypedProgram>>,
58}
59
60pub type Result<T> = std::result::Result<T, KdlScriptError>;
61
62impl Compiler {
63 pub fn new() -> Self {
64 Self {
65 source: None,
72 parsed: None,
73 typed: None,
74 }
75 }
76
77 pub fn compile_path(
78 &mut self,
79 src_path: impl AsRef<Path>,
80 ) -> std::result::Result<Arc<TypedProgram>, KdlScriptError> {
81 let src_path = src_path.as_ref();
82 let input_name = src_path.display().to_string();
83 let mut input_file = File::open(src_path)?;
84 let mut input_string = String::new();
85 input_file.read_to_string(&mut input_string)?;
86
87 self.compile_string(&input_name, input_string)
88 }
89
90 pub fn compile_string(
91 &mut self,
92 input_name: &str,
93 input_string: String,
94 ) -> std::result::Result<Arc<TypedProgram>, KdlScriptError> {
95 let input_string = Arc::new(input_string);
96
97 let src = Arc::new(miette::NamedSource::new(input_name, input_string.clone()));
98 self.source = Some(src.clone());
99
100 let kdl_doc: KdlDocument = input_string.parse::<kdl::KdlDocument>()?;
101 let parsed = Arc::new(parse::parse_kdl_script(self, src, &kdl_doc)?);
102 self.parsed = Some(parsed.clone());
103 let typed = Arc::new(types::typeck(self, &parsed)?);
104 self.typed = Some(typed.clone());
105
106 Ok(typed)
107 }
108
109 pub fn eval(&mut self) -> std::result::Result<Option<i64>, KdlScriptError> {
110 if let (Some(src), Some(parsed)) = (&self.source, &self.parsed) {
111 if parsed.funcs.contains_key("main") {
112 let val = eval::eval_kdl_script(src, parsed)?;
113 return Ok(Some(val));
114 }
115 }
116 Ok(None)
117 }
118}
119
120impl Default for Compiler {
121 fn default() -> Self {
122 Self::new()
123 }
124}