diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e84422e3..45f7e4d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `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) +- `pow2` function: PR [#267](https://github.com/tact-lang/tact/pull/267) ### Changed @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support escape sequences for strings (`\\`, `\"`, `\n`, `\r`, `\t`, `\v`, `\b`, `\f`, `\u{0}` through `\u{FFFFFF}`, `\u0000` through `\uFFFF`, `\x00` through `\xFF`): PR [#192](https://github.com/tact-lang/tact/pull/192) - `newAddress` function now evaluates to a constant value if possible: PR [#237](https://github.com/tact-lang/tact/pull/237) - The `dump()` and `dumpStack()` functions now print the file path, line number, and column number in addition to the data: PR [#271](https://github.com/tact-lang/tact/pull/271). +- `pow` function is now in the standard library, allowing its use at runtime. If constant arguments are used, the result is evaluated at compile-time: PR [#267](https://github.com/tact-lang/tact/pull/267) ### Fixed diff --git a/src/abi/global.ts b/src/abi/global.ts index 0a80782fa..07b187c66 100644 --- a/src/abi/global.ts +++ b/src/abi/global.ts @@ -39,46 +39,6 @@ export const GlobalFunctions: Map = new Map([ }, }, ], - [ - "pow", - { - name: "pow", - resolve: (ctx, args, ref) => { - if (args.length !== 2) { - throwError("pow() expects two integer arguments", ref); - } - if (args[0].kind !== "ref") { - throwError("pow() expects two integer arguments", ref); - } - if (args[0].name !== "Int") { - throwError("pow() expects two integer arguments", ref); - } - if (args[1].kind !== "ref") { - throwError("pow() expects two integer arguments", ref); - } - if (args[1].name !== "Int") { - throwError("pow() expects two integer arguments", ref); - } - return { kind: "ref", name: "Int", optional: false }; - }, - generate: (ctx, args, resolved, ref) => { - if (resolved.length !== 2) { - throwError("pow() expects two integer arguments", ref); - } - const a = resolveConstantValue( - { kind: "ref", name: "Int", optional: false }, - resolved[0], - ctx.ctx, - ) as bigint; - const b = resolveConstantValue( - { kind: "ref", name: "Int", optional: false }, - resolved[1], - ctx.ctx, - ) as bigint; - return (a ** b).toString(10); - }, - }, - ], [ "require", { diff --git a/src/generator/writers/__snapshots__/writeSerialization.spec.ts.snap b/src/generator/writers/__snapshots__/writeSerialization.spec.ts.snap index d438013da..a736d34a2 100644 --- a/src/generator/writers/__snapshots__/writeSerialization.spec.ts.snap +++ b/src/generator/writers/__snapshots__/writeSerialization.spec.ts.snap @@ -3160,6 +3160,35 @@ return result;", "name": "__tact_log", "signature": "int __tact_log(int num, int base)", }, + { + "code": { + "code": "throw_unless(5, exp >= 0); +int result = 1; +repeat (exp) { + result *= base; +} +return result;", + "kind": "generic", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow", + "signature": "int __tact_pow(int base, int exp)", + }, + { + "code": { + "code": "asm "POW2"", + "kind": "asm", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow2", + "signature": "int __tact_pow2(int exp)", + }, { "code": { "code": "var (v'a, v'b, v'c, v'd, v'e, v'f, v'g) = v; @@ -7171,6 +7200,35 @@ return result;", "name": "__tact_log", "signature": "int __tact_log(int num, int base)", }, + { + "code": { + "code": "throw_unless(5, exp >= 0); +int result = 1; +repeat (exp) { + result *= base; +} +return result;", + "kind": "generic", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow", + "signature": "int __tact_pow(int base, int exp)", + }, + { + "code": { + "code": "asm "POW2"", + "kind": "asm", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow2", + "signature": "int __tact_pow2(int exp)", + }, { "code": { "code": "var (v'a, v'b, v'c, v'd, v'e, v'f, v'g) = v; @@ -11182,6 +11240,35 @@ return result;", "name": "__tact_log", "signature": "int __tact_log(int num, int base)", }, + { + "code": { + "code": "throw_unless(5, exp >= 0); +int result = 1; +repeat (exp) { + result *= base; +} +return result;", + "kind": "generic", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow", + "signature": "int __tact_pow(int base, int exp)", + }, + { + "code": { + "code": "asm "POW2"", + "kind": "asm", + }, + "comment": null, + "context": "stdlib", + "depends": Set {}, + "flags": Set {}, + "name": "__tact_pow2", + "signature": "int __tact_pow2(int exp)", + }, { "code": { "code": "var (v'a, v'b, v'c, v'd, v'e, v'f, v'g, v'h) = v; diff --git a/src/generator/writers/writeStdlib.ts b/src/generator/writers/writeStdlib.ts index b3aee04e4..89d04d1bb 100644 --- a/src/generator/writers/writeStdlib.ts +++ b/src/generator/writers/writeStdlib.ts @@ -1437,4 +1437,25 @@ export function writeStdlib(ctx: WriterContext) { `); }); }); + + ctx.fun(`__tact_pow`, () => { + ctx.signature(`int __tact_pow(int base, int exp)`); + ctx.context("stdlib"); + ctx.body(() => { + ctx.write(` + throw_unless(5, exp >= 0); + int result = 1; + repeat (exp) { + result *= base; + } + return result; + `); + }); + }); + + ctx.fun(`__tact_pow2`, () => { + ctx.signature(`int __tact_pow2(int exp)`); + ctx.context("stdlib"); + ctx.asm(`asm "POW2"`); + }); } diff --git a/src/imports/stdlib.ts b/src/imports/stdlib.ts index 1a5a3cf70..484d33038 100644 --- a/src/imports/stdlib.ts +++ b/src/imports/stdlib.ts @@ -186,7 +186,8 @@ files['std/math.tact'] = 'ZXJ2YWwobWF4IC0gbWluKTsKfQoKLy8gTWF0aAoKQG5hbWUobWluKQpuYXRpdmUgbWluKHg6IEludCwgeTogSW50KTogSW50OwoKQG5hbWUobWF4KQpuYXRpdmUgbWF4' + 'KHg6IEludCwgeTogSW50KTogSW50OwoKQG5hbWUoYWJzKQpuYXRpdmUgYWJzKHg6IEludCk6IEludDsKCkBuYW1lKG5vdykKbmF0aXZlIG5vdygpOiBJbnQ7CgpAbmFt' + 'ZShfX3RhY3RfbG9nMikKbmF0aXZlIGxvZzIobnVtOiBJbnQpOiBJbnQ7CgpAbmFtZShfX3RhY3RfbG9nKQpuYXRpdmUgbG9nKG51bTogSW50LCBiYXNlOiBJbnQpOiBJ' + - 'bnQ7'; + 'bnQ7CgpAbmFtZShfX3RhY3RfcG93KQpuYXRpdmUgcG93KGJhc2U6IEludCwgZXhwOiBJbnQpOiBJbnQ7CgpAbmFtZShfX3RhY3RfcG93MikKbmF0aXZlIHBvdzIoZXhw' + + 'OiBJbnQpOiBJbnQ7'; files['std/primitives.tact'] = 'cHJpbWl0aXZlIEludDsKcHJpbWl0aXZlIEJvb2w7CnByaW1pdGl2ZSBCdWlsZGVyOwpwcmltaXRpdmUgU2xpY2U7CnByaW1pdGl2ZSBDZWxsOwpwcmltaXRpdmUgQWRk' + 'cmVzczsKcHJpbWl0aXZlIFN0cmluZzsKcHJpbWl0aXZlIFN0cmluZ0J1aWxkZXI7'; diff --git a/src/test/__snapshots__/feature-constants.spec.ts.snap b/src/test/__snapshots__/feature-constants.spec.ts.snap new file mode 100644 index 000000000..5a134fc77 --- /dev/null +++ b/src/test/__snapshots__/feature-constants.spec.ts.snap @@ -0,0 +1,564 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`feature-constants should implement constants correctly 1`] = ` +ConstantTester { + "abi": { + "errors": { + "10": { + "message": "Dictionary error", + }, + "128": { + "message": "Null reference exception", + }, + "129": { + "message": "Invalid serialization prefix", + }, + "13": { + "message": "Out of gas error", + }, + "130": { + "message": "Invalid incoming message", + }, + "131": { + "message": "Constraints error", + }, + "132": { + "message": "Access denied", + }, + "133": { + "message": "Contract stopped", + }, + "134": { + "message": "Invalid argument", + }, + "135": { + "message": "Code of a contract was not found", + }, + "136": { + "message": "Invalid address", + }, + "137": { + "message": "Masterchain support is not enabled for this contract", + }, + "2": { + "message": "Stack undeflow", + }, + "3": { + "message": "Stack overflow", + }, + "32": { + "message": "Method ID not found", + }, + "34": { + "message": "Action is invalid or not supported", + }, + "37": { + "message": "Not enough TON", + }, + "38": { + "message": "Not enough extra-currencies", + }, + "4": { + "message": "Integer overflow", + }, + "5": { + "message": "Integer out of expected range", + }, + "6": { + "message": "Invalid opcode", + }, + "7": { + "message": "Type check error", + }, + "8": { + "message": "Cell overflow", + }, + "9": { + "message": "Cell underflow", + }, + }, + "getters": [ + { + "arguments": [], + "name": "something1", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something2", + "returnType": { + "format": 257, + "kind": "simple", + "optional": true, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something3", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something4", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something5", + "returnType": { + "kind": "simple", + "optional": false, + "type": "string", + }, + }, + { + "arguments": [], + "name": "something6", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something7", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something8", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something9", + "returnType": { + "kind": "simple", + "optional": false, + "type": "address", + }, + }, + { + "arguments": [], + "name": "something10", + "returnType": { + "kind": "simple", + "optional": false, + "type": "address", + }, + }, + { + "arguments": [], + "name": "something11", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something12", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something13", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something14", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "something15", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "arguments": [], + "name": "globalConst", + "returnType": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + ], + "receivers": [ + { + "message": { + "kind": "empty", + }, + "receiver": "internal", + }, + ], + "types": [ + { + "fields": [ + { + "name": "code", + "type": { + "kind": "simple", + "optional": false, + "type": "cell", + }, + }, + { + "name": "data", + "type": { + "kind": "simple", + "optional": false, + "type": "cell", + }, + }, + ], + "header": null, + "name": "StateInit", + }, + { + "fields": [ + { + "name": "bounced", + "type": { + "kind": "simple", + "optional": false, + "type": "bool", + }, + }, + { + "name": "sender", + "type": { + "kind": "simple", + "optional": false, + "type": "address", + }, + }, + { + "name": "value", + "type": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "name": "raw", + "type": { + "kind": "simple", + "optional": false, + "type": "slice", + }, + }, + ], + "header": null, + "name": "Context", + }, + { + "fields": [ + { + "name": "bounce", + "type": { + "kind": "simple", + "optional": false, + "type": "bool", + }, + }, + { + "name": "to", + "type": { + "kind": "simple", + "optional": false, + "type": "address", + }, + }, + { + "name": "value", + "type": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "name": "mode", + "type": { + "format": 257, + "kind": "simple", + "optional": false, + "type": "int", + }, + }, + { + "name": "body", + "type": { + "kind": "simple", + "optional": true, + "type": "cell", + }, + }, + { + "name": "code", + "type": { + "kind": "simple", + "optional": true, + "type": "cell", + }, + }, + { + "name": "data", + "type": { + "kind": "simple", + "optional": true, + "type": "cell", + }, + }, + ], + "header": null, + "name": "SendParameters", + }, + ], + }, + "address": kQCG5ZO3hYCRKTIcSHbxVD6aemP9eqeRqXiPLuTtmDjr2Wio, + "init": { + "code": x{FF00F4A413F4BCF2C80B} + x{62_} + x{D001D0D3030171B0A301FA400120D74981010BBAF2E08820D70B0A208104FFBAF2D0898309BAF2E088545053036F04F86102F862DB3C59DB3CF2E08230C8F84301CC7F01CA00C9ED54} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{0192307FE07021D749C21F953020D70B1FDEC00001D749C121B0917FE070} + x{2_} + x{6A_} + x{B22EF6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{74} + x{B226B6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8D086002540B846967BD8AD0D9B17DFB2440228EB4C230FA9782F8A2D9B60428BEBB439C} + x{2_} + x{2_} + x{2_} + x{B24DF6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{82186A2BB7D000} + x{B245B6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8BC48656C6C6F20776F726C64218} + x{2_} + x{5} + x{A975DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{7A} + x{AAA2DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8020} + x{5} + x{2_} + x{A6A9B679B67863_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{75} + x{A7A304E0B9D87ABA595CF63D09D873AC950A36CD04E13BAC6A5A56C8F96645A75E5BFBE2C47304E040AB803700CEC7299CB0755C8E4B658704E037A93BDF2A8B2DE38EA7A7BC0AB3864D04E13B2E9CB5669D96E6741D2CDB28CDD149_} + x{AA83DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8100F3} + x{2_} + x{2_} + x{2_} + x{2_} + x{AABEED44D0D20001} + x{AB61DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8064} + x{AF326D9E6D9E18C_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8058} + x{5} + x{79A_} + x{ACB6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{800B} + x{AEE3435697066733A2F2F516D625A38617576474E63656B454543537056507163476A37506868564C69697A724E384D364C515248526E6A5182_} + x{AA45DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{80A6} + x{2_} + x{5} + x{A9F1DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{6D} + x{AA26DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8058} + x{5} + x{A9D0DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{82181CA35F0E00} + x{AA07DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8D086002540B846967BD8AD0D9B17DFB2440228EB4C230FA9782F8A2D9B60428BEBB439C}, + "data": x{4_} + x{C_} + x{A0F903_} + x{FF00F4A413F4BCF2C80B} + x{62_} + x{D001D0D3030171B0A301FA400120D74981010BBAF2E08820D70B0A208104FFBAF2D0898309BAF2E088545053036F04F86102F862DB3C59DB3CF2E08230C8F84301CC7F01CA00C9ED54} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{0192307FE07021D749C21F953020D70B1FDEC00001D749C121B0917FE070} + x{2_} + x{6A_} + x{B22EF6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{74} + x{B226B6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8D086002540B846967BD8AD0D9B17DFB2440228EB4C230FA9782F8A2D9B60428BEBB439C} + x{2_} + x{2_} + x{2_} + x{B24DF6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{82186A2BB7D000} + x{B245B6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8BC48656C6C6F20776F726C64218} + x{2_} + x{5} + x{A975DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{7A} + x{AAA2DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8020} + x{5} + x{2_} + x{A6A9B679B67863_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{75} + x{A7A304E0B9D87ABA595CF63D09D873AC950A36CD04E13BAC6A5A56C8F96645A75E5BFBE2C47304E040AB803700CEC7299CB0755C8E4B658704E037A93BDF2A8B2DE38EA7A7BC0AB3864D04E13B2E9CB5669D96E6741D2CDB28CDD149_} + x{AA83DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8100F3} + x{2_} + x{2_} + x{2_} + x{2_} + x{AABEED44D0D20001} + x{AB61DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8064} + x{AF326D9E6D9E18C_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8058} + x{5} + x{79A_} + x{ACB6CF36CF0C6_} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{800B} + x{AEE3435697066733A2F2F516D625A38617576474E63656B454543537056507163476A37506868564C69697A724E384D364C515248526E6A5182_} + x{AA45DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{80A6} + x{2_} + x{5} + x{A9F1DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{6D} + x{AA26DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8058} + x{5} + x{A9D0DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{82181CA35F0E00} + x{AA07DB3CDB3C31} + x{ED44D0D401F863D20030916DE0F828D70B0A8309BAF2E089DB3C} + x{6D} + x{8D086002540B846967BD8AD0D9B17DFB2440228EB4C230FA9782F8A2D9B60428BEBB439C}, + }, +} +`; diff --git a/src/test/__snapshots__/feature-instrinsics.spec.ts.snap b/src/test/__snapshots__/feature-instrinsics.spec.ts.snap index 62b20f03f..2123077e3 100644 --- a/src/test/__snapshots__/feature-instrinsics.spec.ts.snap +++ b/src/test/__snapshots__/feature-instrinsics.spec.ts.snap @@ -7,7 +7,7 @@ exports[`feature-instrinsics should return correct instinsic results 1`] = ` "events": [ { "$type": "storage-charged", - "amount": "0.00000001", + "amount": "0.000000011", }, { "$type": "received", diff --git a/src/test/feature-constants.spec.ts b/src/test/feature-constants.spec.ts index d7e6ac41e..18aba6d17 100644 --- a/src/test/feature-constants.spec.ts +++ b/src/test/feature-constants.spec.ts @@ -14,6 +14,7 @@ describe("feature-constants", () => { const contract = system.open(await ConstantTester.fromInit()); await contract.send(treasure, { value: toNano("10") }, null); await system.run(); + expect(contract).toMatchSnapshot(); // Check methods expect(await contract.getSomething1()).toEqual(11n); @@ -33,6 +34,8 @@ describe("feature-constants", () => { expect(await contract.getSomething11()).toEqual(88n); expect(await contract.getSomething12()).toEqual(-90n); expect(await contract.getSomething13()).toEqual(88n); + expect(await contract.getSomething14()).toEqual(243n); + expect(await contract.getSomething15()).toEqual(32n); expect(await contract.getGlobalConst()).toEqual(100n); }); }); diff --git a/src/test/feature-math.spec.ts b/src/test/feature-math.spec.ts index 5f93c76df..75f573b82 100644 --- a/src/test/feature-math.spec.ts +++ b/src/test/feature-math.spec.ts @@ -398,6 +398,27 @@ describe("feature-math", () => { } } + expect(await contract.getPow(2n, 0n)).toBe(1n); + expect(await contract.getPow(2n, 1n)).toBe(2n); + expect(await contract.getPow(2n, 2n)).toBe(4n); + expect(await contract.getPow(2n, 3n)).toBe(8n); + expect(await contract.getPow(0n, 0n)).toBe(1n); + expect(await contract.getPow(0n, 1n)).toBe(0n); + expect(await contract.getPow(1n, 10n)).toBe(1n); + expect(await contract.getPow(10n, 2n)).toBe(100n); + + expect(await contract.getPow2(0n)).toBe(1n); + expect(await contract.getPow2(1n)).toBe(2n); + expect(await contract.getPow2(2n)).toBe(4n); + expect(await contract.getPow2(3n)).toBe(8n); + + await expect(contract.getPow(2n, -1n)).rejects.toThrow( + "Integer out of expected range", + ); + await expect(contract.getPow2(-1n)).rejects.toThrow( + "Integer out of expected range", + ); + // Test operation precendence expect(await contract.getPrecendence1()).toBe(12n); diff --git a/src/test/features/constants.tact b/src/test/features/constants.tact index ad00feedb..9a9de38e4 100644 --- a/src/test/features/constants.tact +++ b/src/test/features/constants.tact @@ -14,6 +14,8 @@ contract ConstantTester { const something11: Int = 123 ^ 35; const something12: Int = -123 ^ 35; const something13: Int = -123 ^ -35; + const something14: Int = pow(3, 5); + const something15: Int = pow2(5); init() { @@ -75,6 +77,14 @@ contract ConstantTester { return self.something13; } + get fun something14(): Int { + return self.something14; + } + + get fun something15(): Int { + return self.something15; + } + get fun globalConst(): Int { return someGlobalConst; } diff --git a/src/test/features/math.tact b/src/test/features/math.tact index 248c33e08..3e8b87092 100644 --- a/src/test/features/math.tact +++ b/src/test/features/math.tact @@ -312,6 +312,18 @@ contract MathTester with Deployable { return log(num, base); } + get fun pow(base: Int, exp: Int): Int { + return pow(base, exp); + } + + get fun pow2(exp: Int): Int { + return pow2(exp); + } + + // + // Precedence + // + get fun precendence1(): Int { return 5 & 6 | 1 << 5 + 11 * 3 % 12 >> 11; } diff --git a/src/types/resolveConstantValue.ts b/src/types/resolveConstantValue.ts index a4b5f940e..87a148626 100644 --- a/src/types/resolveConstantValue.ts +++ b/src/types/resolveConstantValue.ts @@ -49,6 +49,11 @@ function reduceIntImpl(ast: ASTExpression): bigint { return reduceInt(ast.args[0]) ** reduceInt(ast.args[1]); } } + if (ast.name === "pow2") { + if (ast.args.length === 1) { + return 2n ** reduceInt(ast.args[0]); + } + } if (ast.name === "sha256") { if (ast.args.length === 1 && ast.args[0].kind === "string") { const str = reduceString(ast.args[0]); diff --git a/stdlib/std/math.tact b/stdlib/std/math.tact index 5fa9ae833..04f9a34a2 100644 --- a/stdlib/std/math.tact +++ b/stdlib/std/math.tact @@ -45,4 +45,10 @@ native now(): Int; native log2(num: Int): Int; @name(__tact_log) -native log(num: Int, base: Int): Int; \ No newline at end of file +native log(num: Int, base: Int): Int; + +@name(__tact_pow) +native pow(base: Int, exp: Int): Int; + +@name(__tact_pow2) +native pow2(exp: Int): Int; \ No newline at end of file