1use crate::interpreter::errors::RuntimeError;
2use crate::interpreter::FunctionMap;
3use crate::interpreter::Interpreter;
4use crate::interpreter::Value;
5use crate::lexer::token::Token;
6use crate::lexer::Lexer;
7use crate::parser::ast::pretty::TreePrinter;
8use crate::parser::ast::Ast;
9use crate::parser::Parser;
10use miette::Report;
11use std::fmt::Write;
12use std::marker::PhantomData;
13use std::path::PathBuf;
14use std::sync::Arc;
15use std::{fmt, fs, io};
16
17pub struct Initialized;
18pub struct Lexed;
19pub struct Parsed;
20pub struct Executed;
21pub struct ExecutedWithDebug;
22
23pub struct ApLang<State = Initialized> {
24 source_code: Arc<str>,
25 file_path: Option<PathBuf>,
26
27 tokens: Option<Vec<Token>>, ast: Option<Ast>, values: Option<Vec<Value>>,
30
31 _state: PhantomData<State>,
32}
33
34impl ApLang {
35 pub fn new_from_file(file_path: PathBuf) -> io::Result<Self> {
36 let source_code: Arc<str> = fs::read_to_string(file_path.clone())?.into();
38
39 Ok(Self {
40 source_code,
41 file_path: Some(file_path),
42
43 tokens: None,
44 ast: None,
45 values: None,
46
47 _state: PhantomData,
48 })
49 }
50
51 pub fn new_from_stdin(source_code: impl Into<Arc<str>>) -> Self {
52 ApLang {
53 source_code: source_code.into(),
54 file_path: Some(PathBuf::default()),
55 tokens: None,
56 ast: None,
57 values: None,
58
59 _state: PhantomData,
60 }
61 }
62
63 pub fn new(source_code: impl Into<Arc<str>>, file_path: Option<PathBuf>) -> Self {
65 Self {
66 source_code: source_code.into(),
67 file_path,
68
69 tokens: None,
70 ast: None,
71 values: None,
72
73 _state: PhantomData,
74 }
75 }
76
77 pub fn get_source_code(&self) -> Arc<str> {
78 self.source_code.clone()
79 }
80}
81
82impl ApLang<Initialized> {
83 pub fn lex(self) -> Result<ApLang<Lexed>, Vec<Report>> {
85 let file_name = self
86 .file_path
87 .clone()
88 .unwrap()
89 .file_name()
90 .map(|name| name.to_string_lossy().into_owned())
91 .unwrap_or_default();
92
93 let tokens = Lexer::scan(self.source_code.clone(), file_name)?;
94
95 Ok(ApLang {
97 source_code: self.source_code,
98 file_path: self.file_path,
99 tokens: Some(tokens), ast: None,
101 values: None,
102
103 _state: PhantomData,
104 })
105 }
106}
107
108impl ApLang<Lexed> {
109 pub fn parse(self) -> Result<ApLang<Parsed>, Vec<Report>> {
110 let tokens = unsafe { self.tokens.unwrap_unchecked() };
112
113 let file_name = self
114 .file_path
115 .clone()
116 .unwrap()
117 .file_name()
118 .map(|name| name.to_string_lossy().into_owned())
119 .unwrap_or_default();
120
121 let mut parser = Parser::new(tokens, Arc::clone(&self.source_code), file_name.as_str());
122
123 let ast = parser.parse()?;
124
125 Ok(ApLang {
126 source_code: self.source_code,
127 file_path: self.file_path,
128 tokens: None,
129 ast: Some(ast),
130 values: None,
131
132 _state: PhantomData,
133 })
134 }
135
136 pub fn debug_output<Writer: Write>(&self, buf: &mut Writer) -> fmt::Result {
137 for token in unsafe { self.tokens.as_ref().unwrap_unchecked() } {
138 if token.is_soft_semi() {
139 write!(buf, " ;")?;
140 }
141
142 write!(buf, "{}", token)?;
143 }
144
145 Ok(())
146 }
147}
148
149impl ApLang<Parsed> {
150 pub fn execute_as_module(self) -> Result<FunctionMap, RuntimeError> {
151 Interpreter::new(unsafe { self.ast.unwrap_unchecked() }, self.file_path).interpret_module()
152 }
153
154 pub fn execute(self) -> Result<ApLang<Executed>, Report> {
155 Interpreter::new(
156 unsafe { self.ast.unwrap_unchecked() },
157 self.file_path.clone(),
158 )
159 .interpret()
160 .map_err(|err| {
161 let named_source = err.named_source.clone();
162 Report::from(err).with_source_code(named_source)
163 })?;
164
165 Ok(ApLang {
166 source_code: self.source_code,
167 file_path: self.file_path,
168 tokens: None,
169 ast: None,
170 values: None,
171
172 _state: PhantomData,
173 })
174 }
175
176 pub fn execute_with_debug(self) -> Result<ApLang<ExecutedWithDebug>, Report> {
177 let ast = unsafe { self.ast.unwrap_unchecked() };
178 let mut interpreter = Interpreter::new(ast, self.file_path.clone());
179 let values = interpreter.interpret_debug().map_err(|err| {
180 let named_source = err.named_source.clone();
181 Report::from(err).with_source_code(named_source)
182 })?;
183
184 Ok(ApLang {
185 source_code: self.source_code,
186 file_path: self.file_path,
187 tokens: None,
188 ast: None,
189 values: Some(values),
190
191 _state: PhantomData,
192 })
193 }
194
195 pub fn debug_output<Writer: Write>(&self, buf: &mut Writer) -> fmt::Result {
196 let ast = unsafe { self.ast.as_ref().unwrap_unchecked() };
197
198 write!(buf, "{}", ast.print_tree())
199 }
200}
201
202impl ApLang<ExecutedWithDebug> {
203 pub fn debug_output<Writer: Write>(&self, buf: &mut Writer) -> fmt::Result {
204 let values = unsafe { self.values.as_ref().unwrap_unchecked() };
205
206 for value in values {
207 writeln!(buf, "EXPR OUTPUT: {}", value)?;
208 }
209
210 Ok(())
211 }
212}