1pub mod common;
6pub mod compiler;
7pub mod core;
8pub mod error;
9pub mod runtime;
10
11pub use ahash; extern crate fnv;
14
15use common::{Function, KaonFile, Spanned, state::State};
16use compiler::{Resolver, Token, TypeChecker, AST};
17use error::{Error, Errors};
18use runtime::{Vm, VmSettings};
19
20use std::{fmt, fmt::Debug, fmt::Display, path::PathBuf, rc::Rc};
21
22pub use {common::Source, common::Value, compiler::Scope};
23
24pub type Result<T> = std::result::Result<T, KaonError>;
25
26pub enum KaonError {
27 ParserError(Error),
28 CompilerError(String),
29 RuntimeError(String),
30 InvalidScriptPath(String),
31 MultipleErrors(Errors),
32}
33
34impl Display for KaonError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 Self::CompilerError(error) => write!(f, "{}", error),
38 Self::ParserError(error) => write!(f, "{}", error),
39 Self::RuntimeError(error) => write!(f, "{}", error),
40 Self::InvalidScriptPath(path) => {
41 write!(f, "the path '{}' could not be found", path)
42 }
43 Self::MultipleErrors(errors) => write!(f, "{}", errors),
44 }
45 }
46}
47
48impl Debug for KaonError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::CompilerError(error) => write!(f, "{error}"),
52 Self::ParserError(error) => write!(f, "{error}"),
53 Self::RuntimeError(error) => write!(f, "{error}"),
54 Self::InvalidScriptPath(path) => {
55 write!(f, "the path '{path}' could not be found")
56 }
57 Self::MultipleErrors(errors) => write!(f, "{errors}"),
58 }
59 }
60}
61
62pub struct KaonSettings {
63 pub stdin: Rc<dyn KaonFile>,
64 pub stdout: Rc<dyn KaonFile>,
65 pub stderr: Rc<dyn KaonFile>,
66}
67
68impl Default for KaonSettings {
69 fn default() -> Self {
70 let settings = VmSettings::default();
71 KaonSettings {
72 stdin: settings.stdin,
73 stdout: settings.stdout,
74 stderr: settings.stderr,
75 }
76 }
77}
78
79pub struct Kaon {
98 pub vm: Vm,
99 pub state: State,
100 chunk: Function,
101}
102
103impl Default for Kaon {
104 fn default() -> Self {
105 Kaon::new()
106 }
107}
108
109impl Kaon {
110 pub fn new() -> Self {
111 Self::with_settings(KaonSettings::default())
112 }
113
114 pub fn with_settings(settings: KaonSettings) -> Self {
115 Kaon {
116 vm: Vm::with_settings(VmSettings {
117 stdin: settings.stdin,
118 stdout: settings.stdout,
119 stderr: settings.stderr,
120 }),
121 state: State::new(),
122 chunk: Function::script(),
123 }
124 }
125
126 pub fn compile(&mut self, script: &str) -> Result<Function> {
128 let source = Source::contents(script);
129 self.compile_from_source(source)
130 }
131
132 pub fn compile_from_source(&mut self, source: Rc<Source>) -> Result<Function> {
134 let tokens = self.tokenize(source)?;
135 let ast = self.parse(tokens)?;
136
137 let scope = self.type_check(&ast)?;
138
139 let mut compiler = compiler::Compiler::default();
140 let bytecode = compiler.run(&ast, scope);
141
142 match bytecode {
143 Ok(bytecode) => {
144 self.chunk = bytecode.clone();
145 Ok(bytecode)
146 }
147 Err(err) => panic!("{:?}", err),
148 }
149 }
150
151 pub fn compile_with_scope(
153 &mut self,
154 scope: &mut Scope,
155 source: Rc<Source>,
156 ) -> Result<(Function, Scope)> {
157 let tokens = self.tokenize(source)?;
158 let ast = self.parse(tokens)?;
159
160 let mut resolver = Resolver::with_scope(scope);
161 resolver.resolve_ast(&ast);
162
163 let globals = resolver.global_scope();
164
165 if !resolver.errors.is_empty() {
166 return Err(KaonError::MultipleErrors(Errors::from(resolver.errors)));
167 }
168
169 let mut compiler = compiler::Compiler::default();
170 let bytecode = compiler.run(&ast, resolver.global_scope());
171
172 match bytecode {
173 Ok(bytecode) => {
174 self.chunk = bytecode.clone();
175 Ok((bytecode, globals))
176 }
177 Err(err) => panic!("{:?}", err),
178 }
179 }
180
181 pub fn compile_ast(
200 &mut self,
201 ast: AST,
202 scope: &mut Scope,
203 ) -> Result<(Function, Scope)> {
204 let mut resolver = Resolver::with_scope(scope);
205 resolver.resolve_ast(&ast);
206
207 let globals = resolver.global_scope();
208
209 if !resolver.errors.is_empty() {
210 return Err(KaonError::MultipleErrors(Errors::from(resolver.errors)));
211 }
212
213 let mut compiler = compiler::Compiler::default();
214 let bytecode = compiler.run(&ast, resolver.global_scope());
215
216 match bytecode {
217 Ok(bytecode) => {
218 self.chunk = bytecode.clone();
219 Ok((bytecode, globals))
220 }
221 Err(err) => Err(KaonError::CompilerError(err.0)),
222 }
223 }
224
225 pub fn run(&mut self) -> Result<Value> {
227 let value = self.vm
228 .execute(Rc::new(self.chunk.clone()))
229 .map_err(KaonError::RuntimeError);
230
231 self.vm.clear();
232
233 value
234 }
235
236 pub fn run_from_script(&mut self, script: &str) -> Result<Value> {
238 self.compile(script)?;
239 self.run()
240 }
241
242 pub fn run_from_source(&mut self, source: Rc<Source>) -> Result<Value> {
244 self.compile_from_source(source)?;
245 self.run()
246 }
247
248 pub fn run_with_scope(
250 &mut self,
251 scope: &mut Scope,
252 source: Rc<Source>,
253 ) -> Result<(Value, Scope)> {
254 let scope = self.compile_with_scope(scope, source)?.1;
255 let value = self.run()?;
256
257 Ok((value, scope))
258 }
259
260 pub fn parse_from_script(&self, script: &str) -> Result<AST> {
262 let source = Source::contents(script);
263 let tokens = self.tokenize(source)?;
264 self.parse(tokens)
265 }
266
267 pub fn parse(&self, tokens: Spanned<Vec<Token>>) -> Result<AST> {
269 let mut parser = compiler::Parser::new(tokens);
270 let ast = parser.parse();
271 match ast {
272 Ok(ast) => Ok(ast),
273 Err(err) => Err(KaonError::ParserError(err)),
274 }
275 }
276
277 pub fn tokenize(&self, source: Rc<Source>) -> Result<Spanned<Vec<Token>>> {
279 let mut lexer = compiler::Lexer::new(source);
280 let tokens = lexer.tokenize();
281 match tokens {
282 Ok(token_stream) => Ok(token_stream),
283 Err(err) => Err(KaonError::ParserError(err)),
284 }
285 }
286
287 pub fn type_check(&mut self, ast: &AST) -> Result<Scope> {
289 let mut resolver = Resolver::default();
290 resolver.resolve_ast(ast);
291
292 if !resolver.errors.is_empty() {
293 return Err(KaonError::MultipleErrors(Errors::from(resolver.errors)));
294 }
295
296 let mut typechecker = TypeChecker::new();
297 typechecker.check_ast(ast);
298
299 if !typechecker.errors.is_empty() {
300 return Err(KaonError::MultipleErrors(Errors::from(typechecker.errors)));
301 }
302
303 Ok(resolver.global_scope())
304 }
305
306 pub fn read_file(&self, path: PathBuf) -> Result<Rc<Source>> {
308 Source::from_file(path.to_str().unwrap())
309 .map_err(|_| KaonError::InvalidScriptPath(path.to_str().unwrap().to_string()))
310 }
311
312 pub fn prelude(&mut self) -> &mut State {
314 self.vm.prelude()
315 }
316
317 pub fn globals(&mut self) -> &mut State {
319 &mut self.state
320 }
321}