Skip to content

Commit 2ad49e6

Browse files
committed
feat: add bitwise operators
1 parent 3ce3747 commit 2ad49e6

File tree

9 files changed

+253
-17
lines changed

9 files changed

+253
-17
lines changed

src/ast/builder/llvmbuilder.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,66 @@ impl<'a, 'ctx> IRBuilder<'a, 'ctx> for LLVMBuilder<'a, 'ctx> {
26012601
let arg_len = self.builder.build_int_mul(len, i64_size, "arg_len");
26022602
self.builder.build_memcpy(to, 8, from, 8, arg_len).unwrap();
26032603
}
2604+
fn build_bit_not(&self, v: ValueHandle) -> ValueHandle {
2605+
let v = self.get_llvm_value(v).unwrap();
2606+
let v = v.into_int_value();
2607+
let v = self
2608+
.builder
2609+
.build_xor(v, v.get_type().const_all_ones(), "not");
2610+
self.get_llvm_value_handle(&v.into())
2611+
}
2612+
fn build_bit_and(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2613+
let lhs = self.get_llvm_value(lhs).unwrap();
2614+
let rhs = self.get_llvm_value(rhs).unwrap();
2615+
let lhs = lhs.into_int_value();
2616+
let rhs = rhs.into_int_value();
2617+
let v = self.builder.build_and(lhs, rhs, "and");
2618+
self.get_llvm_value_handle(&v.into())
2619+
}
2620+
fn build_bit_or(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2621+
let lhs = self.get_llvm_value(lhs).unwrap();
2622+
let rhs = self.get_llvm_value(rhs).unwrap();
2623+
let lhs = lhs.into_int_value();
2624+
let rhs = rhs.into_int_value();
2625+
let v = self.builder.build_or(lhs, rhs, "or");
2626+
self.get_llvm_value_handle(&v.into())
2627+
}
2628+
fn build_bit_xor(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2629+
let lhs = self.get_llvm_value(lhs).unwrap();
2630+
let rhs = self.get_llvm_value(rhs).unwrap();
2631+
let lhs = lhs.into_int_value();
2632+
let rhs = rhs.into_int_value();
2633+
let v = self.builder.build_xor(lhs, rhs, "xor");
2634+
self.get_llvm_value_handle(&v.into())
2635+
}
2636+
fn build_bit_left_shift(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2637+
let lhs = self.get_llvm_value(lhs).unwrap();
2638+
let rhs = self.get_llvm_value(rhs).unwrap();
2639+
let lhs = lhs.into_int_value();
2640+
let rhs = rhs.into_int_value();
2641+
let v = self.builder.build_left_shift(lhs, rhs, "left_shift");
2642+
self.get_llvm_value_handle(&v.into())
2643+
}
2644+
fn build_bit_right_shift(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2645+
let lhs = self.get_llvm_value(lhs).unwrap();
2646+
let rhs = self.get_llvm_value(rhs).unwrap();
2647+
let lhs = lhs.into_int_value();
2648+
let rhs = rhs.into_int_value();
2649+
let v = self
2650+
.builder
2651+
.build_right_shift(lhs, rhs, false, "right_shift");
2652+
self.get_llvm_value_handle(&v.into())
2653+
}
2654+
fn build_bit_right_shift_arithmetic(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle {
2655+
let lhs = self.get_llvm_value(lhs).unwrap();
2656+
let rhs = self.get_llvm_value(rhs).unwrap();
2657+
let lhs = lhs.into_int_value();
2658+
let rhs = rhs.into_int_value();
2659+
let v = self
2660+
.builder
2661+
.build_right_shift(lhs, rhs, true, "right_shift");
2662+
self.get_llvm_value_handle(&v.into())
2663+
}
26042664
}
26052665

