From 14174d23f426d2ee5fc48ddd4f77e4c4e21203af Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 8 Jul 2023 09:50:07 -0400 Subject: [PATCH 01/13] booleanArgAndReturn --- src/lib/compiler.ts | 78 ++++++++++--------- tests/abi.test.ts | 7 ++ tests/contracts/abi.algo.ts | 5 ++ .../ABITestBooleanArgAndReturn.abi.json | 21 +++++ .../ABITestBooleanArgAndReturn.approval.teal | 56 +++++++++++++ .../ABITestBooleanArgAndReturn.clear.teal | 3 + .../artifacts/ABITestBooleanArgAndReturn.json | 57 ++++++++++++++ 7 files changed, 192 insertions(+), 35 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestBooleanArgAndReturn.abi.json create mode 100644 tests/contracts/artifacts/ABITestBooleanArgAndReturn.approval.teal create mode 100644 tests/contracts/artifacts/ABITestBooleanArgAndReturn.clear.teal create mode 100644 tests/contracts/artifacts/ABITestBooleanArgAndReturn.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 3e93d135a..df7b9cd87 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -379,6 +379,14 @@ export default class Compiler { asset: this.getOpParamObjects('asset_params_get'), }; + private checkDecoding(node: ts.Node, type: string) { + if (type === 'bool') { + this.pushLines(node, 'int 0', 'getbit'); + } else if (this.isDynamicArrayOfStaticType(type)) { + this.pushVoid(node, 'extract 2 0'); + } + } + private storageFunctions: {[type: string]: {[f: string]: Function}} = { global: { get: (node: ts.CallExpression) => { @@ -397,7 +405,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -405,7 +413,7 @@ export default class Compiler { } this.push(node.expression, 'app_global_get', valueType); - if (this.isDynamicArrayOfStaticType(valueType) && valueType !== StackType.bytes) this.push(node.expression, 'extract 2 0', valueType); + if (valueType !== StackType.bytes) this.checkDecoding(node, valueType); }, set: (node: ts.CallExpression) => { if (!ts.isPropertyAccessExpression(node.expression)) throw new Error(); @@ -423,7 +431,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -433,7 +441,7 @@ export default class Compiler { if (node.arguments[key ? 0 : 1]) { this.processNode(node.arguments[key ? 0 : 1]); if (valueType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[key ? 0 : 1], this.lastType); + this.checkEncoding(node.arguments[key ? 0 : 1], this.lastType); } } else this.pushVoid(node.expression, 'swap'); // Used when updating storage array @@ -455,7 +463,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -482,7 +490,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -511,7 +519,7 @@ export default class Compiler { this.processNode(node.arguments[1]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[1], this.lastType); + this.checkEncoding(node.arguments[1], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[1], 'itob'); @@ -519,7 +527,7 @@ export default class Compiler { } this.push(node.expression, 'app_local_get', valueType); - if (this.isDynamicArrayOfStaticType(valueType) && valueType !== StackType.bytes) this.push(node.expression, 'extract 2 0', valueType); + if (valueType !== StackType.bytes) this.checkDecoding(node, valueType); }, set: (node: ts.CallExpression) => { if (!ts.isPropertyAccessExpression(node.expression)) throw new Error(); @@ -539,7 +547,7 @@ export default class Compiler { this.processNode(node.arguments[1]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[1], this.lastType); + this.checkEncoding(node.arguments[1], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[1], 'itob'); @@ -549,7 +557,7 @@ export default class Compiler { if (node.arguments[key ? 1 : 2]) { this.processNode(node.arguments[key ? 1 : 2]); if (valueType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[key ? 1 : 2], this.lastType); + this.checkEncoding(node.arguments[key ? 1 : 2], this.lastType); } } else this.pushVoid(node.expression, 'uncover 2'); // Used when updating storage array @@ -573,7 +581,7 @@ export default class Compiler { this.processNode(node.arguments[1]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[1], this.lastType); + this.checkEncoding(node.arguments[1], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[1], 'itob'); @@ -600,7 +608,7 @@ export default class Compiler { this.processNode(node.arguments[1]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[1], this.lastType); + this.checkEncoding(node.arguments[1], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[1], 'itob'); @@ -628,7 +636,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -656,7 +664,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -685,7 +693,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -714,7 +722,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -739,7 +747,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -748,7 +756,7 @@ export default class Compiler { this.maybeValue(node.expression, 'box_get', valueType); if (isNumeric(valueType)) this.push(node.expression, 'btoi', valueType); - if (this.isDynamicArrayOfStaticType(valueType) && valueType !== StackType.bytes) this.push(node.expression, 'extract 2 0', valueType); + if (valueType !== StackType.bytes) this.checkDecoding(node, valueType); }, set: (node: ts.CallExpression) => { if (!ts.isPropertyAccessExpression(node.expression)) throw new Error(); @@ -766,7 +774,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -779,7 +787,7 @@ export default class Compiler { this.processNode(node.arguments[key ? 0 : 1]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[key ? 0 : 1], this.lastType); + this.checkEncoding(node.arguments[key ? 0 : 1], this.lastType); } } else this.pushVoid(node.expression, 'swap'); // Used when updating storage array @@ -803,7 +811,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -828,7 +836,7 @@ export default class Compiler { this.processNode(node.arguments[0]); if (keyType !== StackType.bytes) { - this.potentialLengthPrefix(node.arguments[0], this.lastType); + this.checkEncoding(node.arguments[0], this.lastType); } if (isNumeric(keyType)) this.pushVoid(node.arguments[0], 'itob'); @@ -1109,7 +1117,7 @@ export default class Compiler { if (txnTypes[type]) return txnTypes[type]; - if (type === 'boolean') return 'uint64'; + if (type === 'boolean') return 'bool'; if (type === 'number') return 'uint64'; const typeNode = stringToExpression(abiType) as ts.Expression; @@ -1587,7 +1595,7 @@ export default class Compiler { this.processNode(e); - this.potentialLengthPrefix(e, types[i]); + this.checkEncoding(e, types[i]); if (isNumeric(this.lastType)) this.pushVoid(e, 'itob'); if (this.lastType.match(/uint\d+$/) && this.lastType !== types[i]) this.fixBitWidth(e, parseInt(types[i].match(/\d+$/)![0], 10), !ts.isNumericLiteral(e)); @@ -1602,7 +1610,8 @@ export default class Compiler { this.pushLines(node, 'pop // pop head offset', 'concat // concat head and tail'); } - private potentialLengthPrefix(node: ts.Node, type: string) { + private checkEncoding(node: ts.Node, type: string) { + const abiType = this.getABIType(type); if (this.isDynamicArrayOfStaticType(type)) { const length = this.getTypeLength(type.replace(/\[\]$/, '')); @@ -1625,6 +1634,8 @@ export default class Compiler { 'swap', 'concat', ); + } else if (abiType === 'bool') { + this.pushLines(node, 'byte 0x00', 'int 0', 'uncover 2', 'setbit'); } } @@ -1796,7 +1807,7 @@ export default class Compiler { node.expression.expression.name.getText() ]; - this.potentialLengthPrefix(node, storageProp.valueType); + this.checkEncoding(node, storageProp.valueType); this.storageFunctions[storageProp.type].set(node); } else { @@ -2118,7 +2129,7 @@ export default class Compiler { this.processNode(newValue); if (isNumeric(this.lastType)) this.pushVoid(newValue, 'itob'); - this.potentialLengthPrefix(newValue, this.lastType); + this.checkEncoding(newValue, this.lastType); this.pushLines(newValue, 'dup', `store ${scratch.newElement}`); @@ -2179,9 +2190,8 @@ export default class Compiler { if (isNumeric(element.type)) this.pushVoid(node, 'btoi'); - if (this.isDynamicArrayOfStaticType(element.type)) { - this.pushVoid(node, 'extract 2 0'); - } + this.checkDecoding(node, element.type); + this.lastType = element.type.replace('string', 'bytes'); } } @@ -2302,7 +2312,7 @@ export default class Compiler { } if (isAbiMethod) { - this.potentialLengthPrefix(node, returnType); + this.checkEncoding(node, returnType); this.pushLines(node, 'byte 0x151f7c75', 'swap', 'concat', 'log', 'retsub'); } else { this.pushVoid(node, 'retsub'); @@ -3258,9 +3268,7 @@ export default class Compiler { this.pushVoid(p, 'txn GroupIndex'); this.pushVoid(p, `int ${(gtxnIndex += 1)}`); this.pushVoid(p, '-'); - } else if (this.isDynamicArrayOfStaticType(type)) { - this.pushVoid(p, 'extract 2 0'); - } + } else this.checkDecoding(p, type); args.push({ name: p.name.getText(), type: this.getABIType(abiType).replace('bytes', 'byte[]'), desc: '' }); }); @@ -3435,7 +3443,7 @@ export default class Compiler { this.pushVoid(e, 'itob'); } else { this.processNode(e); - this.potentialLengthPrefix(e, argTypes[i]); + this.checkEncoding(e, argTypes[i]); } this.pushVoid(e, 'itxn_field ApplicationArgs'); }); diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 4c279b7e2..d25259909 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -607,4 +607,11 @@ describe('ABI', function () { expect(await runMethod(appClient, 'emptyDynamicArray')).toEqual([]); }); + test.concurrent('booleanArgAndReturn', async () => { + const { appClient } = await compileAndCreate('booleanArgAndReturn'); + + expect(await runMethod(appClient, 'booleanArgAndReturn', [true])).toEqual(true); + + expect(await runMethod(appClient, 'booleanArgAndReturn', [false])).toEqual(false); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index 31762bbf0..e48db5fa2 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -835,3 +835,8 @@ class ABITestEmptyDynamicArray extends Contract { return []; } } +class ABITestBooleanArgAndReturn extends Contract { + booleanArgAndReturn(a: boolean): boolean { + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestBooleanArgAndReturn.abi.json b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.abi.json new file mode 100644 index 000000000..609498125 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.abi.json @@ -0,0 +1,21 @@ +{ + "name": "ABITestBooleanArgAndReturn", + "desc": "", + "methods": [ + { + "name": "booleanArgAndReturn", + "args": [ + { + "name": "a", + "type": "bool", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBooleanArgAndReturn.approval.teal b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.approval.teal new file mode 100644 index 000000000..0835bbe41 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.approval.teal @@ -0,0 +1,56 @@ +#pragma version 8 + b main + +abi_route_booleanArgAndReturn: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + + // no dupn needed + txna ApplicationArgs 1 + int 0 + getbit + callsub booleanArgAndReturn + int 1 + return + +booleanArgAndReturn: + proto 1 0 + + // tests/contracts/abi.algo.ts:840 + // return a; + frame_dig -1 // a: bool + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "booleanArgAndReturn(bool)bool" + txna ApplicationArgs 0 + match abi_route_booleanArgAndReturn + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBooleanArgAndReturn.clear.teal b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBooleanArgAndReturn.json b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.json new file mode 100644 index 000000000..9f6b97b86 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBooleanArgAndReturn.json @@ -0,0 +1,57 @@ +{ + "hints": { + "booleanArgAndReturn(bool)bool": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xlYW5BcmdBbmRSZXR1cm46Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCgkvLyBubyBkdXBuIG5lZWRlZAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMQoJaW50IDAKCWdldGJpdAoJY2FsbHN1YiBib29sZWFuQXJnQW5kUmV0dXJuCglpbnQgMQoJcmV0dXJuCgpib29sZWFuQXJnQW5kUmV0dXJuOgoJcHJvdG8gMSAwCgoJLy8gdGVzdHMvY29udHJhY3RzL2FiaS5hbGdvLnRzOjg0MAoJLy8gcmV0dXJuIGE7CglmcmFtZV9kaWcgLTEgLy8gYTogYm9vbAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgImJvb2xlYW5BcmdBbmRSZXR1cm4oYm9vbClib29sIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2Jvb2xlYW5BcmdBbmRSZXR1cm4KCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestBooleanArgAndReturn", + "desc": "", + "methods": [ + { + "name": "booleanArgAndReturn", + "args": [ + { + "name": "a", + "type": "bool", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] + } +} \ No newline at end of file From c1a753acc73d6dbce4a7406dde72464c61b48256 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 8 Jul 2023 11:41:56 -0400 Subject: [PATCH 02/13] boolTuple --- src/lib/compiler.ts | 80 ++++++++++++++-- tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 10 ++ .../artifacts/ABITestBoolTuple.abi.json | 15 +++ .../artifacts/ABITestBoolTuple.approval.teal | 95 +++++++++++++++++++ .../artifacts/ABITestBoolTuple.clear.teal | 3 + .../contracts/artifacts/ABITestBoolTuple.json | 51 ++++++++++ 7 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestBoolTuple.abi.json create mode 100644 tests/contracts/artifacts/ABITestBoolTuple.approval.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTuple.clear.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTuple.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index df7b9cd87..f54f6cfee 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-plusplus */ /* eslint-disable max-classes-per-file */ /* eslint-disable no-unused-vars */ import fetch from 'node-fetch'; @@ -5,7 +6,6 @@ import * as vlq from 'vlq'; import ts from 'typescript'; import sourceMap from 'source-map'; import path from 'path'; -import { access } from 'fs'; import * as langspec from '../langspec.json'; export type CompilerOptions = { @@ -1024,6 +1024,8 @@ export default class Compiler { } private getTypeLength(inputType: string): number { + if (inputType === '[]') return 0; + const type = this.getABIType(inputType); const typeNode = stringToExpression(type) as ts.Expression; @@ -1047,9 +1049,25 @@ export default class Compiler { const tNode = stringToExpression(type); if (!ts.isArrayLiteralExpression(tNode)) throw new Error(); let totalLength = 0; + let consecutiveBools = 0; + tNode.elements.forEach((t) => { - totalLength += this.getTypeLength(t.getText()); + const typeString = t.getText(); + if (typeString === 'bool') { + consecutiveBools += 1; + } else { + if (consecutiveBools > 0) { + totalLength += Math.ceil(consecutiveBools / 8); + } + + totalLength += this.getTypeLength(typeString); + + consecutiveBools = 0; + } }); + + totalLength += Math.ceil(consecutiveBools / 8); + return totalLength; } @@ -1064,10 +1082,23 @@ export default class Compiler { if (type.startsWith('{')) { const types = Object.values(this.getObjectTypes(type)); let totalLength = 0; + let consecutiveBools = 0; types.forEach((t) => { - totalLength += this.getTypeLength(t); + if (t === 'bool') { + consecutiveBools += 1; + } else { + if (consecutiveBools > 0) { + totalLength += Math.ceil(consecutiveBools / 8); + } + + totalLength += this.getTypeLength(t); + + consecutiveBools = 0; + } }); + totalLength += Math.ceil(consecutiveBools / 8); + return totalLength; } @@ -1493,6 +1524,8 @@ export default class Compiler { else if (ts.isVariableStatement(node)) this.processNode((node).declarationList); else if (ts.isElementAccessExpression(node)) this.processElementAccessExpression(node); else if (ts.isConditionalExpression(node)) this.processConditionalExpression(node); + else if (node.kind === ts.SyntaxKind.TrueKeyword) this.pushVoid(node, 'int 1'); + else if (node.kind === ts.SyntaxKind.FalseKeyword) this.pushVoid(node, 'int 0'); else throw new Error(`Unknown node type: ${ts.SyntaxKind[node.kind]} (${node.kind})`); } catch (e) { if (!(e instanceof Error)) throw e; @@ -1574,6 +1607,18 @@ export default class Compiler { throw new Error(typeHintNode.getText()); } + private processBools(nodes: ts.Node[]) { + const boolByteLength = Math.ceil(nodes.length / 8); + + this.pushVoid(nodes[0], `byte 0x${'00'.repeat(boolByteLength)}`); + + nodes.forEach((n, i) => { + this.pushVoid(n, `int ${i}`); + this.processNode(n); + this.pushVoid(n, 'setbit'); + }); + } + private processTuple(node: ts.ArrayLiteralExpression) { if (this.typeHint === undefined) throw new Error('Type hint is undefined'); let { typeHint } = this; @@ -1581,18 +1626,30 @@ export default class Compiler { if (!this.getABIType(typeHint).includes(']')) typeHint = `${typeHint}[]`; const types = this.getarrayElementTypes(node.elements.length); - const headLength = types.reduce((sum, t) => { - const length = this.isDynamicType(t) ? 2 : this.getTypeLength(t); - return sum + length; - }, 0); - node.elements.forEach((e, i) => { - this.typeHint = types[i]; + const dynamicTypes = types.filter((t) => this.isDynamicType(t)); + const staticTypes = types.filter((t) => !this.isDynamicType(t)); + const headLength = this.getTypeLength(`[${staticTypes.join(',')}]`) + dynamicTypes.length * 2; + let consecutiveBools: ts.Node[] = []; + node.elements.forEach((e, i) => { if (i === 0) { this.pushLines(node, 'byte 0x // initial head', 'byte 0x // initial tail', `byte 0x${headLength.toString(16).padStart(4, '0')} // initial head offset`); } + if (types[i] === 'bool') { + consecutiveBools.push(e); + return; + } + + if (consecutiveBools.length > 0) { + this.processBools(consecutiveBools); + this.pushVoid(e, 'callsub process_static_tuple_element'); + consecutiveBools = []; + } + + this.typeHint = types[i]; + this.processNode(e); this.checkEncoding(e, types[i]); @@ -1607,6 +1664,11 @@ export default class Compiler { } }); + if (consecutiveBools.length > 0) { + this.processBools(consecutiveBools); + this.pushVoid(node, 'callsub process_static_tuple_element'); + } + this.pushLines(node, 'pop // pop head offset', 'concat // concat head and tail'); } diff --git a/tests/abi.test.ts b/tests/abi.test.ts index d25259909..93f111357 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -614,4 +614,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'booleanArgAndReturn', [false])).toEqual(false); }); + + test.concurrent('boolTuple', async () => { + const { appClient } = await compileAndCreate('boolTuple'); + + expect(await runMethod(appClient, 'boolTuple')).toEqual([true, false, true, true, false, false, true, false, false]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index e48db5fa2..8789b8b27 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -840,3 +840,13 @@ class ABITestBooleanArgAndReturn extends Contract { return a; } } + +class ABITestBoolTuple extends Contract { + boolTuple(): [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] { + const a: [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] = [ + true, false, true, true, false, false, true, false, false, + ]; + + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestBoolTuple.abi.json b/tests/contracts/artifacts/ABITestBoolTuple.abi.json new file mode 100644 index 000000000..7f77ca5e0 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTuple.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestBoolTuple", + "desc": "", + "methods": [ + { + "name": "boolTuple", + "args": [], + "desc": "", + "returns": { + "type": "(bool,bool,bool,bool,bool,bool,bool,bool,bool)", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTuple.approval.teal b/tests/contracts/artifacts/ABITestBoolTuple.approval.teal new file mode 100644 index 000000000..13191caf2 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTuple.approval.teal @@ -0,0 +1,95 @@ +#pragma version 8 + b main + +abi_route_boolTuple: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub boolTuple + int 1 + return + +boolTuple: + proto 1 0 + + // tests/contracts/abi.algo.ts:841 + // a: [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] = [ + byte 0x // initial head + byte 0x // initial tail + byte 0x0002 // initial head offset + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + callsub process_static_tuple_element + pop // pop head offset + concat // concat head and tail + frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + + // tests/contracts/abi.algo.ts:845 + // return a; + frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "boolTuple()(bool,bool,bool,bool,bool,bool,bool,bool,bool)" + txna ApplicationArgs 0 + match abi_route_boolTuple + err + +process_static_tuple_element: + proto 4 3 + frame_dig -4 // tuple head + frame_dig -1 // element + concat + frame_dig -3 // tuple tail + frame_dig -2 // head offset + retsub \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTuple.clear.teal b/tests/contracts/artifacts/ABITestBoolTuple.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTuple.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTuple.json b/tests/contracts/artifacts/ABITestBoolTuple.json new file mode 100644 index 000000000..d155ae2be --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTuple.json @@ -0,0 +1,51 @@ +{ + "hints": { + "boolTuple()(bool,bool,bool,bool,bool,bool,bool,bool,bool)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGUKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NDEKCS8vIGE6IFtib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuXSA9IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODQ1CgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJib29sVHVwbGUoKShib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCkiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfYm9vbFR1cGxlCgllcnIKCnByb2Nlc3Nfc3RhdGljX3R1cGxlX2VsZW1lbnQ6Cglwcm90byA0IDMKCWZyYW1lX2RpZyAtNCAvLyB0dXBsZSBoZWFkCglmcmFtZV9kaWcgLTEgLy8gZWxlbWVudAoJY29uY2F0CglmcmFtZV9kaWcgLTMgLy8gdHVwbGUgdGFpbAoJZnJhbWVfZGlnIC0yIC8vIGhlYWQgb2Zmc2V0CglyZXRzdWI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestBoolTuple", + "desc": "", + "methods": [ + { + "name": "boolTuple", + "args": [], + "desc": "", + "returns": { + "type": "(bool,bool,bool,bool,bool,bool,bool,bool,bool)", + "desc": "" + } + } + ] + } +} \ No newline at end of file From 688d60812aedf691e54a94dea8a5327f4c6cf0cf Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 8 Jul 2023 12:02:43 -0400 Subject: [PATCH 03/13] staticBoolArray --- src/lib/compiler.ts | 20 +++-- tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 8 ++ .../artifacts/ABITestBoolTuple.approval.teal | 4 +- .../contracts/artifacts/ABITestBoolTuple.json | 2 +- .../artifacts/ABITestStaticBoolArray.abi.json | 15 ++++ .../ABITestStaticBoolArray.approval.teal | 80 +++++++++++++++++++ .../ABITestStaticBoolArray.clear.teal | 3 + .../artifacts/ABITestStaticBoolArray.json | 51 ++++++++++++ types/global.d.ts | 4 +- 10 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArray.abi.json create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArray.approval.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArray.clear.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArray.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index f54f6cfee..4dab26c00 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -1607,7 +1607,7 @@ export default class Compiler { throw new Error(typeHintNode.getText()); } - private processBools(nodes: ts.Node[]) { + private processBools(nodes: ts.Node[] | ts.NodeArray) { const boolByteLength = Math.ceil(nodes.length / 8); this.pushVoid(nodes[0], `byte 0x${'00'.repeat(boolByteLength)}`); @@ -1761,14 +1761,18 @@ export default class Compiler { const types = this.getarrayElementTypes(node.elements.length); const arrayTypeHint = typeHint; - node.elements.forEach((e, i) => { - this.typeHint = types[i]; - this.processNode(e); - if (isNumeric(this.lastType)) this.pushVoid(e, 'itob'); - if (this.lastType.match(/uint\d+$/) && this.lastType !== types[i]) this.fixBitWidth(e, parseInt(types[i].match(/\d+$/)![0], 10), !ts.isNumericLiteral(e)); - if (i) this.pushVoid(node, 'concat'); - }); + if (arrayTypeHint.match(/bool\[\d+\]/)) { + this.processBools(node.elements); + } else { + node.elements.forEach((e, i) => { + this.typeHint = types[i]; + this.processNode(e); + if (isNumeric(this.lastType)) this.pushVoid(e, 'itob'); + if (this.lastType.match(/uint\d+$/) && this.lastType !== types[i]) this.fixBitWidth(e, parseInt(types[i].match(/\d+$/)![0], 10), !ts.isNumericLiteral(e)); + if (i) this.pushVoid(node, 'concat'); + }); + } const typeHintNode = stringToExpression(this.getABIType(arrayTypeHint)); if (ts.isElementAccessExpression(typeHintNode)) { diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 93f111357..7d09d16f5 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -620,4 +620,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'boolTuple')).toEqual([true, false, true, true, false, false, true, false, false]); }); + + test.concurrent('staticBoolArray', async () => { + const { appClient } = await compileAndCreate('staticBoolArray'); + + expect(await runMethod(appClient, 'staticBoolArray')).toEqual([true, false, true, true, false, false, true, false, false]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index 8789b8b27..1955e7e14 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -850,3 +850,11 @@ class ABITestBoolTuple extends Contract { return a; } } + +class ABITestStaticBoolArray extends Contract { + staticBoolArray(): StaticArray { + const a: StaticArray = [true, false, true, true, false, false, true, false, false]; + + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestBoolTuple.approval.teal b/tests/contracts/artifacts/ABITestBoolTuple.approval.teal index 13191caf2..914e014c9 100644 --- a/tests/contracts/artifacts/ABITestBoolTuple.approval.teal +++ b/tests/contracts/artifacts/ABITestBoolTuple.approval.teal @@ -18,7 +18,7 @@ abi_route_boolTuple: boolTuple: proto 1 0 - // tests/contracts/abi.algo.ts:841 + // tests/contracts/abi.algo.ts:846 // a: [boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean] = [ byte 0x // initial head byte 0x // initial tail @@ -56,7 +56,7 @@ boolTuple: concat // concat head and tail frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] - // tests/contracts/abi.algo.ts:845 + // tests/contracts/abi.algo.ts:850 // return a; frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] byte 0x151f7c75 diff --git a/tests/contracts/artifacts/ABITestBoolTuple.json b/tests/contracts/artifacts/ABITestBoolTuple.json index d155ae2be..03e9b5d6c 100644 --- a/tests/contracts/artifacts/ABITestBoolTuple.json +++ b/tests/contracts/artifacts/ABITestBoolTuple.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGUKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NDEKCS8vIGE6IFtib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuXSA9IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODQ1CgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJib29sVHVwbGUoKShib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCkiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfYm9vbFR1cGxlCgllcnIKCnByb2Nlc3Nfc3RhdGljX3R1cGxlX2VsZW1lbnQ6Cglwcm90byA0IDMKCWZyYW1lX2RpZyAtNCAvLyB0dXBsZSBoZWFkCglmcmFtZV9kaWcgLTEgLy8gZWxlbWVudAoJY29uY2F0CglmcmFtZV9kaWcgLTMgLy8gdHVwbGUgdGFpbAoJZnJhbWVfZGlnIC0yIC8vIGhlYWQgb2Zmc2V0CglyZXRzdWI=", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGUKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NDYKCS8vIGE6IFtib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuLCBib29sZWFuXSA9IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODUwCgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJib29sVHVwbGUoKShib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCkiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfYm9vbFR1cGxlCgllcnIKCnByb2Nlc3Nfc3RhdGljX3R1cGxlX2VsZW1lbnQ6Cglwcm90byA0IDMKCWZyYW1lX2RpZyAtNCAvLyB0dXBsZSBoZWFkCglmcmFtZV9kaWcgLTEgLy8gZWxlbWVudAoJY29uY2F0CglmcmFtZV9kaWcgLTMgLy8gdHVwbGUgdGFpbAoJZnJhbWVfZGlnIC0yIC8vIGhlYWQgb2Zmc2V0CglyZXRzdWI=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { diff --git a/tests/contracts/artifacts/ABITestStaticBoolArray.abi.json b/tests/contracts/artifacts/ABITestStaticBoolArray.abi.json new file mode 100644 index 000000000..93c6583bb --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArray.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestStaticBoolArray", + "desc": "", + "methods": [ + { + "name": "staticBoolArray", + "args": [], + "desc": "", + "returns": { + "type": "bool[9]", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArray.approval.teal b/tests/contracts/artifacts/ABITestStaticBoolArray.approval.teal new file mode 100644 index 000000000..4a44191c7 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArray.approval.teal @@ -0,0 +1,80 @@ +#pragma version 8 + b main + +abi_route_staticBoolArray: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub staticBoolArray + int 1 + return + +staticBoolArray: + proto 1 0 + + // tests/contracts/abi.algo.ts:856 + // a: StaticArray = [true, false, true, true, false, false, true, false, false] + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + frame_bury -1 // a: bool[9] + + // tests/contracts/abi.algo.ts:858 + // return a; + frame_dig -1 // a: bool[9] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "staticBoolArray()bool[9]" + txna ApplicationArgs 0 + match abi_route_staticBoolArray + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArray.clear.teal b/tests/contracts/artifacts/ABITestStaticBoolArray.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArray.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArray.json b/tests/contracts/artifacts/ABITestStaticBoolArray.json new file mode 100644 index 000000000..357b93a24 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArray.json @@ -0,0 +1,51 @@ +{ + "hints": { + "staticBoolArray()bool[9]": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXkKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NTYKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODU4CgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sWzldCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJzdGF0aWNCb29sQXJyYXkoKWJvb2xbOV0iCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfc3RhdGljQm9vbEFycmF5CgllcnI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestStaticBoolArray", + "desc": "", + "methods": [ + { + "name": "staticBoolArray", + "args": [], + "desc": "", + "returns": { + "type": "bool[9]", + "desc": "" + } + } + ] + } +} \ No newline at end of file diff --git a/types/global.d.ts b/types/global.d.ts index f42a18802..4397f65cc 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -674,7 +674,9 @@ declare class handle { type StaticArray< T extends BytesLike | IntLike | StaticArray, N extends number -> = (T extends byte ? string : (N extends 0 ? never[] : T[])) & {__type?: T, __length?: N} +> = ( + T extends byte ? string : (N extends 0 ? never[] : T extends boolean ? (true | false)[] : T[]) +) & {__type?: T, __length?: N} // eslint-disable-next-line no-shadow enum TransactionType { From 4d1bc079a19ab6d7a6d84aee6e1a7e4c9c305140 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sat, 8 Jul 2023 18:18:16 -0400 Subject: [PATCH 04/13] boolTupleAccess --- src/lib/compiler.ts | 48 +++++++- tests/abi.test.ts | 12 ++ tests/contracts/abi.algo.ts | 12 ++ .../artifacts/ABITestBoolTupleAccess.abi.json | 15 +++ .../ABITestBoolTupleAccess.approval.teal | 109 ++++++++++++++++++ .../ABITestBoolTupleAccess.clear.teal | 3 + .../artifacts/ABITestBoolTupleAccess.json | 51 ++++++++ 7 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestBoolTupleAccess.abi.json create mode 100644 tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTupleAccess.clear.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTupleAccess.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 4dab26c00..973b73163 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -37,13 +37,16 @@ class TupleElement extends Array { // eslint-disable-next-line no-use-before-define parent?: TupleElement; + boolBit?: number; + static idCounter = 0; - constructor(type: string, headOffset: number) { + constructor(type: string, headOffset: number, boolBit?: number) { super(); if (typeof type === 'number') return; + this.boolBit = boolBit; this.id = TupleElement.idCounter; this.type = type; this.headOffset = headOffset; @@ -1707,11 +1710,27 @@ export default class Compiler { const elem: TupleElement = new TupleElement(this.getABIType(type), 0); let offset = 0; + let consecutiveBools = 0; if (ts.isArrayLiteralExpression(expr)) { expr.elements.forEach((e) => { const abiType = this.getABIType(e.getText()); + if (abiType === 'bool') { + consecutiveBools += 1; + return; + } + + if (consecutiveBools > 0) { + for (let i = 0; i < consecutiveBools; i++) { + const byteOffset = Math.floor(i / 8); + const bit = i - 8 * byteOffset; + elem.add(new TupleElement('bool', offset + byteOffset, bit)); + } + + consecutiveBools = 0; + } + if (ts.isArrayLiteralExpression(e)) { const t = new TupleElement(abiType, offset); t.add(...this.getTupleElement(abiType)); @@ -1734,6 +1753,14 @@ export default class Compiler { elem.add(this.getTupleElement(baseType)); } + if (consecutiveBools > 0) { + for (let i = 0; i < consecutiveBools; i++) { + const byteOffset = Math.floor(i / 8); + const bit = i - 8 * byteOffset; + elem.add(new TupleElement('bool', offset + byteOffset, bit)); + } + } + return elem; } @@ -2030,7 +2057,7 @@ export default class Compiler { ? previousTupleElement[0] : previousTupleElement[accNumber] || previousTupleElement[0]; // Element in tuple - if (previousTupleElement.arrayType === 'tuple') { + if (previousTupleElement.arrayType === 'tuple' || (elem.parent?.arrayType === 'static' && elem.type === 'bool')) { this.pushLines( acc, `int ${elem.headOffset} // headOffset`, @@ -2250,6 +2277,23 @@ export default class Compiler { this.updateValue(parentExpression); } else { + if (element.type === 'bool') { + if (element.boolBit !== undefined) { + this.pushLines( + node, + `load ${scratch.fullArray}`, + 'swap', + 'int 1', + 'extract3', + `int ${element.boolBit}`, + 'getbit', + ); + } else throw Error('Not yet supported'); + + this.lastType = 'bool'; + return; + } + if (!this.isDynamicType(element.type)) { this.pushLines(node, `load ${scratch.fullArray}`, 'swap', `int ${this.getTypeLength(element.type)}`, 'extract3'); } diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 7d09d16f5..cfb0bca56 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -626,4 +626,16 @@ describe('ABI', function () { expect(await runMethod(appClient, 'staticBoolArray')).toEqual([true, false, true, true, false, false, true, false, false]); }); + + test.concurrent('boolTupleAccess', async () => { + const { appClient } = await compileAndCreate('boolTupleAccess'); + + expect(await runMethod(appClient, 'boolTupleAccess')).toEqual(true); + }); + + test.concurrent('staticBoolArrayAccess', async () => { + const { appClient } = await compileAndCreate('staticBoolArrayAccess'); + + expect(await runMethod(appClient, 'staticBoolArrayAccess')).toEqual(true); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index 1955e7e14..bb4ff9232 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -858,3 +858,15 @@ class ABITestStaticBoolArray extends Contract { return a; } } + +class ABITestBoolTupleAccess extends Contract { + boolTupleAccess(): boolean { + const a: [ + boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean + ] = [ + false, false, false, false, false, false, false, false, true, + ]; + + return a[8]; + } +} diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.abi.json b/tests/contracts/artifacts/ABITestBoolTupleAccess.abi.json new file mode 100644 index 000000000..cdb62f07b --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestBoolTupleAccess", + "desc": "", + "methods": [ + { + "name": "boolTupleAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal new file mode 100644 index 000000000..d6cd83c98 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal @@ -0,0 +1,109 @@ +#pragma version 8 + b main + +abi_route_boolTupleAccess: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub boolTupleAccess + int 1 + return + +boolTupleAccess: + proto 1 0 + + // tests/contracts/abi.algo.ts:859 + // a: [ + byte 0x // initial head + byte 0x // initial tail + byte 0x0002 // initial head offset + byte 0x0000 + int 0 + int 0 + setbit + int 1 + int 0 + setbit + int 2 + int 0 + setbit + int 3 + int 0 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 0 + setbit + int 7 + int 0 + setbit + int 8 + int 1 + setbit + callsub process_static_tuple_element + pop // pop head offset + concat // concat head and tail + frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + + // tests/contracts/abi.algo.ts:865 + // return a[8]; + frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + store 0 // full array + int 0 // initial offset + int 1 // headOffset + + + load 0 // full array + swap + int 1 + extract3 + int 0 + getbit + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "boolTupleAccess()bool" + txna ApplicationArgs 0 + match abi_route_boolTupleAccess + err + +process_static_tuple_element: + proto 4 3 + frame_dig -4 // tuple head + frame_dig -1 // element + concat + frame_dig -3 // tuple tail + frame_dig -2 // head offset + retsub \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.clear.teal b/tests/contracts/artifacts/ABITestBoolTupleAccess.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.json b/tests/contracts/artifacts/ABITestBoolTupleAccess.json new file mode 100644 index 000000000..e6cf03769 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.json @@ -0,0 +1,51 @@ +{ + "hints": { + "boolTupleAccess()bool": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVBY2Nlc3MKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NTkKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMAoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAwCglzZXRiaXQKCWludCAzCglpbnQgMAoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMAoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAxCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODY1CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMSAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDEKCWV4dHJhY3QzCglpbnQgMAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiYm9vbFR1cGxlQWNjZXNzKClib29sIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzcwoJZXJyCgpwcm9jZXNzX3N0YXRpY190dXBsZV9lbGVtZW50OgoJcHJvdG8gNCAzCglmcmFtZV9kaWcgLTQgLy8gdHVwbGUgaGVhZAoJZnJhbWVfZGlnIC0xIC8vIGVsZW1lbnQKCWNvbmNhdAoJZnJhbWVfZGlnIC0zIC8vIHR1cGxlIHRhaWwKCWZyYW1lX2RpZyAtMiAvLyBoZWFkIG9mZnNldAoJcmV0c3Vi", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestBoolTupleAccess", + "desc": "", + "methods": [ + { + "name": "boolTupleAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] + } +} \ No newline at end of file From 8c60c0c58f7f1f60fb4c752edebdb5ced597956c Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Fri, 21 Jul 2023 13:42:50 +0200 Subject: [PATCH 05/13] staticBoolArrayAccess --- src/lib/compiler.ts | 14 ++- tests/abi.test.ts | 21 +++-- tests/contracts/abi.algo.ts | 8 ++ .../ABITestBoolTupleAccess.approval.teal | 4 +- .../artifacts/ABITestBoolTupleAccess.json | 2 +- .../ABITestStaticBoolArrayAccess.abi.json | 15 +++ ...ABITestStaticBoolArrayAccess.approval.teal | 91 +++++++++++++++++++ .../ABITestStaticBoolArrayAccess.clear.teal | 3 + .../ABITestStaticBoolArrayAccess.json | 51 +++++++++++ 9 files changed, 195 insertions(+), 14 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayAccess.abi.json create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayAccess.clear.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 973b73163..163a2859d 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -1678,7 +1678,9 @@ export default class Compiler { private checkEncoding(node: ts.Node, type: string) { const abiType = this.getABIType(type); if (this.isDynamicArrayOfStaticType(type)) { - const length = this.getTypeLength(type.replace(/\[\]$/, '')); + const baseType = type.replace(/\[\]$/, ''); + if (baseType === 'bool') return; + const length = this.getTypeLength(baseType); this.pushLines( node, @@ -1789,7 +1791,7 @@ export default class Compiler { const types = this.getarrayElementTypes(node.elements.length); const arrayTypeHint = typeHint; - if (arrayTypeHint.match(/bool\[\d+\]/)) { + if (arrayTypeHint.match(/bool\[\d*\]/)) { this.processBools(node.elements); } else { node.elements.forEach((e, i) => { @@ -2288,7 +2290,13 @@ export default class Compiler { `int ${element.boolBit}`, 'getbit', ); - } else throw Error('Not yet supported'); + } else { + if (!ts.isElementAccessExpression(node)) throw new Error(); + + this.pushVoid(node, `load ${scratch.fullArray}`); + this.processNode(node.argumentExpression); + this.pushLines(node, 'getbit'); + } this.lastType = 'bool'; return; diff --git a/tests/abi.test.ts b/tests/abi.test.ts index cfb0bca56..6aa759f5b 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -143,14 +143,19 @@ async function runMethod( sendParams: { suppressLog: true }, }; - if (name.includes('Storage')) { - await appClient.fundAppAccount({ - amount: algokit.microAlgos(127400), - sendParams: { suppressLog: true }, - }); - return (await appClient.optIn(params)).return?.returnValue; + try { + if (name.includes('Storage')) { + await appClient.fundAppAccount({ + amount: algokit.microAlgos(127400), + sendParams: { suppressLog: true }, + }); + return (await appClient.optIn(params)).return?.returnValue; + } + return (await appClient.call(params)).return?.returnValue; + } catch (e) { + console.warn(e); + throw e; } - return (await appClient.call(params)).return?.returnValue; } describe('ABI', function () { @@ -636,6 +641,6 @@ describe('ABI', function () { test.concurrent('staticBoolArrayAccess', async () => { const { appClient } = await compileAndCreate('staticBoolArrayAccess'); - expect(await runMethod(appClient, 'staticBoolArrayAccess')).toEqual(true); + expect(await runMethod(appClient, 'staticBoolArrayAccess')).toEqual(false); }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index bb4ff9232..9e566b706 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -870,3 +870,11 @@ class ABITestBoolTupleAccess extends Contract { return a[8]; } } + +class ABITestStaticBoolArrayAccess extends Contract { + staticBoolArrayAccess(): boolean { + const a: StaticArray = [true, false, true, true, false, false, true, false, false]; + + return a[8]; + } +} diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal index d6cd83c98..e82106ced 100644 --- a/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal @@ -18,7 +18,7 @@ abi_route_boolTupleAccess: boolTupleAccess: proto 1 0 - // tests/contracts/abi.algo.ts:859 + // tests/contracts/abi.algo.ts:864 // a: [ byte 0x // initial head byte 0x // initial tail @@ -56,7 +56,7 @@ boolTupleAccess: concat // concat head and tail frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] - // tests/contracts/abi.algo.ts:865 + // tests/contracts/abi.algo.ts:870 // return a[8]; frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] store 0 // full array diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.json b/tests/contracts/artifacts/ABITestBoolTupleAccess.json index e6cf03769..070da4aee 100644 --- a/tests/contracts/artifacts/ABITestBoolTupleAccess.json +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVBY2Nlc3MKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NTkKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMAoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAwCglzZXRiaXQKCWludCAzCglpbnQgMAoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMAoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAxCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODY1CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMSAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDEKCWV4dHJhY3QzCglpbnQgMAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiYm9vbFR1cGxlQWNjZXNzKClib29sIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzcwoJZXJyCgpwcm9jZXNzX3N0YXRpY190dXBsZV9lbGVtZW50OgoJcHJvdG8gNCAzCglmcmFtZV9kaWcgLTQgLy8gdHVwbGUgaGVhZAoJZnJhbWVfZGlnIC0xIC8vIGVsZW1lbnQKCWNvbmNhdAoJZnJhbWVfZGlnIC0zIC8vIHR1cGxlIHRhaWwKCWZyYW1lX2RpZyAtMiAvLyBoZWFkIG9mZnNldAoJcmV0c3Vi", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVBY2Nlc3MKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NjQKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMAoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAwCglzZXRiaXQKCWludCAzCglpbnQgMAoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMAoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAxCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODcwCgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMSAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDEKCWV4dHJhY3QzCglpbnQgMAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiYm9vbFR1cGxlQWNjZXNzKClib29sIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzcwoJZXJyCgpwcm9jZXNzX3N0YXRpY190dXBsZV9lbGVtZW50OgoJcHJvdG8gNCAzCglmcmFtZV9kaWcgLTQgLy8gdHVwbGUgaGVhZAoJZnJhbWVfZGlnIC0xIC8vIGVsZW1lbnQKCWNvbmNhdAoJZnJhbWVfZGlnIC0zIC8vIHR1cGxlIHRhaWwKCWZyYW1lX2RpZyAtMiAvLyBoZWFkIG9mZnNldAoJcmV0c3Vi", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.abi.json b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.abi.json new file mode 100644 index 000000000..05591c534 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestStaticBoolArrayAccess", + "desc": "", + "methods": [ + { + "name": "staticBoolArrayAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal new file mode 100644 index 000000000..4a745b914 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal @@ -0,0 +1,91 @@ +#pragma version 8 + b main + +abi_route_staticBoolArrayAccess: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub staticBoolArrayAccess + int 1 + return + +staticBoolArrayAccess: + proto 1 0 + + // tests/contracts/abi.algo.ts:876 + // a: StaticArray = [true, false, true, true, false, false, true, false, false] + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + frame_bury -1 // a: bool[9] + + // tests/contracts/abi.algo.ts:878 + // return a[8]; + frame_dig -1 // a: bool[9] + store 0 // full array + int 0 // initial offset + int 0 // headOffset + + + load 0 // full array + int 8 + getbit + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "staticBoolArrayAccess()bool" + txna ApplicationArgs 0 + match abi_route_staticBoolArrayAccess + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.clear.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json new file mode 100644 index 000000000..26c731b94 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json @@ -0,0 +1,51 @@ +{ + "hints": { + "staticBoolArrayAccess()bool": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlBY2Nlc3MKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NzYKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODc4CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sWzldCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMCAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJaW50IDgKCWdldGJpdAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInN0YXRpY0Jvb2xBcnJheUFjY2VzcygpYm9vbCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zdGF0aWNCb29sQXJyYXlBY2Nlc3MKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestStaticBoolArrayAccess", + "desc": "", + "methods": [ + { + "name": "staticBoolArrayAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] + } +} \ No newline at end of file From ebd361363c9747132d32ba75158244461a4dda00 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 10:51:44 +0200 Subject: [PATCH 06/13] dynamicBoolArray --- src/lib/compiler.ts | 12 ++- tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 8 ++ .../ABITestDynamicBoolArray.abi.json | 15 ++++ .../ABITestDynamicBoolArray.approval.teal | 82 +++++++++++++++++++ .../ABITestDynamicBoolArray.clear.teal | 3 + .../artifacts/ABITestDynamicBoolArray.json | 51 ++++++++++++ 7 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArray.abi.json create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArray.approval.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArray.clear.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArray.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 163a2859d..c3f552f5d 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -1610,9 +1610,13 @@ export default class Compiler { throw new Error(typeHintNode.getText()); } - private processBools(nodes: ts.Node[] | ts.NodeArray) { + private processBools( + nodes: ts.Node[] | ts.NodeArray, + isDynamicArray: boolean = false, + ) { const boolByteLength = Math.ceil(nodes.length / 8); + if (isDynamicArray) this.pushVoid(nodes[0], `byte 0x${nodes.length.toString(16).padStart(4, '0')}`); this.pushVoid(nodes[0], `byte 0x${'00'.repeat(boolByteLength)}`); nodes.forEach((n, i) => { @@ -1620,6 +1624,8 @@ export default class Compiler { this.processNode(n); this.pushVoid(n, 'setbit'); }); + + if (isDynamicArray) this.pushVoid(nodes[0], 'concat'); } private processTuple(node: ts.ArrayLiteralExpression) { @@ -1791,8 +1797,8 @@ export default class Compiler { const types = this.getarrayElementTypes(node.elements.length); const arrayTypeHint = typeHint; - if (arrayTypeHint.match(/bool\[\d*\]/)) { - this.processBools(node.elements); + if (arrayTypeHint.match(/bool\[\d*\]$/)) { + this.processBools(node.elements, arrayTypeHint.endsWith('[]')); } else { node.elements.forEach((e, i) => { this.typeHint = types[i]; diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 6aa759f5b..7300b9820 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -643,4 +643,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'staticBoolArrayAccess')).toEqual(false); }); + + test.concurrent('dynamicBoolArray', async () => { + const { appClient } = await compileAndCreate('dynamicBoolArray'); + + expect(await runMethod(appClient, 'dynamicBoolArray')).toEqual([true, false, true, true, false, false, true, false, false]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index 9e566b706..a6cf50448 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -878,3 +878,11 @@ class ABITestStaticBoolArrayAccess extends Contract { return a[8]; } } + +class ABITestDynamicBoolArray extends Contract { + dynamicBoolArray(): boolean[] { + const a: boolean[] = [true, false, true, true, false, false, true, false, false]; + + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArray.abi.json b/tests/contracts/artifacts/ABITestDynamicBoolArray.abi.json new file mode 100644 index 000000000..644654b36 --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArray.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestDynamicBoolArray", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArray", + "args": [], + "desc": "", + "returns": { + "type": "bool[]", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArray.approval.teal b/tests/contracts/artifacts/ABITestDynamicBoolArray.approval.teal new file mode 100644 index 000000000..2820dfd8d --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArray.approval.teal @@ -0,0 +1,82 @@ +#pragma version 8 + b main + +abi_route_dynamicBoolArray: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub dynamicBoolArray + int 1 + return + +dynamicBoolArray: + proto 1 0 + + // tests/contracts/abi.algo.ts:884 + // a: boolean[] = [true, false, true, true, false, false, true, false, false] + byte 0x0009 + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + concat + frame_bury -1 // a: bool[] + + // tests/contracts/abi.algo.ts:886 + // return a; + frame_dig -1 // a: bool[] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "dynamicBoolArray()bool[]" + txna ApplicationArgs 0 + match abi_route_dynamicBoolArray + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArray.clear.teal b/tests/contracts/artifacts/ABITestDynamicBoolArray.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArray.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArray.json b/tests/contracts/artifacts/ABITestDynamicBoolArray.json new file mode 100644 index 000000000..b33314578 --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArray.json @@ -0,0 +1,51 @@ +{ + "hints": { + "dynamicBoolArray()bool[]": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2R5bmFtaWNCb29sQXJyYXk6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZHluYW1pY0Jvb2xBcnJheQoJaW50IDEKCXJldHVybgoKZHluYW1pY0Jvb2xBcnJheToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4ODQKCS8vIGE6IGJvb2xlYW5bXSA9IFt0cnVlLCBmYWxzZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UsIGZhbHNlLCB0cnVlLCBmYWxzZSwgZmFsc2VdCglieXRlIDB4MDAwOQoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiBib29sW10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODg2CgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sW10KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgImR5bmFtaWNCb29sQXJyYXkoKWJvb2xbXSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9keW5hbWljQm9vbEFycmF5CgllcnI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestDynamicBoolArray", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArray", + "args": [], + "desc": "", + "returns": { + "type": "bool[]", + "desc": "" + } + } + ] + } +} \ No newline at end of file From 92aab69f6a2a67b93e6f00ff118a55f4054fb566 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 10:58:56 +0200 Subject: [PATCH 07/13] dynamicBoolArrayAccess --- src/lib/compiler.ts | 14 ++- tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 8 ++ .../ABITestDynamicBoolArrayAccess.abi.json | 15 +++ ...BITestDynamicBoolArrayAccess.approval.teal | 93 +++++++++++++++++++ .../ABITestDynamicBoolArrayAccess.clear.teal | 3 + .../ABITestDynamicBoolArrayAccess.json | 51 ++++++++++ 7 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.abi.json create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.clear.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index c3f552f5d..3d7427154 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -2037,6 +2037,7 @@ export default class Compiler { node: ts.Node, ) { let previousTupleElement = topLevelTuple; + let previousElemIsBool = false; // At the end of this forEach, the stack will contain the HEAD offset of the accessed element accessors.forEach((acc, i) => { @@ -2064,8 +2065,15 @@ export default class Compiler { const elem: TupleElement = Number.isNaN(accNumber) ? previousTupleElement[0] : previousTupleElement[accNumber] || previousTupleElement[0]; - // Element in tuple - if (previousTupleElement.arrayType === 'tuple' || (elem.parent?.arrayType === 'static' && elem.type === 'bool')) { + if (elem.type === 'bool' && !previousElemIsBool) { + this.pushLines( + acc, + `int ${elem.headOffset} // headOffset`, + '+', + ); + + previousElemIsBool = true; + } else if (previousTupleElement.arrayType === 'tuple') { this.pushLines( acc, `int ${elem.headOffset} // headOffset`, @@ -2082,7 +2090,7 @@ export default class Compiler { '+', ); // Static element in array - } else { + } else if (!previousElemIsBool) { this.processNode(acc); this.pushLines( diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 7300b9820..14984ac39 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -649,4 +649,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'dynamicBoolArray')).toEqual([true, false, true, true, false, false, true, false, false]); }); + + test.concurrent('dynamicBoolArrayAccess', async () => { + const { appClient } = await compileAndCreate('dynamicBoolArrayAccess'); + + expect(await runMethod(appClient, 'dynamicBoolArrayAccess')).toEqual(false); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index a6cf50448..e4721bce1 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -886,3 +886,11 @@ class ABITestDynamicBoolArray extends Contract { return a; } } + +class ABITestDynamicBoolArrayAccess extends Contract { + dynamicBoolArrayAccess(): boolean { + const a: boolean[] = [true, false, true, true, false, false, true, false, false]; + + return a[8]; + } +} diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.abi.json b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.abi.json new file mode 100644 index 000000000..eea82d6ab --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestDynamicBoolArrayAccess", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArrayAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal new file mode 100644 index 000000000..e79f077a1 --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal @@ -0,0 +1,93 @@ +#pragma version 8 + b main + +abi_route_dynamicBoolArrayAccess: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub dynamicBoolArrayAccess + int 1 + return + +dynamicBoolArrayAccess: + proto 1 0 + + // tests/contracts/abi.algo.ts:892 + // a: boolean[] = [true, false, true, true, false, false, true, false, false] + byte 0x0009 + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + concat + frame_bury -1 // a: bool[] + + // tests/contracts/abi.algo.ts:894 + // return a[8]; + frame_dig -1 // a: bool[] + store 0 // full array + int 0 // initial offset + int 0 // headOffset + + + load 0 // full array + int 8 + getbit + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "dynamicBoolArrayAccess()bool" + txna ApplicationArgs 0 + match abi_route_dynamicBoolArrayAccess + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.clear.teal b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json new file mode 100644 index 000000000..7b8ad6baf --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json @@ -0,0 +1,51 @@ +{ + "hints": { + "dynamicBoolArrayAccess()bool": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2R5bmFtaWNCb29sQXJyYXlBY2Nlc3M6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZHluYW1pY0Jvb2xBcnJheUFjY2VzcwoJaW50IDEKCXJldHVybgoKZHluYW1pY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4OTIKCS8vIGE6IGJvb2xlYW5bXSA9IFt0cnVlLCBmYWxzZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UsIGZhbHNlLCB0cnVlLCBmYWxzZSwgZmFsc2VdCglieXRlIDB4MDAwOQoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiBib29sW10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODk0CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sW10KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWxvYWQgMCAvLyBmdWxsIGFycmF5CglpbnQgOAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiZHluYW1pY0Jvb2xBcnJheUFjY2VzcygpYm9vbCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9keW5hbWljQm9vbEFycmF5QWNjZXNzCgllcnI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestDynamicBoolArrayAccess", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArrayAccess", + "args": [], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + } + ] + } +} \ No newline at end of file From aa07a0d5ee2885ddd41ea7227d0d4f324d4bf878 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 11:11:27 +0200 Subject: [PATCH 08/13] boolbit refactor --- src/lib/compiler.ts | 46 ++++--------------- .../ABITestBoolTupleAccess.approval.teal | 9 ++-- .../artifacts/ABITestBoolTupleAccess.json | 2 +- ...BITestDynamicBoolArrayAccess.approval.teal | 6 ++- .../ABITestDynamicBoolArrayAccess.json | 2 +- ...ABITestStaticBoolArrayAccess.approval.teal | 6 ++- .../ABITestStaticBoolArrayAccess.json | 2 +- 7 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 3d7427154..ad007af45 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -37,16 +37,13 @@ class TupleElement extends Array { // eslint-disable-next-line no-use-before-define parent?: TupleElement; - boolBit?: number; - static idCounter = 0; - constructor(type: string, headOffset: number, boolBit?: number) { + constructor(type: string, headOffset: number) { super(); if (typeof type === 'number') return; - this.boolBit = boolBit; this.id = TupleElement.idCounter; this.type = type; this.headOffset = headOffset; @@ -1726,17 +1723,10 @@ export default class Compiler { if (abiType === 'bool') { consecutiveBools += 1; + elem.add(new TupleElement('bool', offset)); return; - } - - if (consecutiveBools > 0) { - for (let i = 0; i < consecutiveBools; i++) { - const byteOffset = Math.floor(i / 8); - const bit = i - 8 * byteOffset; - elem.add(new TupleElement('bool', offset + byteOffset, bit)); - } - - consecutiveBools = 0; + } if (consecutiveBools) { + offset += Math.ceil(consecutiveBools / 8); } if (ts.isArrayLiteralExpression(e)) { @@ -1761,14 +1751,6 @@ export default class Compiler { elem.add(this.getTupleElement(baseType)); } - if (consecutiveBools > 0) { - for (let i = 0; i < consecutiveBools; i++) { - const byteOffset = Math.floor(i / 8); - const bit = i - 8 * byteOffset; - elem.add(new TupleElement('bool', offset + byteOffset, bit)); - } - } - return elem; } @@ -2294,23 +2276,11 @@ export default class Compiler { this.updateValue(parentExpression); } else { if (element.type === 'bool') { - if (element.boolBit !== undefined) { - this.pushLines( - node, - `load ${scratch.fullArray}`, - 'swap', - 'int 1', - 'extract3', - `int ${element.boolBit}`, - 'getbit', - ); - } else { - if (!ts.isElementAccessExpression(node)) throw new Error(); + if (!ts.isElementAccessExpression(node)) throw new Error(); - this.pushVoid(node, `load ${scratch.fullArray}`); - this.processNode(node.argumentExpression); - this.pushLines(node, 'getbit'); - } + this.pushLines(node.argumentExpression, 'int 8', '*'); + this.processNode(node.argumentExpression); + this.pushLines(node.argumentExpression, '+', `load ${scratch.fullArray}`, 'swap', 'getbit'); this.lastType = 'bool'; return; diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal index e82106ced..60c24429d 100644 --- a/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.approval.teal @@ -61,13 +61,14 @@ boolTupleAccess: frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] store 0 // full array int 0 // initial offset - int 1 // headOffset + int 0 // headOffset + + + int 8 + * + int 8 + load 0 // full array swap - int 1 - extract3 - int 0 getbit byte 0x00 int 0 diff --git a/tests/contracts/artifacts/ABITestBoolTupleAccess.json b/tests/contracts/artifacts/ABITestBoolTupleAccess.json index 070da4aee..4c1413c28 100644 --- a/tests/contracts/artifacts/ABITestBoolTupleAccess.json +++ b/tests/contracts/artifacts/ABITestBoolTupleAccess.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVBY2Nlc3MKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NjQKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMAoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAwCglzZXRiaXQKCWludCAzCglpbnQgMAoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMAoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAxCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODcwCgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMSAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDEKCWV4dHJhY3QzCglpbnQgMAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiYm9vbFR1cGxlQWNjZXNzKClib29sIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzcwoJZXJyCgpwcm9jZXNzX3N0YXRpY190dXBsZV9lbGVtZW50OgoJcHJvdG8gNCAzCglmcmFtZV9kaWcgLTQgLy8gdHVwbGUgaGVhZAoJZnJhbWVfZGlnIC0xIC8vIGVsZW1lbnQKCWNvbmNhdAoJZnJhbWVfZGlnIC0zIC8vIHR1cGxlIHRhaWwKCWZyYW1lX2RpZyAtMiAvLyBoZWFkIG9mZnNldAoJcmV0c3Vi", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVBY2Nlc3MKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NjQKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMAoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAwCglzZXRiaXQKCWludCAzCglpbnQgMAoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMAoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAxCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODcwCgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBbYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2xdCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJKgoJaW50IDgKCSsKCWxvYWQgMCAvLyBmdWxsIGFycmF5Cglzd2FwCglnZXRiaXQKCWJ5dGUgMHgwMAoJaW50IDAKCXVuY292ZXIgMgoJc2V0Yml0CglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJib29sVHVwbGVBY2Nlc3MoKWJvb2wiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfYm9vbFR1cGxlQWNjZXNzCgllcnIKCnByb2Nlc3Nfc3RhdGljX3R1cGxlX2VsZW1lbnQ6Cglwcm90byA0IDMKCWZyYW1lX2RpZyAtNCAvLyB0dXBsZSBoZWFkCglmcmFtZV9kaWcgLTEgLy8gZWxlbWVudAoJY29uY2F0CglmcmFtZV9kaWcgLTMgLy8gdHVwbGUgdGFpbAoJZnJhbWVfZGlnIC0yIC8vIGhlYWQgb2Zmc2V0CglyZXRzdWI=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal index e79f077a1..81b32c0ba 100644 --- a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.approval.teal @@ -59,8 +59,12 @@ dynamicBoolArrayAccess: int 0 // initial offset int 0 // headOffset + - load 0 // full array int 8 + * + int 8 + + + load 0 // full array + swap getbit byte 0x00 int 0 diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json index 7b8ad6baf..9d028ada7 100644 --- a/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayAccess.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2R5bmFtaWNCb29sQXJyYXlBY2Nlc3M6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZHluYW1pY0Jvb2xBcnJheUFjY2VzcwoJaW50IDEKCXJldHVybgoKZHluYW1pY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4OTIKCS8vIGE6IGJvb2xlYW5bXSA9IFt0cnVlLCBmYWxzZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UsIGZhbHNlLCB0cnVlLCBmYWxzZSwgZmFsc2VdCglieXRlIDB4MDAwOQoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiBib29sW10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODk0CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sW10KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWxvYWQgMCAvLyBmdWxsIGFycmF5CglpbnQgOAoJZ2V0Yml0CglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiZHluYW1pY0Jvb2xBcnJheUFjY2VzcygpYm9vbCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9keW5hbWljQm9vbEFycmF5QWNjZXNzCgllcnI=", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2R5bmFtaWNCb29sQXJyYXlBY2Nlc3M6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZHluYW1pY0Jvb2xBcnJheUFjY2VzcwoJaW50IDEKCXJldHVybgoKZHluYW1pY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4OTIKCS8vIGE6IGJvb2xlYW5bXSA9IFt0cnVlLCBmYWxzZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UsIGZhbHNlLCB0cnVlLCBmYWxzZSwgZmFsc2VdCglieXRlIDB4MDAwOQoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiBib29sW10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODk0CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sW10KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CgkqCglpbnQgOAoJKwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWdldGJpdAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgImR5bmFtaWNCb29sQXJyYXlBY2Nlc3MoKWJvb2wiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfZHluYW1pY0Jvb2xBcnJheUFjY2VzcwoJZXJy", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal index 4a745b914..30cb94d40 100644 --- a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.approval.teal @@ -57,8 +57,12 @@ staticBoolArrayAccess: int 0 // initial offset int 0 // headOffset + - load 0 // full array int 8 + * + int 8 + + + load 0 // full array + swap getbit byte 0x00 int 0 diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json index 26c731b94..d725a1670 100644 --- a/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayAccess.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlBY2Nlc3MKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NzYKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODc4CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sWzldCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMCAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJaW50IDgKCWdldGJpdAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInN0YXRpY0Jvb2xBcnJheUFjY2VzcygpYm9vbCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zdGF0aWNCb29sQXJyYXlBY2Nlc3MKCWVycg==", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlBY2Nlc3MKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheUFjY2VzczoKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4NzYKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODc4CgkvLyByZXR1cm4gYVs4XTsKCWZyYW1lX2RpZyAtMSAvLyBhOiBib29sWzldCglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMCAvLyBoZWFkT2Zmc2V0CgkrCglpbnQgOAoJKgoJaW50IDgKCSsKCWxvYWQgMCAvLyBmdWxsIGFycmF5Cglzd2FwCglnZXRiaXQKCWJ5dGUgMHgwMAoJaW50IDAKCXVuY292ZXIgMgoJc2V0Yml0CglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJzdGF0aWNCb29sQXJyYXlBY2Nlc3MoKWJvb2wiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfc3RhdGljQm9vbEFycmF5QWNjZXNzCgllcnI=", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { From 891f0b908d321c14b0ddbba26ca247be445488fb Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 11:41:01 +0200 Subject: [PATCH 09/13] staticBoolArrayUpdate --- src/lib/compiler.ts | 8 ++ tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 10 ++ .../ABITestStaticBoolArrayUpdate.abi.json | 15 +++ ...ABITestStaticBoolArrayUpdate.approval.teal | 97 +++++++++++++++++++ .../ABITestStaticBoolArrayUpdate.clear.teal | 3 + .../ABITestStaticBoolArrayUpdate.json | 51 ++++++++++ 7 files changed, 190 insertions(+) create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.abi.json create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.clear.teal create mode 100644 tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index ad007af45..c7d9f8b4a 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -2262,6 +2262,14 @@ export default class Compiler { }); this.pushVoid(node, `load ${scratch.fullArray}`); + } else if (element.type === 'bool') { + if (!ts.isElementAccessExpression(node)) throw new Error(); + + this.pushLines(node.argumentExpression, 'int 8', '*'); + this.processNode(node.argumentExpression); + this.pushLines(node.argumentExpression, '+', `load ${scratch.fullArray}`, 'swap'); + this.processNode(newValue); + this.pushVoid(node.argumentExpression, 'setbit'); } else { this.pushLines( node, diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 14984ac39..a2e84a677 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -655,4 +655,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'dynamicBoolArrayAccess')).toEqual(false); }); + + test.concurrent('staticBoolArrayUpdate', async () => { + const { appClient } = await compileAndCreate('staticBoolArrayUpdate'); + + expect(await runMethod(appClient, 'staticBoolArrayUpdate')).toEqual([true, false, true, true, false, false, true, false, true]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index e4721bce1..a2e8a58db 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -894,3 +894,13 @@ class ABITestDynamicBoolArrayAccess extends Contract { return a[8]; } } + +class ABITestStaticBoolArrayUpdate extends Contract { + staticBoolArrayUpdate(): StaticArray { + const a: StaticArray = [true, false, true, true, false, false, true, false, false]; + + a[8] = true; + + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.abi.json b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.abi.json new file mode 100644 index 000000000..a4aad0c73 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestStaticBoolArrayUpdate", + "desc": "", + "methods": [ + { + "name": "staticBoolArrayUpdate", + "args": [], + "desc": "", + "returns": { + "type": "bool[9]", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal new file mode 100644 index 000000000..b92c5723c --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal @@ -0,0 +1,97 @@ +#pragma version 8 + b main + +abi_route_staticBoolArrayUpdate: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub staticBoolArrayUpdate + int 1 + return + +staticBoolArrayUpdate: + proto 1 0 + + // tests/contracts/abi.algo.ts:900 + // a: StaticArray = [true, false, true, true, false, false, true, false, false] + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + frame_bury -1 // a: bool[9] + + // tests/contracts/abi.algo.ts:902 + // a[8] = true + frame_dig -1 // a: bool[9] + store 0 // full array + int 0 // initial offset + int 0 // headOffset + + + int 8 + * + int 8 + + + load 0 // full array + swap + int 1 + setbit + frame_bury -1 // a: bool[9] + + // tests/contracts/abi.algo.ts:904 + // return a; + frame_dig -1 // a: bool[9] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "staticBoolArrayUpdate()bool[9]" + txna ApplicationArgs 0 + match abi_route_staticBoolArrayUpdate + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.clear.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json new file mode 100644 index 000000000..5b44a9a94 --- /dev/null +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json @@ -0,0 +1,51 @@ +{ + "hints": { + "staticBoolArrayUpdate()bool[9]": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlVcGRhdGUKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDAKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6OTAyCgkvLyBhWzhdID0gdHJ1ZQoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CgkqCglpbnQgOAoJKwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCAxCglzZXRiaXQKCWZyYW1lX2J1cnkgLTEgLy8gYTogYm9vbFs5XQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDQKCS8vIHJldHVybiBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInN0YXRpY0Jvb2xBcnJheVVwZGF0ZSgpYm9vbFs5XSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zdGF0aWNCb29sQXJyYXlVcGRhdGUKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestStaticBoolArrayUpdate", + "desc": "", + "methods": [ + { + "name": "staticBoolArrayUpdate", + "args": [], + "desc": "", + "returns": { + "type": "bool[9]", + "desc": "" + } + } + ] + } +} \ No newline at end of file From 93327fe9e958bdc5054e2662ae7f233909a008e1 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 11:52:51 +0200 Subject: [PATCH 10/13] dynamicBoolArrayUpdate --- src/lib/compiler.ts | 9 +- tests/abi.test.ts | 6 ++ tests/contracts/abi.algo.ts | 10 ++ .../ABITestDynamicBoolArrayUpdate.abi.json | 15 +++ ...BITestDynamicBoolArrayUpdate.approval.teal | 101 ++++++++++++++++++ .../ABITestDynamicBoolArrayUpdate.clear.teal | 3 + .../ABITestDynamicBoolArrayUpdate.json | 51 +++++++++ ...ABITestStaticBoolArrayUpdate.approval.teal | 4 +- .../ABITestStaticBoolArrayUpdate.json | 2 +- 9 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.abi.json create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.approval.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.clear.teal create mode 100644 tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.json diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index c7d9f8b4a..f245ca5e3 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -2265,10 +2265,15 @@ export default class Compiler { } else if (element.type === 'bool') { if (!ts.isElementAccessExpression(node)) throw new Error(); - this.pushLines(node.argumentExpression, 'int 8', '*'); + this.pushLines(node.argumentExpression, 'int 8', '* // get bit offset'); this.processNode(node.argumentExpression); - this.pushLines(node.argumentExpression, '+', `load ${scratch.fullArray}`, 'swap'); + this.pushLines(node.argumentExpression, '+ // add accessor bits'); + if (element.parent!.arrayType === 'dynamic') { + this.pushLines(node.argumentExpression, 'int 16', '+ // 16 bits for length prefix'); + } + this.pushLines(node.argumentExpression, `load ${scratch.fullArray}`, 'swap'); this.processNode(newValue); + this.pushVoid(node.argumentExpression, 'setbit'); } else { this.pushLines( diff --git a/tests/abi.test.ts b/tests/abi.test.ts index a2e84a677..76582fa5b 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -661,4 +661,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'staticBoolArrayUpdate')).toEqual([true, false, true, true, false, false, true, false, true]); }); + + test.concurrent('dynamicBoolArrayUpdate', async () => { + const { appClient } = await compileAndCreate('dynamicBoolArrayUpdate'); + + expect(await runMethod(appClient, 'dynamicBoolArrayUpdate')).toEqual([true, false, true, true, false, false, true, false, true]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index a2e8a58db..a33949b9b 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -904,3 +904,13 @@ class ABITestStaticBoolArrayUpdate extends Contract { return a; } } + +class ABITestDynamicBoolArrayUpdate extends Contract { + dynamicBoolArrayUpdate(): boolean[] { + const a: boolean[] = [true, false, true, true, false, false, true, false, false]; + + a[8] = true; + + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.abi.json b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.abi.json new file mode 100644 index 000000000..23c083a81 --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestDynamicBoolArrayUpdate", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArrayUpdate", + "args": [], + "desc": "", + "returns": { + "type": "bool[]", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.approval.teal b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.approval.teal new file mode 100644 index 000000000..b2cf9ac20 --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.approval.teal @@ -0,0 +1,101 @@ +#pragma version 8 + b main + +abi_route_dynamicBoolArrayUpdate: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub dynamicBoolArrayUpdate + int 1 + return + +dynamicBoolArrayUpdate: + proto 1 0 + + // tests/contracts/abi.algo.ts:910 + // a: boolean[] = [true, false, true, true, false, false, true, false, false] + byte 0x0009 + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + concat + frame_bury -1 // a: bool[] + + // tests/contracts/abi.algo.ts:912 + // a[8] = true + frame_dig -1 // a: bool[] + store 0 // full array + int 0 // initial offset + int 0 // headOffset + + + int 8 + * // get bit offset + int 8 + + // add accessor bits + int 16 + + // 16 bits for length prefix + load 0 // full array + swap + int 1 + setbit + frame_bury -1 // a: bool[] + + // tests/contracts/abi.algo.ts:914 + // return a; + frame_dig -1 // a: bool[] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "dynamicBoolArrayUpdate()bool[]" + txna ApplicationArgs 0 + match abi_route_dynamicBoolArrayUpdate + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.clear.teal b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.json b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.json new file mode 100644 index 000000000..2d8292a7a --- /dev/null +++ b/tests/contracts/artifacts/ABITestDynamicBoolArrayUpdate.json @@ -0,0 +1,51 @@ +{ + "hints": { + "dynamicBoolArrayUpdate()bool[]": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2R5bmFtaWNCb29sQXJyYXlVcGRhdGU6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZHluYW1pY0Jvb2xBcnJheVVwZGF0ZQoJaW50IDEKCXJldHVybgoKZHluYW1pY0Jvb2xBcnJheVVwZGF0ZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MTAKCS8vIGE6IGJvb2xlYW5bXSA9IFt0cnVlLCBmYWxzZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UsIGZhbHNlLCB0cnVlLCBmYWxzZSwgZmFsc2VdCglieXRlIDB4MDAwOQoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiBib29sW10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6OTEyCgkvLyBhWzhdID0gdHJ1ZQoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbXQoJc3RvcmUgMCAvLyBmdWxsIGFycmF5CglpbnQgMCAvLyBpbml0aWFsIG9mZnNldAoJaW50IDAgLy8gaGVhZE9mZnNldAoJKwoJaW50IDgKCSogLy8gZ2V0IGJpdCBvZmZzZXQKCWludCA4CgkrIC8vIGFkZCBhY2Nlc3NvciBiaXRzCglpbnQgMTYKCSsgLy8gMTYgYml0cyBmb3IgbGVuZ3RoIHByZWZpeAoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCAxCglzZXRiaXQKCWZyYW1lX2J1cnkgLTEgLy8gYTogYm9vbFtdCgoJLy8gdGVzdHMvY29udHJhY3RzL2FiaS5hbGdvLnRzOjkxNAoJLy8gcmV0dXJuIGE7CglmcmFtZV9kaWcgLTEgLy8gYTogYm9vbFtdCglieXRlIDB4MTUxZjdjNzUKCXN3YXAKCWNvbmNhdAoJbG9nCglyZXRzdWIKCm1haW46Cgl0eG4gTnVtQXBwQXJncwoJYm56IHJvdXRlX2FiaQoKCS8vIGRlZmF1bHQgY3JlYXRlQXBwbGljYXRpb24KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJPT0KCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJJiYKCXJldHVybgoKcm91dGVfYWJpOgoJbWV0aG9kICJkeW5hbWljQm9vbEFycmF5VXBkYXRlKClib29sW10iCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfZHluYW1pY0Jvb2xBcnJheVVwZGF0ZQoJZXJy", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestDynamicBoolArrayUpdate", + "desc": "", + "methods": [ + { + "name": "dynamicBoolArrayUpdate", + "args": [], + "desc": "", + "returns": { + "type": "bool[]", + "desc": "" + } + } + ] + } +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal index b92c5723c..39303b0c6 100644 --- a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.approval.teal @@ -58,9 +58,9 @@ staticBoolArrayUpdate: int 0 // headOffset + int 8 - * + * // get bit offset int 8 - + + + // add accessor bits load 0 // full array swap int 1 diff --git a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json index 5b44a9a94..023c8fbb2 100644 --- a/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json +++ b/tests/contracts/artifacts/ABITestStaticBoolArrayUpdate.json @@ -30,7 +30,7 @@ } }, "source": { - "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlVcGRhdGUKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDAKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6OTAyCgkvLyBhWzhdID0gdHJ1ZQoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CgkqCglpbnQgOAoJKwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCAxCglzZXRiaXQKCWZyYW1lX2J1cnkgLTEgLy8gYTogYm9vbFs5XQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDQKCS8vIHJldHVybiBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInN0YXRpY0Jvb2xBcnJheVVwZGF0ZSgpYm9vbFs5XSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zdGF0aWNCb29sQXJyYXlVcGRhdGUKCWVycg==", + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3N0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBzdGF0aWNCb29sQXJyYXlVcGRhdGUKCWludCAxCglyZXR1cm4KCnN0YXRpY0Jvb2xBcnJheVVwZGF0ZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDAKCS8vIGE6IFN0YXRpY0FycmF5PGJvb2xlYW4sIDk+ID0gW3RydWUsIGZhbHNlLCB0cnVlLCB0cnVlLCBmYWxzZSwgZmFsc2UsIHRydWUsIGZhbHNlLCBmYWxzZV0KCWJ5dGUgMHgwMDAwCglpbnQgMAoJaW50IDEKCXNldGJpdAoJaW50IDEKCWludCAwCglzZXRiaXQKCWludCAyCglpbnQgMQoJc2V0Yml0CglpbnQgMwoJaW50IDEKCXNldGJpdAoJaW50IDQKCWludCAwCglzZXRiaXQKCWludCA1CglpbnQgMAoJc2V0Yml0CglpbnQgNgoJaW50IDEKCXNldGJpdAoJaW50IDcKCWludCAwCglzZXRiaXQKCWludCA4CglpbnQgMAoJc2V0Yml0CglmcmFtZV9idXJ5IC0xIC8vIGE6IGJvb2xbOV0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6OTAyCgkvLyBhWzhdID0gdHJ1ZQoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CgkqIC8vIGdldCBiaXQgb2Zmc2V0CglpbnQgOAoJKyAvLyBhZGQgYWNjZXNzb3IgYml0cwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCAxCglzZXRiaXQKCWZyYW1lX2J1cnkgLTEgLy8gYTogYm9vbFs5XQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MDQKCS8vIHJldHVybiBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IGJvb2xbOV0KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInN0YXRpY0Jvb2xBcnJheVVwZGF0ZSgpYm9vbFs5XSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zdGF0aWNCb29sQXJyYXlVcGRhdGUKCWVycg==", "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" }, "contract": { From d1eba848a61b4b36324a58fbe54bcd088c721903 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 12:02:13 +0200 Subject: [PATCH 11/13] boolTupleUpdate --- tests/abi.test.ts | 6 + tests/contracts/abi.algo.ts | 13 ++ .../artifacts/ABITestBoolTupleUpdate.abi.json | 15 +++ .../ABITestBoolTupleUpdate.approval.teal | 112 ++++++++++++++++++ .../ABITestBoolTupleUpdate.clear.teal | 3 + .../artifacts/ABITestBoolTupleUpdate.json | 51 ++++++++ 6 files changed, 200 insertions(+) create mode 100644 tests/contracts/artifacts/ABITestBoolTupleUpdate.abi.json create mode 100644 tests/contracts/artifacts/ABITestBoolTupleUpdate.approval.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTupleUpdate.clear.teal create mode 100644 tests/contracts/artifacts/ABITestBoolTupleUpdate.json diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 76582fa5b..4e241c14f 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -667,4 +667,10 @@ describe('ABI', function () { expect(await runMethod(appClient, 'dynamicBoolArrayUpdate')).toEqual([true, false, true, true, false, false, true, false, true]); }); + + test.concurrent('boolTupleUpdate', async () => { + const { appClient } = await compileAndCreate('boolTupleUpdate'); + + expect(await runMethod(appClient, 'boolTupleUpdate')).toEqual([true, false, true, true, false, false, true, false, true]); + }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index a33949b9b..18fc45a26 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -914,3 +914,16 @@ class ABITestDynamicBoolArrayUpdate extends Contract { return a; } } + +class ABITestBoolTupleUpdate extends Contract { + boolTupleUpdate(): [ + boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean + ] { + const a: [ + boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean + ] = [true, false, true, true, false, false, true, false, false]; + + a[8] = true; + return a; + } +} diff --git a/tests/contracts/artifacts/ABITestBoolTupleUpdate.abi.json b/tests/contracts/artifacts/ABITestBoolTupleUpdate.abi.json new file mode 100644 index 000000000..bd291143d --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleUpdate.abi.json @@ -0,0 +1,15 @@ +{ + "name": "ABITestBoolTupleUpdate", + "desc": "", + "methods": [ + { + "name": "boolTupleUpdate", + "args": [], + "desc": "", + "returns": { + "type": "(bool,bool,bool,bool,bool,bool,bool,bool,bool)", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleUpdate.approval.teal b/tests/contracts/artifacts/ABITestBoolTupleUpdate.approval.teal new file mode 100644 index 000000000..77152a90b --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleUpdate.approval.teal @@ -0,0 +1,112 @@ +#pragma version 8 + b main + +abi_route_boolTupleUpdate: + txn OnCompletion + int NoOp + == + txn ApplicationID + int 0 + != + && + assert + byte 0x + callsub boolTupleUpdate + int 1 + return + +boolTupleUpdate: + proto 1 0 + + // tests/contracts/abi.algo.ts:922 + // a: [ + byte 0x // initial head + byte 0x // initial tail + byte 0x0002 // initial head offset + byte 0x0000 + int 0 + int 1 + setbit + int 1 + int 0 + setbit + int 2 + int 1 + setbit + int 3 + int 1 + setbit + int 4 + int 0 + setbit + int 5 + int 0 + setbit + int 6 + int 1 + setbit + int 7 + int 0 + setbit + int 8 + int 0 + setbit + callsub process_static_tuple_element + pop // pop head offset + concat // concat head and tail + frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + + // tests/contracts/abi.algo.ts:926 + // a[8] = true + frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + store 0 // full array + int 0 // initial offset + int 0 // headOffset + + + int 8 + * // get bit offset + int 8 + + // add accessor bits + load 0 // full array + swap + int 1 + setbit + frame_bury -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + + // tests/contracts/abi.algo.ts:927 + // return a; + frame_dig -1 // a: [bool,bool,bool,bool,bool,bool,bool,bool,bool] + byte 0x151f7c75 + swap + concat + log + retsub + +main: + txn NumAppArgs + bnz route_abi + + // default createApplication + txn ApplicationID + int 0 + == + txn OnCompletion + int NoOp + == + && + return + +route_abi: + method "boolTupleUpdate()(bool,bool,bool,bool,bool,bool,bool,bool,bool)" + txna ApplicationArgs 0 + match abi_route_boolTupleUpdate + err + +process_static_tuple_element: + proto 4 3 + frame_dig -4 // tuple head + frame_dig -1 // element + concat + frame_dig -3 // tuple tail + frame_dig -2 // head offset + retsub \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleUpdate.clear.teal b/tests/contracts/artifacts/ABITestBoolTupleUpdate.clear.teal new file mode 100644 index 000000000..31588a8ec --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleUpdate.clear.teal @@ -0,0 +1,3 @@ +#pragma version 8 +int 1 +return \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestBoolTupleUpdate.json b/tests/contracts/artifacts/ABITestBoolTupleUpdate.json new file mode 100644 index 000000000..213d19376 --- /dev/null +++ b/tests/contracts/artifacts/ABITestBoolTupleUpdate.json @@ -0,0 +1,51 @@ +{ + "hints": { + "boolTupleUpdate()(bool,bool,bool,bool,bool,bool,bool,bool,bool)": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "CREATE" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2Jvb2xUdXBsZVVwZGF0ZToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBib29sVHVwbGVVcGRhdGUKCWludCAxCglyZXR1cm4KCmJvb2xUdXBsZVVwZGF0ZToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MjIKCS8vIGE6IFsKCWJ5dGUgMHggLy8gaW5pdGlhbCBoZWFkCglieXRlIDB4IC8vIGluaXRpYWwgdGFpbAoJYnl0ZSAweDAwMDIgLy8gaW5pdGlhbCBoZWFkIG9mZnNldAoJYnl0ZSAweDAwMDAKCWludCAwCglpbnQgMQoJc2V0Yml0CglpbnQgMQoJaW50IDAKCXNldGJpdAoJaW50IDIKCWludCAxCglzZXRiaXQKCWludCAzCglpbnQgMQoJc2V0Yml0CglpbnQgNAoJaW50IDAKCXNldGJpdAoJaW50IDUKCWludCAwCglzZXRiaXQKCWludCA2CglpbnQgMQoJc2V0Yml0CglpbnQgNwoJaW50IDAKCXNldGJpdAoJaW50IDgKCWludCAwCglzZXRiaXQKCWNhbGxzdWIgcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudAoJcG9wIC8vIHBvcCBoZWFkIG9mZnNldAoJY29uY2F0IC8vIGNvbmNhdCBoZWFkIGFuZCB0YWlsCglmcmFtZV9idXJ5IC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6OTI2CgkvLyBhWzhdID0gdHJ1ZQoJZnJhbWVfZGlnIC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWludCA4CgkqIC8vIGdldCBiaXQgb2Zmc2V0CglpbnQgOAoJKyAvLyBhZGQgYWNjZXNzb3IgYml0cwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCAxCglzZXRiaXQKCWZyYW1lX2J1cnkgLTEgLy8gYTogW2Jvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sXQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo5MjcKCS8vIHJldHVybiBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IFtib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbF0KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgImJvb2xUdXBsZVVwZGF0ZSgpKGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sLGJvb2wsYm9vbCxib29sKSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9ib29sVHVwbGVVcGRhdGUKCWVycgoKcHJvY2Vzc19zdGF0aWNfdHVwbGVfZWxlbWVudDoKCXByb3RvIDQgMwoJZnJhbWVfZGlnIC00IC8vIHR1cGxlIGhlYWQKCWZyYW1lX2RpZyAtMSAvLyBlbGVtZW50Cgljb25jYXQKCWZyYW1lX2RpZyAtMyAvLyB0dXBsZSB0YWlsCglmcmFtZV9kaWcgLTIgLy8gaGVhZCBvZmZzZXQKCXJldHN1Yg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu" + }, + "contract": { + "name": "ABITestBoolTupleUpdate", + "desc": "", + "methods": [ + { + "name": "boolTupleUpdate", + "args": [], + "desc": "", + "returns": { + "type": "(bool,bool,bool,bool,bool,bool,bool,bool,bool)", + "desc": "" + } + } + ] + } +} \ No newline at end of file From b93041e95cf02d08e55b7310ec595e94415814f7 Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 12:40:25 +0200 Subject: [PATCH 12/13] static bool array length --- src/lib/compiler.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index f245ca5e3..dd6b2b999 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -1038,6 +1038,13 @@ export default class Compiler { } } + if (type.match(/^bool\[\d+\]$/)) { + const lenStr = type.match(/\[\d+]$/)![0].match(/\d+/)![0]; + const length = parseInt(lenStr, 10); + + return Math.ceil(length / 8); + } + if (type.match(/\[\d+]$/)) { const lenStr = type.match(/\[\d+]$/)![0].match(/\d+/)![0]; const length = parseInt(lenStr, 10); @@ -3688,6 +3695,7 @@ export default class Compiler { const json = await response.json(); if (response.status !== 200) { + // eslint-disable-next-line no-console console.warn(this.approvalProgram().split('\n').map((l, i) => `${i + 1}: ${l}`).join('\n')); throw new Error(`${response.statusText}: ${json.message}`); From a27b70112137ac2124345350f7e14d7cfa08d7be Mon Sep 17 00:00:00 2001 From: Joe Polny Date: Sun, 23 Jul 2023 12:49:31 +0200 Subject: [PATCH 13/13] bool return from binary expr --- src/lib/compiler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index dd6b2b999..fcfb5ea0e 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -2416,6 +2416,7 @@ export default class Compiler { if (this.lastType === 'uint64') this.pushVoid(node.expression!, 'itob'); + console.log(this.lastType, returnType); this.pushVoid(node.expression!, `byte 0x${'FF'.repeat(returnBitWidth / 8)}`); this.pushVoid(node.expression!, 'b&'); @@ -2551,6 +2552,10 @@ export default class Compiler { } else { this.push(node.operatorToken, operator, StackType.uint64); } + + if (operator === '==' || operator === '!=') { + this.lastType = 'bool'; + } } private processLogicalExpression(node: ts.BinaryExpression) {