Skip to content

Commit

Permalink
Arithmetics in constants
Browse files Browse the repository at this point in the history
  • Loading branch information
wraitii committed May 24, 2023
1 parent 9a3a9c7 commit 1551c72
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cairo-lang-plugins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cairo-lang-syntax = { path = "../cairo-lang-syntax", version = "1.1.0-rc0" }
cairo-lang-utils = { path = "../cairo-lang-utils", version = "1.1.0-rc0" }
indoc.workspace = true
itertools.workspace = true
num-bigint.workspace = true
salsa.workspace = true
smol_str.workspace = true

Expand Down
3 changes: 2 additions & 1 deletion crates/cairo-lang-plugins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;

use cairo_lang_semantic::plugin::SemanticPlugin;

use crate::plugins::{ConfigPlugin, DerivePlugin, PanicablePlugin};
use crate::plugins::{ArithmeticPlugin, ConfigPlugin, DerivePlugin, PanicablePlugin};

pub mod plugins;

Expand All @@ -13,6 +13,7 @@ mod test;
/// Gets the list of default plugins to load into the Cairo compiler.
pub fn get_default_plugins() -> Vec<Arc<dyn SemanticPlugin>> {
vec![
Arc::new(ArithmeticPlugin::default()),
Arc::new(DerivePlugin::default()),
Arc::new(PanicablePlugin::default()),
Arc::new(ConfigPlugin::default()),
Expand Down
97 changes: 97 additions & 0 deletions crates/cairo-lang-plugins/src/plugins/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use std::sync::Arc;

use cairo_lang_defs::plugin::{
DynGeneratedFileAuxData, MacroPlugin, PluginGeneratedFile, PluginResult,
};
use cairo_lang_semantic::plugin::{AsDynMacroPlugin, SemanticPlugin, TrivialPluginAuxData};
use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::{ast, Terminal, TypedSyntaxNode};
use num_bigint::BigInt;

#[derive(Debug, Default)]
#[non_exhaustive]
pub struct ArithmeticPlugin;

impl MacroPlugin for ArithmeticPlugin {
fn generate_code(&self, db: &dyn SyntaxGroup, item_ast: ast::Item) -> PluginResult {
match item_ast {
ast::Item::Constant(constant_ast) => handle_constant(db, &constant_ast),
_ => PluginResult::default(),
}
}
}

impl AsDynMacroPlugin for ArithmeticPlugin {
fn as_dyn_macro_plugin<'a>(self: Arc<Self>) -> Arc<dyn MacroPlugin + 'a>
where
Self: 'a,
{
self
}
}
impl SemanticPlugin for ArithmeticPlugin {}

fn handle_constant(db: &dyn SyntaxGroup, constant_ast: &ast::ItemConstant) -> PluginResult {
let value = constant_ast.value(db);
if let ast::Expr::Literal(_) = value {
return PluginResult::default();
}
let new_value = rec_compute(db, &value);
if new_value.is_none() {
return PluginResult::default();
}
PluginResult {
code: Some(PluginGeneratedFile {
name: "computed_constants".into(),
content: format!(
"const {}{} = {};",
constant_ast.name(db).text(db),
constant_ast.type_clause(db).as_syntax_node().get_text(db),
new_value.unwrap()
),
aux_data: DynGeneratedFileAuxData(Arc::new(TrivialPluginAuxData {})),
}),
diagnostics: vec![],
remove_original_item: true,
}
}

// Don't print diagnostics, as downstream code will do it for us.
fn rec_compute(db: &dyn SyntaxGroup, value: &ast::Expr) -> Option<BigInt> {
match value {
ast::Expr::Literal(lit) => lit.numeric_value(db),
ast::Expr::Binary(bin_expr) => match bin_expr.op(db) {
ast::BinaryOperator::Plus(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? + rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Mul(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? * rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Minus(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? - rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Div(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? / rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Mod(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? % rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::And(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? & rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Or(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? | rec_compute(db, &bin_expr.rhs(db))?)
}
ast::BinaryOperator::Xor(_) => {
Some(rec_compute(db, &bin_expr.lhs(db))? ^ rec_compute(db, &bin_expr.rhs(db))?)
}
_ => None,
},
ast::Expr::Unary(un_expr) => match un_expr.op(db) {
ast::UnaryOperator::Minus(_) => Some(-rec_compute(db, &un_expr.expr(db))?),
_ => None,
},
ast::Expr::Parenthesized(paren_expr) => rec_compute(db, &paren_expr.expr(db)),
_ => None,
}
}
2 changes: 2 additions & 0 deletions crates/cairo-lang-plugins/src/plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub use arithmetic::*;
pub use config::*;
pub use derive::*;
pub use panicable::*;

mod arithmetic;
mod config;
mod derive;
mod panicable;
2 changes: 1 addition & 1 deletion tests/bug_samples/issue2964.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct GenericStruct<T, U> {
fn main() {
// This assumes that Drop implies Destruct and Copy implies Clone
let mut a = GenericStruct { x: SimpleStruct { x: 1, y: 2 }, y: SimpleStruct { x: 1, y: 2 } };
a.x.x = 34;
a.x.x = 24;
a.y.y = 5;
let mut serialized = ArrayTrait::<felt252>::new();
a.serialize(ref serialized);
Expand Down
7 changes: 7 additions & 0 deletions tests/bug_samples/issue3130.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const a: felt252 = (4 + 2 * 3) * 256;
const b: felt252 = 0xff & (24 + 5 * 2);
const c: felt252 = -0xff & (24 + 5 * 2);
const d: felt252 = 0xff | (24 + 5 * 2);

#[test]
fn main() {}

0 comments on commit 1551c72

Please sign in to comment.