Skip to content

Commit 8e0090c

Browse files
committed
add and, or and xor
1 parent bb1e301 commit 8e0090c

5 files changed

Lines changed: 104 additions & 1 deletion

File tree

examples/infix_operators.simf

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
/*
22
* INFIX OPERATORS
33
*
4-
* Demonstrates all infix operators: +, -, *, /, %, ==, !=, <, <=, >, >=
4+
* Demonstrates all infix operators: +, -, *, /, %, &, |, ^, ==, !=, <, <=, >, >=
55
*
66
* Addition and subtraction panic at runtime on overflow/underflow.
77
* Multiplication returns a type twice the width of the operands (no overflow).
88
* Division and modulo return the same type as the operands.
9+
* Bitwise operators return the same type as the operands.
910
* Comparison operators return bool.
11+
*
12+
* Arithmetic operators require: simc -Z infix_arithmetic_operators
1013
*/
1114
fn main() {
1215
let a: u8 = 20;
@@ -33,6 +36,18 @@ fn main() {
3336
// let remainder: u8 = a % b;
3437
// assert!(jet::eq_8(remainder, 2));
3538

39+
// Bitwise AND: u8 & u8 → u8
40+
let and: u8 = a & b;
41+
assert!(jet::eq_8(and, 4)); // 0b00010100 & 0b00000110 = 0b00000100
42+
43+
// Bitwise OR: u8 | u8 → u8
44+
let or: u8 = a | b;
45+
assert!(jet::eq_8(or, 22)); // 0b00010100 | 0b00000110 = 0b00010110
46+
47+
// Bitwise XOR: u8 ^ u8 → u8
48+
let xor: u8 = a ^ b;
49+
assert!(jet::eq_8(xor, 18)); // 0b00010100 ^ 0b00000110 = 0b00010010
50+
3651
// Equality: u8 == u8 → bool
3752
assert!(a == a); // 20 == 20 is true
3853
assert!(a != b); // 20 != 6 is true

src/ast.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,44 @@ fn determine_comparison_op_jet(
11331133
/// | `*` | `u(2N)` | `MultiplyN` | `uN` | no |
11341134
/// | `/` | `uN` | `DivideN` | `uN` | no |
11351135
/// | `%` | `uN` | `ModuloN` | `uN` | no |
1136+
/// Maps a bitwise infix operator and operand type to the corresponding Simplicity jet.
1137+
///
1138+
/// | Operator | Output type | Jet | Input type |
1139+
/// |----------|-------------|--------|------------|
1140+
/// | `&` | `uN` | `AndN` | `uN` |
1141+
/// | `\|` | `uN` | `OrN` | `uN` |
1142+
/// | `^` | `uN` | `XorN` | `uN` |
1143+
fn determine_infix_bitwise_op_jet(
1144+
op: &parse::InfixOp,
1145+
ty: &ResolvedType,
1146+
) -> Result<Elements, Error> {
1147+
use parse::InfixOp::*;
1148+
use UIntType::*;
1149+
1150+
let uint_ty = ty
1151+
.as_integer()
1152+
.ok_or_else(|| Error::ExpressionUnexpectedType(ty.clone()))?;
1153+
1154+
match (op, uint_ty) {
1155+
(BitAnd, U1) => Ok(Elements::And1),
1156+
(BitAnd, U8) => Ok(Elements::And8),
1157+
(BitAnd, U16) => Ok(Elements::And16),
1158+
(BitAnd, U32) => Ok(Elements::And32),
1159+
(BitAnd, U64) => Ok(Elements::And64),
1160+
(BitOr, U1) => Ok(Elements::Or1),
1161+
(BitOr, U8) => Ok(Elements::Or8),
1162+
(BitOr, U16) => Ok(Elements::Or16),
1163+
(BitOr, U32) => Ok(Elements::Or32),
1164+
(BitOr, U64) => Ok(Elements::Or64),
1165+
(BitXor, U1) => Ok(Elements::Xor1),
1166+
(BitXor, U8) => Ok(Elements::Xor8),
1167+
(BitXor, U16) => Ok(Elements::Xor16),
1168+
(BitXor, U32) => Ok(Elements::Xor32),
1169+
(BitXor, U64) => Ok(Elements::Xor64),
1170+
_ => Err(Error::ExpressionUnexpectedType(ty.clone())),
1171+
}
1172+
}
1173+
11361174
fn determine_infix_arith_op_jet(
11371175
op: &parse::InfixOp,
11381176
ty: &ResolvedType,
@@ -1411,6 +1449,29 @@ impl AbstractSyntaxTree for SingleExpression {
14111449
lhs_warnings,
14121450
)
14131451
}
1452+
BitAnd | BitOr | BitXor => {
1453+
// Bitwise operators: same input and output type, no carry or overflow
1454+
let jet =
1455+
determine_infix_bitwise_op_jet(binary.op(), ty).with_span(from)?;
1456+
let (lhs, mut lhs_warnings) =
1457+
Expression::analyze(binary.lhs(), ty, scope)?;
1458+
let (rhs, mut rhs_warnings) =
1459+
Expression::analyze(binary.rhs(), ty, scope)?;
1460+
lhs_warnings.append(&mut rhs_warnings);
1461+
scope.track_call(from, TrackedCallName::Jet);
1462+
(
1463+
SingleExpressionInner::BinaryOp {
1464+
jet,
1465+
lhs: Arc::new(lhs),
1466+
rhs: Arc::new(rhs),
1467+
assert_no_carry: false,
1468+
swap_args: false,
1469+
negate_result: false,
1470+
check_nonzero_divisor: false,
1471+
},
1472+
lhs_warnings,
1473+
)
1474+
}
14141475
Add | Sub | Mul | Div | Rem => {
14151476
// Arithmetic operators
14161477
let (jet, arg_ty, assert_no_carry) =

src/lexer.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ pub enum Token<'src> {
5959
Slash,
6060
/// `%`
6161
Percent,
62+
/// `&`
63+
Ampersand,
64+
/// `|`
65+
Pipe,
66+
/// `^`
67+
Caret,
6268
/// `==`
6369
EqEq,
6470
/// `!=`
@@ -124,6 +130,9 @@ impl<'src> fmt::Display for Token<'src> {
124130
Token::Star => write!(f, "*"),
125131
Token::Slash => write!(f, "/"),
126132
Token::Percent => write!(f, "%"),
133+
Token::Ampersand => write!(f, "&"),
134+
Token::Pipe => write!(f, "|"),
135+
Token::Caret => write!(f, "^"),
127136
Token::EqEq => write!(f, "=="),
128137
Token::BangEq => write!(f, "!="),
129138
Token::LtEq => write!(f, "<="),
@@ -226,6 +235,9 @@ pub fn lexer<'src>(
226235
just("*").to(Token::Star),
227236
just("/").to(Token::Slash),
228237
just("%").to(Token::Percent),
238+
just("&").to(Token::Ampersand),
239+
just("|").to(Token::Pipe),
240+
just("^").to(Token::Caret),
229241
));
230242

231243
let comment = just("//")

src/parse.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,12 @@ pub enum InfixOp {
316316
Div,
317317
/// `%`
318318
Rem,
319+
/// `&`
320+
BitAnd,
321+
/// `|`
322+
BitOr,
323+
/// `^`
324+
BitXor,
319325
/// `==`
320326
Eq,
321327
/// `!=`
@@ -338,6 +344,9 @@ impl fmt::Display for InfixOp {
338344
InfixOp::Mul => write!(f, "*"),
339345
InfixOp::Div => write!(f, "/"),
340346
InfixOp::Rem => write!(f, "%"),
347+
InfixOp::BitAnd => write!(f, "&"),
348+
InfixOp::BitOr => write!(f, "|"),
349+
InfixOp::BitXor => write!(f, "^"),
341350
InfixOp::Eq => write!(f, "=="),
342351
InfixOp::Ne => write!(f, "!="),
343352
InfixOp::Lt => write!(f, "<"),
@@ -1711,6 +1720,9 @@ impl SingleExpression {
17111720
Token::Star if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Mul,
17121721
Token::Slash if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Div,
17131722
Token::Percent if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Rem,
1723+
Token::Ampersand => InfixOp::BitAnd,
1724+
Token::Pipe => InfixOp::BitOr,
1725+
Token::Caret => InfixOp::BitXor,
17141726
Token::EqEq => InfixOp::Eq,
17151727
Token::BangEq => InfixOp::Ne,
17161728
Token::LAngle => InfixOp::Lt,

src/unstable_flags.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use std::str::FromStr;
1212
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1313
pub enum UnstableFlag {
1414
/// Enable infix arithmetic operators: `+`, `-`, `*`, `/`, `%`.
15+
///
16+
/// These operators have side effects (overflow/underflow panics for `+`/`-`,
17+
/// division-by-zero panics for `/`/`%`) and so are opt-in.
1518
InfixArithmeticOperators,
1619
// ^^^ Add new flags here. Each flag needs:
1720
// 1. A variant in this enum

0 commit comments

Comments
 (0)