From 13e43c621fc80719e6c316810166972aaf4a2216 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 10:07:05 -0700 Subject: [PATCH 1/8] feat: Implement missing box proxy methods --- src/awst_build/eb/storage/box.ts | 559 -------- src/awst_build/eb/storage/box/base.ts | 71 + src/awst_build/eb/storage/box/box-map.ts | 235 +++ src/awst_build/eb/storage/box/box-ref.ts | 215 +++ src/awst_build/eb/storage/box/box.ts | 163 +++ src/awst_build/eb/storage/box/index.ts | 4 + src/awst_build/type-resolver.ts | 2 +- tests/approvals/box-proxies.algo.ts | 13 +- tests/approvals/out/box-proxies.awst | 12 +- tests/approvals/out/box-proxies.awst.json | 1591 ++++++++++++++++----- 10 files changed, 1963 insertions(+), 902 deletions(-) delete mode 100644 src/awst_build/eb/storage/box.ts create mode 100644 src/awst_build/eb/storage/box/base.ts create mode 100644 src/awst_build/eb/storage/box/box-map.ts create mode 100644 src/awst_build/eb/storage/box/box-ref.ts create mode 100644 src/awst_build/eb/storage/box/box.ts create mode 100644 src/awst_build/eb/storage/box/index.ts diff --git a/src/awst_build/eb/storage/box.ts b/src/awst_build/eb/storage/box.ts deleted file mode 100644 index 88e8215d..00000000 --- a/src/awst_build/eb/storage/box.ts +++ /dev/null @@ -1,559 +0,0 @@ -import { intrinsicFactory } from '../../../awst/intrinsic-factory' -import { nodeFactory } from '../../../awst/node-factory' -import type { BoxValueExpression, Expression } from '../../../awst/nodes' -import { BytesConstant } from '../../../awst/nodes' -import type { SourceLocation } from '../../../awst/source-location' -import { boolWType, boxKeyWType, bytesWType, voidWType } from '../../../awst/wtypes' -import { codeInvariant, invariant } from '../../../util' -import { AppStorageDeclaration } from '../../contract-data' -import type { ContractClassPType, PType } from '../../ptypes' -import { - boolPType, - BoxMapPType, - BoxPType, - BoxRefPType, - boxRefType, - bytesPType, - stringPType, - TuplePType, - uint64PType, - voidPType, -} from '../../ptypes' -import { instanceEb, typeRegistry } from '../../type-registry' -import { BooleanExpressionBuilder } from '../boolean-expression-builder' -import type { InstanceBuilder, NodeBuilder } from '../index' -import { FunctionBuilder, InstanceExpressionBuilder, ParameterlessFunctionBuilder } from '../index' -import { requireExpressionOfType } from '../util' -import { parseFunctionArgs } from '../util/arg-parsing' -import { VoidExpressionBuilder } from '../void-expression-builder' -import { extractKey } from './util' -import { ValueProxy } from './value-proxy' - -export class BoxFunctionBuilder extends FunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - ptypes: [contentPType], - args: [{ key }], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: `Box`, - callLocation: sourceLocation, - genericTypeArgs: 1, - argSpec: (a) => [a.obj({ key: a.required(bytesPType, stringPType) })], - }) - - const ptype = new BoxPType({ content: contentPType }) - return new BoxExpressionBuilder(extractKey(key, boxKeyWType), ptype) - } -} -export class BoxRefFunctionBuilder extends FunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [{ key }], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: `BoxRef`, - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.obj({ key: a.required(bytesPType, stringPType) })], - }) - - return new BoxRefExpressionBuilder(extractKey(key, boxKeyWType), boxRefType) - } -} -export class BoxMapFunctionBuilder extends FunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - ptypes: [keySuffixType, contentPType], - args: [{ keyPrefix }], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: `BoxMap`, - callLocation: sourceLocation, - genericTypeArgs: 2, - argSpec: (a) => [a.obj({ keyPrefix: a.required(bytesPType, stringPType) })], - }) - - const ptype = new BoxMapPType({ content: contentPType, keyType: keySuffixType }) - return new BoxMapExpressionBuilder(extractKey(keyPrefix, boxKeyWType), ptype) - } -} - -export abstract class BoxProxyExpressionBuilder< - TProxyType extends BoxMapPType | BoxRefPType | BoxPType, -> extends InstanceExpressionBuilder { - buildStorageDeclaration(memberName: string, memberLocation: SourceLocation, contractType: ContractClassPType): AppStorageDeclaration { - codeInvariant( - this._expr instanceof BytesConstant, - `key${this.ptype instanceof BoxMapPType ? ' prefix' : ''} must be a compile time constant value if ${this.typeDescription} is assigned to a contract member`, - ) - return new AppStorageDeclaration({ - sourceLocation: memberLocation, - ptype: this.ptype, - memberName: memberName, - keyOverride: this._expr ?? null, - description: null, - definedIn: contractType, - }) - } -} - -export class BoxMapExpressionBuilder extends BoxProxyExpressionBuilder { - constructor(expr: Expression, ptype: PType) { - invariant(ptype instanceof BoxMapPType, 'BoxMapExpressionBuilder must be constructed with ptype of BoxMapPType') - super(expr, ptype) - } - memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { - switch (name) { - case 'set': - return new BoxMapSetFunctionBuilder(this._expr, this.ptype, sourceLocation) - case 'delete': - return new BoxMapDeleteFunctionBuilder(this._expr, this.ptype, sourceLocation) - case 'get': - return new BoxMapGetFunctionBuilder(this._expr, this.ptype, sourceLocation) - case 'has': - return new BoxMapHasFunctionBuilder(this._expr, this.ptype, sourceLocation) - } - return super.memberAccess(name, sourceLocation) - } -} -export class BoxRefExpressionBuilder extends BoxProxyExpressionBuilder { - constructor(expr: Expression, ptype: PType) { - invariant(ptype instanceof BoxRefPType, 'BoxRefExpressionBuilder must be constructed with ptype of BoxRefPType') - super(expr, ptype) - } - - memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { - const boxValueExpr = boxValue({ - key: this._expr, - sourceLocation, - contentType: this.ptype.contentType, - }) - switch (name) { - case 'put': - return new BoxRefPutFunctionBuilder(boxValueExpr) - case 'splice': - return new BoxRefSpliceFunctionBuilder(boxValueExpr) - case 'create': - return new BoxRefCreateFunctionBuilder(boxValueExpr) - case 'extract': - return new BoxRefExtractFunctionBuilder(boxValueExpr) - case 'replace': - return new BoxRefReplaceFunctionBuilder(boxValueExpr) - case 'value': - return new BoxValueExpressionBuilder(boxValueExpr, this.ptype.contentType) - } - return super.memberAccess(name, sourceLocation) - } -} - -export abstract class BoxRefBaseFunctionBuilder extends FunctionBuilder { - constructor(protected readonly boxValue: BoxValueExpression) { - super(boxValue.sourceLocation) - } -} - -export class BoxRefCreateFunctionBuilder extends BoxRefBaseFunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [{ size }], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - funcName: 'BoxRef.create', - callLocation: sourceLocation, - argSpec: (a) => [a.obj({ size: a.required(uint64PType) })], - }) - return instanceEb( - nodeFactory.intrinsicCall({ - opCode: 'box_create', - stackArgs: [this.boxValue, size.resolve()], - wtype: boolWType, - immediates: [], - sourceLocation, - }), - boolPType, - ) - } -} -export class BoxRefExtractFunctionBuilder extends BoxRefBaseFunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [start, length], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - funcName: 'BoxRef.extract', - callLocation: sourceLocation, - argSpec: (a) => [a.required(uint64PType), a.required(uint64PType)], - }) - return instanceEb( - nodeFactory.intrinsicCall({ - opCode: 'box_extract', - stackArgs: [this.boxValue, start.resolve(), length.resolve()], - wtype: bytesWType, - immediates: [], - sourceLocation, - }), - bytesPType, - ) - } -} -export class BoxRefReplaceFunctionBuilder extends BoxRefBaseFunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [start, value], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - funcName: 'BoxRef.replace', - callLocation: sourceLocation, - argSpec: (a) => [a.required(uint64PType), a.required(bytesPType)], - }) - return instanceEb( - nodeFactory.intrinsicCall({ - opCode: 'box_replace', - stackArgs: [this.boxValue, start.resolve(), value.resolve()], - wtype: voidWType, - immediates: [], - sourceLocation, - }), - voidPType, - ) - } -} - -export class BoxRefPutFunctionBuilder extends BoxRefBaseFunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [value], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - funcName: 'BoxRef.put', - callLocation: sourceLocation, - argSpec: (a) => [a.required(bytesPType)], - }) - return instanceEb( - nodeFactory.intrinsicCall({ - opCode: 'box_put', - stackArgs: [this.boxValue, value.resolve()], - wtype: voidWType, - immediates: [], - sourceLocation, - }), - voidPType, - ) - } -} -export class BoxRefSpliceFunctionBuilder extends BoxRefBaseFunctionBuilder { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [start, stop, value], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - funcName: 'BoxRef.splice', - callLocation: sourceLocation, - argSpec: (a) => [a.required(uint64PType), a.required(uint64PType), a.required(bytesPType)], - }) - return instanceEb( - nodeFactory.intrinsicCall({ - opCode: 'box_splice', - stackArgs: [this.boxValue, start.resolve(), stop.resolve(), value.resolve()], - wtype: voidWType, - immediates: [], - sourceLocation, - }), - voidPType, - ) - } -} - -function boxValue({ - key, - sourceLocation, - contentType, -}: { - key: Expression - sourceLocation: SourceLocation - contentType: PType -}): BoxValueExpression { - return nodeFactory.boxValueExpression({ - key, - sourceLocation, - wtype: contentType.wtypeOrThrow, - existsAssertionMessage: 'Box must have value', - }) -} - -export class BoxExpressionBuilder extends BoxProxyExpressionBuilder { - constructor(expr: Expression, ptype: PType) { - invariant(ptype instanceof BoxPType, 'BoxExpressionBuilder must be constructed with ptype of BoxPType') - super(expr, ptype) - } - - memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { - const boxValueExpr = boxValue({ - key: this._expr, - sourceLocation, - contentType: this.ptype.contentType, - }) - switch (name) { - case 'value': - return new BoxValueExpressionBuilder(boxValueExpr, this.ptype.contentType) - case 'exists': - return new BooleanExpressionBuilder( - nodeFactory.stateExists({ - field: boxValueExpr, - sourceLocation, - wtype: boolWType, - }), - ) - case 'delete': - return new BoxDeleteFunctionBuilder(boxValueExpr, sourceLocation) - case 'get': - return new BoxGetFunctionBuilder(boxValueExpr, this.ptype.contentType, sourceLocation) - case 'maybe': - return new BoxMaybeFunctionBuilder(boxValueExpr, this.ptype.contentType, sourceLocation) - } - return super.memberAccess(name, sourceLocation) - } -} - -/** - * Wraps the box value expression and watches for certain expressions which can be optimized. - * - * For example box.value.bytes.slice(...) can be optimized to use box_extract directly rather - * than reading the entire box into memory and then slicing it. All unhandled scenarios are proxied - * through to the underlying builder for the given type. - */ -class BoxValueExpressionBuilder extends ValueProxy { - constructor(boxValue: BoxValueExpression, ptype: PType) { - super(boxValue, ptype) - } - assign(other: InstanceBuilder, sourceLocation: SourceLocation): InstanceBuilder { - const value = requireExpressionOfType(other, this.ptype) - return typeRegistry.getInstanceEb( - nodeFactory.assignmentExpression({ - target: this.resolveLValue(), - value, - sourceLocation, - }), - this.ptype, - ) - } -} -class BoxDeleteFunctionBuilder extends ParameterlessFunctionBuilder { - constructor(boxValue: BoxValueExpression, sourceLocation: SourceLocation) { - super( - boxValue, - (expr) => - new VoidExpressionBuilder( - nodeFactory.stateDelete({ - sourceLocation, - field: boxValue, - wtype: voidWType, - }), - ), - ) - } -} - -class BoxGetFunctionBuilder extends FunctionBuilder { - constructor( - private readonly boxValue: BoxValueExpression, - private readonly contentType: PType, - sourceLocation: SourceLocation, - ) { - super(sourceLocation) - } - - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [{ default: defaultValue }], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: 'Box.get', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.obj({ default: a.optional(this.contentType) })], - }) - - if (defaultValue) { - return instanceEb( - nodeFactory.stateGet({ - sourceLocation, - default: defaultValue.resolve(), - wtype: this.contentType.wtypeOrThrow, - field: this.boxValue, - }), - this.contentType, - ) - } else { - return new BoxValueExpressionBuilder(this.boxValue, this.contentType) - } - } -} -class BoxMaybeFunctionBuilder extends FunctionBuilder { - constructor( - private readonly boxValue: BoxValueExpression, - private readonly contentType: PType, - sourceLocation: SourceLocation, - ) { - super(sourceLocation) - } - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - parseFunctionArgs({ - args, - typeArgs, - funcName: 'Box.maybe', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: () => [], - }) - const type = new TuplePType({ items: [this.contentType, boolPType], immutable: true }) - - return instanceEb( - nodeFactory.stateGetEx({ - sourceLocation, - wtype: type.wtype, - field: this.boxValue, - }), - type, - ) - } -} -abstract class BoxMapFunctionBuilderBase extends FunctionBuilder { - #mapPType: BoxMapPType - #boxMapExpr: Expression - constructor(boxMapExpr: Expression, mapPType: BoxMapPType, sourceLocation: SourceLocation) { - super(sourceLocation) - this.#mapPType = mapPType - this.#boxMapExpr = boxMapExpr - } - protected get contentType() { - return this.#mapPType.contentType - } - protected get keyType() { - return this.#mapPType.keyType - } - protected boxValueExpression(key: Expression): BoxValueExpression { - const keyBytes = instanceEb(key, this.keyType).toBytes(this.sourceLocation) - - return nodeFactory.boxValueExpression({ - sourceLocation: this.sourceLocation, - existsAssertionMessage: 'Box must have value', - key: intrinsicFactory.bytesConcat({ - left: this.#boxMapExpr, - right: keyBytes, - sourceLocation: this.sourceLocation, - }), - wtype: this.contentType.wtypeOrThrow, - }) - } -} -class BoxMapHasFunctionBuilder extends BoxMapFunctionBuilderBase { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [key], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: 'BoxMap.has', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.required(this.keyType)], - }) - return new BooleanExpressionBuilder( - nodeFactory.stateExists({ - wtype: boolWType, - field: this.boxValueExpression(key.resolve()), - sourceLocation, - }), - ) - } -} - -class BoxMapGetFunctionBuilder extends BoxMapFunctionBuilderBase { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [key, { default: defaultValue }], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: 'BoxMap.set', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.required(this.keyType), a.obj({ default: a.optional(this.contentType) })], - }) - - if (defaultValue) { - return instanceEb( - nodeFactory.stateGet({ - sourceLocation, - default: defaultValue.resolve(), - wtype: this.contentType.wtypeOrThrow, - field: this.boxValueExpression(key.resolve()), - }), - this.contentType, - ) - } else { - return new BoxValueExpressionBuilder(this.boxValueExpression(key.resolve()), this.contentType) - } - } -} -class BoxMapSetFunctionBuilder extends BoxMapFunctionBuilderBase { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [key, value], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: 'BoxMap.set', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.required(this.keyType), a.required(this.contentType)], - }) - - return instanceEb( - nodeFactory.assignmentExpression({ - target: this.boxValueExpression(key.resolve()), - sourceLocation, - value: value.resolve(), - }), - this.contentType, - ) - } -} -class BoxMapDeleteFunctionBuilder extends BoxMapFunctionBuilderBase { - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - const { - args: [key], - } = parseFunctionArgs({ - args, - typeArgs, - funcName: 'BoxMap.delete', - callLocation: sourceLocation, - genericTypeArgs: 0, - argSpec: (a) => [a.required(this.keyType)], - }) - - return new VoidExpressionBuilder( - nodeFactory.stateDelete({ - field: this.boxValueExpression(key.resolve()), - sourceLocation, - wtype: voidWType, - }), - ) - } -} diff --git a/src/awst_build/eb/storage/box/base.ts b/src/awst_build/eb/storage/box/base.ts new file mode 100644 index 00000000..8041c4ce --- /dev/null +++ b/src/awst_build/eb/storage/box/base.ts @@ -0,0 +1,71 @@ +import { nodeFactory } from '../../../../awst/node-factory' +import { type BoxValueExpression, BytesConstant, type Expression } from '../../../../awst/nodes' +import type { SourceLocation } from '../../../../awst/source-location' +import { codeInvariant } from '../../../../util' +import { AppStorageDeclaration } from '../../../contract-data' +import type { BoxPType, BoxRefPType } from '../../../ptypes' +import { BoxMapPType, type ContractClassPType, type PType } from '../../../ptypes' +import { typeRegistry } from '../../../type-registry' +import { type InstanceBuilder, InstanceExpressionBuilder } from '../../index' +import { requireExpressionOfType } from '../../util' +import { ValueProxy } from '../value-proxy' + +export abstract class BoxProxyExpressionBuilder< + TProxyType extends BoxMapPType | BoxRefPType | BoxPType, +> extends InstanceExpressionBuilder { + buildStorageDeclaration(memberName: string, memberLocation: SourceLocation, contractType: ContractClassPType): AppStorageDeclaration { + codeInvariant( + this._expr instanceof BytesConstant, + `key${this.ptype instanceof BoxMapPType ? ' prefix' : ''} must be a compile time constant value if ${this.typeDescription} is assigned to a contract member`, + ) + return new AppStorageDeclaration({ + sourceLocation: memberLocation, + ptype: this.ptype, + memberName: memberName, + keyOverride: this._expr ?? null, + description: null, + definedIn: contractType, + }) + } +} + +/** + * Wraps the box value expression and watches for certain expressions which can be optimized. + * + * For example box.value.bytes.slice(...) can be optimized to use box_extract directly rather + * than reading the entire box into memory and then slicing it. All unhandled scenarios are proxied + * through to the underlying builder for the given type. + */ +export class BoxValueExpressionBuilder extends ValueProxy { + constructor(boxValue: BoxValueExpression, ptype: PType) { + super(boxValue, ptype) + } + assign(other: InstanceBuilder, sourceLocation: SourceLocation): InstanceBuilder { + const value = requireExpressionOfType(other, this.ptype) + return typeRegistry.getInstanceEb( + nodeFactory.assignmentExpression({ + target: this.resolveLValue(), + value, + sourceLocation, + }), + this.ptype, + ) + } +} + +export function boxValue({ + key, + sourceLocation, + contentType, +}: { + key: Expression + sourceLocation: SourceLocation + contentType: PType +}): BoxValueExpression { + return nodeFactory.boxValueExpression({ + key, + sourceLocation, + wtype: contentType.wtypeOrThrow, + existsAssertionMessage: 'Box must have value', + }) +} diff --git a/src/awst_build/eb/storage/box/box-map.ts b/src/awst_build/eb/storage/box/box-map.ts new file mode 100644 index 00000000..65dd5a31 --- /dev/null +++ b/src/awst_build/eb/storage/box/box-map.ts @@ -0,0 +1,235 @@ +import { intrinsicFactory } from '../../../../awst/intrinsic-factory' +import { nodeFactory } from '../../../../awst/node-factory' +import type { BoxValueExpression, Expression } from '../../../../awst/nodes' +import type { SourceLocation } from '../../../../awst/source-location' +import { boolWType, boxKeyWType, uint64WType, voidWType, WTuple } from '../../../../awst/wtypes' +import { invariant } from '../../../../util' +import type { PType } from '../../../ptypes' +import { boolPType, BoxMapPType, bytesPType, stringPType, TuplePType, uint64PType } from '../../../ptypes' +import { instanceEb } from '../../../type-registry' +import { BooleanExpressionBuilder } from '../../boolean-expression-builder' +import { FunctionBuilder, type InstanceBuilder, type NodeBuilder } from '../../index' +import { parseFunctionArgs } from '../../util/arg-parsing' +import { VoidExpressionBuilder } from '../../void-expression-builder' +import { extractKey } from '../util' +import { BoxProxyExpressionBuilder, BoxValueExpressionBuilder } from './base' + +export class BoxMapFunctionBuilder extends FunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + ptypes: [keySuffixType, contentPType], + args: [{ keyPrefix }], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: `BoxMap`, + callLocation: sourceLocation, + genericTypeArgs: 2, + argSpec: (a) => [a.obj({ keyPrefix: a.required(bytesPType, stringPType) })], + }) + + const ptype = new BoxMapPType({ content: contentPType, keyType: keySuffixType }) + return new BoxMapExpressionBuilder(extractKey(keyPrefix, boxKeyWType), ptype) + } +} + +export class BoxMapExpressionBuilder extends BoxProxyExpressionBuilder { + constructor(expr: Expression, ptype: PType) { + invariant(ptype instanceof BoxMapPType, 'BoxMapExpressionBuilder must be constructed with ptype of BoxMapPType') + super(expr, ptype) + } + memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { + switch (name) { + case 'set': + return new BoxMapSetFunctionBuilder(this._expr, this.ptype, sourceLocation) + case 'delete': + return new BoxMapDeleteFunctionBuilder(this._expr, this.ptype, sourceLocation) + case 'get': + return new BoxMapGetFunctionBuilder(this._expr, this.ptype, sourceLocation) + case 'has': + return new BoxMapHasFunctionBuilder(this._expr, this.ptype, sourceLocation) + case 'maybe': + return new BoxMapMaybeFunctionBuilder(this._expr, this.ptype, sourceLocation) + case 'length': + return new BoxMapLengthFunctionBuilder(this._expr, this.ptype, sourceLocation) + } + return super.memberAccess(name, sourceLocation) + } +} + +abstract class BoxMapFunctionBuilderBase extends FunctionBuilder { + #mapPType: BoxMapPType + #boxMapExpr: Expression + constructor(boxMapExpr: Expression, mapPType: BoxMapPType, sourceLocation: SourceLocation) { + super(sourceLocation) + this.#mapPType = mapPType + this.#boxMapExpr = boxMapExpr + } + protected get contentType() { + return this.#mapPType.contentType + } + protected get keyType() { + return this.#mapPType.keyType + } + protected boxValueExpression(key: Expression): BoxValueExpression { + const keyBytes = instanceEb(key, this.keyType).toBytes(this.sourceLocation) + + return nodeFactory.boxValueExpression({ + sourceLocation: this.sourceLocation, + existsAssertionMessage: 'Box must have value', + key: intrinsicFactory.bytesConcat({ + left: this.#boxMapExpr, + right: keyBytes, + sourceLocation: this.sourceLocation, + }), + wtype: this.contentType.wtypeOrThrow, + }) + } +} +class BoxMapHasFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.has', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType)], + }) + return new BooleanExpressionBuilder( + nodeFactory.stateExists({ + wtype: boolWType, + field: this.boxValueExpression(key.resolve()), + sourceLocation, + }), + ) + } +} + +class BoxMapGetFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key, { default: defaultValue }], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.get', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType), a.obj({ default: a.optional(this.contentType) })], + }) + + if (defaultValue) { + return instanceEb( + nodeFactory.stateGet({ + sourceLocation, + default: defaultValue.resolve(), + wtype: this.contentType.wtypeOrThrow, + field: this.boxValueExpression(key.resolve()), + }), + this.contentType, + ) + } else { + return new BoxValueExpressionBuilder(this.boxValueExpression(key.resolve()), this.contentType) + } + } +} +class BoxMapSetFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key, value], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.set', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType), a.required(this.contentType)], + }) + + return instanceEb( + nodeFactory.assignmentExpression({ + target: this.boxValueExpression(key.resolve()), + sourceLocation, + value: value.resolve(), + }), + this.contentType, + ) + } +} +class BoxMapMaybeFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.maybe', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType)], + }) + const type = new TuplePType({ items: [this.contentType, boolPType], immutable: true }) + + return instanceEb( + nodeFactory.stateGetEx({ + field: this.boxValueExpression(key.resolve()), + sourceLocation, + wtype: type.wtype, + }), + type, + ) + } +} +class BoxMapLengthFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.length', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType)], + }) + + return instanceEb( + nodeFactory.checkedMaybe({ + expr: nodeFactory.intrinsicCall({ + opCode: 'box_length', + stackArgs: [this.boxValueExpression(key.resolve())], + wtype: new WTuple({ types: [uint64WType, boolWType], immutable: true }), + immediates: [], + sourceLocation, + }), + comment: 'Box must exist', + }), + uint64PType, + ) + } +} +class BoxMapDeleteFunctionBuilder extends BoxMapFunctionBuilderBase { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [key], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'BoxMap.delete', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.required(this.keyType)], + }) + + return new VoidExpressionBuilder( + nodeFactory.stateDelete({ + field: this.boxValueExpression(key.resolve()), + sourceLocation, + wtype: voidWType, + }), + ) + } +} diff --git a/src/awst_build/eb/storage/box/box-ref.ts b/src/awst_build/eb/storage/box/box-ref.ts new file mode 100644 index 00000000..6f44c680 --- /dev/null +++ b/src/awst_build/eb/storage/box/box-ref.ts @@ -0,0 +1,215 @@ +import { nodeFactory } from '../../../../awst/node-factory' +import type { BoxValueExpression, Expression } from '../../../../awst/nodes' +import type { SourceLocation } from '../../../../awst/source-location' +import { boolWType, boxKeyWType, bytesWType, uint64WType, voidWType, WTuple } from '../../../../awst/wtypes' +import { invariant } from '../../../../util' +import type { PType } from '../../../ptypes' +import { boolPType, BoxRefPType, boxRefType, bytesPType, stringPType, uint64PType, voidPType } from '../../../ptypes' +import { instanceEb } from '../../../type-registry' +import { FunctionBuilder, type InstanceBuilder, type NodeBuilder } from '../../index' +import { parseFunctionArgs } from '../../util/arg-parsing' +import { extractKey } from '../util' +import { BoxProxyExpressionBuilder, boxValue, BoxValueExpressionBuilder } from './base' + +export class BoxRefFunctionBuilder extends FunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [{ key }], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: `BoxRef`, + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.obj({ key: a.required(bytesPType, stringPType) })], + }) + + return new BoxRefExpressionBuilder(extractKey(key, boxKeyWType), boxRefType) + } +} + +export class BoxRefExpressionBuilder extends BoxProxyExpressionBuilder { + constructor(expr: Expression, ptype: PType) { + invariant(ptype instanceof BoxRefPType, 'BoxRefExpressionBuilder must be constructed with ptype of BoxRefPType') + super(expr, ptype) + } + + memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { + const boxValueExpr = boxValue({ + key: this._expr, + sourceLocation, + contentType: this.ptype.contentType, + }) + switch (name) { + case 'put': + return new BoxRefPutFunctionBuilder(boxValueExpr) + case 'splice': + return new BoxRefSpliceFunctionBuilder(boxValueExpr) + case 'create': + return new BoxRefCreateFunctionBuilder(boxValueExpr) + case 'extract': + return new BoxRefExtractFunctionBuilder(boxValueExpr) + case 'replace': + return new BoxRefReplaceFunctionBuilder(boxValueExpr) + case 'exists': + case 'length': { + const boxLength = nodeFactory.intrinsicCall({ + opCode: 'box_length', + stackArgs: [boxValueExpr], + wtype: new WTuple({ types: [uint64WType, boolWType], immutable: true }), + immediates: [], + sourceLocation, + }) + if (name === 'exists') { + return instanceEb( + nodeFactory.tupleItemExpression({ + base: boxLength, + sourceLocation, + index: 1n, + }), + boolPType, + ) + } else { + return instanceEb( + nodeFactory.checkedMaybe({ + expr: boxLength, + comment: 'Box must exist', + }), + uint64PType, + ) + } + } + case 'value': + return new BoxValueExpressionBuilder(boxValueExpr, this.ptype.contentType) + } + return super.memberAccess(name, sourceLocation) + } +} + +export abstract class BoxRefBaseFunctionBuilder extends FunctionBuilder { + constructor(protected readonly boxValue: BoxValueExpression) { + super(boxValue.sourceLocation) + } +} + +export class BoxRefCreateFunctionBuilder extends BoxRefBaseFunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [{ size }], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + funcName: 'BoxRef.create', + callLocation: sourceLocation, + argSpec: (a) => [a.obj({ size: a.required(uint64PType) })], + }) + return instanceEb( + nodeFactory.intrinsicCall({ + opCode: 'box_create', + stackArgs: [this.boxValue, size.resolve()], + wtype: boolWType, + immediates: [], + sourceLocation, + }), + boolPType, + ) + } +} +export class BoxRefExtractFunctionBuilder extends BoxRefBaseFunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [start, length], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + funcName: 'BoxRef.extract', + callLocation: sourceLocation, + argSpec: (a) => [a.required(uint64PType), a.required(uint64PType)], + }) + return instanceEb( + nodeFactory.intrinsicCall({ + opCode: 'box_extract', + stackArgs: [this.boxValue, start.resolve(), length.resolve()], + wtype: bytesWType, + immediates: [], + sourceLocation, + }), + bytesPType, + ) + } +} +export class BoxRefReplaceFunctionBuilder extends BoxRefBaseFunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [start, value], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + funcName: 'BoxRef.replace', + callLocation: sourceLocation, + argSpec: (a) => [a.required(uint64PType), a.required(bytesPType)], + }) + return instanceEb( + nodeFactory.intrinsicCall({ + opCode: 'box_replace', + stackArgs: [this.boxValue, start.resolve(), value.resolve()], + wtype: voidWType, + immediates: [], + sourceLocation, + }), + voidPType, + ) + } +} + +export class BoxRefPutFunctionBuilder extends BoxRefBaseFunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [value], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + funcName: 'BoxRef.put', + callLocation: sourceLocation, + argSpec: (a) => [a.required(bytesPType)], + }) + return instanceEb( + nodeFactory.intrinsicCall({ + opCode: 'box_put', + stackArgs: [this.boxValue, value.resolve()], + wtype: voidWType, + immediates: [], + sourceLocation, + }), + voidPType, + ) + } +} +export class BoxRefSpliceFunctionBuilder extends BoxRefBaseFunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [start, stop, value], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + funcName: 'BoxRef.splice', + callLocation: sourceLocation, + argSpec: (a) => [a.required(uint64PType), a.required(uint64PType), a.required(bytesPType)], + }) + return instanceEb( + nodeFactory.intrinsicCall({ + opCode: 'box_splice', + stackArgs: [this.boxValue, start.resolve(), stop.resolve(), value.resolve()], + wtype: voidWType, + immediates: [], + sourceLocation, + }), + voidPType, + ) + } +} diff --git a/src/awst_build/eb/storage/box/box.ts b/src/awst_build/eb/storage/box/box.ts new file mode 100644 index 00000000..e929e5f7 --- /dev/null +++ b/src/awst_build/eb/storage/box/box.ts @@ -0,0 +1,163 @@ +import { nodeFactory } from '../../../../awst/node-factory' +import type { BoxValueExpression, Expression } from '../../../../awst/nodes' +import type { SourceLocation } from '../../../../awst/source-location' +import { boolWType, boxKeyWType, uint64WType, voidWType, WTuple } from '../../../../awst/wtypes' +import { invariant } from '../../../../util' +import type { PType } from '../../../ptypes' +import { boolPType, BoxPType, bytesPType, stringPType, TuplePType, uint64PType } from '../../../ptypes' +import { instanceEb } from '../../../type-registry' +import { BooleanExpressionBuilder } from '../../boolean-expression-builder' +import { FunctionBuilder, type InstanceBuilder, type NodeBuilder, ParameterlessFunctionBuilder } from '../../index' +import { parseFunctionArgs } from '../../util/arg-parsing' +import { VoidExpressionBuilder } from '../../void-expression-builder' +import { extractKey } from '../util' +import { BoxProxyExpressionBuilder, boxValue, BoxValueExpressionBuilder } from './base' + +export class BoxFunctionBuilder extends FunctionBuilder { + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + ptypes: [contentPType], + args: [{ key }], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: `Box`, + callLocation: sourceLocation, + genericTypeArgs: 1, + argSpec: (a) => [a.obj({ key: a.required(bytesPType, stringPType) })], + }) + + const ptype = new BoxPType({ content: contentPType }) + return new BoxExpressionBuilder(extractKey(key, boxKeyWType), ptype) + } +} + +export class BoxExpressionBuilder extends BoxProxyExpressionBuilder { + constructor(expr: Expression, ptype: PType) { + invariant(ptype instanceof BoxPType, 'BoxExpressionBuilder must be constructed with ptype of BoxPType') + super(expr, ptype) + } + + memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { + const boxValueExpr = boxValue({ + key: this._expr, + sourceLocation, + contentType: this.ptype.contentType, + }) + switch (name) { + case 'value': + return new BoxValueExpressionBuilder(boxValueExpr, this.ptype.contentType) + case 'exists': + return new BooleanExpressionBuilder( + nodeFactory.stateExists({ + field: boxValueExpr, + sourceLocation, + wtype: boolWType, + }), + ) + case 'length': + return instanceEb( + nodeFactory.checkedMaybe({ + expr: nodeFactory.intrinsicCall({ + opCode: 'box_length', + stackArgs: [boxValueExpr], + wtype: new WTuple({ types: [uint64WType, boolWType], immutable: true }), + immediates: [], + sourceLocation, + }), + comment: 'Box must exist', + }), + uint64PType, + ) + case 'delete': + return new BoxDeleteFunctionBuilder(boxValueExpr, sourceLocation) + case 'get': + return new BoxGetFunctionBuilder(boxValueExpr, this.ptype.contentType, sourceLocation) + case 'maybe': + return new BoxMaybeFunctionBuilder(boxValueExpr, this.ptype.contentType, sourceLocation) + } + return super.memberAccess(name, sourceLocation) + } +} + +class BoxDeleteFunctionBuilder extends ParameterlessFunctionBuilder { + constructor(boxValue: BoxValueExpression, sourceLocation: SourceLocation) { + super( + boxValue, + (expr) => + new VoidExpressionBuilder( + nodeFactory.stateDelete({ + sourceLocation, + field: boxValue, + wtype: voidWType, + }), + ), + ) + } +} + +class BoxGetFunctionBuilder extends FunctionBuilder { + constructor( + private readonly boxValue: BoxValueExpression, + private readonly contentType: PType, + sourceLocation: SourceLocation, + ) { + super(sourceLocation) + } + + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [{ default: defaultValue }], + } = parseFunctionArgs({ + args, + typeArgs, + funcName: 'Box.get', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: (a) => [a.obj({ default: a.optional(this.contentType) })], + }) + + if (defaultValue) { + return instanceEb( + nodeFactory.stateGet({ + sourceLocation, + default: defaultValue.resolve(), + wtype: this.contentType.wtypeOrThrow, + field: this.boxValue, + }), + this.contentType, + ) + } else { + return new BoxValueExpressionBuilder(this.boxValue, this.contentType) + } + } +} +class BoxMaybeFunctionBuilder extends FunctionBuilder { + constructor( + private readonly boxValue: BoxValueExpression, + private readonly contentType: PType, + sourceLocation: SourceLocation, + ) { + super(sourceLocation) + } + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + parseFunctionArgs({ + args, + typeArgs, + funcName: 'Box.maybe', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: () => [], + }) + const type = new TuplePType({ items: [this.contentType, boolPType], immutable: true }) + + return instanceEb( + nodeFactory.stateGetEx({ + sourceLocation, + wtype: type.wtype, + field: this.boxValue, + }), + type, + ) + } +} diff --git a/src/awst_build/eb/storage/box/index.ts b/src/awst_build/eb/storage/box/index.ts new file mode 100644 index 00000000..4f4e9180 --- /dev/null +++ b/src/awst_build/eb/storage/box/index.ts @@ -0,0 +1,4 @@ +export { BoxFunctionBuilder, BoxExpressionBuilder } from './box' +export { BoxMapFunctionBuilder, BoxMapExpressionBuilder } from './box-map' +export { BoxRefFunctionBuilder, BoxRefExpressionBuilder } from './box-ref' +export { BoxProxyExpressionBuilder } from './base' diff --git a/src/awst_build/type-resolver.ts b/src/awst_build/type-resolver.ts index fa58219d..e7bf3efd 100644 --- a/src/awst_build/type-resolver.ts +++ b/src/awst_build/type-resolver.ts @@ -74,7 +74,7 @@ export class TypeResolver { resolve(node: ts.Node, sourceLocation: SourceLocation): PType { const symbol = this.getUnaliasedSymbolForNode(node) - if (symbol !== undefined) { + if (symbol !== undefined && symbol.declarations?.length) { const symbolName = symbol && this.getSymbolFullName(symbol, sourceLocation) if (symbolName.name === '*') { return new NamespacePType(symbolName) diff --git a/tests/approvals/box-proxies.algo.ts b/tests/approvals/box-proxies.algo.ts index c719ff8b..8b7d812d 100644 --- a/tests/approvals/box-proxies.algo.ts +++ b/tests/approvals/box-proxies.algo.ts @@ -1,4 +1,4 @@ -import type { bytes } from '@algorandfoundation/algorand-typescript' +import type { bytes, uint64 } from '@algorandfoundation/algorand-typescript' import { assert, Box, BoxMap, BoxRef, Bytes } from '@algorandfoundation/algorand-typescript' const boxA = Box({ key: Bytes('A') }) @@ -10,6 +10,8 @@ function testBox(box: Box, value: string) { assert(box.exists && boxA.exists) + assert(box.length) + box.delete() boxA.delete() assert(!box.exists && !boxA.exists) @@ -30,6 +32,10 @@ function testBoxMap(box: BoxMap, key: string, value: bytes) { box.set(key, value) boxMap.set(key, value) + assert(box.length(key)) + + assert(box.maybe(key)[1]) + assert(box.get(key) === boxMap.get(key)) box.delete(key) @@ -39,7 +45,10 @@ function testBoxMap(box: BoxMap, key: string, value: bytes) { const boxRef = BoxRef({ key: 'abc' }) -function testBoxRef(box: BoxRef) { +function testBoxRef(box: BoxRef, length: uint64) { + if (!boxRef.exists && boxRef.length !== length) { + boxRef.create({ size: 1000 }) + } const someBytes = Bytes.fromHex('FFFFFFFF') box.put(someBytes) boxRef.put(someBytes) diff --git a/tests/approvals/out/box-proxies.awst b/tests/approvals/out/box-proxies.awst index b4c1665f..e3d57b78 100644 --- a/tests/approvals/out/box-proxies.awst +++ b/tests/approvals/out/box-proxies.awst @@ -4,6 +4,7 @@ subroutine testBox(box: box_key, value: string): void var Box["A"].value: string = value assert(box.value == Box["A"].value) assert(STATE_EXISTS(box.value) and STATE_EXISTS(Box["A"].value)) + assert(Boolean(checked_maybe(box_length(box.value), comment=Box must exist))) STATE_DEL(box.value) STATE_DEL(Box["A"].value) assert(!STATE_EXISTS(box.value) and !STATE_EXISTS(Box["A"].value)) @@ -19,16 +20,21 @@ subroutine testBoxMap(box: box_key, key: string, value: bytes): void { var concat(box, reinterpret_cast(key)).value: bytes = value var concat("", reinterpret_cast(key)).value: bytes = value + assert(Boolean(checked_maybe(box_length(concat(box, reinterpret_cast(key)).value), comment=Box must exist))) + assert(STATE_GET_EX(concat(box, reinterpret_cast(key)).value).1) assert(concat(box, reinterpret_cast(key)).value == concat("", reinterpret_cast(key)).value) STATE_DEL(concat(box, reinterpret_cast(key)).value) assert(STATE_GET(concat(box, reinterpret_cast("" + key + "x")).value, default="b") == STATE_GET(concat("", reinterpret_cast("" + key + "x")).value, default="b")) } -subroutine testBoxRef(box: box_key): void +subroutine testBoxRef(box: box_key, length: uint64): void { - var someBytes: bytes = 0x0f0f0f0f + if (!box_length(Box["abc"].value).1 and checked_maybe(box_length(Box["abc"].value), comment=Box must exist) != length) { + box_create(Box["abc"].value, 1000) + } + var someBytes: bytes = 0xffffffff box_put(box.value, someBytes) box_put(Box["abc"].value, someBytes) box_splice(box.value, 1, 2, 0x00) box_splice(Box["abc"].value, 1, 2, 0x00) - assert(box.value == 0x0f000f0f) + assert(box.value == 0xff00ffff) } \ No newline at end of file diff --git a/tests/approvals/out/box-proxies.awst.json b/tests/approvals/out/box-proxies.awst.json index 295d6464..5697ecfc 100644 --- a/tests/approvals/out/box-proxies.awst.json +++ b/tests/approvals/out/box-proxies.awst.json @@ -4,7 +4,7 @@ "source_location": { "file": "tests/approvals/box-proxies.algo.ts", "line": 5, - "end_line": 25, + "end_line": 27, "column": 0, "end_column": 1 }, @@ -58,7 +58,7 @@ "source_location": { "file": "tests/approvals/box-proxies.algo.ts", "line": 5, - "end_line": 25, + "end_line": 27, "column": 50, "end_column": 1 }, @@ -479,15 +479,156 @@ "line": 13, "end_line": 13, "column": 2, - "end_column": 12 + "end_column": 20 }, "expr": { - "_type": "StateDelete", + "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", "line": 13, "end_line": 13, "column": 2, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "void", + "immutable": true, + "ephemeral": false, + "scalar_type": null + }, + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "ReinterpretCast", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 13, + "end_line": 13, + "column": 2, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "expr": { + "_type": "CheckedMaybe", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 13, + "end_line": 13, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 13, + "end_line": 13, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WTuple", + "name": "WTuple", + "immutable": true, + "ephemeral": false, + "scalar_type": null, + "types": [ + { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + } + ] + }, + "op_code": "box_length", + "immediates": [], + "stack_args": [ + { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 13, + "end_line": 13, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WType", + "name": "string", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 13, + "end_line": 13, + "column": 9, + "end_column": 12 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "box" + }, + "exists_assertion_message": "Box must have value" + } + ], + "comment": null + }, + "comment": "Box must exist" + } + } + ], + "comment": null + } + }, + { + "_type": "ExpressionStatement", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 15, + "end_line": 15, + "column": 2, + "end_column": 12 + }, + "expr": { + "_type": "StateDelete", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 15, + "end_line": 15, + "column": 2, "end_column": 12 }, "wtype": { @@ -501,8 +642,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 13, - "end_line": 13, + "line": 15, + "end_line": 15, "column": 2, "end_column": 12 }, @@ -517,8 +658,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 13, - "end_line": 13, + "line": 15, + "end_line": 15, "column": 2, "end_column": 5 }, @@ -539,8 +680,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 14, - "end_line": 14, + "line": 16, + "end_line": 16, "column": 2, "end_column": 13 }, @@ -548,8 +689,8 @@ "_type": "StateDelete", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 14, - "end_line": 14, + "line": 16, + "end_line": 16, "column": 2, "end_column": 13 }, @@ -564,8 +705,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 14, - "end_line": 14, + "line": 16, + "end_line": 16, "column": 2, "end_column": 13 }, @@ -603,8 +744,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 2, "end_column": 37 }, @@ -612,8 +753,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 2, "end_column": 37 }, @@ -631,8 +772,8 @@ "_type": "BooleanBinaryOperation", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 9, "end_column": 36 }, @@ -647,8 +788,8 @@ "_type": "Not", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 9, "end_column": 20 }, @@ -663,8 +804,8 @@ "_type": "StateExists", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 10, "end_column": 20 }, @@ -679,8 +820,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 10, "end_column": 20 }, @@ -695,8 +836,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 10, "end_column": 13 }, @@ -718,8 +859,8 @@ "_type": "Not", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 24, "end_column": 36 }, @@ -734,8 +875,8 @@ "_type": "StateExists", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 25, "end_column": 36 }, @@ -750,8 +891,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 15, - "end_line": 15, + "line": 17, + "end_line": 17, "column": 25, "end_column": 36 }, @@ -794,8 +935,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 17, - "end_line": 17, + "line": 19, + "end_line": 19, "column": 8, "end_column": 24 }, @@ -803,8 +944,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 17, - "end_line": 17, + "line": 19, + "end_line": 19, "column": 8, "end_column": 18 }, @@ -821,8 +962,8 @@ "_type": "StringConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 17, - "end_line": 17, + "line": 19, + "end_line": 19, "column": 21, "end_column": 24 }, @@ -840,8 +981,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 2, "end_column": 80 }, @@ -849,8 +990,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 2, "end_column": 80 }, @@ -868,8 +1009,8 @@ "_type": "BytesComparisonExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 9, "end_column": 79 }, @@ -884,8 +1025,8 @@ "_type": "StateGet", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 9, "end_column": 42 }, @@ -900,8 +1041,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 9, "end_column": 17 }, @@ -937,8 +1078,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 29, "end_column": 39 }, @@ -957,8 +1098,8 @@ "_type": "StateGet", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 47, "end_column": 79 }, @@ -973,8 +1114,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 47, "end_column": 54 }, @@ -989,8 +1130,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 47, "end_column": 50 }, @@ -1009,8 +1150,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 18, - "end_line": 18, + "line": 20, + "end_line": 20, "column": 66, "end_column": 76 }, @@ -1033,8 +1174,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 6, "end_column": 25 }, @@ -1042,8 +1183,8 @@ "_type": "TupleExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 6, "end_column": 25 }, @@ -1075,8 +1216,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 6, "end_column": 25 }, @@ -1093,8 +1234,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 9, "end_column": 10 }, @@ -1113,8 +1254,8 @@ "_type": "StateGetEx", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 14, "end_column": 25 }, @@ -1145,8 +1286,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 14, "end_column": 23 }, @@ -1161,8 +1302,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 20, - "end_line": 20, + "line": 22, + "end_line": 22, "column": 14, "end_column": 17 }, @@ -1183,8 +1324,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 21, - "end_line": 21, + "line": 23, + "end_line": 23, "column": 2, "end_column": 12 }, @@ -1192,8 +1333,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 21, - "end_line": 21, + "line": 23, + "end_line": 23, "column": 2, "end_column": 12 }, @@ -1211,8 +1352,8 @@ "_type": "Not", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 21, - "end_line": 21, + "line": 23, + "end_line": 23, "column": 9, "end_column": 11 }, @@ -1227,8 +1368,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 21, - "end_line": 21, + "line": 23, + "end_line": 23, "column": 10, "end_column": 11 }, @@ -1250,8 +1391,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 22, - "end_line": 22, + "line": 24, + "end_line": 24, "column": 2, "end_column": 19 }, @@ -1259,8 +1400,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 22, - "end_line": 22, + "line": 24, + "end_line": 24, "column": 2, "end_column": 11 }, @@ -1275,8 +1416,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 22, - "end_line": 22, + "line": 24, + "end_line": 24, "column": 2, "end_column": 5 }, @@ -1295,8 +1436,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 22, - "end_line": 22, + "line": 24, + "end_line": 24, "column": 14, "end_column": 19 }, @@ -1314,8 +1455,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 3, "end_column": 22 }, @@ -1323,8 +1464,8 @@ "_type": "TupleExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 3, "end_column": 22 }, @@ -1356,8 +1497,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 3, "end_column": 22 }, @@ -1374,8 +1515,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 6, "end_column": 7 }, @@ -1394,8 +1535,8 @@ "_type": "StateGetEx", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 11, "end_column": 22 }, @@ -1426,8 +1567,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 11, "end_column": 20 }, @@ -1442,8 +1583,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 23, - "end_line": 23, + "line": 25, + "end_line": 25, "column": 11, "end_column": 14 }, @@ -1464,8 +1605,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 24, - "end_line": 24, + "line": 26, + "end_line": 26, "column": 2, "end_column": 11 }, @@ -1473,8 +1614,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 24, - "end_line": 24, + "line": 26, + "end_line": 26, "column": 2, "end_column": 11 }, @@ -1492,8 +1633,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 24, - "end_line": 24, + "line": 26, + "end_line": 26, "column": 9, "end_column": 10 }, @@ -1527,8 +1668,8 @@ "_type": "Subroutine", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 29, - "end_line": 38, + "line": 31, + "end_line": 44, "column": 0, "end_column": 1 }, @@ -1545,8 +1686,8 @@ }, "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 29, - "end_line": 29, + "line": 31, + "end_line": 31, "column": 20, "end_column": 46 } @@ -1563,8 +1704,8 @@ }, "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 29, - "end_line": 29, + "line": 31, + "end_line": 31, "column": 48, "end_column": 59 } @@ -1581,8 +1722,8 @@ }, "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 29, - "end_line": 29, + "line": 31, + "end_line": 31, "column": 61, "end_column": 73 } @@ -1599,8 +1740,8 @@ "_type": "Block", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 29, - "end_line": 38, + "line": 31, + "end_line": 44, "column": 75, "end_column": 1 }, @@ -1609,8 +1750,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 2, "end_column": 21 }, @@ -1618,8 +1759,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 2, "end_column": 9 }, @@ -1634,8 +1775,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 2, "end_column": 9 }, @@ -1653,8 +1794,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 2, "end_column": 5 }, @@ -1671,8 +1812,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 2, "end_column": 9 }, @@ -1687,8 +1828,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 10, "end_column": 13 }, @@ -1711,8 +1852,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 30, - "end_line": 30, + "line": 32, + "end_line": 32, "column": 15, "end_column": 20 }, @@ -1730,8 +1871,8 @@ "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 2, "end_column": 24 }, @@ -1739,8 +1880,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 2, "end_column": 12 }, @@ -1755,8 +1896,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 2, "end_column": 12 }, @@ -1774,8 +1915,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 27, - "end_line": 27, + "line": 29, + "end_line": 29, "column": 50, "end_column": 52 }, @@ -1793,8 +1934,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 2, "end_column": 12 }, @@ -1809,8 +1950,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 13, "end_column": 16 }, @@ -1833,8 +1974,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 31, - "end_line": 31, + "line": 33, + "end_line": 33, "column": 18, "end_column": 23 }, @@ -1852,19 +1993,19 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 35, + "end_line": 35, "column": 2, - "end_column": 42 + "end_column": 25 }, "expr": { "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 35, + "end_line": 35, "column": 2, - "end_column": 42 + "end_column": 25 }, "wtype": { "_type": "WType", @@ -1877,13 +2018,13 @@ "immediates": [], "stack_args": [ { - "_type": "BytesComparisonExpression", + "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, - "column": 9, - "end_column": 41 + "line": 35, + "end_line": 35, + "column": 2, + "end_column": 25 }, "wtype": { "_type": "WType", @@ -1892,47 +2033,421 @@ "ephemeral": false, "scalar_type": 2 }, - "lhs": { - "_type": "BoxValueExpression", + "expr": { + "_type": "CheckedMaybe", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 35, + "end_line": 35, "column": 9, - "end_column": 16 + "end_column": 24 }, "wtype": { "_type": "WType", - "name": "bytes", + "name": "uint64", "immutable": true, "ephemeral": false, - "scalar_type": 1 + "scalar_type": 2 }, - "key": { + "expr": { "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 35, + "end_line": 35, "column": 9, - "end_column": 16 + "end_column": 24 }, "wtype": { - "_type": "WType", - "name": "box_key", + "_type": "WTuple", + "name": "WTuple", "immutable": true, "ephemeral": false, - "scalar_type": 1 - }, - "op_code": "concat", - "immediates": [], - "stack_args": [ - { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "scalar_type": null, + "types": [ + { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + } + ] + }, + "op_code": "box_length", + "immediates": [], + "stack_args": [ + { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 35, + "end_line": 35, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 35, + "end_line": 35, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "op_code": "concat", + "immediates": [], + "stack_args": [ + { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 35, + "end_line": 35, + "column": 9, + "end_column": 12 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "box" + }, + { + "_type": "ReinterpretCast", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 35, + "end_line": 35, + "column": 9, + "end_column": 19 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "expr": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 35, + "end_line": 35, + "column": 20, + "end_column": 23 + }, + "wtype": { + "_type": "WType", + "name": "string", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "key" + } + } + ], + "comment": null + }, + "exists_assertion_message": "Box must have value" + } + ], + "comment": null + }, + "comment": "Box must exist" + } + } + ], + "comment": null + } + }, + { + "_type": "ExpressionStatement", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 2, + "end_column": 27 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 2, + "end_column": 27 + }, + "wtype": { + "_type": "WType", + "name": "void", + "immutable": true, + "ephemeral": false, + "scalar_type": null + }, + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "TupleItemExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 26 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "base": { + "_type": "StateGetEx", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 23 + }, + "wtype": { + "_type": "WTuple", + "name": "WTuple", + "immutable": true, + "ephemeral": false, + "scalar_type": null, + "types": [ + { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + } + ] + }, + "field": { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 18 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 18 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "op_code": "concat", + "immediates": [], + "stack_args": [ + { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 12 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "box" + }, + { + "_type": "ReinterpretCast", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 9, + "end_column": 18 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "expr": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 37, + "end_line": 37, + "column": 19, + "end_column": 22 + }, + "wtype": { + "_type": "WType", + "name": "string", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "key" + } + } + ], + "comment": null + }, + "exists_assertion_message": "Box must have value" + } + }, + "index": "1" + } + ], + "comment": null + } + }, + { + "_type": "ExpressionStatement", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, + "column": 2, + "end_column": 42 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, + "column": 2, + "end_column": 42 + }, + "wtype": { + "_type": "WType", + "name": "void", + "immutable": true, + "ephemeral": false, + "scalar_type": null + }, + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "BytesComparisonExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, + "column": 9, + "end_column": 41 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "lhs": { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, + "column": 9, + "end_column": 16 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, + "column": 9, + "end_column": 16 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "op_code": "concat", + "immediates": [], + "stack_args": [ + { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 39, + "end_line": 39, "column": 9, "end_column": 12 }, @@ -1949,8 +2464,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 9, "end_column": 16 }, @@ -1965,8 +2480,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 17, "end_column": 20 }, @@ -1990,8 +2505,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 26, "end_column": 36 }, @@ -2006,8 +2521,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 26, "end_column": 36 }, @@ -2025,8 +2540,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 27, - "end_line": 27, + "line": 29, + "end_line": 29, "column": 50, "end_column": 52 }, @@ -2044,8 +2559,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 26, "end_column": 36 }, @@ -2060,8 +2575,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 33, - "end_line": 33, + "line": 39, + "end_line": 39, "column": 37, "end_column": 40 }, @@ -2089,8 +2604,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 17 }, @@ -2098,8 +2613,8 @@ "_type": "StateDelete", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 17 }, @@ -2114,8 +2629,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 12 }, @@ -2130,8 +2645,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 12 }, @@ -2149,8 +2664,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 5 }, @@ -2167,8 +2682,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 2, "end_column": 12 }, @@ -2183,8 +2698,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 35, - "end_line": 35, + "line": 41, + "end_line": 41, "column": 13, "end_column": 16 }, @@ -2209,8 +2724,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 2, "end_column": 104 }, @@ -2218,8 +2733,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 2, "end_column": 104 }, @@ -2237,8 +2752,8 @@ "_type": "BytesComparisonExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 103 }, @@ -2253,8 +2768,8 @@ "_type": "StateGet", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 52 }, @@ -2269,8 +2784,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 16 }, @@ -2285,8 +2800,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 16 }, @@ -2304,8 +2819,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 12 }, @@ -2322,8 +2837,8 @@ "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 9, "end_column": 16 }, @@ -2338,8 +2853,8 @@ "_type": "BytesBinaryOperation", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 17, "end_column": 26 }, @@ -2354,8 +2869,8 @@ "_type": "BytesBinaryOperation", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 17, "end_column": 26 }, @@ -2370,8 +2885,8 @@ "_type": "StringConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 17, "end_column": 26 }, @@ -2389,8 +2904,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 20, "end_column": 23 }, @@ -2409,8 +2924,8 @@ "_type": "StringConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 17, "end_column": 26 }, @@ -2434,8 +2949,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 45, "end_column": 48 }, @@ -2455,8 +2970,8 @@ "_type": "StateGet", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 57, "end_column": 103 }, @@ -2471,8 +2986,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 57, "end_column": 67 }, @@ -2487,8 +3002,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 57, "end_column": 67 }, @@ -2506,8 +3021,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 27, - "end_line": 27, + "line": 29, + "end_line": 29, "column": 50, "end_column": 52 }, @@ -2524,9 +3039,9 @@ { "_type": "ReinterpretCast", "source_location": { - "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "file": "tests/approvals/box-proxies.algo.ts", + "line": 43, + "end_line": 43, "column": 57, "end_column": 67 }, @@ -2541,8 +3056,8 @@ "_type": "BytesBinaryOperation", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 68, "end_column": 77 }, @@ -2557,8 +3072,8 @@ "_type": "BytesBinaryOperation", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 68, "end_column": 77 }, @@ -2573,8 +3088,8 @@ "_type": "StringConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 68, "end_column": 77 }, @@ -2592,8 +3107,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 71, "end_column": 74 }, @@ -2612,8 +3127,8 @@ "_type": "StringConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 68, "end_column": 77 }, @@ -2637,8 +3152,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 37, - "end_line": 37, + "line": 43, + "end_line": 43, "column": 96, "end_column": 99 }, @@ -2675,8 +3190,8 @@ "_type": "Subroutine", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 42, - "end_line": 49, + "line": 48, + "end_line": 58, "column": 0, "end_column": 1 }, @@ -2693,11 +3208,29 @@ }, "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 42, - "end_line": 42, + "line": 48, + "end_line": 48, "column": 20, "end_column": 31 } + }, + { + "_type": "SubroutineArgument", + "name": "length", + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 48, + "end_line": 48, + "column": 33, + "end_column": 47 + } } ], "return_type": { @@ -2711,18 +3244,402 @@ "_type": "Block", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 42, - "end_line": 49, - "column": 33, + "line": 48, + "end_line": 58, + "column": 49, "end_column": 1 }, "body": [ + { + "_type": "IfElse", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 51, + "column": 2, + "end_column": 3 + }, + "condition": { + "_type": "BooleanBinaryOperation", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 6, + "end_column": 48 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "left": { + "_type": "Not", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 6, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "expr": { + "_type": "TupleItemExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 7, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "base": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 7, + "end_column": 20 + }, + "wtype": { + "_type": "WTuple", + "name": "WTuple", + "immutable": true, + "ephemeral": false, + "scalar_type": null, + "types": [ + { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + } + ] + }, + "op_code": "box_length", + "immediates": [], + "stack_args": [ + { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 7, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 46, + "end_line": 46, + "column": 29, + "end_column": 34 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "VPaz", + "encoding": "utf8" + }, + "exists_assertion_message": "Box must have value" + } + ], + "comment": null + }, + "index": "1" + } + }, + "op": "and", + "right": { + "_type": "NumericComparisonExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 24, + "end_column": 48 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "lhs": { + "_type": "CheckedMaybe", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 24, + "end_column": 37 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 24, + "end_column": 37 + }, + "wtype": { + "_type": "WTuple", + "name": "WTuple", + "immutable": true, + "ephemeral": false, + "scalar_type": null, + "types": [ + { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + } + ] + }, + "op_code": "box_length", + "immediates": [], + "stack_args": [ + { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 24, + "end_column": 37 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 46, + "end_line": 46, + "column": 29, + "end_column": 34 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "VPaz", + "encoding": "utf8" + }, + "exists_assertion_message": "Box must have value" + } + ], + "comment": null + }, + "comment": "Box must exist" + }, + "operator": "!=", + "rhs": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 49, + "column": 42, + "end_column": 48 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "length" + } + } + }, + "if_branch": { + "_type": "Block", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 51, + "column": 50, + "end_column": 3 + }, + "body": [ + { + "_type": "Block", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 49, + "end_line": 51, + "column": 50, + "end_column": 3 + }, + "body": [ + { + "_type": "ExpressionStatement", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 50, + "end_line": 50, + "column": 4, + "end_column": 33 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 50, + "end_line": 50, + "column": 4, + "end_column": 33 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "op_code": "box_create", + "immediates": [], + "stack_args": [ + { + "_type": "BoxValueExpression", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 50, + "end_line": 50, + "column": 4, + "end_column": 17 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "key": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 46, + "end_line": 46, + "column": 29, + "end_column": 34 + }, + "wtype": { + "_type": "WType", + "name": "box_key", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "VPaz", + "encoding": "utf8" + }, + "exists_assertion_message": "Box must have value" + }, + { + "_type": "IntegerConstant", + "source_location": { + "file": "tests/approvals/box-proxies.algo.ts", + "line": 50, + "end_line": 50, + "column": 26, + "end_column": 30 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "value": "1000", + "teal_alias": null + } + ], + "comment": null + } + } + ], + "label": null, + "comment": null + } + ], + "label": null, + "comment": null + }, + "else_branch": null + }, { "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 43, - "end_line": 43, + "line": 52, + "end_line": 52, "column": 8, "end_column": 45 }, @@ -2730,8 +3647,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 43, - "end_line": 43, + "line": 52, + "end_line": 52, "column": 8, "end_column": 17 }, @@ -2748,8 +3665,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 43, - "end_line": 43, + "line": 52, + "end_line": 52, "column": 20, "end_column": 45 }, @@ -2760,7 +3677,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "4-XFy", + "value": "|NsC0", "encoding": "base16" } }, @@ -2768,8 +3685,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 44, - "end_line": 44, + "line": 53, + "end_line": 53, "column": 2, "end_column": 20 }, @@ -2777,8 +3694,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 44, - "end_line": 44, + "line": 53, + "end_line": 53, "column": 2, "end_column": 20 }, @@ -2796,8 +3713,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 44, - "end_line": 44, + "line": 53, + "end_line": 53, "column": 2, "end_column": 9 }, @@ -2812,8 +3729,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 44, - "end_line": 44, + "line": 53, + "end_line": 53, "column": 2, "end_column": 5 }, @@ -2832,8 +3749,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 44, - "end_line": 44, + "line": 53, + "end_line": 53, "column": 10, "end_column": 19 }, @@ -2854,8 +3771,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 45, - "end_line": 45, + "line": 54, + "end_line": 54, "column": 2, "end_column": 23 }, @@ -2863,8 +3780,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 45, - "end_line": 45, + "line": 54, + "end_line": 54, "column": 2, "end_column": 23 }, @@ -2882,8 +3799,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 45, - "end_line": 45, + "line": 54, + "end_line": 54, "column": 2, "end_column": 12 }, @@ -2898,8 +3815,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 40, - "end_line": 40, + "line": 46, + "end_line": 46, "column": 29, "end_column": 34 }, @@ -2919,8 +3836,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 45, - "end_line": 45, + "line": 54, + "end_line": 54, "column": 13, "end_column": 22 }, @@ -2941,8 +3858,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 2, "end_column": 39 }, @@ -2950,8 +3867,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 2, "end_column": 39 }, @@ -2969,8 +3886,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 2, "end_column": 12 }, @@ -2985,8 +3902,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 2, "end_column": 5 }, @@ -3005,8 +3922,8 @@ "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 13, "end_column": 14 }, @@ -3024,8 +3941,8 @@ "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 16, "end_column": 17 }, @@ -3043,8 +3960,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 46, - "end_line": 46, + "line": 55, + "end_line": 55, "column": 19, "end_column": 38 }, @@ -3066,8 +3983,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 2, "end_column": 42 }, @@ -3075,8 +3992,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 2, "end_column": 42 }, @@ -3094,8 +4011,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 2, "end_column": 15 }, @@ -3110,8 +4027,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 40, - "end_line": 40, + "line": 46, + "end_line": 46, "column": 29, "end_column": 34 }, @@ -3131,8 +4048,8 @@ "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 16, "end_column": 17 }, @@ -3150,8 +4067,8 @@ "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 19, "end_column": 20 }, @@ -3169,8 +4086,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 47, - "end_line": 47, + "line": 56, + "end_line": 56, "column": 22, "end_column": 41 }, @@ -3192,8 +4109,8 @@ "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 2, "end_column": 49 }, @@ -3201,8 +4118,8 @@ "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 2, "end_column": 49 }, @@ -3220,8 +4137,8 @@ "_type": "BytesComparisonExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 9, "end_column": 48 }, @@ -3236,8 +4153,8 @@ "_type": "BoxValueExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 9, "end_column": 18 }, @@ -3252,8 +4169,8 @@ "_type": "VarExpression", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 9, "end_column": 12 }, @@ -3273,8 +4190,8 @@ "_type": "BytesConstant", "source_location": { "file": "tests/approvals/box-proxies.algo.ts", - "line": 48, - "end_line": 48, + "line": 57, + "end_line": 57, "column": 23, "end_column": 48 }, @@ -3285,7 +4202,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "4*(Aj", + "value": "{{a90", "encoding": "base16" } } From 5ee11cb1878f27c4e045307746cb75570bb787ae Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 10:08:03 -0700 Subject: [PATCH 2/8] fix: biguint construction from uint64 and conversion to bytes --- .../eb/biguint-expression-builder.ts | 15 +++-- .../out/boolean-conversions.awst.json | 16 ++--- tests/approvals/out/byte-expressions.awst | 4 +- .../approvals/out/byte-expressions.awst.json | 66 +++++++++++-------- tests/approvals/out/itxn.awst | 2 +- tests/approvals/out/itxn.awst.json | 4 +- tests/approvals/out/switch-statements.awst | 4 +- .../approvals/out/switch-statements.awst.json | 2 +- 8 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/awst_build/eb/biguint-expression-builder.ts b/src/awst_build/eb/biguint-expression-builder.ts index 8617a81d..c2700258 100644 --- a/src/awst_build/eb/biguint-expression-builder.ts +++ b/src/awst_build/eb/biguint-expression-builder.ts @@ -4,6 +4,7 @@ import { nodeFactory } from '../../awst/node-factory' import type { Expression } from '../../awst/nodes' import { BigUIntBinaryOperator, BigUIntPostfixUnaryOperator, IntegerConstant, NumericComparison } from '../../awst/nodes' import type { SourceLocation } from '../../awst/source-location' +import { bytesWType } from '../../awst/wtypes' import { NotSupported } from '../../errors' import { logger } from '../../logger' import { tryConvertEnum } from '../../util' @@ -65,13 +66,15 @@ export class BigUintFunctionBuilder extends FunctionBuilder { if (expr instanceof IntegerConstant) { biguint = nodeFactory.bigUIntConstant({ ...expr, + sourceLocation, + }) + } else { + biguint = nodeFactory.reinterpretCast({ + expr: initialValue.toBytes(sourceLocation), + sourceLocation, + wtype: biguintPType.wtype, }) } - biguint = nodeFactory.reinterpretCast({ - expr: initialValue.toBytes(sourceLocation), - sourceLocation, - wtype: biguintPType.wtype, - }) } else { return initialValue } @@ -204,6 +207,6 @@ export class BigUintExpressionBuilder extends InstanceExpressionBuilder(itob(b)) == b) + assert(reinterpret_cast(256) == 0x0100) + assert(reinterpret_cast(reinterpret_cast(b)) == b) assert(reinterpret_cast(reinterpret_cast(c)) == c) assert("123" == "123") assert(0x01020304 == 0x01020304) diff --git a/tests/approvals/out/byte-expressions.awst.json b/tests/approvals/out/byte-expressions.awst.json index 5ecc4eaf..99703c9a 100644 --- a/tests/approvals/out/byte-expressions.awst.json +++ b/tests/approvals/out/byte-expressions.awst.json @@ -454,7 +454,7 @@ "scalar_type": 2 }, "lhs": { - "_type": "BytesConstant", + "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", "line": 8, @@ -469,8 +469,25 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "0RR", - "encoding": "base16" + "expr": { + "_type": "IntegerConstant", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 8, + "end_line": 8, + "column": 15, + "end_column": 27 + }, + "wtype": { + "_type": "WType", + "name": "biguint", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "256", + "teal_alias": null + } }, "operator": "==", "rhs": { @@ -558,7 +575,7 @@ "scalar_type": 1 }, "expr": { - "_type": "IntrinsicCall", + "_type": "ReinterpretCast", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", "line": 9, @@ -573,29 +590,24 @@ "ephemeral": false, "scalar_type": 1 }, - "op_code": "itob", - "immediates": [], - "stack_args": [ - { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/byte-expressions.algo.ts", - "line": 9, - "end_line": 9, - "column": 23, - "end_column": 24 - }, - "wtype": { - "_type": "WType", - "name": "biguint", - "immutable": true, - "ephemeral": false, - "scalar_type": 1 - }, - "name": "b" - } - ], - "comment": null + "expr": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 9, + "end_line": 9, + "column": 23, + "end_column": 24 + }, + "wtype": { + "_type": "WType", + "name": "biguint", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "b" + } } }, "operator": "==", diff --git a/tests/approvals/out/itxn.awst b/tests/approvals/out/itxn.awst index e2484dde..1e9edc7f 100644 --- a/tests/approvals/out/itxn.awst +++ b/tests/approvals/out/itxn.awst @@ -45,7 +45,7 @@ contract ItxnDemoContract extends @algorandfoundation/algorand-typescript/base-c assert(asset2_txn.ConfigAssetName == "AST2") assert(checked_maybe(asset_params_get(asset1_txn.CreatedAssetID), comment=asset exists) == "AST1") assert(checked_maybe(asset_params_get(asset2_txn.CreatedAssetID), comment=asset exists) == "AST2") - var appCreateParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApprovalProgram=0x000800, ClearStateProgram=0x000800) + var appCreateParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApprovalProgram=0x098101, ClearStateProgram=0x098101) update_inner_transaction(assetParams, ConfigAssetName="AST3") var [appCreateTxn, asset3_txn]: tuple[inner_transaction_appl, inner_transaction_acfg] = submit_txn(appCreateParams, assetParams) assert(Boolean(appCreateTxn.ApplicationID)) diff --git a/tests/approvals/out/itxn.awst.json b/tests/approvals/out/itxn.awst.json index 1d0434e0..e9d6b0da 100644 --- a/tests/approvals/out/itxn.awst.json +++ b/tests/approvals/out/itxn.awst.json @@ -1898,7 +1898,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "00;m", + "value": "34s9", "encoding": "base16" }, "ClearStateProgram": { @@ -1917,7 +1917,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "00;m", + "value": "34s9", "encoding": "base16" } } diff --git a/tests/approvals/out/switch-statements.awst b/tests/approvals/out/switch-statements.awst index b2506fc2..c48b3f7c 100644 --- a/tests/approvals/out/switch-statements.awst +++ b/tests/approvals/out/switch-statements.awst @@ -42,13 +42,13 @@ subroutine test_bytes(x: bytes): bytes case "hmmm": #switch₁ᶜ₀: goto #switch₁ᶜ₁ - case 0x0f: + case 0xff: #switch₁ᶜ₁: goto #switch₁ᶜ₂ case b64: #switch₁ᶜ₂: goto #switch₁ᶜ₃ - case b32: + case b32: #switch₁ᶜ₃: return x } diff --git a/tests/approvals/out/switch-statements.awst.json b/tests/approvals/out/switch-statements.awst.json index 0c0423cb..75ad59ff 100644 --- a/tests/approvals/out/switch-statements.awst.json +++ b/tests/approvals/out/switch-statements.awst.json @@ -1084,7 +1084,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "4*", + "value": "{{", "encoding": "base16" }, { From 6d5fb6978c75a2791a788cd2c3d13e3844a03541 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 10:26:23 -0700 Subject: [PATCH 3/8] refactor: Simplify reinterpret casts of constant values --- src/awst/node-factory.ts | 25 ++++++- tests/approvals/out/assert-match.awst | 2 +- tests/approvals/out/assert-match.awst.json | 23 +------ tests/approvals/out/boolean-conversions.awst | 4 +- .../out/boolean-conversions.awst.json | 69 +++---------------- tests/approvals/out/byte-expressions.awst | 2 +- .../approvals/out/byte-expressions.awst.json | 23 +------ 7 files changed, 43 insertions(+), 105 deletions(-) diff --git a/src/awst/node-factory.ts b/src/awst/node-factory.ts index cec1d412..09b50823 100644 --- a/src/awst/node-factory.ts +++ b/src/awst/node-factory.ts @@ -21,6 +21,7 @@ import { MethodDocumentation, Not, NumericComparisonExpression, + ReinterpretCast, SingleEvaluation, StringConstant, TupleExpression, @@ -237,7 +238,29 @@ const explicitNodeFactory = { wtype: props.base.wtype.types[Number(props.index)], }) }, -} satisfies { [key in keyof ConcreteNodes]?: (...args: DeliberateAny[]) => InstanceType } + reinterpretCast({ expr, wtype, sourceLocation }: { expr: Expression; wtype: WType; sourceLocation: SourceLocation }) { + if (expr instanceof BytesConstant) { + return new BytesConstant({ + ...expr, + wtype, + sourceLocation, + }) + } + if (expr instanceof IntegerConstant) { + return new IntegerConstant({ + ...expr, + wtype, + sourceLocation, + }) + } + + return new ReinterpretCast({ + expr, + wtype, + sourceLocation, + }) + }, +} satisfies { [key in keyof ConcreteNodes]?: (...args: DeliberateAny[]) => DeliberateAny } type ExplicitNodeFactory = typeof explicitNodeFactory diff --git a/tests/approvals/out/assert-match.awst b/tests/approvals/out/assert-match.awst index 790b884c..92b9b551 100644 --- a/tests/approvals/out/assert-match.awst +++ b/tests/approvals/out/assert-match.awst @@ -11,7 +11,7 @@ contract AssertMatchContract extends @algorandfoundation/algorand-typescript/bas approvalProgram(): bool { - var txn: group_transaction_pay = reinterpret_cast(1) + var txn: group_transaction_pay = 1 tests/approvals/assert-match.algo.ts::test(txn) return True } diff --git a/tests/approvals/out/assert-match.awst.json b/tests/approvals/out/assert-match.awst.json index 905d16aa..857df3f3 100644 --- a/tests/approvals/out/assert-match.awst.json +++ b/tests/approvals/out/assert-match.awst.json @@ -911,7 +911,7 @@ "name": "txn" }, "value": { - "_type": "ReinterpretCast", + "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/assert-match.algo.ts", "line": 16, @@ -927,25 +927,8 @@ "scalar_type": 2, "transaction_type": 1 }, - "expr": { - "_type": "IntegerConstant", - "source_location": { - "file": "tests/approvals/assert-match.algo.ts", - "line": 16, - "end_line": 16, - "column": 32, - "end_column": 33 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "value": "1", - "teal_alias": null - } + "value": "1", + "teal_alias": null } }, { diff --git a/tests/approvals/out/boolean-conversions.awst b/tests/approvals/out/boolean-conversions.awst index 5f3daedc..f4b32fc8 100644 --- a/tests/approvals/out/boolean-conversions.awst +++ b/tests/approvals/out/boolean-conversions.awst @@ -3,7 +3,7 @@ subroutine test_truthyness(a: uint64, b: uint64, c: string, d: bytes, e: uint64) assert(True) assert(True) assert(!0) - assert(Boolean(1)) + assert(1) assert(!bitlen(0)) assert(Boolean(bitlen(1))) assert(!len(0x)) @@ -16,7 +16,7 @@ subroutine test_truthyness(a: uint64, b: uint64, c: string, d: bytes, e: uint64) subroutine test_booleans_are_equal(): void { assert(!!True == !!True) - assert(!!Boolean(1) == !!Boolean(5)) + assert(!!1 == !!5) assert(!!Boolean(bitlen(1)) == !!Boolean(bitlen(5))) assert("abc" != 0x == "abcdef" != 0x) assert("abc" != 0x == "abcdef" != 0x) diff --git a/tests/approvals/out/boolean-conversions.awst.json b/tests/approvals/out/boolean-conversions.awst.json index fa670507..f456e8b0 100644 --- a/tests/approvals/out/boolean-conversions.awst.json +++ b/tests/approvals/out/boolean-conversions.awst.json @@ -314,7 +314,7 @@ "immediates": [], "stack_args": [ { - "_type": "ReinterpretCast", + "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 8, @@ -329,25 +329,8 @@ "ephemeral": false, "scalar_type": 2 }, - "expr": { - "_type": "IntegerConstant", - "source_location": { - "file": "tests/approvals/boolean-conversions.algo.ts", - "line": 8, - "end_line": 8, - "column": 16, - "end_column": 17 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "value": "1", - "teal_alias": null - } + "value": "1", + "teal_alias": null } ], "comment": "Non zero is truthy" @@ -1279,7 +1262,7 @@ "scalar_type": 2 }, "expr": { - "_type": "ReinterpretCast", + "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 23, @@ -1294,25 +1277,8 @@ "ephemeral": false, "scalar_type": 2 }, - "expr": { - "_type": "IntegerConstant", - "source_location": { - "file": "tests/approvals/boolean-conversions.algo.ts", - "line": 23, - "end_line": 23, - "column": 24, - "end_column": 25 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "value": "1", - "teal_alias": null - } + "value": "1", + "teal_alias": null } } }, @@ -1350,7 +1316,7 @@ "scalar_type": 2 }, "expr": { - "_type": "ReinterpretCast", + "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 23, @@ -1365,25 +1331,8 @@ "ephemeral": false, "scalar_type": 2 }, - "expr": { - "_type": "IntegerConstant", - "source_location": { - "file": "tests/approvals/boolean-conversions.algo.ts", - "line": 23, - "end_line": 23, - "column": 47, - "end_column": 48 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "value": "5", - "teal_alias": null - } + "value": "5", + "teal_alias": null } } } diff --git a/tests/approvals/out/byte-expressions.awst b/tests/approvals/out/byte-expressions.awst index b305d34f..b440d55c 100644 --- a/tests/approvals/out/byte-expressions.awst +++ b/tests/approvals/out/byte-expressions.awst @@ -3,7 +3,7 @@ subroutine test(a: uint64, b: biguint, c: string): void assert(len(0x) == 0) assert(itob(a) == itob(a)) assert(0x01 == 0x0000000000000001) - assert(reinterpret_cast(256) == 0x0100) + assert(256 == 0x0100) assert(reinterpret_cast(reinterpret_cast(b)) == b) assert(reinterpret_cast(reinterpret_cast(c)) == c) assert("123" == "123") diff --git a/tests/approvals/out/byte-expressions.awst.json b/tests/approvals/out/byte-expressions.awst.json index 99703c9a..a591fe37 100644 --- a/tests/approvals/out/byte-expressions.awst.json +++ b/tests/approvals/out/byte-expressions.awst.json @@ -454,7 +454,7 @@ "scalar_type": 2 }, "lhs": { - "_type": "ReinterpretCast", + "_type": "IntegerConstant", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", "line": 8, @@ -469,25 +469,8 @@ "ephemeral": false, "scalar_type": 1 }, - "expr": { - "_type": "IntegerConstant", - "source_location": { - "file": "tests/approvals/byte-expressions.algo.ts", - "line": 8, - "end_line": 8, - "column": 15, - "end_column": 27 - }, - "wtype": { - "_type": "WType", - "name": "biguint", - "immutable": true, - "ephemeral": false, - "scalar_type": 1 - }, - "value": "256", - "teal_alias": null - } + "value": "256", + "teal_alias": null }, "operator": "==", "rhs": { From 967dcf9195ad69034519784e2c3b0ee12d1a7e6c Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 10:26:55 -0700 Subject: [PATCH 4/8] refactor: Simplify expression statement of assignment expression to assignment statement --- src/awst/node-factory.ts | 6 ++++++ src/awst_build/base-visitor.ts | 9 +-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/awst/node-factory.ts b/src/awst/node-factory.ts index 09b50823..036b8747 100644 --- a/src/awst/node-factory.ts +++ b/src/awst/node-factory.ts @@ -137,6 +137,12 @@ const explicitNodeFactory = { }) }, expressionStatement({ expr }: { expr: Expression }) { + if (expr instanceof AssignmentExpression) { + return new AssignmentStatement({ + ...expr, + }) + } + return new ExpressionStatement({ expr, sourceLocation: expr.sourceLocation, diff --git a/src/awst_build/base-visitor.ts b/src/awst_build/base-visitor.ts index c2176c83..8c7aae10 100644 --- a/src/awst_build/base-visitor.ts +++ b/src/awst_build/base-visitor.ts @@ -1,5 +1,4 @@ import ts from 'typescript' -import { awst } from '../awst' import { nodeFactory } from '../awst/node-factory' import type { Expression, LValue, Statement } from '../awst/nodes' import type { SourceLocation } from '../awst/source-location' @@ -453,13 +452,7 @@ export abstract class BaseVisitor implements Visitor { } handleAssignmentStatement(target: InstanceBuilder, source: InstanceBuilder, sourceLocation: SourceLocation): Statement { - const expr = this.handleAssignment(target, source, sourceLocation).resolve() - if (expr instanceof awst.AssignmentExpression) { - return nodeFactory.assignmentStatement({ - ...expr, - }) - } - return nodeFactory.expressionStatement({ expr }) + return nodeFactory.expressionStatement({ expr: this.handleAssignment(target, source, sourceLocation).resolve() }) } handleAssignment(target: InstanceBuilder, source: InstanceBuilder, sourceLocation: SourceLocation): InstanceBuilder { From 3c553fa04990651bc3491c16aac4213a58c87d98 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 13:32:45 -0700 Subject: [PATCH 5/8] feat: Support Boolean() with no args --- .../eb/boolean-expression-builder.ts | 20 +++++++++++++------ tests/approvals/boolean-conversions.algo.ts | 7 +++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/awst_build/eb/boolean-expression-builder.ts b/src/awst_build/eb/boolean-expression-builder.ts index 56adeb73..0eae49e4 100644 --- a/src/awst_build/eb/boolean-expression-builder.ts +++ b/src/awst_build/eb/boolean-expression-builder.ts @@ -4,18 +4,29 @@ import { nodeFactory } from '../../awst/node-factory' import type { Expression } from '../../awst/nodes' import { EqualityComparison, NumericComparison } from '../../awst/nodes' import type { SourceLocation } from '../../awst/source-location' -import { CodeError } from '../../errors' import { codeInvariant, tryConvertEnum } from '../../util' import type { InstanceType, PType } from '../ptypes' import { boolPType, bytesPType, stringPType } from '../ptypes' import type { InstanceBuilder, NodeBuilder } from './index' import { BuilderComparisonOp, FunctionBuilder, InstanceExpressionBuilder } from './index' +import { parseFunctionArgs } from './util/arg-parsing' export class BooleanFunctionBuilder extends FunctionBuilder { call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { - if (args.length !== 1) throw CodeError.unexpectedUnhandledArgs({ sourceLocation }) + const { + args: [value], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + callLocation: sourceLocation, + funcName: 'Boolean', + argSpec: (a) => [a.optional()], + }) + if (!value) { + return new BooleanExpressionBuilder(nodeFactory.boolConstant({ value: false, sourceLocation })) + } - const [value] = args if (value.ptype.equals(boolPType)) { return value } @@ -38,9 +49,6 @@ export class BooleanFunctionBuilder extends FunctionBuilder { }), ) } else { - // TODO: See if there's a better way to do this. boolEval only returns a truthy/falsy value - // Whilst 1 and 5 for example are both truthy, they are not equal - // and we expect Boolean(1) to equal Boolean(5) return new BooleanExpressionBuilder( nodeFactory.not({ sourceLocation, diff --git a/tests/approvals/boolean-conversions.algo.ts b/tests/approvals/boolean-conversions.algo.ts index e5359576..5e783ae7 100644 --- a/tests/approvals/boolean-conversions.algo.ts +++ b/tests/approvals/boolean-conversions.algo.ts @@ -10,8 +10,8 @@ function test_truthyness(a: uint64, b: uint64, c: string, d: bytes, e: uint64) { assert(BigUint(1), 'Non zero is truthy') assert(!Bytes(), 'Empty is falsy') assert(Bytes('abc'), 'Non empty is truthy') - // @ts-expect-error 2873 - assert(!'', 'Empty is falsy') + const empty = '' + assert(!empty, 'Empty is falsy') assert('abc', 'Non empty is truthy') assert(!false, 'False is falsy') assert(true, 'True is truthy') @@ -25,4 +25,7 @@ function test_booleans_are_equal() { assert(Boolean(Bytes('abc')) === Boolean(Bytes('abcdef'))) // eslint-disable-next-line no-constant-binary-expression assert(Boolean('abc') === Boolean('abcdef')) + + const boolNoArgs = Boolean() + assert(!boolNoArgs) } From 83ba48048f2d4de7ff2bcd2c7188c24ac59ee3c4 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 14:16:50 -0700 Subject: [PATCH 6/8] chore: Remove 'var' from awst to code visitor --- src/awst/to-code-visitor.ts | 4 +- tests/approvals/out/abi-decorators.awst | 2 +- tests/approvals/out/arc4-types.awst | 20 +- tests/approvals/out/array-destructuring.awst | 12 +- tests/approvals/out/array-literals.awst | 12 +- tests/approvals/out/assert-match.awst | 2 +- tests/approvals/out/boolean-conversions.awst | 5 +- .../out/boolean-conversions.awst.json | 177 ++++++++- tests/approvals/out/boolean-expressions.awst | 8 +- tests/approvals/out/box-proxies.awst | 18 +- .../approvals/out/conditional-expression.awst | 12 +- tests/approvals/out/destructured-params.awst | 8 +- tests/approvals/out/do-loops.awst | 4 +- tests/approvals/out/for-loops.awst | 36 +- tests/approvals/out/for-loops.awst.json | 355 +++++++----------- tests/approvals/out/for-of-loops.awst | 4 +- tests/approvals/out/global-state.awst | 12 +- tests/approvals/out/inheritance-b.awst | 4 +- tests/approvals/out/intrinsic-calls.awst | 4 +- tests/approvals/out/itxn.awst | 24 +- tests/approvals/out/local-state.awst | 12 +- tests/approvals/out/named-types.awst | 6 +- tests/approvals/out/non-arc4.awst | 2 +- .../out/numeric-literal-expressions.awst | 12 +- tests/approvals/out/object-destructuring.awst | 14 +- .../out/prefix-postfix-operators.awst | 12 +- tests/approvals/out/shadowed-variables.awst | 2 +- tests/approvals/out/switch-statements.awst | 6 +- tests/approvals/out/while-loops.awst | 4 +- 29 files changed, 434 insertions(+), 359 deletions(-) diff --git a/src/awst/to-code-visitor.ts b/src/awst/to-code-visitor.ts index 58eea284..0035c4cb 100644 --- a/src/awst/to-code-visitor.ts +++ b/src/awst/to-code-visitor.ts @@ -243,8 +243,6 @@ export class ToCodeVisitor } visitStateGetEx(expression: nodes.StateGetEx): string { return `STATE_GET_EX(${expression.field.accept(this)})` - - throw new TodoError('Method not implemented.', { sourceLocation: expression.sourceLocation }) } visitStateExists(expression: nodes.StateExists): string { return `STATE_EXISTS(${expression.field.accept(this)})` @@ -282,7 +280,7 @@ export class ToCodeVisitor return [`return ${statement.value?.accept(this) ?? ''}`] } visitAssignmentStatement(statement: nodes.AssignmentStatement): string[] { - return [`var ${statement.target.accept(this)}: ${statement.target.wtype} = ${statement.value.accept(this)}`] + return [`${statement.target.accept(this)}: ${statement.target.wtype} = ${statement.value.accept(this)}`] } visitUInt64AugmentedAssignment(statement: nodes.UInt64AugmentedAssignment): string[] { throw new TodoError('Method not implemented.', { sourceLocation: statement.sourceLocation }) diff --git a/tests/approvals/out/abi-decorators.awst b/tests/approvals/out/abi-decorators.awst index bffcb8a0..0fe6d559 100644 --- a/tests/approvals/out/abi-decorators.awst +++ b/tests/approvals/out/abi-decorators.awst @@ -6,7 +6,7 @@ contract AbiDecorators extends @algorandfoundation/algorand-typescript/arc4/inde constructor(): void { void - var GlobalState["globalValue"]: uint64 = 123 + GlobalState["globalValue"]: uint64 = 123 } justNoop(): void diff --git a/tests/approvals/out/arc4-types.awst b/tests/approvals/out/arc4-types.awst index fcc03f3c..46b0e438 100644 --- a/tests/approvals/out/arc4-types.awst +++ b/tests/approvals/out/arc4-types.awst @@ -1,18 +1,18 @@ subroutine test(n: uint64, b: biguint, c: arc4.uint256): void { - var x: arc4.uint8 = 0x04 - var x2: arc4.uint8 = 0xff - var y: arc4.uint16 = 0x00 - var z: arc4.uint8 = ARC4_ENCODE(n, wtype=arc4.uint8) - var z_native: uint64 = btoi(z) - var a: arc4.uint128 = ARC4_ENCODE(b, wtype=arc4.uint128) - var a_native: biguint = reinterpret_cast(a) + x: arc4.uint8 = 0x04 + x2: arc4.uint8 = 0xff + y: arc4.uint16 = 0x00 + z: arc4.uint8 = ARC4_ENCODE(n, wtype=arc4.uint8) + z_native: uint64 = btoi(z) + a: arc4.uint128 = ARC4_ENCODE(b, wtype=arc4.uint128) + a_native: biguint = reinterpret_cast(a) } subroutine test_arrays(n: arc4.uint64): void { - var myArray: arc4.dynamic_array = new arc4.dynamic_array(n, n, n) - var myStatic: arc4.static_array = new arc4.static_array(n, n) - var myStatic2: arc4.static_array = new arc4.static_array(n, n, n) + myArray: arc4.dynamic_array = new arc4.dynamic_array(n, n, n) + myStatic: arc4.static_array = new arc4.static_array(n, n) + myStatic2: arc4.static_array = new arc4.static_array(n, n, n) } contract Arc4TypesTestContract extends @algorandfoundation/algorand-typescript/base-contract.d.ts::BaseContract { diff --git a/tests/approvals/out/array-destructuring.awst b/tests/approvals/out/array-destructuring.awst index d69bf158..3e0666a3 100644 --- a/tests/approvals/out/array-destructuring.awst +++ b/tests/approvals/out/array-destructuring.awst @@ -1,8 +1,8 @@ subroutine test(): void { - var [a, b, c, d]: tuple[uint64, bytes, bool, biguint] = tests/approvals/array-destructuring.algo.ts::produceItems() - var [_, _₁, e, _₂]: tuple[uint64, bytes, bool, biguint] = tests/approvals/array-destructuring.algo.ts::produceItems() - var f: tuple[uint64, bytes, bool, biguint] = ([g, _₃, _₄, i] = tests/approvals/array-destructuring.algo.ts::produceItems()) + [a, b, c, d]: tuple[uint64, bytes, bool, biguint] = tests/approvals/array-destructuring.algo.ts::produceItems() + [_, _₁, e, _₂]: tuple[uint64, bytes, bool, biguint] = tests/approvals/array-destructuring.algo.ts::produceItems() + f: tuple[uint64, bytes, bool, biguint] = ([g, _₃, _₄, i] = tests/approvals/array-destructuring.algo.ts::produceItems()) } subroutine produceItems(): tuple[uint64, bytes, bool, biguint] { @@ -10,9 +10,9 @@ subroutine produceItems(): tuple[uint64, bytes, bool, biguint] } subroutine testLiteralDestructuring(): void { - var a: uint64 = 1 - var b: uint64 = 2 - var [x, y]: tuple[uint64, uint64] = ([b, a] = [a, b]) + a: uint64 = 1 + b: uint64 = 2 + [x, y]: tuple[uint64, uint64] = ([b, a] = [a, b]) assert(x == b) assert(y == a) } \ No newline at end of file diff --git a/tests/approvals/out/array-literals.awst b/tests/approvals/out/array-literals.awst index 1bb1a702..b4a72725 100644 --- a/tests/approvals/out/array-literals.awst +++ b/tests/approvals/out/array-literals.awst @@ -1,9 +1,9 @@ subroutine test(a: uint64, b: uint64): void { - var inferTuple: readonlytuple[uint64, uint64] = [a, b] - var explicitTuple: tuple[uint64, uint64] = [a, b] - var conditionalExplicitTuple: tuple[uint64, uint64] = (a < b ? [a, b] : [b, a]) - var [c, d]: tuple[uint64, uint64] = [a, b] - var [_, g]: tuple[uint64, uint64] = [a, b] - var [h, _₁]: tuple[uint64, uint64] = [a, b] + inferTuple: readonlytuple[uint64, uint64] = [a, b] + explicitTuple: tuple[uint64, uint64] = [a, b] + conditionalExplicitTuple: tuple[uint64, uint64] = (a < b ? [a, b] : [b, a]) + [c, d]: tuple[uint64, uint64] = [a, b] + [_, g]: tuple[uint64, uint64] = [a, b] + [h, _₁]: tuple[uint64, uint64] = [a, b] } \ No newline at end of file diff --git a/tests/approvals/out/assert-match.awst b/tests/approvals/out/assert-match.awst index 92b9b551..7aad9643 100644 --- a/tests/approvals/out/assert-match.awst +++ b/tests/approvals/out/assert-match.awst @@ -11,7 +11,7 @@ contract AssertMatchContract extends @algorandfoundation/algorand-typescript/bas approvalProgram(): bool { - var txn: group_transaction_pay = 1 + txn: group_transaction_pay = 1 tests/approvals/assert-match.algo.ts::test(txn) return True } diff --git a/tests/approvals/out/boolean-conversions.awst b/tests/approvals/out/boolean-conversions.awst index f4b32fc8..18e3abd6 100644 --- a/tests/approvals/out/boolean-conversions.awst +++ b/tests/approvals/out/boolean-conversions.awst @@ -8,7 +8,8 @@ subroutine test_truthyness(a: uint64, b: uint64, c: string, d: bytes, e: uint64) assert(Boolean(bitlen(1))) assert(!len(0x)) assert(Boolean(len("abc"))) - assert(!len("")) + empty: string = "" + assert(!len(empty)) assert(Boolean(len("abc"))) assert(!False) assert(True) @@ -20,4 +21,6 @@ subroutine test_booleans_are_equal(): void assert(!!Boolean(bitlen(1)) == !!Boolean(bitlen(5))) assert("abc" != 0x == "abcdef" != 0x) assert("abc" != 0x == "abcdef" != 0x) + boolNoArgs: bool = False + assert(!boolNoArgs) } \ No newline at end of file diff --git a/tests/approvals/out/boolean-conversions.awst.json b/tests/approvals/out/boolean-conversions.awst.json index f456e8b0..b433e96f 100644 --- a/tests/approvals/out/boolean-conversions.awst.json +++ b/tests/approvals/out/boolean-conversions.awst.json @@ -696,6 +696,52 @@ "comment": "Non empty is truthy" } }, + { + "_type": "AssignmentStatement", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 13, + "end_line": 13, + "column": 8, + "end_column": 18 + }, + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 13, + "end_line": 13, + "column": 8, + "end_column": 13 + }, + "wtype": { + "_type": "WType", + "name": "string", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "name": "empty" + }, + "value": { + "_type": "StringConstant", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 13, + "end_line": 13, + "column": 16, + "end_column": 18 + }, + "wtype": { + "_type": "WType", + "name": "string", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "" + } + }, { "_type": "ExpressionStatement", "source_location": { @@ -703,7 +749,7 @@ "line": 14, "end_line": 14, "column": 2, - "end_column": 31 + "end_column": 34 }, "expr": { "_type": "IntrinsicCall", @@ -712,7 +758,7 @@ "line": 14, "end_line": 14, "column": 2, - "end_column": 31 + "end_column": 34 }, "wtype": { "_type": "WType", @@ -731,7 +777,7 @@ "line": 14, "end_line": 14, "column": 9, - "end_column": 12 + "end_column": 15 }, "wtype": { "_type": "WType", @@ -747,7 +793,7 @@ "line": 14, "end_line": 14, "column": 9, - "end_column": 12 + "end_column": 15 }, "wtype": { "_type": "WType", @@ -760,13 +806,13 @@ "immediates": [], "stack_args": [ { - "_type": "StringConstant", + "_type": "VarExpression", "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 14, "end_line": 14, "column": 10, - "end_column": 12 + "end_column": 15 }, "wtype": { "_type": "WType", @@ -775,7 +821,7 @@ "ephemeral": false, "scalar_type": 1 }, - "value": "" + "name": "empty" } ], "comment": null @@ -1009,7 +1055,7 @@ "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 20, - "end_line": 28, + "end_line": 31, "column": 0, "end_column": 1 }, @@ -1026,7 +1072,7 @@ "source_location": { "file": "tests/approvals/boolean-conversions.algo.ts", "line": 20, - "end_line": 28, + "end_line": 31, "column": 35, "end_column": 1 }, @@ -1898,6 +1944,119 @@ ], "comment": null } + }, + { + "_type": "AssignmentStatement", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 29, + "end_line": 29, + "column": 8, + "end_column": 30 + }, + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 29, + "end_line": 29, + "column": 8, + "end_column": 18 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "boolNoArgs" + }, + "value": { + "_type": "BoolConstant", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 29, + "end_line": 29, + "column": 21, + "end_column": 30 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "value": false + } + }, + { + "_type": "ExpressionStatement", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 30, + "end_line": 30, + "column": 2, + "end_column": 21 + }, + "expr": { + "_type": "IntrinsicCall", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 30, + "end_line": 30, + "column": 2, + "end_column": 21 + }, + "wtype": { + "_type": "WType", + "name": "void", + "immutable": true, + "ephemeral": false, + "scalar_type": null + }, + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "Not", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 30, + "end_line": 30, + "column": 9, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "expr": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/boolean-conversions.algo.ts", + "line": 30, + "end_line": 30, + "column": 10, + "end_column": 20 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "boolNoArgs" + } + } + ], + "comment": null + } } ], "label": null, diff --git a/tests/approvals/out/boolean-expressions.awst b/tests/approvals/out/boolean-expressions.awst index d47e0cf9..28811887 100644 --- a/tests/approvals/out/boolean-expressions.awst +++ b/tests/approvals/out/boolean-expressions.awst @@ -1,13 +1,13 @@ subroutine test(a: uint64, b: uint64, c: string, d: bytes, e: uint64): bool { - var x: uint64 = (Boolean((#10 = (Boolean(a) ? a : b))) ? #10 : e) + x: uint64 = (Boolean((#10 = (Boolean(a) ? a : b))) ? #10 : e) assert(Boolean((Boolean((#11 = (Boolean(a) ? b : a))) ? e : #11))) - var y: uint64 = (Boolean(a) ? b : a) - var z: uint64 = (Boolean(a) and Boolean(len(d)) or Boolean(y) ? (Boolean(x) ? x : y) : (Boolean(x) ? y : x)) + y: uint64 = (Boolean(a) ? b : a) + z: uint64 = (Boolean(a) and Boolean(len(d)) or Boolean(y) ? (Boolean(x) ? x : y) : (Boolean(x) ? y : x)) if (Boolean(a) or Boolean(len(c)) and Boolean(len(d))) { return True } - var f: uint64 = 0 + f: uint64 = 0 if (Boolean((f = (Boolean(a) ? a : b)))) { return True } diff --git a/tests/approvals/out/box-proxies.awst b/tests/approvals/out/box-proxies.awst index e3d57b78..203c7c19 100644 --- a/tests/approvals/out/box-proxies.awst +++ b/tests/approvals/out/box-proxies.awst @@ -1,25 +1,25 @@ subroutine testBox(box: box_key, value: string): void { - var box.value: string = value - var Box["A"].value: string = value + box.value: string = value + Box["A"].value: string = value assert(box.value == Box["A"].value) assert(STATE_EXISTS(box.value) and STATE_EXISTS(Box["A"].value)) assert(Boolean(checked_maybe(box_length(box.value), comment=Box must exist))) STATE_DEL(box.value) STATE_DEL(Box["A"].value) assert(!STATE_EXISTS(box.value) and !STATE_EXISTS(Box["A"].value)) - var defaultVal: string = "O" + defaultVal: string = "O" assert(STATE_GET(Box["A"].value, default=defaultVal) == STATE_GET(box.value, default=defaultVal)) - var [_, e]: tuple[string, bool] = STATE_GET_EX(box.value) + [_, e]: tuple[string, bool] = STATE_GET_EX(box.value) assert(!e) - var box.value: string = value - var [_₁, e]: tuple[string, bool] = STATE_GET_EX(box.value) + box.value: string = value + [_₁, e]: tuple[string, bool] = STATE_GET_EX(box.value) assert(e) } subroutine testBoxMap(box: box_key, key: string, value: bytes): void { - var concat(box, reinterpret_cast(key)).value: bytes = value - var concat("", reinterpret_cast(key)).value: bytes = value + concat(box, reinterpret_cast(key)).value: bytes = value + concat("", reinterpret_cast(key)).value: bytes = value assert(Boolean(checked_maybe(box_length(concat(box, reinterpret_cast(key)).value), comment=Box must exist))) assert(STATE_GET_EX(concat(box, reinterpret_cast(key)).value).1) assert(concat(box, reinterpret_cast(key)).value == concat("", reinterpret_cast(key)).value) @@ -31,7 +31,7 @@ subroutine testBoxRef(box: box_key, length: uint64): void if (!box_length(Box["abc"].value).1 and checked_maybe(box_length(Box["abc"].value), comment=Box must exist) != length) { box_create(Box["abc"].value, 1000) } - var someBytes: bytes = 0xffffffff + someBytes: bytes = 0xffffffff box_put(box.value, someBytes) box_put(Box["abc"].value, someBytes) box_splice(box.value, 1, 2, 0x00) diff --git a/tests/approvals/out/conditional-expression.awst b/tests/approvals/out/conditional-expression.awst index 9d82697f..4653e6d7 100644 --- a/tests/approvals/out/conditional-expression.awst +++ b/tests/approvals/out/conditional-expression.awst @@ -1,10 +1,10 @@ subroutine test(x: uint64, y: uint64): bool { - var a: uint64 = (x < 4 ? x : y) + x - var b: uint64 = (Boolean(y % 2) ? 2 : 1) - var c: uint64 = (x > y ? (y > 10 ? 3 : y) : x) - var d: uint64 = (Boolean(y % 2) ? 2 : 1) + (x < 4 ? x : y) - var e: uint64 = (Boolean(x) ? x : 4) - var f: bool = (Boolean(y % 2) ? 2 : 1) == (x < 4 ? x : y) + a: uint64 = (x < 4 ? x : y) + x + b: uint64 = (Boolean(y % 2) ? 2 : 1) + c: uint64 = (x > y ? (y > 10 ? 3 : y) : x) + d: uint64 = (Boolean(y % 2) ? 2 : 1) + (x < 4 ? x : y) + e: uint64 = (Boolean(x) ? x : 4) + f: bool = (Boolean(y % 2) ? 2 : 1) == (x < 4 ? x : y) return True } \ No newline at end of file diff --git a/tests/approvals/out/destructured-params.awst b/tests/approvals/out/destructured-params.awst index 56c8ca22..77544b5a 100644 --- a/tests/approvals/out/destructured-params.awst +++ b/tests/approvals/out/destructured-params.awst @@ -1,16 +1,16 @@ subroutine test(p: tuple[uint64, bytes, bool]): void { - var [a, b, c]: tuple[uint64, bytes, bool] = [p.0, p.1, p.2] + [a, b, c]: tuple[uint64, bytes, bool] = [p.0, p.1, p.2] log(concat(concat(itob(a), b), itob(c))) } subroutine init(): void { tests/approvals/destructured-params.algo.ts::test([1, "", False]) - var temp: tuple[uint64, bytes, bool] = [2, "Hello", True] + temp: tuple[uint64, bytes, bool] = [2, "Hello", True] tests/approvals/destructured-params.algo.ts::test([temp.0, temp.1, temp.2]) } subroutine test2(args: tuple[bool, bool, readonlytuple[string, string]]): void { - var [a, [x, y], b]: tuple[bool, tuple[bool, bool], bool] = [True, [args.0, args.1, args.2], False] - var args2: tuple[bool, bool, readonlytuple[string, string]] = [True, True, args.2] + [a, [x, y], b]: tuple[bool, tuple[bool, bool], bool] = [True, [args.0, args.1, args.2], False] + args2: tuple[bool, bool, readonlytuple[string, string]] = [True, True, args.2] } \ No newline at end of file diff --git a/tests/approvals/out/do-loops.awst b/tests/approvals/out/do-loops.awst index 6cc9547f..7c51ebfb 100644 --- a/tests/approvals/out/do-loops.awst +++ b/tests/approvals/out/do-loops.awst @@ -1,8 +1,8 @@ subroutine test_do(stop: uint64): void { - var i: uint64 = 0 + i: uint64 = 0 while (True) { - var i: uint64 = i + 1 + i: uint64 = i + 1 #loop₁ᶜ: if (!i < stop) { goto #loop₁ᵇ diff --git a/tests/approvals/out/for-loops.awst b/tests/approvals/out/for-loops.awst index dda78775..d599bf21 100644 --- a/tests/approvals/out/for-loops.awst +++ b/tests/approvals/out/for-loops.awst @@ -1,60 +1,60 @@ subroutine test_for_loop(start: uint64, stop: uint64, step: uint64): uint64 { - var total: uint64 = 0 - var i: uint64 = start + total: uint64 = 0 + i: uint64 = start while (i < stop) { - var total: uint64 = total + i + total: uint64 = total + i #loop₁ᶜ: - (i = i + step) + i: uint64 = i + step } #loop₁ᵇ: return total } subroutine test_for_loop_break(start: uint64, stop: uint64, step: uint64): uint64 { - var total: uint64 = 0 - var i: uint64 = start + total: uint64 = 0 + i: uint64 = start while (i < stop) { - var total: uint64 = total + i + total: uint64 = total + i if (total > 10) { goto #loop₁ᵇ } #loop₁ᶜ: - (i = i + step) + i: uint64 = i + step } #loop₁ᵇ: return total } subroutine test_for_loop_continue(start: uint64, stop: uint64, step: uint64): uint64 { - var total: uint64 = 0 - var i: uint64 = start + total: uint64 = 0 + i: uint64 = start while (i < stop) { if (i % 5 == 0) { goto #loop₁ᶜ } - var total: uint64 = total + i + total: uint64 = total + i #loop₁ᶜ: - (i = i + step) + i: uint64 = i + step } #loop₁ᵇ: return total } subroutine test_for_loop_labelled(start: uint64, stop: uint64, step: uint64): uint64 { - var total: uint64 = 0 - var i: uint64 = start + total: uint64 = 0 + i: uint64 = start while (i < stop) { - var j: uint64 = start + j: uint64 = start while (j < stop) { - var total: uint64 = total + j + j + total: uint64 = total + j + j goto outer₁ᵇ #loop₁ᶜ: - (j = j + step) + j: uint64 = j + step } #loop₁ᵇ: outer₁ᶜ: - (i = i + step) + i: uint64 = i + step } outer₁ᵇ: return total diff --git a/tests/approvals/out/for-loops.awst.json b/tests/approvals/out/for-loops.awst.json index 692dc8ef..57192aee 100644 --- a/tests/approvals/out/for-loops.awst.json +++ b/tests/approvals/out/for-loops.awst.json @@ -357,7 +357,7 @@ "comment": null }, { - "_type": "ExpressionStatement", + "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 6, @@ -365,8 +365,26 @@ "column": 32, "end_column": 41 }, - "expr": { - "_type": "AssignmentExpression", + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/for-loops.algo.ts", + "line": 6, + "end_line": 6, + "column": 32, + "end_column": 33 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "i" + }, + "value": { + "_type": "UInt64BinaryOperation", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 6, @@ -381,7 +399,7 @@ "ephemeral": false, "scalar_type": 2 }, - "target": { + "left": { "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", @@ -399,13 +417,14 @@ }, "name": "i" }, - "value": { - "_type": "UInt64BinaryOperation", + "op": "+", + "right": { + "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 6, "end_line": 6, - "column": 32, + "column": 37, "end_column": 41 }, "wtype": { @@ -415,43 +434,7 @@ "ephemeral": false, "scalar_type": 2 }, - "left": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 6, - "end_line": 6, - "column": 32, - "end_column": 33 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "i" - }, - "op": "+", - "right": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 6, - "end_line": 6, - "column": 37, - "end_column": 41 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "step" - } + "name": "step" } } } @@ -977,7 +960,7 @@ "comment": null }, { - "_type": "ExpressionStatement", + "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 14, @@ -985,8 +968,26 @@ "column": 32, "end_column": 41 }, - "expr": { - "_type": "AssignmentExpression", + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/for-loops.algo.ts", + "line": 14, + "end_line": 14, + "column": 32, + "end_column": 33 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "i" + }, + "value": { + "_type": "UInt64BinaryOperation", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 14, @@ -1001,7 +1002,7 @@ "ephemeral": false, "scalar_type": 2 }, - "target": { + "left": { "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", @@ -1019,13 +1020,14 @@ }, "name": "i" }, - "value": { - "_type": "UInt64BinaryOperation", + "op": "+", + "right": { + "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 14, "end_line": 14, - "column": 32, + "column": 37, "end_column": 41 }, "wtype": { @@ -1035,43 +1037,7 @@ "ephemeral": false, "scalar_type": 2 }, - "left": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 14, - "end_line": 14, - "column": 32, - "end_column": 33 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "i" - }, - "op": "+", - "right": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 14, - "end_line": 14, - "column": 37, - "end_column": 41 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "step" - } + "name": "step" } } } @@ -1620,7 +1586,7 @@ "comment": null }, { - "_type": "ExpressionStatement", + "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 25, @@ -1628,8 +1594,26 @@ "column": 32, "end_column": 41 }, - "expr": { - "_type": "AssignmentExpression", + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/for-loops.algo.ts", + "line": 25, + "end_line": 25, + "column": 32, + "end_column": 33 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "i" + }, + "value": { + "_type": "UInt64BinaryOperation", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 25, @@ -1644,7 +1628,7 @@ "ephemeral": false, "scalar_type": 2 }, - "target": { + "left": { "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", @@ -1662,13 +1646,14 @@ }, "name": "i" }, - "value": { - "_type": "UInt64BinaryOperation", + "op": "+", + "right": { + "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 25, "end_line": 25, - "column": 32, + "column": 37, "end_column": 41 }, "wtype": { @@ -1678,43 +1663,7 @@ "ephemeral": false, "scalar_type": 2 }, - "left": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 25, - "end_line": 25, - "column": 32, - "end_column": 33 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "i" - }, - "op": "+", - "right": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 25, - "end_line": 25, - "column": 37, - "end_column": 41 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "step" - } + "name": "step" } } } @@ -2311,7 +2260,7 @@ "comment": null }, { - "_type": "ExpressionStatement", + "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 35, @@ -2319,8 +2268,26 @@ "column": 34, "end_column": 43 }, - "expr": { - "_type": "AssignmentExpression", + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/for-loops.algo.ts", + "line": 35, + "end_line": 35, + "column": 34, + "end_column": 35 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "j" + }, + "value": { + "_type": "UInt64BinaryOperation", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 35, @@ -2335,7 +2302,7 @@ "ephemeral": false, "scalar_type": 2 }, - "target": { + "left": { "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", @@ -2353,13 +2320,14 @@ }, "name": "j" }, - "value": { - "_type": "UInt64BinaryOperation", + "op": "+", + "right": { + "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 35, "end_line": 35, - "column": 34, + "column": 39, "end_column": 43 }, "wtype": { @@ -2369,43 +2337,7 @@ "ephemeral": false, "scalar_type": 2 }, - "left": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 35, - "end_line": 35, - "column": 34, - "end_column": 35 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "j" - }, - "op": "+", - "right": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 35, - "end_line": 35, - "column": 39, - "end_column": 43 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "step" - } + "name": "step" } } } @@ -2445,7 +2377,7 @@ "comment": null }, { - "_type": "ExpressionStatement", + "_type": "AssignmentStatement", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 34, @@ -2453,8 +2385,26 @@ "column": 39, "end_column": 48 }, - "expr": { - "_type": "AssignmentExpression", + "target": { + "_type": "VarExpression", + "source_location": { + "file": "tests/approvals/for-loops.algo.ts", + "line": 34, + "end_line": 34, + "column": 39, + "end_column": 40 + }, + "wtype": { + "_type": "WType", + "name": "uint64", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "name": "i" + }, + "value": { + "_type": "UInt64BinaryOperation", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 34, @@ -2469,7 +2419,7 @@ "ephemeral": false, "scalar_type": 2 }, - "target": { + "left": { "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", @@ -2487,13 +2437,14 @@ }, "name": "i" }, - "value": { - "_type": "UInt64BinaryOperation", + "op": "+", + "right": { + "_type": "VarExpression", "source_location": { "file": "tests/approvals/for-loops.algo.ts", "line": 34, "end_line": 34, - "column": 39, + "column": 44, "end_column": 48 }, "wtype": { @@ -2503,43 +2454,7 @@ "ephemeral": false, "scalar_type": 2 }, - "left": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 34, - "end_line": 34, - "column": 39, - "end_column": 40 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "i" - }, - "op": "+", - "right": { - "_type": "VarExpression", - "source_location": { - "file": "tests/approvals/for-loops.algo.ts", - "line": 34, - "end_line": 34, - "column": 44, - "end_column": 48 - }, - "wtype": { - "_type": "WType", - "name": "uint64", - "immutable": true, - "ephemeral": false, - "scalar_type": 2 - }, - "name": "step" - } + "name": "step" } } } diff --git a/tests/approvals/out/for-of-loops.awst b/tests/approvals/out/for-of-loops.awst index e21b31df..8052b4bb 100644 --- a/tests/approvals/out/for-of-loops.awst +++ b/tests/approvals/out/for-of-loops.awst @@ -1,8 +1,8 @@ subroutine test_for_of_loop(items: readonlytuple[uint64, uint64, uint64]): uint64 { - var total: uint64 = 0 + total: uint64 = 0 for (item in items) { - var total: uint64 = total + item + total: uint64 = total + item #loop₁ᶜ: } #loop₁ᵇ: diff --git a/tests/approvals/out/global-state.awst b/tests/approvals/out/global-state.awst index ff48c6d9..29c173fd 100644 --- a/tests/approvals/out/global-state.awst +++ b/tests/approvals/out/global-state.awst @@ -6,7 +6,7 @@ contract BaseTestContract extends @algorandfoundation/algorand-typescript/arc4/i constructor(): void { void - var GlobalState["baseTestState"]: string = "testing 123" + GlobalState["baseTestState"]: string = "testing 123" } } @@ -21,19 +21,19 @@ contract TestContract extends tests/approvals/global-state.algo.ts::BaseTestCont } constructor(): void { - var someValue: uint64 = 72057594037927936 + someValue: uint64 = 72057594037927936 super.constructor() - var GlobalState["testState"]: uint64 = 2 - var GlobalState["TESTSTATE"]: uint64 = 5 + GlobalState["testState"]: uint64 = 2 + GlobalState["TESTSTATE"]: uint64 = 5 assert(GlobalState["baseTestState"] == "testing 123") - var GlobalState["noInitialInt"]: uint64 = someValue * GlobalState["testState"] + GlobalState["noInitialInt"]: uint64 = someValue * GlobalState["testState"] } approvalProgram(): bool { assert(STATE_EXISTS(GlobalState["testState"])) assert(GlobalState["testState"] == 2) - var GlobalState["testState"]: uint64 = btoi(txnas(0)) + GlobalState["testState"]: uint64 = btoi(txnas(0)) return True } diff --git a/tests/approvals/out/inheritance-b.awst b/tests/approvals/out/inheritance-b.awst index 958ebd4e..7870fada 100644 --- a/tests/approvals/out/inheritance-b.awst +++ b/tests/approvals/out/inheritance-b.awst @@ -10,8 +10,8 @@ contract ConcreteSimpleContract extends tests/approvals/inheritance-a.algo.ts::S approvalProgram(): uint64 { - var a: uint64 = btoi(txnas(0)) - var b: uint64 = btoi(txnas(1)) + a: uint64 = btoi(txnas(0)) + b: uint64 = btoi(txnas(1)) return this.simpleMethod(a, b) } diff --git a/tests/approvals/out/intrinsic-calls.awst b/tests/approvals/out/intrinsic-calls.awst index 82ba3813..2a25d8f3 100644 --- a/tests/approvals/out/intrinsic-calls.awst +++ b/tests/approvals/out/intrinsic-calls.awst @@ -1,5 +1,5 @@ subroutine test(a: uint64, b: bytes): void { - var x: uint64 = setbit(a, 8, 1) - var y: bytes = setbit(b, 12, 9) + x: uint64 = setbit(a, 8, 1) + y: bytes = setbit(b, 12, 9) } \ No newline at end of file diff --git a/tests/approvals/out/itxn.awst b/tests/approvals/out/itxn.awst index 1e9edc7f..f92abaab 100644 --- a/tests/approvals/out/itxn.awst +++ b/tests/approvals/out/itxn.awst @@ -6,7 +6,7 @@ contract ItxnDemoContract extends @algorandfoundation/algorand-typescript/base-c constructor(): void { void - var GlobalState["name"]: bytes = 0x + GlobalState["name"]: bytes = 0x } approvalProgram(): bool @@ -35,19 +35,19 @@ contract ItxnDemoContract extends @algorandfoundation/algorand-typescript/base-c test1(): void { - var GlobalState["name"]: bytes = "AST1" - var assetParams: inner_transaction_fields_acfg = create_inner_transaction(Fee=0, ConfigAssetName=GlobalState["name"], ConfigAssetDecimals=3, ConfigAssetManager=global(), ConfigAssetReserve=global(), ConfigAssetTotal=1000, ConfigAssetUnitName="unit") - var GlobalState["name"]: bytes = "AST2" - var asset1_txn: inner_transaction_acfg = submit_txn(assetParams) + GlobalState["name"]: bytes = "AST1" + assetParams: inner_transaction_fields_acfg = create_inner_transaction(Fee=0, ConfigAssetName=GlobalState["name"], ConfigAssetDecimals=3, ConfigAssetManager=global(), ConfigAssetReserve=global(), ConfigAssetTotal=1000, ConfigAssetUnitName="unit") + GlobalState["name"]: bytes = "AST2" + asset1_txn: inner_transaction_acfg = submit_txn(assetParams) update_inner_transaction(assetParams, ConfigAssetName=GlobalState["name"]) - var asset2_txn: inner_transaction_acfg = submit_txn(assetParams) + asset2_txn: inner_transaction_acfg = submit_txn(assetParams) assert(asset1_txn.ConfigAssetName == "AST1") assert(asset2_txn.ConfigAssetName == "AST2") assert(checked_maybe(asset_params_get(asset1_txn.CreatedAssetID), comment=asset exists) == "AST1") assert(checked_maybe(asset_params_get(asset2_txn.CreatedAssetID), comment=asset exists) == "AST2") - var appCreateParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApprovalProgram=0x098101, ClearStateProgram=0x098101) + appCreateParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApprovalProgram=0x098101, ClearStateProgram=0x098101) update_inner_transaction(assetParams, ConfigAssetName="AST3") - var [appCreateTxn, asset3_txn]: tuple[inner_transaction_appl, inner_transaction_acfg] = submit_txn(appCreateParams, assetParams) + [appCreateTxn, asset3_txn]: tuple[inner_transaction_appl, inner_transaction_acfg] = submit_txn(appCreateParams, assetParams) assert(Boolean(appCreateTxn.ApplicationID)) assert(asset3_txn.ConfigAssetName == "AST3") update_inner_transaction(appCreateParams, Note="3rd") @@ -58,12 +58,12 @@ contract ItxnDemoContract extends @algorandfoundation/algorand-typescript/base-c test2(): void { if (Boolean(txn())) { - var args: readonlytuple[bytes, bytes] = ["1", "2"] - var createAppParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApplicationArgs=[args.0, args.1], ApprovalProgram=" ", ClearStateProgram=" ", Note="with args param set", OnCompletion=0) + args: readonlytuple[bytes, bytes] = ["1", "2"] + createAppParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApplicationArgs=[args.0, args.1], ApprovalProgram=" ", ClearStateProgram=" ", Note="with args param set", OnCompletion=0) } else { - var createAppParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApplicationArgs=["3", "4", "5"], ApprovalProgram=" ", ClearStateProgram=" ", Note="no args param set") + createAppParams: inner_transaction_fields_appl = create_inner_transaction(Fee=0, ApplicationArgs=["3", "4", "5"], ApprovalProgram=" ", ClearStateProgram=" ", Note="no args param set") } - var createAppTxn: inner_transaction_appl = submit_txn(createAppParams) + createAppTxn: inner_transaction_appl = submit_txn(createAppParams) assert(createAppTxn.ApplicationArgs[0] == "1") assert(createAppTxn.ApplicationArgs[1] == "2") assert(createAppTxn.Note == "with args param set") diff --git a/tests/approvals/out/local-state.awst b/tests/approvals/out/local-state.awst index f0374279..7ff002c1 100644 --- a/tests/approvals/out/local-state.awst +++ b/tests/approvals/out/local-state.awst @@ -14,12 +14,12 @@ contract LocalStateDemo extends @algorandfoundation/algorand-typescript/arc4/ind setState(): void { - var [a, b, c]: tuple[uint64, bytes, arc4.static_array] = [p.0, p.1, p.2] - var GlobalState["l1"]: uint64 = a - var GlobalState["localUint2"]: uint64 = a - var GlobalState["b1"]: bytes = b - var GlobalState["localBytes2"]: bytes = b - var GlobalState["localEncoded"]: arc4.static_array = copy(c) + [a, b, c]: tuple[uint64, bytes, arc4.static_array] = [p.0, p.1, p.2] + GlobalState["l1"]: uint64 = a + GlobalState["localUint2"]: uint64 = a + GlobalState["b1"]: bytes = b + GlobalState["localBytes2"]: bytes = b + GlobalState["localEncoded"]: arc4.static_array = copy(c) } getState(): tuple[bytes, bytes, arc4.static_array, uint64, uint64] diff --git a/tests/approvals/out/named-types.awst b/tests/approvals/out/named-types.awst index 9e8268c2..44652d9e 100644 --- a/tests/approvals/out/named-types.awst +++ b/tests/approvals/out/named-types.awst @@ -22,9 +22,9 @@ contract MyContract extends @algorandfoundation/algorand-typescript/arc4/index.d testing(): readonlytuple[tuple[uint64, uint64], tuple[uint64, uint64], tuple[uint64, uint64]] { - var a: tuple[uint64, uint64] = [(#7 = this.getXY()).0, #7.1] - var b: tuple[uint64, uint64] = [(#8 = this.getYX()).0, #8.1] - var c: tuple[uint64, uint64] = [(#9 = this.getAnon()).0, #9.1] + a: tuple[uint64, uint64] = [(#7 = this.getXY()).0, #7.1] + b: tuple[uint64, uint64] = [(#8 = this.getYX()).0, #8.1] + c: tuple[uint64, uint64] = [(#9 = this.getAnon()).0, #9.1] return [[a.0, a.1], [b.0, b.1], [c.0, c.1]] } diff --git a/tests/approvals/out/non-arc4.awst b/tests/approvals/out/non-arc4.awst index 76a9b36b..4d900fb6 100644 --- a/tests/approvals/out/non-arc4.awst +++ b/tests/approvals/out/non-arc4.awst @@ -7,7 +7,7 @@ contract HelloWorldContract extends @algorandfoundation/algorand-typescript/base approvalProgram(): bool { - var name: string = reinterpret_cast(txnas(0)) + name: string = reinterpret_cast(txnas(0)) log(reinterpret_cast("Hello, " + name)) return True } diff --git a/tests/approvals/out/numeric-literal-expressions.awst b/tests/approvals/out/numeric-literal-expressions.awst index b0d464ec..fbe28620 100644 --- a/tests/approvals/out/numeric-literal-expressions.awst +++ b/tests/approvals/out/numeric-literal-expressions.awst @@ -1,8 +1,8 @@ subroutine test_uint64(): bool { - var x: uint64 = 410 - var y: uint64 = 100 // x - var z: uint64 = x ** 2 + x: uint64 = 410 + y: uint64 = 100 // x + z: uint64 = x ** 2 if (x == 4 or 2 <= y) { return True } @@ -10,7 +10,7 @@ subroutine test_uint64(): bool } subroutine test_biguint(): void { - var x: biguint = 410 - var y: biguint = 100 // x - var z: biguint = 25 + x: biguint = 410 + y: biguint = 100 // x + z: biguint = 25 } \ No newline at end of file diff --git a/tests/approvals/out/object-destructuring.awst b/tests/approvals/out/object-destructuring.awst index 81cf4229..3a3e9919 100644 --- a/tests/approvals/out/object-destructuring.awst +++ b/tests/approvals/out/object-destructuring.awst @@ -1,8 +1,8 @@ subroutine test(): void { - var [a, b, c, d]: tuple[uint64, bytes, bool, biguint] = [(#0 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #0.1, #0.2, #0.3] - var [_, _₁, _₂, e]: tuple[uint64, bytes, bool, biguint] = [(#1 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #1.1, #1.2, #1.3] - var f: tuple[uint64, bytes, bool, biguint] = [(#3 = ([g, _₃, _₄, i] = [(#2 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #2.1, #2.2, #2.3])).0, #3.1, #3.2, #3.3] + [a, b, c, d]: tuple[uint64, bytes, bool, biguint] = [(#0 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #0.1, #0.2, #0.3] + [_, _₁, _₂, e]: tuple[uint64, bytes, bool, biguint] = [(#1 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #1.1, #1.2, #1.3] + f: tuple[uint64, bytes, bool, biguint] = [(#3 = ([g, _₃, _₄, i] = [(#2 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #2.1, #2.2, #2.3])).0, #3.1, #3.2, #3.3] tests/approvals/object-destructuring.algo.ts::receivePartial([(#4 = tests/approvals/object-destructuring.algo.ts::produceItems()).0, #4.3]) } subroutine produceItems(): tuple[uint64, bytes, bool, biguint] @@ -14,11 +14,11 @@ subroutine receivePartial(x: tuple[uint64, biguint]): void } subroutine testLiteralToLiteral(): void { - var a: uint64 = 4 - var b: uint64 = 1 - var [e, f]: tuple[uint64, uint64] = [(#5 = ([c, d] = [a, b])).0, #5.1] + a: uint64 = 4 + b: uint64 = 1 + [e, f]: tuple[uint64, uint64] = [(#5 = ([c, d] = [a, b])).0, #5.1] } subroutine testNumericResolution(): void { - var x: tuple[uint64] = [(#6 = (y = [434])).0] + x: tuple[uint64] = [(#6 = (y = [434])).0] } \ No newline at end of file diff --git a/tests/approvals/out/prefix-postfix-operators.awst b/tests/approvals/out/prefix-postfix-operators.awst index a93112ef..3dce0183 100644 --- a/tests/approvals/out/prefix-postfix-operators.awst +++ b/tests/approvals/out/prefix-postfix-operators.awst @@ -2,20 +2,20 @@ subroutine test_uint64(x: uint64, y: uint64): bool { x++ x-- - var x: uint64 = (y = y - 1) - var x: uint64 = (y = y + 1) - var y: uint64 = ~y + x: uint64 = (y = y - 1) + x: uint64 = (y = y + 1) + y: uint64 = ~y return !y } subroutine test_biguint(x: biguint, y: biguint): bool { x++ x-- - var x: biguint = (y = y - 1) - var x: biguint = (y = y + 1) + x: biguint = (y = y - 1) + x: biguint = (y = y + 1) return !bitlen(y) } subroutine test_bytes(x: bytes): void { - var y: bytes = ~x + y: bytes = ~x } \ No newline at end of file diff --git a/tests/approvals/out/shadowed-variables.awst b/tests/approvals/out/shadowed-variables.awst index adc6f09a..7ef534ec 100644 --- a/tests/approvals/out/shadowed-variables.awst +++ b/tests/approvals/out/shadowed-variables.awst @@ -1,7 +1,7 @@ subroutine test(a₁: bytes): bytes { if (Boolean(len(a₁))) { - var a₂: bytes = "hmmm" + a₂: bytes = "hmmm" return a₂ } } \ No newline at end of file diff --git a/tests/approvals/out/switch-statements.awst b/tests/approvals/out/switch-statements.awst index c48b3f7c..2150fda3 100644 --- a/tests/approvals/out/switch-statements.awst +++ b/tests/approvals/out/switch-statements.awst @@ -17,7 +17,7 @@ subroutine test_uint64(x: uint64): uint64 } subroutine test_break(x: uint64): uint64 { - var i: uint64 = 0 + i: uint64 = 0 switch (x) { case 1: #switch₁ᶜ₀: @@ -27,11 +27,11 @@ subroutine test_break(x: uint64): uint64 goto #switch₁ᶜ₂ case 4: #switch₁ᶜ₂: - var i: uint64 = i + x + i: uint64 = i + x goto #switch₁ᵇ case 5: #switch₁ᶜ₃: - var i: uint64 = i * x + i: uint64 = i * x } #switch₁ᵇ: return i diff --git a/tests/approvals/out/while-loops.awst b/tests/approvals/out/while-loops.awst index f3913013..d08911cb 100644 --- a/tests/approvals/out/while-loops.awst +++ b/tests/approvals/out/while-loops.awst @@ -1,8 +1,8 @@ subroutine test_while(stop: uint64): void { - var i: uint64 = 0 + i: uint64 = 0 while (i < stop) { - var i: uint64 = i + 1 + i: uint64 = i + 1 #loop₁ᶜ: } #loop₁ᵇ: From 109ab5d45a4913f02f903ac57e85adfe800717d2 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 14:20:39 -0700 Subject: [PATCH 7/8] feat: Array push, pop, slice, and at --- src/awst_build/eb/arc4/arrays.ts | 96 +++++++++------ src/awst_build/eb/bytes-expression-builder.ts | 115 ++---------------- .../eb/shared/at-function-builder.ts | 74 +++++++++++ .../eb/shared/slice-function-builder.ts | 43 +++++++ src/awst_build/eb/util/index.ts | 13 +- 5 files changed, 196 insertions(+), 145 deletions(-) create mode 100644 src/awst_build/eb/shared/at-function-builder.ts create mode 100644 src/awst_build/eb/shared/slice-function-builder.ts diff --git a/src/awst_build/eb/arc4/arrays.ts b/src/awst_build/eb/arc4/arrays.ts index 4c792979..3c473202 100644 --- a/src/awst_build/eb/arc4/arrays.ts +++ b/src/awst_build/eb/arc4/arrays.ts @@ -2,7 +2,6 @@ import { nodeFactory } from '../../../awst/node-factory' import type { Expression } from '../../../awst/nodes' import type { SourceLocation } from '../../../awst/source-location' import { uint64WType } from '../../../awst/wtypes' -import { logger } from '../../../logger' import { codeInvariant, invariant } from '../../../util' import type { PType } from '../../ptypes' import { IterableIteratorType, NumericLiteralPType, TuplePType, uint64PType } from '../../ptypes' @@ -15,11 +14,12 @@ import { } from '../../ptypes/arc4-types' import { instanceEb } from '../../type-registry' import type { InstanceBuilder } from '../index' -import { BuilderBinaryOp, FunctionBuilder, InstanceExpressionBuilder, NodeBuilder } from '../index' +import { FunctionBuilder, InstanceExpressionBuilder, NodeBuilder } from '../index' import { IterableIteratorExpressionBuilder } from '../iterable-iterator-expression-builder' -import { BigIntLiteralExpressionBuilder } from '../literal/big-int-literal-expression-builder' +import { AtFunctionBuilder } from '../shared/at-function-builder' +import { SliceFunctionBuilder } from '../shared/slice-function-builder' import { UInt64ExpressionBuilder } from '../uint64-expression-builder' -import { requireExpressionOfType, requireInstanceBuilder } from '../util' +import { requireExpressionOfType } from '../util' import { parseFunctionArgs } from '../util/arg-parsing' export class DynamicArrayConstructorBuilder extends NodeBuilder { @@ -101,11 +101,19 @@ export abstract class ArrayExpressionBuilder< memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder { switch (name) { case 'at': - return new ArrayAtFunctionBuilder(this) + return new AtFunctionBuilder( + this.resolve(), + this.ptype.elementType, + this.ptype instanceof StaticArrayType + ? this.ptype.arraySize + : requireExpressionOfType(this.memberAccess('length', sourceLocation), uint64PType), + ) case 'entries': return new EntriesFunctionBuilder(this) case 'copy': return new CopyFunctionBuilder(this) + case 'slice': + return new SliceFunctionBuilder(this.resolve(), this.ptype) } return super.memberAccess(name, sourceLocation) } @@ -117,6 +125,7 @@ class CopyFunctionBuilder extends FunctionBuilder { } call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + parseFunctionArgs({ args, typeArgs, genericTypeArgs: 0, argSpec: (a) => [], funcName: 'copy', callLocation: sourceLocation }) return instanceEb( nodeFactory.copy({ value: this.arrayBuilder.resolve(), @@ -164,6 +173,10 @@ export class DynamicArrayExpressionBuilder extends ArrayExpressionBuilder) { +export class ArrayPushFunctionBuilder extends FunctionBuilder { + constructor(private arrayBuilder: ArrayExpressionBuilder) { super(arrayBuilder.sourceLocation) } call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const elementType = this.arrayBuilder.ptype.elementType const { - args: [index], + args: [...items], } = parseFunctionArgs({ args, typeArgs, funcName: 'at', callLocation: sourceLocation, genericTypeArgs: 0, - argSpec: (a) => [a.required()], + argSpec: (a) => [a.required(elementType), ...args.slice(1).map(() => a.required(elementType))], + }) + + return instanceEb( + nodeFactory.arrayExtend({ + base: this.arrayBuilder.resolve(), + other: nodeFactory.tupleExpression({ + items: items.map((i) => i.resolve()), + sourceLocation, + }), + sourceLocation, + wtype: this.arrayBuilder.ptype.wtype, + }), + this.arrayBuilder.ptype, + ) + } +} +export class ArrayPopFunctionBuilder extends FunctionBuilder { + constructor(private arrayBuilder: ArrayExpressionBuilder) { + super(arrayBuilder.sourceLocation) + } + + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const elementType = this.arrayBuilder.ptype.elementType + parseFunctionArgs({ + args, + typeArgs, + funcName: 'at', + callLocation: sourceLocation, + genericTypeArgs: 0, + argSpec: () => [], }) - let indexExpr: Expression - - if (index instanceof BigIntLiteralExpressionBuilder) { - if (this.arrayBuilder.ptype instanceof StaticArrayType) { - const staticSize = this.arrayBuilder.ptype.arraySize - if (index.value < -staticSize || index.value >= staticSize) { - logger.error(index.sourceLocation, 'Index access outside the bounds of the array') - } - indexExpr = nodeFactory.uInt64Constant({ - value: index.value < 0 ? staticSize + index.value : index.value, - sourceLocation: index.sourceLocation, - }) - } else { - const dynamicSize = requireInstanceBuilder(this.arrayBuilder.memberAccess('length', sourceLocation)) - const absoluteIndex = nodeFactory.uInt64Constant({ - value: index.value < 0n ? index.value * -1n : index.value, - sourceLocation: index.sourceLocation, - }) - if (index.value < 0) { - indexExpr = dynamicSize.binaryOp(new UInt64ExpressionBuilder(absoluteIndex), BuilderBinaryOp.sub, index.sourceLocation).resolve() - } else { - indexExpr = absoluteIndex - } - } - } else { - indexExpr = index.resolveToPType(uint64PType).resolve() - } return instanceEb( - nodeFactory.indexExpression({ + nodeFactory.arrayPop({ base: this.arrayBuilder.resolve(), - index: indexExpr, - wtype: this.arrayBuilder.ptype.elementType.wtype, sourceLocation, + wtype: elementType.wtype, }), - this.arrayBuilder.ptype.elementType, + elementType, ) } } diff --git a/src/awst_build/eb/bytes-expression-builder.ts b/src/awst_build/eb/bytes-expression-builder.ts index 0eac0bf9..c617db63 100644 --- a/src/awst_build/eb/bytes-expression-builder.ts +++ b/src/awst_build/eb/bytes-expression-builder.ts @@ -3,20 +3,12 @@ import { wtypes } from '../../awst' import { intrinsicFactory } from '../../awst/intrinsic-factory' import { nodeFactory } from '../../awst/node-factory' import type { Expression } from '../../awst/nodes' -import { - BytesBinaryOperator, - BytesConstant, - BytesEncoding, - BytesUnaryOperator, - IntegerConstant, - StringConstant, - UInt64BinaryOperator, -} from '../../awst/nodes' +import { BytesBinaryOperator, BytesConstant, BytesEncoding, BytesUnaryOperator, IntegerConstant, StringConstant } from '../../awst/nodes' import type { SourceLocation } from '../../awst/source-location' import { stringWType } from '../../awst/wtypes' import { CodeError, wrapInCodeError } from '../../errors' import { logger } from '../../logger' -import { base32ToUint8Array, base64ToUint8Array, hexToUint8Array, invariant, uint8ArrayToUtf8, utf8ToUint8Array } from '../../util' +import { base32ToUint8Array, base64ToUint8Array, hexToUint8Array, uint8ArrayToUtf8, utf8ToUint8Array } from '../../util' import type { InstanceType, PType } from '../ptypes' import { ArrayPType, @@ -29,11 +21,12 @@ import { stringPType, uint64PType, } from '../ptypes' -import { instanceEb } from '../type-registry' import type { BuilderComparisonOp, InstanceBuilder, NodeBuilder } from './index' import { BuilderUnaryOp, FunctionBuilder, InstanceExpressionBuilder, ParameterlessFunctionBuilder } from './index' import { ArrayLiteralExpressionBuilder } from './literal/array-literal-expression-builder' import { BigIntLiteralExpressionBuilder } from './literal/big-int-literal-expression-builder' +import { AtFunctionBuilder } from './shared/at-function-builder' +import { SliceFunctionBuilder } from './shared/slice-function-builder' import { StringExpressionBuilder } from './string-expression-builder' import { UInt64ExpressionBuilder } from './uint64-expression-builder' import { requireExpressionOfType, requireExpressionsOfType } from './util' @@ -203,7 +196,13 @@ export class BytesExpressionBuilder extends InstanceExpressionBuilder, typeArgs: ReadonlyArray, sourceLocation: SourceLocation) { - const { - args: [start, stop], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - callLocation: sourceLocation, - funcName: 'slice', - argSpec: (a) => [a.optional(uint64PType, numberPType), a.optional(uint64PType, numberPType)], - }) - - return new BytesExpressionBuilder( - nodeFactory.intersectionSliceExpression({ - base: this.expr, - sourceLocation: sourceLocation, - beginIndex: start ? getBigIntOrUint64Expr(start) : null, - endIndex: stop ? getBigIntOrUint64Expr(stop) : null, - wtype: wtypes.bytesWType, - }), - ) - } -} - -function getBigIntOrUint64Expr(builder: InstanceBuilder) { - if (builder.ptype.equals(numberPType)) { - invariant(builder instanceof BigIntLiteralExpressionBuilder, 'Builder for number type must be BigIntLiteral') - return builder.value - } else { - invariant(builder.ptype.equals(uint64PType), 'Builder must be uint64 if not number') - return builder.resolve() - } -} - export class ToStringBuilder extends ParameterlessFunctionBuilder { constructor(private expr: awst.Expression) { super( @@ -325,57 +286,3 @@ export class ToStringBuilder extends ParameterlessFunctionBuilder { ) } } - -export class BytesAtBuilder extends FunctionBuilder { - constructor(private expr: awst.Expression) { - super(expr.sourceLocation) - } - - call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation) { - const { - args: [index], - } = parseFunctionArgs({ - args, - typeArgs, - genericTypeArgs: 0, - callLocation: sourceLocation, - funcName: 'at', - argSpec: (a) => [a.required(uint64PType, numberPType)], - }) - - let indexExpr: Expression - - if (index.ptype.equals(numberPType)) { - invariant(index instanceof BigIntLiteralExpressionBuilder, 'Builder for number type must be BigIntLiteral') - - if (index.value < 0) { - indexExpr = nodeFactory.uInt64BinaryOperation({ - op: UInt64BinaryOperator.sub, - left: intrinsicFactory.bytesLen({ - value: this.expr, - sourceLocation, - }), - right: nodeFactory.uInt64Constant({ - value: index.value * -1n, - sourceLocation, - }), - sourceLocation, - }) - } else { - indexExpr = index.resolveToPType(uint64PType).resolve() - } - } else { - indexExpr = index.resolve() - } - - return instanceEb( - nodeFactory.indexExpression({ - base: this.expr, - sourceLocation: sourceLocation, - index: indexExpr, - wtype: wtypes.bytesWType, - }), - bytesPType, - ) - } -} diff --git a/src/awst_build/eb/shared/at-function-builder.ts b/src/awst_build/eb/shared/at-function-builder.ts new file mode 100644 index 00000000..f21d60a2 --- /dev/null +++ b/src/awst_build/eb/shared/at-function-builder.ts @@ -0,0 +1,74 @@ +import { nodeFactory } from '../../../awst/node-factory' +import type { Expression } from '../../../awst/nodes' +import { UInt64BinaryOperator } from '../../../awst/nodes' +import type { SourceLocation } from '../../../awst/source-location' +import type { WType } from '../../../awst/wtypes' +import { logger } from '../../../logger' +import type { PType } from '../../ptypes' +import { numberPType, uint64PType } from '../../ptypes' +import { instanceEb } from '../../type-registry' +import { FunctionBuilder, type InstanceBuilder } from '../index' +import { getBigIntOrUint64Expr } from '../util' +import { parseFunctionArgs } from '../util/arg-parsing' + +export class AtFunctionBuilder extends FunctionBuilder { + constructor( + private expr: Expression, + private itemPType: PType & { wtype: WType }, + private exprLength: Expression | bigint, + ) { + super(expr.sourceLocation) + } + + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation) { + const { + args: [index], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + callLocation: sourceLocation, + funcName: 'at', + argSpec: (a) => [a.required(uint64PType, numberPType)], + }) + + const indexParam = getBigIntOrUint64Expr(index) + let indexExpr: Expression + + if (typeof indexParam === 'bigint') { + if (typeof this.exprLength === 'bigint') { + let indexValue = indexParam < 0 ? this.exprLength + indexParam : indexParam + if (indexValue < 0n || indexValue >= this.exprLength) { + logger.warn(index.sourceLocation, 'Index access out of bounds') + indexValue = 0n + } + indexExpr = nodeFactory.uInt64Constant({ + value: indexValue, + sourceLocation: index.sourceLocation, + }) + } else { + indexExpr = nodeFactory.uInt64BinaryOperation({ + op: UInt64BinaryOperator.sub, + left: this.exprLength, + right: nodeFactory.uInt64Constant({ + value: indexParam * -1n, + sourceLocation: index.sourceLocation, + }), + sourceLocation: index.sourceLocation, + }) + } + } else { + indexExpr = indexParam + } + + return instanceEb( + nodeFactory.indexExpression({ + base: this.expr, + sourceLocation: sourceLocation, + index: indexExpr, + wtype: this.itemPType.wtype, + }), + this.itemPType, + ) + } +} diff --git a/src/awst_build/eb/shared/slice-function-builder.ts b/src/awst_build/eb/shared/slice-function-builder.ts new file mode 100644 index 00000000..0312f6a8 --- /dev/null +++ b/src/awst_build/eb/shared/slice-function-builder.ts @@ -0,0 +1,43 @@ +import { nodeFactory } from '../../../awst/node-factory' +import type { Expression } from '../../../awst/nodes' +import type { SourceLocation } from '../../../awst/source-location' +import type { WType } from '../../../awst/wtypes' +import type { PType } from '../../ptypes' +import { numberPType, uint64PType } from '../../ptypes' +import { BytesExpressionBuilder } from '../bytes-expression-builder' +import type { NodeBuilder } from '../index' +import { FunctionBuilder, type InstanceBuilder } from '../index' +import { getBigIntOrUint64Expr } from '../util' +import { parseFunctionArgs } from '../util/arg-parsing' + +export class SliceFunctionBuilder extends FunctionBuilder { + constructor( + private base: Expression, + private resultPType: PType & { wtype: WType }, + ) { + super(base.sourceLocation) + } + + call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation): NodeBuilder { + const { + args: [start, stop], + } = parseFunctionArgs({ + args, + typeArgs, + genericTypeArgs: 0, + callLocation: sourceLocation, + funcName: 'slice', + argSpec: (a) => [a.optional(uint64PType, numberPType), a.optional(uint64PType, numberPType)], + }) + + return new BytesExpressionBuilder( + nodeFactory.intersectionSliceExpression({ + base: this.base, + sourceLocation: sourceLocation, + beginIndex: start ? getBigIntOrUint64Expr(start) : null, + endIndex: stop ? getBigIntOrUint64Expr(stop) : null, + wtype: this.resultPType.wtype, + }), + ) + } +} diff --git a/src/awst_build/eb/util/index.ts b/src/awst_build/eb/util/index.ts index 11993a99..6f344076 100644 --- a/src/awst_build/eb/util/index.ts +++ b/src/awst_build/eb/util/index.ts @@ -4,13 +4,14 @@ import type { Expression } from '../../../awst/nodes' import { BoolConstant, IntegerConstant, StringConstant } from '../../../awst/nodes' import type { SourceLocation } from '../../../awst/source-location' import { CodeError } from '../../../errors' -import { codeInvariant } from '../../../util' +import { codeInvariant, invariant } from '../../../util' import type { PType, PTypeOrClass } from '../../ptypes' import { bigIntPType, biguintPType, boolPType, bytesPType, numberPType, stringPType, uint64PType } from '../../ptypes' import { UintNType } from '../../ptypes/arc4-types' import type { NodeBuilder } from '../index' import { InstanceBuilder } from '../index' import { LiteralExpressionBuilder } from '../literal-expression-builder' +import { BigIntLiteralExpressionBuilder } from '../literal/big-int-literal-expression-builder' export function requireExpressionOfType(builder: NodeBuilder, ptype: PTypeOrClass): Expression { if (builder instanceof InstanceBuilder) { @@ -141,3 +142,13 @@ export function isValidLiteralForPType(literalValue: ConstantValue, ptype: PType } return false } + +export function getBigIntOrUint64Expr(builder: InstanceBuilder) { + if (builder.ptype.equals(numberPType)) { + invariant(builder instanceof BigIntLiteralExpressionBuilder, 'Builder for number type must be BigIntLiteral') + return builder.value + } else { + invariant(builder.ptype.equals(uint64PType), 'Builder must be uint64 if not number') + return builder.resolve() + } +} From 947b0e37036e1fdf7be65cf5231f7187ed078d5a Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Thu, 10 Oct 2024 14:21:26 -0700 Subject: [PATCH 8/8] fix: Boolean function generic param count --- src/awst_build/eb/boolean-expression-builder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/awst_build/eb/boolean-expression-builder.ts b/src/awst_build/eb/boolean-expression-builder.ts index 0eae49e4..7247195c 100644 --- a/src/awst_build/eb/boolean-expression-builder.ts +++ b/src/awst_build/eb/boolean-expression-builder.ts @@ -18,7 +18,7 @@ export class BooleanFunctionBuilder extends FunctionBuilder { } = parseFunctionArgs({ args, typeArgs, - genericTypeArgs: 0, + genericTypeArgs: 1, callLocation: sourceLocation, funcName: 'Boolean', argSpec: (a) => [a.optional()],