206 lines
5.3 KiB
Rust
206 lines
5.3 KiB
Rust
use regex::{Captures, Regex};
|
|
use std::{
|
|
cell::{Ref, RefCell},
|
|
collections::{HashMap, HashSet},
|
|
ops::Add,
|
|
rc::Rc,
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
};
|
|
pub use util::Variable;
|
|
|
|
use crate::{
|
|
errors::{Error, Result},
|
|
utils::{find_file, Code, CodeBlock, Function, Hook, ShareVariable, SnippetCode},
|
|
};
|
|
mod util;
|
|
pub use util::merge_includes;
|
|
use util::*;
|
|
|
|
use super::CodeComponent;
|
|
|
|
static SNIP_ID: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum InputType {
|
|
Vertex(usize, Variable),
|
|
Other(Variable),
|
|
}
|
|
|
|
pub enum CodeType<S: std::borrow::Borrow<str>> {
|
|
Code(S),
|
|
Path(std::path::PathBuf),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Snippet {
|
|
id: usize,
|
|
name: &'static str,
|
|
parsed: CodeBlock,
|
|
link: Option<Box<Snippet>>,
|
|
alias: Option<HashMap<String, String>>,
|
|
chained: String,
|
|
main: Option<String>,
|
|
}
|
|
|
|
impl Snippet {
|
|
pub fn new<S: std::borrow::Borrow<str>>(
|
|
name: &'static str,
|
|
code: CodeType<S>,
|
|
mangling: bool,
|
|
main: Option<String>,
|
|
) -> Result<Self> {
|
|
let code = match code {
|
|
CodeType::Code(code) => code.borrow().to_string(),
|
|
CodeType::Path(path) => {
|
|
let code = find_file(path).expect("Failed to find file");
|
|
code
|
|
}
|
|
};
|
|
|
|
let merged_code = merge_includes(code)
|
|
.map(|code| {
|
|
let clean_code = remove_comments(&code);
|
|
let clean_code = remove_version(&clean_code);
|
|
clean_code
|
|
})
|
|
.map_err(|v| {
|
|
let err_msg = format!("Failed to merge includes cause of {:?}", v);
|
|
Error::InvalidSnippet(err_msg)
|
|
})?;
|
|
|
|
let id = SNIP_ID.fetch_add(1, Ordering::SeqCst);
|
|
|
|
let mut parsed_code = CodeBlock::new(&merged_code)?;
|
|
let call = if let Some(main) = main {
|
|
Some(main)
|
|
} else {
|
|
parsed_code
|
|
.all_functions()
|
|
.first()
|
|
.map(|f| f.borrow().name.clone())
|
|
};
|
|
|
|
let alias = if mangling {
|
|
let alias = parsed_code.mangling(id.to_string());
|
|
Some(alias)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let chained = format!(
|
|
"// START {} //\n{}\n// END {} //\n",
|
|
name, parsed_code, name
|
|
);
|
|
|
|
Ok(Self {
|
|
id,
|
|
name,
|
|
parsed: parsed_code,
|
|
chained,
|
|
alias,
|
|
link: None,
|
|
main: call,
|
|
})
|
|
}
|
|
|
|
pub fn all_hooks(&self) -> HashSet<Hook> {
|
|
self.parsed.all_hooks()
|
|
}
|
|
|
|
pub fn chain(mut self, snippet: Snippet) -> Self {
|
|
self.chained = format!(
|
|
"// START {} //\n{}\n// END {} //\n{}\n\n",
|
|
snippet.name, snippet.chained, snippet.name, self.chained,
|
|
);
|
|
|
|
self.link = Some(Box::new(snippet));
|
|
self
|
|
}
|
|
|
|
pub fn call(&self, paras: &Vec<String>) -> Option<String> {
|
|
(self.main.as_ref()).map(|name| {
|
|
if let Some(link) = &self.link {
|
|
let call_name = self.alias.as_ref().map(|a| a.get(name).unwrap()).unwrap_or(name);
|
|
let c = link.call(paras);
|
|
if let Some(c) = c {
|
|
return format!("{}({})", call_name, c);
|
|
} else {
|
|
return format!("{}()", call_name);
|
|
}
|
|
} else {
|
|
let call_name = self.alias.as_ref().map(|a| a.get(name).unwrap()).unwrap_or(name);
|
|
// let call_name = self.alias.get(name).unwrap();
|
|
format!("{}({})", call_name, paras.join(", "))
|
|
}
|
|
})
|
|
}
|
|
|
|
pub fn prepare_code(&self) -> &str {
|
|
&self.chained
|
|
}
|
|
|
|
pub fn find_symbol(&self, name: &str) -> Option<&String> {
|
|
self.alias.as_ref().map(|a| a.get(name)).flatten()
|
|
}
|
|
|
|
pub fn find_variable(&self, name: &str) -> Option<&Rc<RefCell<ShareVariable>>> {
|
|
self.find_symbol(name)
|
|
.map(|v| self.parsed.find_variable(v))
|
|
.flatten()
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Snippet {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.parsed)
|
|
}
|
|
}
|
|
|
|
impl Add for Snippet {
|
|
type Output = Self;
|
|
|
|
fn add(self, rhs: Self) -> Self::Output {
|
|
let mut raw_code = self.parsed.to_string();
|
|
let code = rhs.parsed.to_string();
|
|
|
|
raw_code.push_str(&code);
|
|
Snippet::new(self.name, CodeType::Code(raw_code),false, None).unwrap()
|
|
}
|
|
}
|
|
|
|
impl CodeComponent for Snippet {
|
|
fn add_snippet_after(self, snippet: Snippet) -> Self {
|
|
self + snippet
|
|
}
|
|
|
|
fn add_snippet_before(self, snippet: Snippet) -> Self {
|
|
snippet + self
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_snippet_new() {
|
|
let code = r#"
|
|
#version 450
|
|
#include "math/constants.glsl"
|
|
void main() {
|
|
gl_Position = vec4(0.0);
|
|
}
|
|
"#;
|
|
|
|
let snippet = Snippet::new("polar", CodeType::Code(code), true, None).unwrap();
|
|
|
|
let snippet2 = Snippet::new("polar2", CodeType::Code(code),true, None).unwrap();
|
|
|
|
let snippet3 = snippet.clone() + snippet2.clone();
|
|
|
|
let snippet = snippet.chain(snippet2.chain(snippet3));
|
|
|
|
println!("{}", snippet.prepare_code());
|
|
}
|
|
}
|