26062666
fn add_field(st_v: AnyValueEnum<'_>, field_tp: inkwell::types::AnyTypeEnum<'_>) -> u32 {

src/ast/builder/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,13 @@ pub trait IRBuilder<'a, 'ctx> {
236236
fn correct_generator_ctx_malloc_inst(&self, ctx: &mut Ctx<'a>, name: &str);
237237
fn sizeof(&self, pltype: &PLType, ctx: &mut Ctx<'a>) -> u64;
238238
fn build_memcpy(&self, from: ValueHandle, to: ValueHandle, len: ValueHandle);
239+
fn build_bit_not(&self, v: ValueHandle) -> ValueHandle;
240+
fn build_bit_and(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
241+
fn build_bit_or(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
242+
fn build_bit_xor(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
243+
fn build_bit_left_shift(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
244+
fn build_bit_right_shift(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
245+
fn build_bit_right_shift_arithmetic(&self, lhs: ValueHandle, rhs: ValueHandle) -> ValueHandle;
239246
}
240247

241248
pub type ValueHandle = usize;

src/ast/builder/no_op_builder.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,36 @@ impl<'a, 'ctx> IRBuilder<'a, 'ctx> for NoOpBuilder<'a, 'ctx> {
501501
0
502502
}
503503
fn build_memcpy(&self, _from: ValueHandle, _to: ValueHandle, _len: ValueHandle) {}
504+
505+
fn build_bit_not(&self, _v: ValueHandle) -> ValueHandle {
506+
0
507+
}
508+
509+
fn build_bit_and(&self, _lhs: ValueHandle, _rhs: ValueHandle) -> ValueHandle {
510+
0
511+
}
512+
513+
fn build_bit_or(&self, _lhs: ValueHandle, _rhs: ValueHandle) -> ValueHandle {
514+
0
515+
}
516+
517+
fn build_bit_xor(&self, _lhs: ValueHandle, _rhs: ValueHandle) -> ValueHandle {
518+
0
519+
}
520+
521+
fn build_bit_left_shift(&self, _lhs: ValueHandle, _rhs: ValueHandle) -> ValueHandle {
522+
0
523+
}
524+
525+
fn build_bit_right_shift(&self, _lhs: ValueHandle, _rhs: ValueHandle) -> ValueHandle {
526+
0
527+
}
528+
529+
fn build_bit_right_shift_arithmetic(
530+
&self,
531+
_lhs: ValueHandle,
532+
_rhs: ValueHandle,
533+
) -> ValueHandle {
534+
0
535+
}
504536
}

src/ast/diag.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ define_error!(
143143
INVALID_RET_IN_GENERATOR_FUNCTION = "invalid `return` in generator function",
144144
ARRAY_LEN_MUST_BE_I64 = "array len must be i64",
145145
EXPECT_ARRAY_TYPE = "expect array type",
146+
EXPECT_INT_VALUE = "expect int value",
146147
);
147148
macro_rules! define_warn {
148149
($(

src/ast/node/operator.rs

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,9 @@ impl Node for UnaryOpNode {
5858
PriType::I128 | PriType::I64 | PriType::I32 | PriType::I16 | PriType::I8,
5959
),
6060
TokenType::MINUS,
61-
) => {
62-
// (
63-
// Some(plv!(builder.build_int_neg(exp, "negtmp"))),
64-
// Some(pltype.clone()),
65-
// TerminatorEnum::None,
66-
// )
67-
builder
68-
.build_int_neg(exp, "negtmp")
69-
.new_output(pltype.clone())
70-
}
61+
) => builder
62+
.build_int_neg(exp, "negtmp")
63+
.new_output(pltype.clone()),
7164
(PLType::Primitive(PriType::F64 | PriType::F32), TokenType::MINUS) => builder
7265
.build_float_neg(exp, "negtmp")
7366
.new_output(pltype.clone()),
@@ -79,6 +72,7 @@ impl Node for UnaryOpNode {
7972
"nottmp",
8073
)
8174
.new_output(pltype.clone()),
75+
(_, TokenType::BIT_NOT) => builder.build_bit_not(exp).new_output(pltype.clone()),
8276
(_exp, _op) => {
8377
return Err(ctx.add_diag(self.range.new_err(ErrorCode::INVALID_UNARY_EXPRESSION)));
8478
}
@@ -185,6 +179,54 @@ impl Node for BinOpNode {
185179
}
186180
let right = ctx.try_load2var(rrange, re.unwrap().get_value(), builder)?;
187181
Ok(match self.op.0 {
182+
TokenType::BIT_AND => {
183+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
184+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
185+
}
186+
builder
187+
.build_bit_and(left, right)
188+
.new_output(lpltype.clone())
189+
}
190+
TokenType::BIT_OR => {
191+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
192+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
193+
}
194+
builder
195+
.build_bit_or(left, right)
196+
.new_output(lpltype.clone())
197+
}
198+
TokenType::BIT_XOR => {
199+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
200+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
201+
}
202+
builder
203+
.build_bit_xor(left, right)
204+
.new_output(lpltype.clone())
205+
}
206+
TokenType::BIT_LEFT_SHIFT => {
207+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
208+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
209+
}
210+
builder
211+
.build_bit_left_shift(left, right)
212+
.new_output(lpltype.clone())
213+
}
214+
TokenType::BIT_RIGHT_SHIFT => {
215+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
216+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
217+
}
218+
builder
219+
.build_bit_right_shift_arithmetic(left, right)
220+
.new_output(lpltype.clone())
221+
}
222+
TokenType::BIT_RIGHT_SHIFT_NO_SIGN => {
223+
if !lpltype.borrow().is_int() || !lpltype.borrow().is_int() {
224+
return Err(ctx.add_diag(self.range.new_err(ErrorCode::EXPECT_INT_VALUE)));
225+
}
226+
builder
227+
.build_bit_right_shift(left, right)
228+
.new_output(lpltype.clone())
229+
}
188230
TokenType::PLUS => {
189231
handle_calc!(ctx, add, float_add, lpltype, left, right, self.range, builder)
190232
}
@@ -214,7 +256,8 @@ impl Node for BinOpNode {
214256
| PriType::U64
215257
| PriType::U32
216258
| PriType::U16
217-
| PriType::U8,
259+
| PriType::U8
260+
| PriType::BOOL,
218261
) => { builder.build_int_compare(self.op.0.get_op(), left, right, "cmptmp") }
219262
.new_output(Arc::new(RefCell::new(PLType::Primitive(PriType::BOOL)))),
220263
PLType::Primitive(PriType::F64 | PriType::F32) => {

src/ast/pltype.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,22 @@ impl PriType {
281281
PriType::I8 | PriType::I16 | PriType::I32 | PriType::I64 | PriType::I128
282282
)
283283
}
284+
pub fn is_int(&self) -> bool {
285+
matches!(
286+
self,
287+
PriType::I8
288+
| PriType::I16
289+
| PriType::I32
290+
| PriType::I64
291+
| PriType::I128
292+
| PriType::U8
293+
| PriType::U16
294+
| PriType::U32
295+
| PriType::U64
296+
| PriType::U128
297+
| PriType::BOOL
298+
)
299+
}
284300
pub fn try_from_str(str: &str) -> Option<Self> {
285301
match str {
286302
"i8" => Some(PriType::I8),
@@ -380,6 +396,13 @@ impl PLType {
380396
}
381397
}
382398

399+
pub fn is_int(&self) -> bool {
400+
match self {
401+
PLType::Primitive(p) => p.is_int(),
402+
_ => false,
403+
}
404+
}
405+
383406
pub fn get_kind_name(&self) -> String {
384407
match self {
385408
PLType::Primitive(_) | PLType::Void => "primitive".to_string(),

src/ast/tokens.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ define_tokens!(
9696
IS = "is",
9797
YIELD = "yield",
9898
GENERATOR_MARKER = "gen",
99+
BIT_AND = "&",
100+
BIT_OR = "|",
101+
BIT_XOR = "^",
102+
BIT_LEFT_SHIFT = "<<",
103+
BIT_RIGHT_SHIFT = ">>",
104+
BIT_NOT = "~",
105+
BIT_RIGHT_SHIFT_NO_SIGN = ">>>",
99106
);
100107

101108
impl TokenType {

src/nomparser/expression.rs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use nom::{
22
branch::alt,
3-
combinator::{map_res, opt},
3+
combinator::{map_res, not, opt, peek},
44
multi::{many0, separated_list0},
5-
sequence::{delimited, pair, preceded, tuple},
5+
sequence::{delimited, pair, preceded, terminated, tuple},
66
IResult,
77
};
88

@@ -29,17 +29,61 @@ pub fn general_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
2929
#[test_parser("a&&b")]
3030
#[test_parser("a||b")]
3131
pub fn logic_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
32-
parse_bin_ops!(compare_exp, AND, OR)(input)
32+
parse_bin_ops!(compare_exp_eq, AND, OR)(input)
33+
}
34+
35+
#[test_parser("a==b")]
36+
#[test_parser("a!=b")]
37+
fn compare_exp_eq(input: Span) -> IResult<Span, Box<NodeEnum>> {
38+
parse_bin_ops!(compare_exp, NE, EQ)(input)
3339
}
3440

3541
#[test_parser("a>b")]
3642
#[test_parser("a>=b")]
3743
#[test_parser("a<b")]
3844
#[test_parser("a<=b")]
39-
#[test_parser("a==b")]
40-
#[test_parser("a!=b")]
4145
fn compare_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
42-
parse_bin_ops!(add_exp, GEQ, LEQ, NE, EQ, LESS, GREATER)(input)
46+
parse_bin_ops!(bit_or, GEQ, LEQ, LESS, GREATER)(input)
47+
}
48+
49+
#[test_parser("a|b")]
50+
fn bit_or(input: Span) -> IResult<Span, Box<NodeEnum>> {
51+
parse_bin_ops!(bit_xor, BIT_OR)(input)
52+
}
53+
54+
#[test_parser("a^b")]
55+
fn bit_xor(input: Span) -> IResult<Span, Box<NodeEnum>> {
56+
parse_bin_ops!(bit_and, BIT_XOR)(input)
57+
}
58+
59+
#[test_parser("a&b")]
60+
#[test_parser_error("a&&b")]
61+
fn bit_and(input: Span) -> IResult<Span, Box<NodeEnum>> {
62+
delspace(map_res(
63+
tuple((
64+
bit_move,
65+
many0(tuple((
66+
alt((terminated(
67+
tag_token_symbol(TokenType::BIT_AND),
68+
not(peek(tag_token_symbol(TokenType::BIT_AND))),
69+
),)),
70+
bit_move,
71+
))),
72+
)),
73+
create_bin,
74+
))(input)
75+
}
76+
77+
#[test_parser("a>>>b")]
78+
#[test_parser("a<<b")]
79+
#[test_parser("a>>b")]
80+
fn bit_move(input: Span) -> IResult<Span, Box<NodeEnum>> {
81+
parse_bin_ops!(
82+
add_exp,
83+
BIT_LEFT_SHIFT,
84+
BIT_RIGHT_SHIFT_NO_SIGN,
85+
BIT_RIGHT_SHIFT
86+
)(input)
4387
}
4488

4589
#[test_parser("a + 1")]
@@ -56,6 +100,7 @@ fn mul_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
56100

57101
#[test_parser("-1")]
58102
#[test_parser("!a")]
103+
#[test_parser("~a")]
59104
#[test_parser_error("+a")]
60105
fn unary_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
61106
delspace(alt((
@@ -65,6 +110,7 @@ fn unary_exp(input: Span) -> IResult<Span, Box<NodeEnum>> {
65110
alt((
66111
tag_token_symbol(TokenType::MINUS),
67112
tag_token_symbol(TokenType::NOT),
113+
tag_token_symbol(TokenType::BIT_NOT),
68114
)),
69115
pointer_exp,
70116
)),

test/test/simple.pi

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ pub fn test_primitives() void {
1414
testf32 = testf32 + 1.2;
1515
let utest: u8 = 1;
1616
utest = utest + 2;
17+
test = 127;
18+
test = -test - 1;
19+
panic::assert(test as i64 == -128);
20+
let b = test | 1;
21+
panic::assert(b as i64 == -127);
22+
let c = test & 1;
23+
panic::assert(c == 0);
24+
let d = test ^ 1;
25+
panic::assert(d as i64 == -127);
26+
let e = test << 1;
27+
panic::assert(e as i64 == 0);
28+
let f = test >> 1;
29+
panic::assert(f as i64 == -64);
30+
let g = test >>> 1;
31+
panic::assert(g as i64 == 64);
32+
let h = ~test;
33+
panic::assert(h as i64 == 127);
1734
return;
1835
}
1936

0 commit comments

Comments
 (0)