#![recursion_limit = "256"]
#![warn(clippy::pedantic,clippy::nursery,clippy::complexity,clippy::perf,clippy::correctness,clippy::all)]
#![warn(clippy::cognitive_complexity,clippy::large_const_arrays)]
#![warn(clippy::style,clippy::suspicious,large_assignments,rustdoc::all)]
#![warn(missing_docs)]
#![allow(clippy::must_use_candidate,clippy::wildcard_imports,clippy::enum_glob_use,clippy::missing_panics_doc,clippy::missing_errors_doc)]
pub(crate) mod ccarp;
pub(crate) mod ccarp_c;
pub(crate) mod ccarp_rust;
pub use ccarp::error::{CCErr,Result,ProjectResult};
pub use ccarp::translator::*;
#[cfg(test)]
mod unit_tests {
use pest::Parser;
use crate::{ccarp::error::{parse_err, rule_err}, ccarp_c::{decl::*, defs::*, expr::*, stmt::Statement, trans_unit::{FunctionDef, TranslationUnit}, tt::*}, ccarp_rust::{defs::{Context, RFrom}, rustdecl::RDecl, rustexpr::RExpr}, CCErr, Result};
fn tokenise(string: &str) -> Result<(String,Vec<Include>)> {
let string=string.replace("\\\n", "");
let parsed=ParserTy::parse(Rule::tokentree, &string).map_err(|e| parse_err!(e))?.next().ok_or_else(|| rule_err!("Parsed code is empty!"))?;
let tt=TokenTree::take(parsed)?;
let (includes,tt): (Vec<Token>,Vec<Token>)=tt.0.into_iter().partition(|x| matches!(x,Token::Include(_)));
let includes=includes.into_iter().map(|x| if let Token::Include(incl)=x { incl } else { Include(String::new()) }).collect();
Ok((format!("{}",TokenTree(tt)),includes))
}
#[test]
fn parsing_ok() {
assert!(ParserTy::parse(Rule::tokentree, "int main() { return 0; }").is_ok());
}
#[test]
fn parsing_ident() {
let parsed=ParserTy::parse(Rule::ident, "ident");
assert!(parsed.is_ok());
let ident=Identifier::take(parsed.unwrap().next().unwrap());
assert!(ident.is_ok(),"Error: {}",ident.unwrap_err());
assert_eq!(ident.unwrap(),Identifier(String::from("ident")));
}
#[test]
fn parsing_tt() {
let parsed=ParserTy::parse(Rule::tokentree, "struct ABStruct { int a,b; char* c; }");
assert!(parsed.is_ok());
let tt=TokenTree::take(parsed.unwrap().next().unwrap());
assert!(tt.is_ok(),"Error: {}",tt.unwrap_err());
assert_eq!(tt.unwrap(),TokenTree(vec![
Token::Keyword(Keyword(String::from("struct"))),
Token::Identifier(Identifier(String::from("ABStruct"))),
Token::Punctuator(Punctuator(String::from("{"))),
Token::Keyword(Keyword(String::from("int"))),
Token::Identifier(Identifier(String::from("a"))),
Token::Punctuator(Punctuator(String::from(","))),
Token::Identifier(Identifier(String::from("b"))),
Token::Punctuator(Punctuator(String::from(";"))),
Token::Keyword(Keyword(String::from("char"))),
Token::Punctuator(Punctuator(String::from("*"))),
Token::Identifier(Identifier(String::from("c"))),
Token::Punctuator(Punctuator(String::from(";"))),
Token::Punctuator(Punctuator(String::from("}")))
]));
}
#[test]
fn tokenisation() {
let res=tokenise("int func(long long a, char *b) { return (int)a; }");
assert!(res.is_ok());
assert_eq!(res.unwrap().0.as_str(),"int #ifunc#i #p(#p long long #ia#i #p,#p char #p*#p #ib#i #p)#p #p{#p return #p(#p int #p)#p #ia#i #p;#p #p}#p");
}
#[test]
fn parsing_expr() {
let tt=tokenise("2+2");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::expr, tt.0.as_str());
let expr=Expression::take(pair.unwrap().next().unwrap());
assert!(expr.is_ok());
}
#[test]
fn parsing_decl() {
let tt=tokenise("int a=2;");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::decl, tt.0.as_str());
let decl=Declaration::take(pair.unwrap().next().unwrap());
assert!(decl.is_ok());
}
#[test]
fn parsing_stmt() {
let tt=tokenise("if (i<10) { for(int j=0;j<100;j++) i+=1; } else { return 0; }");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::stmt, tt.0.as_str());
let stmt=Statement::take(pair.unwrap().next().unwrap());
assert!(stmt.is_ok());
}
#[test]
fn parsing_fn() {
let tt=tokenise("int main() { int a=1,b=0,*c,d=2; a++; b+=a+d; return 0; }");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::fn_def, tt.0.as_str());
let fun=FunctionDef::take(pair.unwrap().next().unwrap());
assert!(fun.is_ok());
}
#[test]
fn parsing_translation_unit() {
let tt=tokenise("int a; char *b; struct CDStruct { int c,d; }; int main() { int a=1,b=0,*c,d=2; a++; b+=a+d; return 0; }");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::trans_unit, tt.0.as_str());
let unit=TranslationUnit::take(pair.unwrap().next().unwrap());
assert!(unit.is_ok());
}
#[test]
fn translate_expr() {
let tt=tokenise("2+2");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::expr, tt.0.as_str());
let expr=Expression::take(pair.unwrap().next().unwrap());
assert!(expr.is_ok());
let expr=RExpr::rfrom(expr.unwrap(), &mut Context::default());
assert!(expr.is_ok());
assert!(expr.unwrap().to_string().as_str()=="2 + 2");
}
#[test]
fn translate_decl() {
let tt=tokenise("int a=0,b=2;");
assert!(tt.is_ok());
let tt=tt.unwrap();
let pair=ParserTy::parse(Rule::decl, tt.0.as_str());
let decl=Declaration::take(pair.unwrap().next().unwrap());
assert!(decl.is_ok());
let decl=RDecl::rfrom(decl.unwrap(), &mut Context::default());
assert!(decl.is_ok());
assert!(decl.unwrap().to_string().as_str()=="let mut a: i32=(0);\nlet mut b: i32=(2);");
}
}