···
12
-
closures::CLOSURE_LIST,
13
-
macros::template::SkidTemplate,
reservednames::RESERVED_NAMES_MISC,
16
-
types::{Expand, SkidContext},
12
+
stringtools::TokenTools,
13
+
types::{IsScoped, MacroExpand, SkidContext},
use markdown::{CompileOptions, Constructs, Options, ParseOptions};
···
30
-
use stringtools::{collect_arguments, collect_block, split_to_tokens, trim_whitespace_tokens};
26
+
use stringtools::{collect_arguments, collect_block, split_to_tokens};
use types::{InputFile, Token};
// really need to change this whole thing to work with characters rather than
···
' ', '\n', '\t', '(', ')', '{', '}', '[', ']', '<', '>', '\\', '\'', '\"', ';', '?', '^', '-',
35
+
#[derive(PartialEq)]
36
+
enum EphemeralType {
// let args = ProgramArgs::parse();
···
for group in &mut project.filegroups {
for infile in &mut group.files {
fs::read_to_string(&infile.file_input).expect("File unreadable or missing");
split_to_tokens(contents, project.context.index_of_file(&infile.file_input));
82
-
let mut skid_context = SkidContext::new();
85
-
project.context.index_of_file(&infile.file_input),
86
-
&mut project.context,
88
+
let mut skid_context =
89
+
SkidContext::new(project.context.index_of_file(&infile.file_input));
93
+
&process_skid(&tokens, &mut project.context, &mut skid_context),
94
-
tokens_in: &mut [Token],
96
-
context: &mut ProjectContext,
99
+
fn find_and_run_macro(
100
+
tokens_in: &[Token],
101
+
proj_context: &mut ProjectContext,
skid_context: &mut SkidContext,
99
-
//}, context: &mut ProjectContext) {
100
-
//println!("{}\n {}", f.filename_out, contents);
103
+
) -> Option<(Vec<Token>, usize)> {
104
+
// (Output, to be consumed size)
102
-
//file.tokens = strings_to_tokens(split_keep_delimiters(contents), file.filename_input.clone());
106
+
// At this point we think its a macro (starts with ! or &) so check which, we have the rest of the file
107
+
let ephemeral_type: EphemeralType;
108
+
if tokens_in.len() < 2 {
112
+
if tokens_in[0] == '!' && tokens_in[1] == '&' {
113
+
ephemeral_type = EphemeralType::InverseEphemeral;
114
+
} else if tokens_in[0] == '!' {
115
+
ephemeral_type = EphemeralType::Normal;
116
+
} else if tokens_in[0] == '&' {
117
+
ephemeral_type = EphemeralType::Ephemeral;
104
-
//let mut escaped = false;
105
-
let mut tokens = tokens_in.to_vec();
106
-
let mut starting_template_count = skid_context.templates.len();
122
+
let mut chars_consumed = if ephemeral_type == EphemeralType::InverseEphemeral {
128
+
let mut symbol: String = "".into();
129
+
for tok in &tokens_in[chars_consumed..] {
130
+
if tok.contents.is_whitespace() || DELIMITERS.contains(&tok.contents) {
133
+
symbol.push(tok.contents);
134
+
chars_consumed += 1;
108
-
let mut working_index = 0;
137
+
if symbol.is_empty() {
110
-
while working_index < tokens.len() {
111
-
//look for macros or blocks
112
-
//println!(">\"{}\"<", tokens[working_index].contents);
114
-
if tokens[working_index].contents.len() == 0 {
115
-
working_index += 1;
145
+
let mut expander: &dyn IsScoped = &MACRO_LIST[0]; // assinging because it complains about possibly being empty later even if not the case
146
+
let mut found = false;
147
+
// Check if its a macro
148
+
for m in MACRO_LIST {
149
+
if m.symbol == symbol {
119
-
if tokens[working_index].contents == "\\" {
120
-
tokens[working_index].contents = "".into();
121
-
working_index += 2;
122
-
//println!("Hit backslash");
156
+
// Not a macro check templates
158
+
for t in &skid_context.templates {
159
+
if t.symbol == symbol {
126
-
let mut matched_macro: bool = false;
127
-
if tokens[working_index].contents.starts_with(['!', '&']) {
128
-
let mut prefix_len = 1;
129
-
let mut symbol = tokens[working_index].contents.clone();
130
-
symbol = symbol.trim().to_string();
132
-
if symbol.len() > 2 {
133
-
let mut ephemeral = false;
134
-
let same_file = tokens[working_index].origin_file != file_index;
167
+
// Not a template either, see if its reserved or not to see if we should say something
169
+
let name = symbol.to_lowercase();
170
+
let mut dont_error = false;
136
-
// Inversely Ephemeral
137
-
if symbol.starts_with("!&") {
139
-
ephemeral = !same_file;
172
+
for reserved in RESERVED_NAMES_HTML {
173
+
if name.starts_with(reserved) {
142
-
else if symbol.starts_with("&") {
143
-
ephemeral = same_file;
180
+
for reserved in RESERVED_NAMES_MISC {
181
+
if name.starts_with(reserved) {
146
-
// Check if its a macro
147
-
for m in MACRO_LIST {
148
-
if &symbol[prefix_len..] == m.symbol {
149
-
matched_macro = true;
150
-
//println!("Found a macro ({})", m.symbol);
191
+
tokens_in[0].origin_index,
192
+
tokens_in[0].origin_line,
193
+
&format!("No such macro or defined template \"{symbol}\""),
152
-
let (args, args_tokcount) = collect_arguments(&tokens[working_index..]);
153
-
let expansion: Vec<Token>;
154
-
let block_tokcount: usize;
156
-
//println!("is scoped.");
199
+
let args_result = collect_arguments(&tokens_in[chars_consumed..]);
200
+
if args_result.is_none() {
203
+
tokens_in[0].origin_index,
204
+
tokens_in[0].origin_line,
205
+
&format!("Didnt find any arguments for macro \"{symbol}\"."),
159
-
collect_block(&tokens[(working_index + args_tokcount)..]);
160
-
if block_opt.is_none() {
163
-
tokens[working_index].template_origin,
164
-
tokens[working_index].line_number,
165
-
&"Malformed Block".into(),
168
-
let block: Vec<Token>;
169
-
(block, block_tokcount) = block_opt.unwrap();
210
+
let consumed_by_args;
211
+
(args, consumed_by_args) = args_result.unwrap();
212
+
chars_consumed += consumed_by_args;
172
-
expansion = Vec::new();
174
-
expansion = m.expand(
175
-
tokens[working_index].origin_file,
176
-
tokens[working_index].line_number,
184
-
block_tokcount = 0;
214
+
if expander.is_scoped() {
215
+
let block_result = collect_block(&tokens_in[chars_consumed..]);
216
+
if block_result.is_none() {
219
+
tokens_in[0].origin_index,
220
+
tokens_in[0].origin_line,
221
+
&format!("Didnt find a block for macro \"{symbol}\"."),
225
+
let consumed_by_block;
226
+
(block, consumed_by_block) = block_result.unwrap();
227
+
chars_consumed += consumed_by_block;
229
+
block = Vec::new();
187
-
expansion = Vec::new();
189
-
expansion = m.expand(
190
-
tokens[working_index].origin_file,
191
-
tokens[working_index].line_number,
200
-
let trimmed = trim_whitespace_tokens(&expansion);
202
-
tokens.remove(working_index);
204
-
working_index..(working_index + args_tokcount + block_tokcount - 1),
205
-
trimmed.iter().cloned(),
207
-
if expansion.len() == 0 && working_index > 0 {
208
-
working_index -= 1;
233
+
let return_empty: bool;
213
-
// check for templates
214
-
// todo maybe deduplicate this
215
-
for t in &skid_context.templates {
216
-
if &symbol[prefix_len..] == t.symbol {
217
-
matched_macro = true;
218
-
//println!("Found a macro ({})", m.symbol);
235
+
match ephemeral_type {
236
+
EphemeralType::Normal => return_empty = false,
237
+
EphemeralType::Ephemeral => {
238
+
return_empty = skid_context.file_index != tokens_in[0].origin_index
240
+
EphemeralType::InverseEphemeral => {
241
+
return_empty = skid_context.file_index == tokens_in[0].origin_index
220
-
let (args, args_tokcount) = collect_arguments(&tokens[working_index..]);
221
-
let expansion: Vec<Token>;
222
-
let block_tokcount: usize;
246
+
return Some((Vec::new(), chars_consumed));
248
+
// we have to find it again because of borrower
249
+
for m in MACRO_LIST {
250
+
if m.symbol == symbol {
253
+
tokens_in[0].origin_index,
254
+
tokens_in[0].origin_line,
267
+
while i < skid_context.templates.len() {
268
+
if skid_context.templates[i].symbol == symbol {
270
+
skid_context.templates[i]
272
+
tokens_in[0].origin_index,
273
+
tokens_in[0].origin_line,
225
-
//println!("is scoped.");
226
-
let block: Vec<Token>;
228
-
collect_block(&tokens[(working_index + args_tokcount)..]);
229
-
if block_opt.is_none() {
232
-
tokens[working_index].template_origin,
233
-
tokens[working_index].line_number,
234
-
&"Malformed Block".into(),
290
+
tokens_in: &[Token],
291
+
proj_context: &mut ProjectContext,
292
+
skid_context: &mut SkidContext,
294
+
//}, context: &mut ProjectContext) {
295
+
//println!("{}\n {}", f.filename_out, contents);
238
-
(block, block_tokcount) = block_opt.unwrap();
297
+
//file.tokens = strings_to_tokens(split_keep_delimiters(contents), file.filename_input.clone());
241
-
expansion = Vec::new();
243
-
expansion = t.expand(
245
-
tokens[working_index].origin_file,
246
-
tokens[working_index].line_number,
253
-
block_tokcount = 0;
299
+
//let mut escaped = false;
300
+
let mut tokens = tokens_in.to_vec();
301
+
let starting_template_count = skid_context.templates.len();
256
-
expansion = Vec::new();
258
-
expansion = t.expand(
260
-
tokens[working_index].origin_file,
261
-
tokens[working_index].line_number,
303
+
let mut escaped = false;
304
+
let mut working_index = 0;
269
-
let trimmed = trim_whitespace_tokens(&expansion);
306
+
while working_index < tokens.len() {
307
+
if tokens[working_index] == '\\' && !escaped {
308
+
tokens[working_index].contents = '\0'; // skip over this later when outputting to avoid shifting memory rn
310
+
working_index += 1;
271
-
tokens.remove(working_index);
273
-
working_index..(working_index + args_tokcount + block_tokcount - 1),
274
-
trimmed.iter().cloned(),
276
-
if expansion.len() == 0 && working_index > 0 {
277
-
working_index -= 1;
312
+
// bit of a hack for reverse ephemeral escaping behavior to be the same as previously
313
+
if tokens.len() > working_index + 1
314
+
&& tokens[working_index] == '!'
315
+
&& tokens[working_index + 1] == '&'
317
+
working_index += 1;
282
-
if !matched_macro {
283
-
let name = tokens[working_index].contents.trim().to_lowercase();
284
-
let mut dont_error = name.len() <= 1;
287
-
for reserved in RESERVED_NAMES_HTML {
288
-
if name[1..].starts_with(reserved) {
296
-
for reserved in RESERVED_NAMES_MISC {
297
-
if name[1..].starts_with(reserved) {
307
-
tokens[working_index].origin_file,
308
-
tokens[working_index].line_number,
310
-
"Token written as a function but no such function exists \"{}\"",
311
-
tokens[working_index].contents.trim()
322
+
if (tokens[working_index] == '!' || tokens[working_index] == '&') && !escaped {
324
+
find_and_run_macro(&tokens[working_index..], proj_context, skid_context);
325
+
if expansion.is_some() {
327
+
working_index..working_index + expansion.as_ref().unwrap().1,
328
+
expansion.unwrap().0,
···
327
-
if !matched_macro {
328
-
working_index += 1;
343
+
working_index += 1;
skid_context.templates.truncate(starting_template_count);
349
+
tokens.retain(|t| t.contents != '\0');
335
-
fn write_file(file: InputFile, convert_html: bool) {
354
+
fn write_file(file: &InputFile, convert_html: bool, tokens: &[Token]) {
//println!("{:?}", tokens);
let mut skid_output: String = "".to_string();
338
-
for t in &file.tokens {
339
-
skid_output += &t.contents;
358
+
skid_output.push(t.contents);
let mut folder = file.file_skidout.clone();