rust catch_unwind as a safeguard

This commit is contained in:
2025-12-01 15:35:44 -07:00
parent 997dd50585
commit abaefa294b
2 changed files with 84 additions and 66 deletions

View File

@@ -797,7 +797,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
self.write_output(format!("j {end_label}"))?; self.write_output(format!("j {end_label}"))?;
self.write_output(format!("{else_label}:"))?; self.write_output(format!("{else_label}:"))?;
match expr.else_branch.unwrap().node { match expr
.else_branch
.ok_or(Error::Unknown("Missing else branch. This should not happen and indicates a Compiler Error. Please report to the author.".into(), None))?
.node
{
Expression::Block(block) => self.expression_block(block.node, scope)?, Expression::Block(block) => self.expression_block(block.node, scope)?,
Expression::If(if_expr) => self.expression_if(if_expr.node, scope)?, Expression::If(if_expr) => self.expression_if(if_expr.node, scope)?,
_ => unreachable!("Parser ensures else branch is Block or If"), _ => unreachable!("Parser ensures else branch is Block or If"),

View File

@@ -82,90 +82,104 @@ pub fn free_string(s: safer_ffi::String) {
/// from the GC from a `GetBytes()` call on a string in C#. /// from the GC from a `GetBytes()` call on a string in C#.
#[ffi_export] #[ffi_export]
pub fn compile_from_string(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::String { pub fn compile_from_string(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::String {
let mut writer = BufWriter::new(Vec::new()); let res = std::panic::catch_unwind(|| {
let mut writer = BufWriter::new(Vec::new());
let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice())); let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice()));
let parser = Parser::new(tokenizer); let parser = Parser::new(tokenizer);
let compiler = Compiler::new(parser, &mut writer, None); let compiler = Compiler::new(parser, &mut writer, None);
if !compiler.compile().is_empty() { if !compiler.compile().is_empty() {
return safer_ffi::String::EMPTY; return safer_ffi::String::EMPTY;
} }
let Ok(compiled_vec) = writer.into_inner() else { let Ok(compiled_vec) = writer.into_inner() else {
return safer_ffi::String::EMPTY; return safer_ffi::String::EMPTY;
}; };
// Safety: I know the compiler only outputs valid utf8 // Safety: I know the compiler only outputs valid utf8
safer_ffi::String::from(unsafe { String::from_utf8_unchecked(compiled_vec) }) safer_ffi::String::from(unsafe { String::from_utf8_unchecked(compiled_vec) })
});
res.unwrap_or("".into())
} }
#[ffi_export] #[ffi_export]
pub fn tokenize_line(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::Vec<FfiToken> { pub fn tokenize_line(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::Vec<FfiToken> {
let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice())); let res = std::panic::catch_unwind(|| {
let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice()));
let mut tokens = Vec::new(); let mut tokens = Vec::new();
for token in tokenizer { for token in tokenizer {
if matches!( if matches!(
token, token,
Ok(Token { Ok(Token {
token_type: TokenType::EOF, token_type: TokenType::EOF,
.. ..
})
) {
continue;
}
match token {
Err(ref e) => {
use tokenizer::Error::*;
let (err_str, col, og) = match e {
NumberParseError(_, _, col, og)
| DecimalParseError(_, _, col, og)
| UnknownSymbolError(_, _, col, og)
| UnknownKeywordOrIdentifierError(_, _, col, og) => (e.to_string(), col, og),
_ => continue,
};
tokens.push(FfiToken {
column: *col as i32,
error: err_str.into(),
tooltip: "".into(),
length: og.len() as i32,
token_kind: 0,
}) })
) {
continue;
} }
Ok(Token { match token {
column, Err(ref e) => {
original_string, use tokenizer::Error::*;
token_type, let (err_str, col, og) = match e {
.. NumberParseError(_, _, col, og)
}) => tokens.push(FfiToken { | DecimalParseError(_, _, col, og)
column: column as i32, | UnknownSymbolError(_, _, col, og)
error: "".into(), | UnknownKeywordOrIdentifierError(_, _, col, og) => {
length: (original_string.unwrap_or_default().len()) as i32, (e.to_string(), col, og)
token_kind: token_type.into(), }
tooltip: "".into(), _ => continue,
}), };
}
}
tokens.into() tokens.push(FfiToken {
column: *col as i32,
error: err_str.into(),
tooltip: "".into(),
length: og.len() as i32,
token_kind: 0,
})
}
Ok(Token {
column,
original_string,
token_type,
..
}) => tokens.push(FfiToken {
column: column as i32,
error: "".into(),
length: (original_string.unwrap_or_default().len()) as i32,
token_kind: token_type.into(),
tooltip: "".into(),
}),
}
}
tokens.into()
});
res.unwrap_or(vec![].into())
} }
#[ffi_export] #[ffi_export]
pub fn diagnose_source(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::Vec<FfiDiagnostic> { pub fn diagnose_source(input: safer_ffi::slice::Ref<'_, u16>) -> safer_ffi::Vec<FfiDiagnostic> {
let mut writer = BufWriter::new(Vec::new()); let res = std::panic::catch_unwind(|| {
let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice())); let mut writer = BufWriter::new(Vec::new());
let compiler = Compiler::new(Parser::new(tokenizer), &mut writer, None); let tokenizer = Tokenizer::from(String::from_utf16_lossy(input.as_slice()));
let compiler = Compiler::new(Parser::new(tokenizer), &mut writer, None);
let diagnosis = compiler.compile(); let diagnosis = compiler.compile();
let mut result_vec: Vec<FfiDiagnostic> = Vec::with_capacity(diagnosis.len()); let mut result_vec: Vec<FfiDiagnostic> = Vec::with_capacity(diagnosis.len());
for err in diagnosis { for err in diagnosis {
result_vec.push(lsp_types::Diagnostic::from(err).into()); result_vec.push(lsp_types::Diagnostic::from(err).into());
} }
result_vec.into() result_vec.into()
});
res.unwrap_or(vec![].into())
} }