1mod bsjfl;
2mod error;
3mod file;
4mod parse;
5mod session;
6mod statement;
7mod ty;
8mod value;
9
10#[cfg(test)]
11mod tests;
12
13pub use error::SJFLError;
14pub use session::Session;
15pub use ty::SJFLType;
16pub use value::{
17 Datetime,
18 InternedString,
19 List,
20 Table,
21 Value,
22};
23
24use bsjfl::decode_timestamp;
25use parse::{ Parse, skip_whitespaces_and_comments };
26use statement::Statement;
27use std::collections::HashMap;
28
29pub fn evaluate(s: &str, session: &mut Session) -> Result<Value, (SJFLError, String)> {
33 let mut index = 0;
34 let s = s.as_bytes();
35
36 index = skip_whitespaces_and_comments(s, index).map_err(|e| (e.clone(), e.to_string(session, s)))?;
37
38 let (mut v, _) = Value::parse(s, index, session).map_err(|e| (e.clone(), e.to_string(session, s)))?;
39 v.reduce_vars(session).map_err(|e| (e.clone(), e.to_string(session, s)))?;
40
41 Ok(v)
42}
43
44pub fn evaluate_file(file_name: &str, session: &mut Session) -> Result<Value, (SJFLError, String)> {
55 let session_vars = session.vars.clone();
56 session.vars = HashMap::new();
57
58 let result = evaluate_file_(file_name, session);
59 session.vars = session_vars;
60
61 result
62}
63
64fn evaluate_file_(file_name: &str, session: &mut Session) -> Result<Value, (SJFLError, String)> {
65 let mut candidates = (None, None, None); for file in session.files.iter() {
68 if file.get_file_name() == file_name {
69 if file.is_json {
70 candidates.1 = Some(file.clone());
71 }
72
73 else if file.is_binary {
74 candidates.2 = Some(file.clone());
75 }
76
77 else {
78 candidates.0 = Some(file.clone());
79 }
80 }
81 }
82
83 match candidates {
85 (None, None, None) => Err(
86 SJFLError::FileError {
87 path: Some(file_name.to_string()),
88 msg: format!("failed to evaluate `{file_name}`! make sure that it does not contain extension (eg: `foo`, not `foo.sjfl`), and the session is properly initialized (call `session.init_dir` or `Session::new_dir`)"),
89 }
90 ).map_err(|e| (e.clone(), e.to_string(session, &[]))),
91 (Some(f), None, None) | (None, Some(f), None) | (Some(f), Some(_), None) => match f.get_content() {
92 Ok(b) => {
93 let result = evaluate(&String::from_utf8_lossy(&b), session)?;
94 let new_binary_file = f.save_binary(result.clone(), session, f.timestamp);
95 session.files.push(new_binary_file);
96
97 Ok(result)
98 },
99 Err(e) => Err(SJFLError::FileError {
100 path: Some(f.path.clone()),
101 msg: format!("{e:?}"),
102 }).map_err(|e| (e.clone(), e.to_string(session, &[]))),
103 },
104 (None, None, Some(f)) => {
105 let mut cursor = 0;
106
107 match f.get_content() {
108 Ok(b) => Value::from_bin(&b, &mut cursor, session).map_err(|e| (e.clone(), e.to_string(session, &[]))),
109 Err(e) => Err(SJFLError::FileError {
110 path: Some(f.path.clone()),
111 msg: format!("{e:?}"),
112 }).map_err(|e| (e.clone(), e.to_string(session, &[]))),
113 }
114 },
115 (Some(f), None, Some(bf)) | (None, Some(f), Some(bf)) | (Some(f), Some(_), Some(bf)) => {
116 let (bf_content, has_to_read_raw_text) = if let Ok(bf_content) = bf.get_content() {
117 if let Ok(timestamp) = decode_timestamp(&bf_content, session) {
118 if timestamp == f.timestamp {
119 (bf_content, false)
120 }
121
122 else {
123 (vec![], true)
124 }
125 }
126
127 else {
128 (vec![], true)
129 }
130 }
131
132 else {
133 (vec![], true)
134 };
135
136 if has_to_read_raw_text {
137 match f.get_content() {
138 Ok(f_content) => {
139 let result = evaluate(&String::from_utf8_lossy(&f_content), session)?;
140 let new_binary_file = f.save_binary(result.clone(), session, f.timestamp);
141 session.files.push(new_binary_file);
142
143 Ok(result)
144 },
145 Err(e) => Err(SJFLError::FileError {
146 path: Some(f.path.clone()),
147 msg: format!("Binary file is outdated, and raw-text file is broken: {e:?}"),
148 }).map_err(|e| (e.clone(), e.to_string(session, &[]))),
149 }
150 }
151
152 else {
153 let mut cursor = 0;
154
155 Value::from_bin(&bf_content, &mut cursor, session).map_err(|e| (e.clone(), e.to_string(session, &[])))
156 }
157 },
158 }
159}
160
161pub fn execute(s: &str, session: &mut Session) -> Result<(), (SJFLError, String)> {
165 let mut index = 0;
166 let s = s.as_bytes();
167
168 loop {
169 index = match skip_whitespaces_and_comments(s, index) {
170 Err(SJFLError::UnexpectedEof(_)) => { return Ok(()); }, Err(e) => { return Err((e.clone(), e.to_string(session, s))); }
172 Ok(n) => n
173 };
174
175 let (st, new_index) = Statement::parse(s, index, session).map_err(|e| (e.clone(), e.to_string(session, s)))?;
176 index = new_index;
177
178 st.execute(session).map_err(|e| (e.clone(), e.to_string(session, s)))?;
179 }
180}
181
182pub fn execute_file(file_name: &str, session: &mut Session) -> Result<(), (SJFLError, String)> {
186 todo!()
187}