Tholp's bespoke website generator

templates

Tholp1 3349e4c1 0bb5d81b

+1
src/macros/clear.rs
···
pub fn macro_clear(
_file: &mut InputFile,
_origin_index: usize,
+
_origin_line: usize,
_context: &mut ProjectContext,
_args: &Vec<String>,
_scope: &[Token],
+4 -2
src/macros/insert.rs
···
pub fn macro_insert(
_file: &mut InputFile,
_origin_index: usize,
+
origin_line: usize,
_context: &mut ProjectContext,
args: &Vec<String>,
_scope: &[Token],
) -> Vec<Token> {
-
let mut origin_file = _context
+
let origin_file = _context
.file_for_index(_origin_index)
.expect("Macro 'Insert' was given a bad origin index")
.clone();
if args.len() != 1 {
println!(
-
"\"{:?}\":Insert only accepts 1 argument, got given {} ({:?})",
+
"{:?}:{} ;Insert only accepts 1 argument, got given {} ({:?})",
origin_file.to_str(),
+
origin_line,
args.len(),
args
);
+3
src/macros/simple_blocks.rs
···
pub fn macro_comment(
_file: &mut InputFile,
_origin_index: usize,
+
_origin_line: usize,
_context: &mut ProjectContext,
_args: &Vec<String>,
_scope: &[Token],
···
pub fn macro_null(
_file: &mut InputFile,
_origin_index: usize,
+
_origin_line: usize,
_context: &mut ProjectContext,
_args: &Vec<String>,
scope: &[Token],
···
pub fn macro_repeat(
_file: &mut InputFile,
_origin_index: usize,
+
_origin_line: usize,
_context: &mut ProjectContext,
args: &Vec<String>,
scope: &[Token],
+134
src/macros/template.rs
···
+
use std::{process::exit, thread::scope};
+
+
use crate::{
+
projectparse::{FileIndexing, ProjectContext},
+
stringtools::{find_pattern, split_to_tokens, strings_to_tokens, WhitespaceChecks},
+
types::{InputFile, Token},
+
};
+
+
use super::MACRO_LIST;
+
+
pub struct SkidTemplate {
+
pub symbol: String,
+
pub args: Vec<String>,
+
pub tokens: Vec<Token>,
+
+
pub has_scope: bool,
+
}
+
+
impl SkidTemplate {
+
pub fn new(name: String, args: &[String], tokens: &[Token]) -> SkidTemplate {
+
let scoped: bool = find_pattern(&tokens, "[[{}]]".into()).is_some();
+
+
SkidTemplate {
+
symbol: name,
+
args: args.to_vec(),
+
tokens: tokens.to_vec(),
+
has_scope: scoped,
+
}
+
}
+
+
pub fn expand(
+
&self,
+
//_file: &mut InputFile,
+
origin_index: usize,
+
_context: &mut ProjectContext,
+
args: &Vec<String>,
+
scope: &[Token],
+
) -> Vec<Token> {
+
println!("{:?}", args);
+
+
let mut output = self.tokens.clone();
+
+
let mut args_index: usize = 0;
+
for param in &self.args {
+
let mut found_pattern = find_pattern(&output, format!("[[{}]]", param));
+
while found_pattern.is_some() {
+
let (start, len) = found_pattern.unwrap();
+
let replacement = split_to_tokens(args[args_index].clone(), origin_index);
+
found_pattern = find_pattern(
+
&output[start + replacement.len()..],
+
format!("[[{}]]", param),
+
);
+
output.splice(start..start + len, replacement);
+
}
+
args_index += 1;
+
}
+
+
let mut found_pattern = find_pattern(&output, "[[{}]]".into());
+
while found_pattern.is_some() {
+
let (start, len) = found_pattern.unwrap();
+
let replacement = scope.to_vec();
+
found_pattern = find_pattern(&output[start + replacement.len()..], "[[{}]]".into());
+
output.splice(start..start + len, replacement);
+
}
+
+
output
+
}
+
}
+
+
pub fn macro_template(
+
file: &mut InputFile,
+
origin_index: usize,
+
origin_line: usize,
+
context: &mut ProjectContext,
+
args: &Vec<String>,
+
scope: &[Token],
+
) -> Vec<Token> {
+
for t in &file.templates {
+
if t.symbol == args[0] {
+
println!(
+
"{:?}:{} ; Attempted template redefinition of \"{}\"",
+
context.file_for_index(origin_index).unwrap(),
+
origin_line,
+
args[0]
+
);
+
exit(1);
+
}
+
}
+
+
for t in &MACRO_LIST {
+
if t.symbol == args[0] {
+
println!(
+
"{:?}:{} ; Attempted to make a template using a reserved name \"{}\"",
+
context.file_for_index(origin_index).unwrap(),
+
origin_line,
+
args[0]
+
);
+
exit(1);
+
}
+
}
+
+
let mut used_params = 0;
+
for param in &args[1..] {
+
if find_pattern(scope, format!("[[{}]]", param)).is_some() {
+
used_params += 1;
+
}
+
if param.contains_whitespace() {
+
println!(
+
"{:?}:{} ; Attempted to make a template with a parameter that contains whitespace \"{}\"",
+
context.file_for_index(origin_index).unwrap(),
+
origin_line,
+
param
+
);
+
exit(1);
+
}
+
}
+
+
if used_params < args.len() - 1 {
+
println!(
+
"{:?}:{} ; Template definition of \"{}\" has {} paramters but only uses {}",
+
context.file_for_index(origin_index).unwrap(),
+
origin_line,
+
args[0],
+
args.len() - 1,
+
used_params
+
);
+
exit(1);
+
}
+
+
let template = SkidTemplate::new(args[0].clone(), &args[1..], scope);
+
file.templates.push(template);
+
+
return Vec::new();
+
}
+65 -4
src/main.rs
···
expansion = (m.expand)(
file,
file.tokens[file.working_index].origin_file,
+
file.tokens[file.working_index].line_number,
context,
&args,
-
&block[3..block.len() - 3],
+
&block,
);
}
} else {
···
expansion = (m.expand)(
file,
file.tokens[file.working_index].origin_file,
+
file.tokens[file.working_index].line_number,
context,
&args,
&Vec::new()[..],
···
}
}
}
-
// Check if its a block
-
// for b in &BLOCK_LIST {}}
+
+
// Make this less copied
+
// check for templates
+
for m in &mut file.templates {
+
if &symbol[prefix_len..] == m.symbol {
+
matched_macro = true;
+
println!("Found a macro ({})", m.symbol);
+
+
let (args, args_tokcount) =
+
collect_arguments(&file.tokens[file.working_index..]);
+
let expansion: Vec<Token>;
+
let block_tokcount: usize;
+
+
if m.has_scope {
+
println!("is scoped.");
+
let block: Vec<Token>;
+
(block, block_tokcount) =
+
collect_block(&file.tokens[(file.working_index + args_tokcount)..]);
+
+
if ephemeral {
+
expansion = Vec::new();
+
} else {
+
expansion = m.expand(
+
//file,
+
file.tokens[file.working_index].origin_file,
+
//file.tokens[file.working_index].line_number,
+
context,
+
&args,
+
&block,
+
);
+
}
+
} else {
+
block_tokcount = 0;
+
+
if ephemeral {
+
expansion = Vec::new();
+
} else {
+
expansion = m.expand(
+
//file,
+
file.tokens[file.working_index].origin_file,
+
//file.tokens[file.working_index].line_number,
+
context,
+
&args,
+
&Vec::new()[..],
+
);
+
}
+
}
+
+
let trimmed = trim_whitespace_tokens(&expansion);
+
+
file.tokens.remove(file.working_index);
+
file.tokens.splice(
+
file.working_index
+
..(file.working_index + args_tokcount + block_tokcount - 1),
+
trimmed.iter().cloned(),
+
);
+
if expansion.len() == 0 && file.working_index > 0 {
+
file.working_index -= 1;
+
}
+
}
+
}
}
if !matched_macro {
println!(
···
allow_any_img_src: true,
..CompileOptions::gfm()
},
-
..Options::default()
+
..Options::gfm()
},
)
.unwrap();
+55 -3
src/stringtools.rs
···
// Scope Start
if tok.contents == "{" {
entering_bracket_count += 1;
+
if entering_bracket_count == 3 {
scope_count += 1;
entering_bracket_count = 0;
···
} else {
exiting_bracket_count = 0;
}
+
if tok.contents == "\\" {
escaped = true;
} else {
block.push(tok.clone());
}
}
+
+
// if block.len() == 6
+
// // things get ugly if its empty
+
// {
+
// let mut emptyblock = Vec::new();
+
// emptyblock.push(Token::new(
+
// "".into(),
+
// tokens[0].origin_file,
+
// tokens[0].line_number,
+
// ));
+
// return (emptyblock, tokens_consumed);
+
// }
+
// pop brackets, bad and ugly but idgaf
+
block.drain(..3);
+
block.drain(block.len() - 3..);
return (block, tokens_consumed);
}
···
pub fn strings_to_tokens(in_strings: Vec<String>, origin_file: usize) -> Vec<Token> {
let mut tokens = Vec::new();
-
let mut line_count: u32 = 1;
+
let mut line_count = 1;
for str in in_strings {
let current_line = line_count;
···
return &tokens[start..end];
}
-
pub trait OnlyWhitespace {
+
pub fn find_pattern(tokens: &[Token], pat: String) -> Option<(usize, usize)> {
+
// (startpoint, length)
+
let split_pattern = split_to_tokens(pat, 0);
+
let mut pattern_index: usize = 0;
+
let mut token_index: usize = 0;
+
let mut working_pattern_index: usize = 0;
+
+
for t in tokens {
+
if t.contents == split_pattern[pattern_index].contents {
+
pattern_index += 1;
+
} else {
+
pattern_index = 0;
+
working_pattern_index = token_index + 1;
+
}
+
+
if pattern_index == split_pattern.len() {
+
return Some((working_pattern_index, split_pattern.len()));
+
}
+
+
token_index += 1;
+
}
+
+
None
+
}
+
+
pub trait WhitespaceChecks {
fn is_only_whitespace(&self) -> bool;
+
fn contains_whitespace(&self) -> bool;
}
-
impl OnlyWhitespace for String {
+
impl WhitespaceChecks for String {
fn is_only_whitespace(&self) -> bool {
for c in self.chars() {
if !c.is_whitespace() {
···
}
}
return true;
+
}
+
+
fn contains_whitespace(&self) -> bool {
+
for c in self.chars() {
+
if c.is_whitespace() {
+
return true;
+
}
+
}
+
return false;
}
}
+15 -4
src/types.rs
···
use std::path::PathBuf;
-
use crate::projectparse::ProjectContext;
+
use crate::{macros::template::SkidTemplate, projectparse::ProjectContext};
pub struct Token {
pub contents: String,
pub origin_file: usize,
-
pub line_number: u32,
+
pub line_number: usize,
}
pub struct InputFile {
···
pub file_htmlout: PathBuf,
pub tokens: Vec<Token>,
pub working_index: usize,
+
pub templates: Vec<SkidTemplate>,
}
type MacroExpansion =
-
fn(&mut InputFile, usize, &mut ProjectContext, &Vec<String>, &[Token]) -> Vec<Token>;
+
fn(&mut InputFile, usize, usize, &mut ProjectContext, &Vec<String>, &[Token]) -> Vec<Token>;
+
// (
+
// _file: &mut InputFile,
+
// origin_index: usize,
+
// origin_line: usize,
+
// context: &mut ProjectContext,
+
// args: &Vec<String>,
+
// _scope: &[Token],
+
// ) -> Vec<Token>
+
pub struct Macro<'a> {
pub symbol: &'a str,
pub expand: MacroExpansion,
···
file_htmlout: "".into(),
tokens: Vec::new(),
working_index: 0,
+
templates: Vec::new(),
}
}
}
impl Token {
-
pub fn new(contents: String, origin_file: usize, line_number: u32) -> Token {
+
pub fn new(contents: String, origin_file: usize, line_number: usize) -> Token {
Token {
contents: contents,
origin_file: origin_file,