use std::fmt;
use crate::setup::*;
#[derive(Clone, Copy)]
pub struct Indentation {
}
impl Indentation {
pub fn new() -> Indentation {
Indentation { }
}
}
impl CodeGenerate for Indentation {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let indent ;
match info.indent_type {
IndentationType::Spaces => indent = " ".repeat(info.indent_amount*info.indent_level),
IndentationType::Tabs => indent = " ".repeat(
((info.indent_amount+3) / 4) * info.indent_level
),
}
write!(f, "{}", indent)
}
}
#[derive(Clone, Copy)]
pub enum NameType {
Default,
ConstDefine,
Type,
Member,
Function,
File,
FixedCase(CaseType),
Bypass,
}
#[derive(Clone)]
pub struct Name {
parts: Vec<String>,
name_type: NameType
}
impl Name {
pub fn new(snake_case_name: &str) -> Name {
let name = snake_case_name;
let mut parts = Vec::<String>::new();
for entry in name.split("_") {
if !entry.is_empty() {
parts.push(entry.to_ascii_lowercase());
}
}
if parts.len() == 0 {
parts.push("invalid".into());
parts.push("name".into());
}
Name {
parts: parts,
name_type: NameType::Default
}
}
pub fn new_with_type(snake_case_name: &str, name_type: NameType) -> Name {
if let NameType::Bypass = name_type {
Name {
parts: vec![snake_case_name.into()],
name_type: NameType::Bypass
}
} else {
Name::new(snake_case_name).with_type(name_type)
}
}
pub fn with_type(mut self, name_type: NameType) -> Name {
match self.name_type {
NameType::Bypass => (),
NameType::FixedCase(_) => (),
_ => self.name_type = name_type,
}
self
}
pub fn as_include_guard(&self) -> Name {
Name::new_with_type(&format!("{}_H", self.parts.join("_")), NameType::ConstDefine)
}
pub fn as_c_include(&self) -> Name {
Name::new_with_type(&format!("{}.h", self.parts.join("_")), NameType::File)
}
pub fn as_c_source(&self) -> Name {
Name::new_with_type(&format!("{}.c", self.parts.join("_")), NameType::File)
}
fn caps_first_letter(string: String) -> String {
let mut result = String::new();
let mut iter = string.chars();
if let Some(char) = iter.next() {
result.push(char.to_ascii_uppercase());
}
for char in iter {
result.push(char);
}
result
}
fn casify(&self, case: CaseType) -> String {
if let NameType::Bypass = self.name_type {
return self.parts.join("");
}
let mut parts = Vec::new();
let mut is_first = true;
for part in self.parts.iter() {
parts.push (match case {
CaseType::CamelCase => if is_first {part.clone()} else {Self::caps_first_letter(part.clone())},
CaseType::FlatCase => part.clone(),
CaseType::PascalCase => Self::caps_first_letter(part.clone()),
CaseType::ScreamingCase => part.to_ascii_uppercase(),
CaseType::ScreamingSnakeCase => part.to_ascii_uppercase(),
CaseType::SnakeCase => part.clone(),
});
is_first = false;
}
match case {
CaseType::CamelCase => parts.join(""),
CaseType::FlatCase => parts.join(""),
CaseType::PascalCase => parts.join(""),
CaseType::ScreamingCase => parts.join(""),
CaseType::ScreamingSnakeCase => parts.join("_"),
CaseType::SnakeCase => parts.join("_"),
}
}
fn get_case_type(&self, info: CaseTypes) -> CaseType {
match self.name_type {
NameType::Default => info.default_case,
NameType::ConstDefine => info.const_define_case,
NameType::Function => info.function_name_case,
NameType::Member => info.member_name_case,
NameType::Type => info.type_name_case,
NameType::File => info.file_name_case,
NameType::FixedCase(case) => case,
NameType::Bypass => info.default_case,
}
}
}
impl CodeGenerate for Name {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let case_type = self.get_case_type(info.case_types);
write!(f, "{}", self.casify(case_type))
}
}
pub struct Include {
file_name: Name,
is_sys_inc: bool,
}
impl Include {
pub fn new(file_name: Name) -> Include {
Include {
file_name,
is_sys_inc: false
}
}
pub fn new_sys(file_name: &str) -> Include {
Include {
file_name: Name::new_with_type(
file_name,
NameType::Bypass
),
is_sys_inc: true
}
}
}
impl CodeGenerate for Include {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
match self.is_sys_inc {
true => write!(f, "#include <{}>", self.file_name.display(info)),
false => write!(f, "#include \"{}.h\"", self.file_name.display(info))
}
}
}
#[derive(Clone, Copy)]
pub struct NewLine {
}
impl NewLine {
pub fn new() -> NewLine {
NewLine { }
}
}
impl CodeGenerate for NewLine {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
match info.new_line_type {
NewLineType::Cr => write!(f, "\r"),
NewLineType::Nl => write!(f, "\n"),
NewLineType::CrNl => write!(f, "\r\n"),
NewLineType::None => write!(f, ""),
}
}
}
pub struct CodeSet {
code_set: Vec<Box<dyn CodeGenerate>>,
is_separated: bool,
}
impl CodeSet {
pub fn new(set: Vec<Box<dyn CodeGenerate>>) -> CodeSet {
CodeSet { code_set: set, is_separated: false }
}
pub fn new_separated(set: Vec<Box<dyn CodeGenerate>>) -> CodeSet {
CodeSet { code_set: set, is_separated: true }
}
}
impl CodeGenerate for CodeSet {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result = fmt::Result::Ok(());
let mut iter = self.code_set.iter();
if let Some(item) = iter.next() {
result = result.and(item.generate(f, info));
for item in iter {
result = result.and(NewLine::new().generate(f, info));
if self.is_separated {
result = result.and(NewLine::new().generate(f, info));
}
result = result.and(Indentation::new().generate(f, info));
result = result.and(item.generate(f, info));
}
}
result
}
}
pub struct JoinedCode {
code_set: Vec<Box<dyn CodeGenerate>>,
}
impl JoinedCode {
pub fn new(set: Vec<Box<dyn CodeGenerate>>) -> JoinedCode {
JoinedCode { code_set: set }
}
}
impl CodeGenerate for JoinedCode {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result = fmt::Result::Ok(());
for item in self.code_set.iter() {
result = result.and(item.generate(f, info));
}
result
}
}
impl CodeGenerate for String {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
let mut iter = self.lines();
if let Some(line) = iter.next() {
result = result.and(result.and(write!(f, "{}", line)));
}
for line in iter {
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{}", line));
}
return result;
}
}
pub struct SeparatedCode {
items: Vec<Box<dyn CodeGenerate>>,
separator: Box<dyn CodeGenerate>,
}
impl SeparatedCode {
pub fn new(items: Vec<Box<dyn CodeGenerate>>, separator: Box<dyn CodeGenerate>) -> SeparatedCode {
SeparatedCode { items: items, separator: separator }
}
}
impl CodeGenerate for SeparatedCode {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
let mut iterator = self.items.iter();
if let Some(item) = iterator.next() {
result = result.and(item.generate(f, info));
}
for item in iterator {
result = result.and(self.separator.generate(f, info));
result = result.and(item.generate(f, info));
}
result
}
}
pub struct CodeBody {
raw_code: CodeSet,
}
impl CodeBody {
pub fn new(code: Vec<Box<dyn CodeGenerate>>) -> CodeBody {
CodeBody {raw_code: CodeSet::new(code)}
}
}
impl CodeGenerate for CodeBody {
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
match info.indent_style {
IndentationStyle::Allman => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent()));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::GNU => {
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent().indent()));
result = result.and(self.raw_code.generate(f, info.indent().indent()));
result = result.and(NewLine::new().generate(f, info));
if info.context != GeneratorContext::Function {
result = result.and(Indentation::new().generate(f, info.indent()));
}
result = result.and(write!(f, "}}"));
}
IndentationStyle::Horstmann => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
let mut temp_info = info;
temp_info.indent_level = 1;
temp_info.indent_amount -= 1; result = result.and(Indentation::new().generate(f, temp_info));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::KnR => {
result = result.and(write!(f, "{{"));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info.indent()));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(NewLine::new().generate(f, info));
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "}}"));
}
IndentationStyle::Pico => {
result = result.and(Indentation::new().generate(f, info));
result = result.and(write!(f, "{{"));
let mut temp_info = info;
temp_info.indent_level = 1;
temp_info.indent_amount -= 1; result = result.and(Indentation::new().generate(f, temp_info));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(write!(f, " }}"));
}
IndentationStyle::None => {
result = result.and(write!(f, "{{"));
result = result.and(self.raw_code.generate(f, info.indent()));
result = result.and(write!(f, "}}"));
}
_ => result = result.and(write!(f, "NOT SUPPORTED YET!")),
}
result
}
}
pub struct HeaderPlusBody<HT> {
header: HT,
body: CodeBody,
}
impl<HT> HeaderPlusBody<HT> {
pub fn new(header: HT, body: CodeBody) -> HeaderPlusBody<HT>{
HeaderPlusBody {header: header, body: body}
}
}
impl<HT> CodeGenerate for HeaderPlusBody<HT>
where HT: CodeGenerate,{
fn generate(&self, f: &mut fmt::Formatter<'_>, info: CodeGenerationInfo) -> fmt::Result {
let mut result: fmt::Result = fmt::Result::Ok(());
result = result.and(self.header.generate(f, info));
match info.indent_style {
IndentationStyle::Allman |
IndentationStyle::Horstmann |
IndentationStyle::Pico => {
result = result.and(NewLine::new().generate(f, info));
},
IndentationStyle::GNU => {
result = result.and(NewLine::new().generate(f, info));
if info.context != GeneratorContext::Function {
result = result.and(Indentation::new().generate(f, info.indent()));
}
}
IndentationStyle::KnR => {
result = result.and(write!(f, " "));
}
_ => (),
}
result = result.and(self.body.generate(f, info));
result
}
}