Skip to content

Commit

Permalink
feat: bitwise XOR (^) operation (tact-lang#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gusarich authored Apr 19, 2024
1 parent f2bb897 commit ab7c7aa
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Display an error for integer overflow at compile-time: PR [#200](https://github.com/tact-lang/tact/pull/200)
- Non-modifying `StringBuilder`'s `concat` method for chained string concatenations: PR [#217](https://github.com/tact-lang/tact/pull/217)
- `toString` extension function for `Address` type: PR [#224](https://github.com/tact-lang/tact/pull/224)
- Bitwise XOR operation (`^`): PR [#238](https://github.com/tact-lang/tact/pull/238)
- `isEmpty` method for `Map` type: PR [#266](https://github.com/tact-lang/tact/pull/266)

### Changed
Expand Down
2 changes: 2 additions & 0 deletions src/generator/writers/writeExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ export function writeExpression(f: ASTExpression, ctx: WriterContext): string {
op = "&";
} else if (f.op === "|") {
op = "|";
} else if (f.op === "^") {
op = "^";
} else {
throwError("Unknown binary operator: " + f.op, f.ref);
}
Expand Down
3 changes: 2 additions & 1 deletion src/grammar/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ export type ASTOpBinary = {
| "<<"
| ">>"
| "&"
| "|";
| "|"
| "^";
left: ASTExpression;
right: ASTExpression;
ref: ASTRef;
Expand Down
5 changes: 4 additions & 1 deletion src/grammar/grammar.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ Tact {
ExpressionAnd = ExpressionAnd "&&" ExpressionBinaryOr --and
| ExpressionBinaryOr

ExpressionBinaryOr = ExpressionBinaryOr "|" ExpressionBinaryAnd --bin_or
ExpressionBinaryOr = ExpressionBinaryOr "|" ExpressionBinaryXor --bin_or
| ExpressionBinaryXor

ExpressionBinaryXor = ExpressionBinaryXor "^" ExpressionBinaryAnd --bin_xor
| ExpressionBinaryAnd

ExpressionBinaryAnd = ExpressionBinaryAnd "&" ExpressionEquality --bin_and
Expand Down
9 changes: 9 additions & 0 deletions src/grammar/grammar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,15 @@ semantics.addOperation<ASTNode>("resolve_expression", {
ref: createRef(this),
});
},
ExpressionBinaryXor_bin_xor(arg0, _arg1, arg2) {
return createNode({
kind: "op_binary",
op: "^",
left: arg0.resolve_expression(),
right: arg2.resolve_expression(),
ref: createRef(this),
});
},

// Unary
ExpressionUnary_add(_arg0, arg1) {
Expand Down
3 changes: 3 additions & 0 deletions src/test/feature-constants.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ describe("feature-constants", () => {
expect((await contract.getSomething10()).toRawString()).toEqual(
"0:4a81708d2cf7b15a1b362fbf64880451d698461f52f05f145b36c08517d76873",
);
expect(await contract.getSomething11()).toEqual(88n);
expect(await contract.getSomething12()).toEqual(-90n);
expect(await contract.getSomething13()).toEqual(88n);
expect(await contract.getGlobalConst()).toEqual(100n);
});
});
15 changes: 15 additions & 0 deletions src/test/feature-math.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ describe("feature-math", () => {
expect(await contract.getSub(1n, -2n)).toBe(3n);
expect(await contract.getMul(2n, 2n)).toBe(4n);
expect(await contract.getDiv(2n, 2n)).toBe(1n);
expect(await contract.getMod(2n, 2n)).toBe(0n);
expect(await contract.getShr(4n, 1n)).toBe(2n);
expect(await contract.getShl(2n, 1n)).toBe(4n);
expect(await contract.getAnd(2n, 3n)).toBe(2n);
expect(await contract.getOr(2n, 3n)).toBe(3n);
expect(await contract.getXor(2n, 3n)).toBe(1n);
expect(await contract.getXor(2n, -3n)).toBe(-1n);
expect(await contract.getXor(-2n, 3n)).toBe(-3n);
expect(await contract.getXor(-2n, -3n)).toBe(3n);

// Augmented Assign
expect(await contract.getAddAug(1n, 2n)).toBe(3n);
Expand Down Expand Up @@ -397,5 +406,11 @@ describe("feature-math", () => {
expect(await contract.getPrecendence4()).toBe(12n);
expect(await contract.getPrecendence5()).toBe(5n);
expect(await contract.getPrecendence6()).toBe(0n);
expect(await contract.getPrecendence7()).toBe(7n);
expect(await contract.getPrecendence8()).toBe(3n);
expect(await contract.getPrecendence9()).toBe(7n);
expect(await contract.getPrecendence10()).toBe(3n);
expect(await contract.getPrecendence11()).toBe(3n);
expect(await contract.getPrecendence12()).toBe(5n);
});
});
15 changes: 15 additions & 0 deletions src/test/features/constants.tact
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ contract ConstantTester {
const something8: Int = (2 + 4) & 4;
const something9: Address = address("UQBKgXCNLPexWhs2L79kiARR1phGH1LwXxRbNsCFF9doczSI");
const something10: Address = newAddress(0, 0x4a81708d2cf7b15a1b362fbf64880451d698461f52f05f145b36c08517d76873);
const something11: Int = 123 ^ 35;
const something12: Int = -123 ^ 35;
const something13: Int = -123 ^ -35;

init() {

Expand Down Expand Up @@ -60,6 +63,18 @@ contract ConstantTester {
return self.something10;
}

get fun something11(): Int {
return self.something11;
}

get fun something12(): Int {
return self.something12;
}

get fun something13(): Int {
return self.something13;
}

get fun globalConst(): Int {
return someGlobalConst;
}
Expand Down
28 changes: 28 additions & 0 deletions src/test/features/math.tact
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ contract MathTester with Deployable {
return a | b;
}

get fun xor(a: Int, b: Int): Int {
return a ^ b;
}

//
// Augmented assignment
//
Expand Down Expand Up @@ -331,4 +335,28 @@ contract MathTester with Deployable {
get fun precendence6(): Int {
return (5 | 6) & 8;
}

get fun precendence7(): Int {
return 5 ^ 6 | 7;
}

get fun precendence8(): Int {
return 5 ^ 6 & 7;
}

get fun precendence9(): Int {
return (5 ^ 6) | 7;
}

get fun precendence10(): Int {
return 5 ^ 6 | 7 & 8;
}

get fun precendence11(): Int {
return (5 ^ 6) | (7 & 8);
}

get fun precendence12(): Int {
return 5 ^ (6 | 7) & 8;
}
}
2 changes: 2 additions & 0 deletions src/types/resolveConstantValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ function reduceIntImpl(ast: ASTExpression): bigint {
return l & r;
} else if (ast.op === "|") {
return l | r;
} else if (ast.op === "^") {
return l ^ r;
}
} else if (ast.kind === "op_unary") {
if (ast.op === "-") {
Expand Down
3 changes: 2 additions & 1 deletion src/types/resolveExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ function resolveBinaryOp(
exp.op === ">>" ||
exp.op === "<<" ||
exp.op === "&" ||
exp.op === "|"
exp.op === "|" ||
exp.op === "^"
) {
if (le.kind !== "ref" || le.optional || le.name !== "Int") {
throwError(
Expand Down

0 comments on commit ab7c7aa

Please sign in to comment.