From 88bf321aee61348e8ea317ca8c2d130b391c9423 Mon Sep 17 00:00:00 2001 From: Tristan Menzel Date: Wed, 9 Oct 2024 15:19:29 -0700 Subject: [PATCH] feat: Expand Bytes factory method to support iterable (ie. uint8array) --- package-lock.json | 2 +- packages/algo-ts/package-lock.json | 12 +- packages/algo-ts/package.json | 3 +- packages/algo-ts/src/impl/primitives.ts | 2 +- packages/algo-ts/src/primitives.ts | 19 +- .../eb/biguint-expression-builder.ts | 15 +- src/awst_build/eb/bytes-expression-builder.ts | 125 ++++++++-- .../big-int-literal-expression-builder.ts | 16 +- src/awst_build/eb/util/arg-parsing.ts | 4 +- src/awst_build/eb/util/index.ts | 10 +- src/awst_build/ptypes/index.ts | 4 +- tests/approvals/byte-expressions.algo.ts | 1 + tests/approvals/out/byte-expressions.awst | 7 +- .../approvals/out/byte-expressions.awst.json | 229 +++++++++++------- tests/expected-output/_run.spec.ts | 2 +- .../biguint-expressions.algo.ts | 6 +- .../expected-output/byte-expressions.algo.ts | 2 + 17 files changed, 313 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6cf374f6..1847b7f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12965,7 +12965,7 @@ }, "packages/algo-ts/dist": { "name": "@algorandfoundation/algorand-typescript", - "version": "0.0.1-alpha.6", + "version": "0.0.1-alpha.7", "dev": true, "peerDependencies": { "tslib": "^2.6.2" diff --git a/packages/algo-ts/package-lock.json b/packages/algo-ts/package-lock.json index a6b1ad88..b1535807 100644 --- a/packages/algo-ts/package-lock.json +++ b/packages/algo-ts/package-lock.json @@ -1,12 +1,12 @@ { "name": "@algorandfoundation/algorand-typescript", - "version": "0.0.1-alpha.1", + "version": "0.0.1-alpha.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@algorandfoundation/algorand-typescript", - "version": "0.0.1-alpha.1", + "version": "0.0.1-alpha.6", "devDependencies": { "@eslint/eslintrc": "^3.1.0", "@eslint/js": "^9.11.1", @@ -18,7 +18,6 @@ "@rollup/plugin-node-resolve": "15.3.0", "@rollup/plugin-typescript": "12.1.0", "@tsconfig/node20": "20.1.4", - "@types/lodash": "^4.17.9", "@types/node": "22.6.1", "@typescript-eslint/eslint-plugin": "8.7.0", "@typescript-eslint/parser": "8.7.0", @@ -1479,13 +1478,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/lodash": { - "version": "4.17.9", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz", - "integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "22.6.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz", diff --git a/packages/algo-ts/package.json b/packages/algo-ts/package.json index ebd29f44..46bb55c3 100644 --- a/packages/algo-ts/package.json +++ b/packages/algo-ts/package.json @@ -1,6 +1,6 @@ { "name": "@algorandfoundation/algorand-typescript", - "version": "0.0.1-alpha.6", + "version": "0.0.1-alpha.7", "description": "This package contains definitions for the types which comprise Algorand TypeScript which can be compiled to run on the Algorand Virtual Machine using the Puya compiler.", "private": false, "main": "index.js", @@ -31,7 +31,6 @@ "@rollup/plugin-node-resolve": "15.3.0", "@rollup/plugin-typescript": "12.1.0", "@tsconfig/node20": "20.1.4", - "@types/lodash": "^4.17.9", "@types/node": "22.6.1", "@typescript-eslint/eslint-plugin": "8.7.0", "@typescript-eslint/parser": "8.7.0", diff --git a/packages/algo-ts/src/impl/primitives.ts b/packages/algo-ts/src/impl/primitives.ts index 727c1ed8..4ea32363 100644 --- a/packages/algo-ts/src/impl/primitives.ts +++ b/packages/algo-ts/src/impl/primitives.ts @@ -304,7 +304,7 @@ export class BytesCls extends AlgoTsPrimitiveCls { return isInstanceOfTypeByName(x, BytesCls) } - static fromCompat(v: StubBytesCompat | undefined): BytesCls { + static fromCompat(v: StubBytesCompat | Uint8Array | undefined): BytesCls { if (v === undefined) return new BytesCls(new Uint8Array()) if (typeof v === 'string') return new BytesCls(utf8ToUint8Array(v)) if (v instanceof BytesCls) return v diff --git a/packages/algo-ts/src/primitives.ts b/packages/algo-ts/src/primitives.ts index 779531f2..489505fb 100644 --- a/packages/algo-ts/src/primitives.ts +++ b/packages/algo-ts/src/primitives.ts @@ -1,4 +1,5 @@ -import { BigUintCls, BytesCls, Uint64Cls } from './impl/primitives' +import { CodeError } from './impl/errors' +import { BigUintCls, BytesCls, getNumber, Uint64Cls } from './impl/primitives' export type Uint64Compat = uint64 | bigint | boolean | number export type BigUintCompat = bigint | bytes | number | boolean @@ -115,17 +116,31 @@ export function Bytes(value: biguint): bytes * Create a byte array from a uint64 value encoded as a fixed length 64-bit number */ export function Bytes(value: uint64): bytes +/** + * Create a byte array from an Iterable where each item is interpreted as a single byte and must be between 0 and 255 inclusively + */ +export function Bytes(value: Iterable): bytes /** * Create an empty byte array */ export function Bytes(): bytes -export function Bytes(value?: BytesCompat | TemplateStringsArray | biguint | uint64, ...replacements: BytesCompat[]): bytes { +export function Bytes( + value?: BytesCompat | TemplateStringsArray | biguint | uint64 | Iterable, + ...replacements: BytesCompat[] +): bytes { if (isTemplateStringsArray(value)) { return BytesCls.fromInterpolation(value, replacements).asAlgoTs() } else if (typeof value === 'bigint' || value instanceof BigUintCls) { return BigUintCls.fromCompat(value).toBytes().asAlgoTs() } else if (typeof value === 'number' || value instanceof Uint64Cls) { return Uint64Cls.fromCompat(value).toBytes().asAlgoTs() + } else if (typeof value === 'object' && Symbol.iterator in value) { + const valueItems = Array.from(value).map((v) => getNumber(v)) + const invalidValue = valueItems.find((v) => v < 0 && v > 255) + if (invalidValue) { + throw new CodeError(`Cannot convert ${invalidValue} to a byte`) + } + return new BytesCls(new Uint8Array(value)).asAlgoTs() } else { return BytesCls.fromCompat(value).asAlgoTs() } diff --git a/src/awst_build/eb/biguint-expression-builder.ts b/src/awst_build/eb/biguint-expression-builder.ts index 0cf113cf..8617a81d 100644 --- a/src/awst_build/eb/biguint-expression-builder.ts +++ b/src/awst_build/eb/biguint-expression-builder.ts @@ -8,11 +8,10 @@ import { NotSupported } from '../../errors' import { logger } from '../../logger' import { tryConvertEnum } from '../../util' import type { InstanceType, PType } from '../ptypes' -import { BigUintFunction, biguintPType, boolPType, bytesPType, numberPType, stringPType, uint64PType } from '../ptypes' +import { BigUintFunction, biguintPType, boolPType, bytesPType, stringPType, uint64PType } from '../ptypes' import { BooleanExpressionBuilder } from './boolean-expression-builder' import type { InstanceBuilder } from './index' import { BuilderBinaryOp, BuilderComparisonOp, BuilderUnaryOp, FunctionBuilder, InstanceExpressionBuilder } from './index' -import { BigIntLiteralExpressionBuilder } from './literal/big-int-literal-expression-builder' import { UInt64ExpressionBuilder } from './uint64-expression-builder' import { requireExpressionOfType } from './util' import { parseFunctionArgs } from './util/arg-parsing' @@ -29,7 +28,7 @@ export class BigUintFunctionBuilder extends FunctionBuilder { genericTypeArgs: 0, callLocation: sourceLocation, funcName: 'BigUInt', - argSpec: (a) => [a.optional(boolPType, stringPType, bytesPType, biguintPType, numberPType, uint64PType)], + argSpec: (a) => [a.optional(boolPType, stringPType, bytesPType, biguintPType, uint64PType)], }) let biguint: Expression @@ -61,16 +60,6 @@ export class BigUintFunctionBuilder extends FunctionBuilder { sourceLocation, wtype: biguintPType.wtype, }) - } else if (initialValue.ptype.equals(numberPType)) { - if (initialValue instanceof BigIntLiteralExpressionBuilder) { - biguint = nodeFactory.bigUIntConstant({ - value: initialValue.value, - sourceLocation, - }) - } else { - logger.error(initialValue.sourceLocation, 'Only compile time numeric values are supported') - biguint = nodeFactory.bigUIntConstant({ value: 0n, sourceLocation }) - } } else if (initialValue.ptype.equals(uint64PType)) { const expr = initialValue.resolve() if (expr instanceof IntegerConstant) { diff --git a/src/awst_build/eb/bytes-expression-builder.ts b/src/awst_build/eb/bytes-expression-builder.ts index 368c5840..0eac0bf9 100644 --- a/src/awst_build/eb/bytes-expression-builder.ts +++ b/src/awst_build/eb/bytes-expression-builder.ts @@ -3,17 +3,36 @@ 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, StringConstant } from '../../awst/nodes' +import { + BytesBinaryOperator, + BytesConstant, + BytesEncoding, + BytesUnaryOperator, + IntegerConstant, + StringConstant, + UInt64BinaryOperator, +} 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, uint8ArrayToUtf8, utf8ToUint8Array } from '../../util' +import { base32ToUint8Array, base64ToUint8Array, hexToUint8Array, invariant, uint8ArrayToUtf8, utf8ToUint8Array } from '../../util' import type { InstanceType, PType } from '../ptypes' -import { bigIntPType, biguintPType, BytesFunction, bytesPType, numberPType, NumericLiteralPType, stringPType, uint64PType } from '../ptypes' +import { + ArrayPType, + bigIntPType, + biguintPType, + BytesFunction, + bytesPType, + numberPType, + NumericLiteralPType, + 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 { StringExpressionBuilder } from './string-expression-builder' import { UInt64ExpressionBuilder } from './uint64-expression-builder' @@ -66,7 +85,9 @@ export class BytesFunctionBuilder extends FunctionBuilder { genericTypeArgs: 0, callLocation: sourceLocation, funcName: 'Bytes', - argSpec: (a) => [a.optional(numberPType, bigIntPType, uint64PType, biguintPType, stringPType, bytesPType)], + argSpec: (a) => [ + a.optional(numberPType, bigIntPType, uint64PType, biguintPType, stringPType, bytesPType, new ArrayPType({ itemType: uint64PType })), + ], }) const empty = nodeFactory.bytesConstant({ sourceLocation, @@ -86,8 +107,29 @@ export class BytesFunctionBuilder extends FunctionBuilder { bytesExpr = initialValue.toBytes(sourceLocation) } else if (initialValue.ptype.equals(stringPType)) { bytesExpr = initialValue.toBytes(sourceLocation) - } else { + } else if (initialValue.ptype.equals(bytesPType)) { return initialValue + } else { + // Array + if (initialValue instanceof ArrayLiteralExpressionBuilder) { + const bytes: number[] = [] + for (const item of initialValue.getItemBuilders()) { + const byte = item.resolve() + if (byte instanceof IntegerConstant && byte.value < 256n) { + bytes.push(Number(byte.value)) + } else { + logger.error(item.sourceLocation, 'A compile time constant value between 0 and 255 is expected here') + break + } + } + bytesExpr = nodeFactory.bytesConstant({ + value: Uint8Array.from(bytes), + sourceLocation: initialValue.sourceLocation, + }) + } else { + logger.error(initialValue.sourceLocation, 'Only array literals are supported here') + bytesExpr = empty + } } return new BytesExpressionBuilder(bytesExpr) } @@ -235,21 +277,39 @@ export class BytesSliceBuilder extends FunctionBuilder { super(expr.sourceLocation) } call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation) { - // TODO: Needs to do range check on target and handle negative values - // TODO: Also handle single arg - const [start, stop] = requireExpressionsOfType(args, [uint64PType, uint64PType], 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.sliceExpression({ + nodeFactory.intersectionSliceExpression({ base: this.expr, sourceLocation: sourceLocation, - beginIndex: start, - endIndex: stop, + 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( @@ -272,14 +332,47 @@ export class BytesAtBuilder extends FunctionBuilder { } call(args: ReadonlyArray, typeArgs: ReadonlyArray, sourceLocation: SourceLocation) { - const [index] = requireExpressionsOfType(args, [uint64PType], sourceLocation) - // TODO: Needs to do range check on target and handle negative values + 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.sliceExpression({ + nodeFactory.indexExpression({ base: this.expr, sourceLocation: sourceLocation, - beginIndex: index, - endIndex: nodeFactory.uInt64Constant({ value: 1n, sourceLocation }), + index: indexExpr, wtype: wtypes.bytesWType, }), bytesPType, diff --git a/src/awst_build/eb/literal/big-int-literal-expression-builder.ts b/src/awst_build/eb/literal/big-int-literal-expression-builder.ts index 299fe91f..25fd88d2 100644 --- a/src/awst_build/eb/literal/big-int-literal-expression-builder.ts +++ b/src/awst_build/eb/literal/big-int-literal-expression-builder.ts @@ -37,6 +37,7 @@ export class BigIntLiteralExpressionBuilder extends LiteralExpressionBuilder { } resolvableToPType(ptype: PTypeOrClass): boolean { + if (!isValidLiteralForPType(this.value, ptype)) return false if (this.ptype instanceof NumericLiteralPType || this.ptype.equals(numberPType)) { return ptype.equals(uint64PType) || ptype.equals(numberPType) || ptype.equals(this.ptype) } else if (this.ptype instanceof BigIntLiteralPType || this.ptype.equals(bigIntPType)) { @@ -75,7 +76,8 @@ export class BigIntLiteralExpressionBuilder extends LiteralExpressionBuilder { return this.resolveToPType(other.ptype).binaryOp(other, op, sourceLocation) } if (other instanceof BigIntLiteralExpressionBuilder) { - return new BigIntLiteralExpressionBuilder(foldBinaryOp(this.value, other.value, op, sourceLocation), this.ptype, sourceLocation) + const folded = foldBinaryOp(this.value, other.value, op, sourceLocation) + return new BigIntLiteralExpressionBuilder(folded, this.getUpdatedPType(folded), sourceLocation) } return super.binaryOp(other, op, sourceLocation) } @@ -91,10 +93,20 @@ export class BigIntLiteralExpressionBuilder extends LiteralExpressionBuilder { prefixUnaryOp(op: BuilderUnaryOp, sourceLocation: SourceLocation): InstanceBuilder { switch (op) { case BuilderUnaryOp.neg: - return new BigIntLiteralExpressionBuilder(-this.value, this.ptype, sourceLocation) + return new BigIntLiteralExpressionBuilder(-this.value, this.getUpdatedPType(-this.value), sourceLocation) case BuilderUnaryOp.pos: return new BigIntLiteralExpressionBuilder(this.value, this.ptype, sourceLocation) } return super.prefixUnaryOp(op, sourceLocation) } + + private getUpdatedPType(value: bigint) { + if (this.ptype instanceof BigIntLiteralPType) { + return new BigIntLiteralPType({ literalValue: value }) + } + if (this.ptype instanceof NumericLiteralPType) { + return new NumericLiteralPType({ literalValue: value }) + } + return this.ptype + } } diff --git a/src/awst_build/eb/util/arg-parsing.ts b/src/awst_build/eb/util/arg-parsing.ts index c89fcd11..33a3aae7 100644 --- a/src/awst_build/eb/util/arg-parsing.ts +++ b/src/awst_build/eb/util/arg-parsing.ts @@ -209,8 +209,8 @@ export function parseFunctionArgs` } - constructor(props: { itemType: PType; immutable: boolean }) { + constructor(props: { itemType: PType; immutable?: boolean }) { const name = `Array<${props.itemType.name}>` super({ name, @@ -519,7 +519,7 @@ export class ArrayPType extends TransientType { singleton: false, }) this.itemType = props.itemType - this.immutable = props.immutable + this.immutable = props.immutable ?? true } get wtype() { diff --git a/tests/approvals/byte-expressions.algo.ts b/tests/approvals/byte-expressions.algo.ts index 27daf974..6d088883 100644 --- a/tests/approvals/byte-expressions.algo.ts +++ b/tests/approvals/byte-expressions.algo.ts @@ -9,4 +9,5 @@ function test(a: uint64, b: biguint, c: string) { assert(BigUint(Bytes(b)) === b) assert(String(Bytes(c)) === c) assert(Bytes(Bytes('123')) === Bytes('123')) + assert(Bytes([1, 2, 3, 4]) === Bytes.fromHex('01020304')) } diff --git a/tests/approvals/out/byte-expressions.awst b/tests/approvals/out/byte-expressions.awst index 5e320aab..8467c8ed 100644 --- a/tests/approvals/out/byte-expressions.awst +++ b/tests/approvals/out/byte-expressions.awst @@ -6,9 +6,6 @@ subroutine test(a: uint64, b: biguint, c: string): void assert(0x0100 == 0x0100) assert(reinterpret_cast(itob(b)) == b) assert(reinterpret_cast(reinterpret_cast(c)) == c) -} -subroutine testUnsupported(b: bytes): void -{ - 0x - 0x + assert("123" == "123") + assert(0x01020304 == 0x01020304) } \ No newline at end of file diff --git a/tests/approvals/out/byte-expressions.awst.json b/tests/approvals/out/byte-expressions.awst.json index 8e1b46aa..5ecc4eaf 100644 --- a/tests/approvals/out/byte-expressions.awst.json +++ b/tests/approvals/out/byte-expressions.awst.json @@ -4,7 +4,7 @@ "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", "line": 4, - "end_line": 11, + "end_line": 13, "column": 0, "end_column": 1 }, @@ -76,7 +76,7 @@ "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", "line": 4, - "end_line": 11, + "end_line": 13, "column": 48, "end_column": 1 }, @@ -741,122 +741,181 @@ ], "comment": null } - } - ], - "label": null, - "comment": null - }, - "documentation": { - "_type": "MethodDocumentation", - "description": null, - "args": {}, - "returns": null - }, - "id": "tests/approvals/byte-expressions.algo.ts::test", - "name": "test" - }, - { - "_type": "Subroutine", - "source_location": { - "file": "tests/approvals/byte-expressions.algo.ts", - "line": 13, - "end_line": 16, - "column": 0, - "end_column": 1 - }, - "args": [ - { - "_type": "SubroutineArgument", - "name": "b", - "wtype": { - "_type": "WType", - "name": "bytes", - "immutable": true, - "ephemeral": false, - "scalar_type": 1 }, - "source_location": { - "file": "tests/approvals/byte-expressions.algo.ts", - "line": 13, - "end_line": 13, - "column": 25, - "end_column": 33 - } - } - ], - "return_type": { - "_type": "WType", - "name": "void", - "immutable": true, - "ephemeral": false, - "scalar_type": null - }, - "body": { - "_type": "Block", - "source_location": { - "file": "tests/approvals/byte-expressions.algo.ts", - "line": 13, - "end_line": 16, - "column": 35, - "end_column": 1 - }, - "body": [ { "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", - "line": 14, - "end_line": 14, + "line": 11, + "end_line": 11, "column": 2, - "end_column": 10 + "end_column": 46 }, "expr": { - "_type": "BytesConstant", + "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", - "line": 14, - "end_line": 14, + "line": 11, + "end_line": 11, "column": 2, - "end_column": 10 + "end_column": 46 }, "wtype": { "_type": "WType", - "name": "bytes", + "name": "void", "immutable": true, "ephemeral": false, - "scalar_type": 1 + "scalar_type": null }, - "value": "", - "encoding": "unknown" + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "BytesComparisonExpression", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 11, + "end_line": 11, + "column": 9, + "end_column": 45 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "lhs": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 11, + "end_line": 11, + "column": 21, + "end_column": 26 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "F)}j", + "encoding": "utf8" + }, + "operator": "==", + "rhs": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 11, + "end_line": 11, + "column": 39, + "end_column": 44 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "F)}j", + "encoding": "utf8" + } + } + ], + "comment": null } }, { "_type": "ExpressionStatement", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", - "line": 15, - "end_line": 15, + "line": 12, + "end_line": 12, "column": 2, - "end_column": 11 + "end_column": 59 }, "expr": { - "_type": "BytesConstant", + "_type": "IntrinsicCall", "source_location": { "file": "tests/approvals/byte-expressions.algo.ts", - "line": 15, - "end_line": 15, + "line": 12, + "end_line": 12, "column": 2, - "end_column": 11 + "end_column": 59 }, "wtype": { "_type": "WType", - "name": "bytes", + "name": "void", "immutable": true, "ephemeral": false, - "scalar_type": 1 + "scalar_type": null }, - "value": "", - "encoding": "unknown" + "op_code": "assert", + "immediates": [], + "stack_args": [ + { + "_type": "BytesComparisonExpression", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 12, + "end_line": 12, + "column": 9, + "end_column": 58 + }, + "wtype": { + "_type": "WType", + "name": "bool", + "immutable": true, + "ephemeral": false, + "scalar_type": 2 + }, + "lhs": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 12, + "end_line": 12, + "column": 15, + "end_column": 27 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "0RjUA", + "encoding": "unknown" + }, + "operator": "==", + "rhs": { + "_type": "BytesConstant", + "source_location": { + "file": "tests/approvals/byte-expressions.algo.ts", + "line": 12, + "end_line": 12, + "column": 33, + "end_column": 58 + }, + "wtype": { + "_type": "WType", + "name": "bytes", + "immutable": true, + "ephemeral": false, + "scalar_type": 1 + }, + "value": "0RjUA", + "encoding": "base16" + } + } + ], + "comment": null } } ], @@ -869,7 +928,7 @@ "args": {}, "returns": null }, - "id": "tests/approvals/byte-expressions.algo.ts::testUnsupported", - "name": "testUnsupported" + "id": "tests/approvals/byte-expressions.algo.ts::test", + "name": "test" } ] \ No newline at end of file diff --git a/tests/expected-output/_run.spec.ts b/tests/expected-output/_run.spec.ts index d011e92f..60ef4187 100644 --- a/tests/expected-output/_run.spec.ts +++ b/tests/expected-output/_run.spec.ts @@ -90,7 +90,7 @@ class MissingLogError implements Error { return `Expected log: [${this.expectedLog.level}] ${this.expectedLog.message}\n${foundLog}` } get stack() { - return this.expectedLog.sourceLocation.toString() + return this.potentialMatch?.sourceLocation?.toString() ?? this.expectedLog.sourceLocation.toString() } get name() { return 'MissingLogError' diff --git a/tests/expected-output/biguint-expressions.algo.ts b/tests/expected-output/biguint-expressions.algo.ts index cd17aacd..e4063077 100644 --- a/tests/expected-output/biguint-expressions.algo.ts +++ b/tests/expected-output/biguint-expressions.algo.ts @@ -1,11 +1,11 @@ import { BigUint } from '@algorandfoundation/algorand-typescript' function testErrors(b: string) { - // @expect-error biguint overflow or underflow: -1 + // @expect-error Arg 0 of BigUInt has an incorrect type of -1... BigUint(-1) - // @expect-error biguint overflow or underflow: -1 + // @expect-error Arg 0 of BigUInt has an incorrect type of -1... BigUint(-1n) - // @expect-error biguint overflow or underflow: 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096 + // @expect-error Arg 0 of BigUInt has an incorrect type of 13407807929... BigUint(2n ** 512n) // @expect-error Only compile time constant string values are supported BigUint(b) diff --git a/tests/expected-output/byte-expressions.algo.ts b/tests/expected-output/byte-expressions.algo.ts index f61b23f5..e3e0db77 100644 --- a/tests/expected-output/byte-expressions.algo.ts +++ b/tests/expected-output/byte-expressions.algo.ts @@ -5,4 +5,6 @@ function testUnsupported() { Bytes(1) // @expect-error Expression of type `bigint` must be explicitly converted to an algo-ts type... Bytes(1n) + // @expect-error A compile time constant value between 0 and 255 is expected here... + Bytes([500]) }