use compiler::Compiler; use parser::Parser; use safer_ffi::prelude::*; use std::io::BufWriter; use tokenizer::{Error as TokenizerError, Tokenizer}; #[derive_ReprC] #[repr(C)] pub struct FfiToken { pub text: safer_ffi::String, pub tooltip: Option, pub error: Option, pub status: Option, pub column: i32, } #[ffi_export] pub fn compile_from_string(input: safer_ffi::String) -> safer_ffi::String { let mut writer = BufWriter::new(Vec::new()); let tokenizer = Tokenizer::from(String::from(input)); let parser = Parser::new(tokenizer); let compiler = Compiler::new(parser, &mut writer, None); if compiler.compile().is_err() { return safer_ffi::String::EMPTY; } let Ok(compiled_vec) = writer.into_inner() else { return safer_ffi::String::EMPTY; }; // Safety: I know the compiler only outputs valid utf8 safer_ffi::String::from(unsafe { String::from_utf8_unchecked(compiled_vec) }) } #[ffi_export] pub fn tokenize_line(input: safer_ffi::String) -> safer_ffi::Vec { let tokenizer = Tokenizer::from(String::from(input)); let mut tokens = Vec::::new(); for token in tokenizer { match token { Err(TokenizerError::NumberParseError(_, _, col)) | Err(TokenizerError::UnknownSymbolError(_, _, col)) | Err(TokenizerError::DecimalParseError(_, _, col)) | Err(TokenizerError::UnknownKeywordOrIdentifierError(_, _, col)) => { tokens.push(FfiToken { column: col as i32, text: "".into(), tooltip: None, // Safety: it's okay to unwrap the err here because we are matching on the `Err` variant error: Some(token.unwrap_err().to_string().into()), status: None, }); } Err(_) => return safer_ffi::Vec::EMPTY, Ok(token) => tokens.push(FfiToken { text: token.token_type.to_string().into(), tooltip: None, error: None, status: None, column: token.column as i32, }), } } tokens.into() } #[cfg(feature = "headers")] pub fn generate_headers() -> std::io::Result<()> { ::safer_ffi::headers::builder() .with_language(safer_ffi::headers::Language::CSharp) .to_file("SlangGlue.cs")? .generate() }