Skip to content

Commit

Permalink
Avoid call to panic_with_byte_array in simple usage of panic! (#5958)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyalesokhin-starkware authored Jul 7, 2024
1 parent 917a571 commit 1af57c9
Show file tree
Hide file tree
Showing 8 changed files with 1,268 additions and 7,369 deletions.
2 changes: 1 addition & 1 deletion corelib/src/byte_array.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use core::zeroable::NonZeroIntoImpl;
/// A magic constant for identifying serialization of ByteArrays. An array of felt252s with this
/// magic as one of the felt252s indicates that right after it you should expect a serialized
/// ByteArray. This is currently used mainly for prints and panics.
pub(crate) const BYTE_ARRAY_MAGIC: felt252 =
pub const BYTE_ARRAY_MAGIC: felt252 =
0x46a6158a16a947e5916b2a2ca68501a45e93d7110e81aa2d6438b1c57c879a3;
const BYTES_IN_U128: usize = 16;
const BYTES_IN_BYTES31_MINUS_ONE: usize = BYTES_IN_BYTES31 - 1;
Expand Down
81 changes: 37 additions & 44 deletions crates/cairo-lang-runner/src/profiling_test_data/circuit

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,88 @@ error: Type annotations needed. Failed to infer ?0.
--> lib.cairo:2:1
array![]
^******^

//! > ==========================================================================

//! > Test expansion of panic macro with no arguments

//! > test_runner_name
test_expand_expr(expect_diagnostics: false)

//! > expr_code
panic!()

//! > expanded_code
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, 0, 0)

//! > diagnostics

//! > ==========================================================================

//! > Test expansion of panic macro with a simple short string

//! > test_runner_name
test_expand_expr(expect_diagnostics: false)

//! > expr_code
panic!("0123456")

//! > expanded_code
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, 0x30313233343536, 7)

//! > diagnostics

//! > ==========================================================================

//! > Test expansion of panic macro with a 31 byte string.

//! > test_runner_name
test_expand_expr(expect_diagnostics: false)

//! > expr_code
panic!("0123456789012345678901234567890")

//! > expanded_code
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 1, 0x30313233343536373839303132333435363738393031323334353637383930, 0, 0)

//! > diagnostics

//! > ==========================================================================

//! > Test expansion of panic macro with a simple 35 bytes string.

//! > test_runner_name
test_expand_expr(expect_diagnostics: false)

//! > expr_code
panic!("01234567890123456789012345678901234")

//! > expanded_code
core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 1, 0x30313233343536373839303132333435363738393031323334353637383930, 0x31323334, 4)

//! > diagnostics

//! > ==========================================================================

//! > Test expansion of panic macro with args

//! > test_runner_name
test_expand_expr(expect_diagnostics: true)

//! > expr_code
panic!("bad_format(})")

//! > expanded_code
{
let mut __formatter_for_panic_macro__: core::fmt::Formatter = core::traits::Default::default();
core::result::ResultTrait::<(), core::fmt::Error>::unwrap(
write!(__formatter_for_panic_macro__, "bad_format(})")
);
core::panics::panic_with_byte_array(@__formatter_for_panic_macro__.buffer)
}

//! > diagnostics
error: Plugin diagnostic: Closing `}` without a matching `{`.
--> lib.cairo:2:8
panic!("bad_format(})")
^*************^
71 changes: 66 additions & 5 deletions crates/cairo-lang-semantic/src/inline_macros/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,73 @@ use cairo_lang_defs::plugin::{
InlineMacroExprPlugin, InlinePluginResult, MacroPluginMetadata, NamedPlugin,
PluginGeneratedFile,
};
use cairo_lang_defs::plugin_utils::unsupported_bracket_diagnostic;
use cairo_lang_syntax::node::ast::WrappedArgList;
use cairo_lang_defs::plugin_utils::{try_extract_unnamed_arg, unsupported_bracket_diagnostic};
use cairo_lang_syntax::node::ast::{Arg, WrappedArgList};
use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::{ast, TypedSyntaxNode};
use indoc::formatdoc;
use num_bigint::BigUint;

use super::write::FELT252_BYTES;

/// Try to generate a simple panic handlic code.
/// Return true if successful and updates the buiilder if successful.
fn try_handle_simple_panic(
db: &dyn SyntaxGroup,
builder: &mut PatchBuilder<'_>,
arguments: &[Arg],
) -> bool {
let format_string_expr = match arguments {
[] => {
// Trivial panic!() with no arguments case.
builder.add_str(
"core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, 0, 0);",
);
return true;
}
[arg] => {
let Some(ast::Expr::String(format_string_expr)) = try_extract_unnamed_arg(db, arg)
else {
return false;
};
format_string_expr
}
// We have more than one argument, fallback to more generic handling.
_ => return false,
};

let Some(format_str) = format_string_expr.string_value(db) else {
return false;
};

if format_str.find(|c| c == '{' || c == '}').is_some() {
return false;
}

builder.add_str(&format!(
"core::panics::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, {}, ",
format_str.len() / FELT252_BYTES,
));

for chunk in format_str.as_bytes().chunks(FELT252_BYTES) {
builder.add_str(&format!("{:#x}, ", BigUint::from_bytes_be(chunk)));
}

let remainder_size = format_str.len() % FELT252_BYTES;
if remainder_size == 0 {
// Adding the empty remainder word.
builder.add_str("0, ");
}
builder.add_str(&format!("{remainder_size}))"));

builder.add_str(&format!(
"core::panic(array![core::byte_array::BYTE_ARRAY_MAGIC, 0, '{}', {}",
format_str,
format_str.len()
));

true
}

/// Macro for panicking with a format string.
#[derive(Default, Debug)]
Expand All @@ -25,11 +87,10 @@ impl InlineMacroExprPlugin for PanicMacro {
let WrappedArgList::ParenthesizedArgList(arguments_syntax) = syntax.arguments(db) else {
return unsupported_bracket_diagnostic(db, syntax);
};

let mut builder = PatchBuilder::new(db, syntax);
let arguments = arguments_syntax.arguments(db).elements(db);
if arguments.is_empty() {
builder.add_str(r#"core::panics::panic_with_byte_array(@"")"#);
} else {
if !try_handle_simple_panic(db, &mut builder, &arguments) {
builder.add_modified(RewriteNode::interpolate_patched(
&formatdoc! {
r#"
Expand Down
3 changes: 2 additions & 1 deletion crates/cairo-lang-semantic/src/inline_macros/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use cairo_lang_utils::{try_extract_matches, OptionHelper};
use indoc::indoc;
use num_bigint::{BigInt, Sign};

pub const FELT252_BYTES: usize = 31;

/// Macro for writing into a formatter.
#[derive(Debug, Default)]
pub struct WriteMacro;
Expand Down Expand Up @@ -407,7 +409,6 @@ impl FormattingInfo {
pending_chars: &mut String,
ident_count: usize,
) {
const FELT252_BYTES: usize = 31;
for chunk in pending_chars.as_bytes().chunks(FELT252_BYTES) {
self.add_indentation(builder, ident_count);
builder.add_modified(RewriteNode::interpolate_patched(
Expand Down
Loading

0 comments on commit 1af57c9

Please sign in to comment.