Skip to content

Commit

Permalink
feat: Add DynamicBytes and StaticBytes types
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanmenzel committed Nov 27, 2024
1 parent 49f0cd6 commit 607d15f
Show file tree
Hide file tree
Showing 20 changed files with 4,380 additions and 2,460 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"dev:examples": "tsx src/cli.ts build examples --output-awst --output-awst-json",
"dev:approvals": "rimraf tests/approvals/out && tsx src/cli.ts build tests/approvals --dry-run",
"dev:expected-output": "tsx src/cli.ts build tests/expected-output --dry-run",
"dev:testing": "tsx src/cli.ts build tests/approvals/named-types.algo.ts --output-awst --output-awst-json --output-ssa-ir --log-level=info --log-level debug --out-dir out/[name]",
"dev:testing": "tsx src/cli.ts build tests/approvals/arc4-types.algo.ts --output-awst --output-awst-json --output-ssa-ir --log-level=info --log-level debug --out-dir out/[name]",
"audit": "better-npm-audit audit",
"format": "prettier --write .",
"lint": "eslint \"src/**/*.ts\"",
Expand Down
41 changes: 41 additions & 0 deletions packages/algo-ts/src/arc4/encoded-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,44 @@ class StructImpl<T extends StructConstraint> extends StructBase {
type StructConstructor = new <T extends StructConstraint>(initial: T) => StructBase & T

export const Struct = StructImpl as StructConstructor

export class DynamicBytes extends Arc4ReadonlyArray<Byte> {
[TypeProperty]?: `arc4.DynamicBytes`

constructor(value?: bytes | string) {
let byteValues: Uint8Array
if (value === undefined) {
byteValues = new Uint8Array(0)
} else if (typeof value === 'string') {
byteValues = BytesCls.fromCompat(value).asUint8Array()
} else {
byteValues = getUint8Array(value)
}
super(Array.from(byteValues).map((b) => new Byte(b)))
}

get native(): bytes {
return Bytes(this.items.map((i) => i.native))
}
}

export class StaticBytes<TLength extends number = 0> extends Arc4ReadonlyArray<Byte> {
[TypeProperty]?: `arc4.StaticBytes<${TLength}>`

constructor(value?: bytes | string) {
let byteValues: Uint8Array
if (value === undefined) {
// TODO: Should be init to TLength
byteValues = new Uint8Array(0)
} else if (typeof value === 'string') {
byteValues = BytesCls.fromCompat(value).asUint8Array()
} else {
byteValues = getUint8Array(value)
}
super(Array.from(byteValues).map((b) => new Byte(b)))
}

get native(): bytes {
return Bytes(this.items.map((i) => i.native))
}
}
9 changes: 8 additions & 1 deletion src/awst_build/ast-visitors/source-file-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ export class SourceFileVisitor extends BaseVisitor implements Visitor<ModuleStat
super(context)

for (const statement of sourceFile.statements) {
this._moduleStatements.push(this.accept(statement))
try {
this._moduleStatements.push(this.accept(statement))
} catch (e) {
// Ignore this error and continue visiting other members, so we can show additional errors
if (!(e instanceof AwstBuildFailureError)) {
throw e
}
}
}
}

Expand Down
135 changes: 133 additions & 2 deletions src/awst_build/eb/arc4/arrays.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { nodeFactory } from '../../../awst/node-factory'
import type { Expression } from '../../../awst/nodes'
import { IntegerConstant, StringConstant } from '../../../awst/nodes'
import { BytesConstant, IntegerConstant, StringConstant } from '../../../awst/nodes'
import type { SourceLocation } from '../../../awst/source-location'
import { wtypes } from '../../../awst/wtypes'
import { Constants } from '../../../constants'
import { wrapInCodeError } from '../../../errors'
import { logger } from '../../../logger'

import { base32ToUint8Array, codeInvariant, invariant } from '../../../util'
import { base32ToUint8Array, bigIntToUint8Array, codeInvariant, invariant } from '../../../util'
import type { PType } from '../../ptypes'
import { accountPType, bytesPType, IterableIteratorGeneric, NumericLiteralPType, stringPType, TuplePType, uint64PType } from '../../ptypes'
import {
Expand All @@ -16,8 +16,12 @@ import {
ARC4EncodedType,
DynamicArrayConstructor,
DynamicArrayType,
DynamicBytesConstructor,
DynamicBytesType,
StaticArrayConstructor,
StaticArrayType,
StaticBytesConstructor,
StaticBytesGeneric,
} from '../../ptypes/arc4-types'
import { instanceEb } from '../../type-registry'
import type { InstanceBuilder, NodeBuilder } from '../index'
Expand Down Expand Up @@ -163,6 +167,106 @@ export class AddressClassBuilder extends ClassBuilder {
)
}
}
export class StaticBytesClassBuilder extends ClassBuilder {
readonly ptype = StaticBytesConstructor

newCall(args: ReadonlyArray<NodeBuilder>, typeArgs: ReadonlyArray<PType>, sourceLocation: SourceLocation): InstanceBuilder {
const {
ptypes: [length],
args: [initialValue],
} = parseFunctionArgs({
args,
typeArgs,
callLocation: sourceLocation,
funcName: `${this.ptype.name} constructor`,
genericTypeArgs: 1,
argSpec: (a) => [a.optional(bytesPType)],
})
const resultPType = StaticBytesGeneric.parameterise([length])

codeInvariant(length instanceof NumericLiteralPType, 'length must be numeric literal', sourceLocation)
const byteLength = Number(length.literalValue)
if (!initialValue) {
return instanceEb(
nodeFactory.bytesConstant({
value: new Uint8Array(byteLength),
sourceLocation,
wtype: resultPType.wtype,
}),
resultPType,
)
}
const value = initialValue.resolve()
if (value instanceof BytesConstant) {
codeInvariant(value.value.length === byteLength, `Value should have byte length of ${byteLength}`, sourceLocation)
return instanceEb(
nodeFactory.bytesConstant({
value: value.value,
wtype: resultPType.wtype,
sourceLocation,
}),
resultPType,
)
} else {
return instanceEb(
nodeFactory.aRC4Encode({
value: initialValue.resolve(),
sourceLocation,
wtype: resultPType.wtype,
}),
resultPType,
)
}
}
}
export class DynamicBytesClassBuilder extends ClassBuilder {
readonly ptype = DynamicBytesConstructor

newCall(args: ReadonlyArray<NodeBuilder>, typeArgs: ReadonlyArray<PType>, sourceLocation: SourceLocation): InstanceBuilder {
const {
args: [initialValue],
} = parseFunctionArgs({
args,
typeArgs,
callLocation: sourceLocation,
funcName: `${this.ptype.name} constructor`,
genericTypeArgs: 0,
argSpec: (a) => [a.optional(bytesPType)],
})
const resultPType = DynamicBytesType

if (!initialValue) {
return instanceEb(
nodeFactory.bytesConstant({
value: new Uint8Array([0, 0]),
sourceLocation,
wtype: resultPType.wtype,
}),
resultPType,
)
}
const value = initialValue.resolve()
if (value instanceof BytesConstant) {
return instanceEb(
nodeFactory.bytesConstant({
value: new Uint8Array([...bigIntToUint8Array(BigInt(value.value.length), 2), ...value.value]),
sourceLocation,
wtype: resultPType.wtype,
}),
resultPType,
)
} else {
return instanceEb(
nodeFactory.aRC4Encode({
value,
sourceLocation,
wtype: resultPType.wtype,
}),
resultPType,
)
}
}
}

export abstract class ArrayExpressionBuilder<
TArrayType extends DynamicArrayType | StaticArrayType,
Expand Down Expand Up @@ -288,6 +392,33 @@ export class StaticArrayExpressionBuilder extends ArrayExpressionBuilder<StaticA
return super.memberAccess(name, sourceLocation)
}
}

export class DynamicBytesExpressionBuilder extends DynamicArrayExpressionBuilder {
memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder {
switch (name) {
case 'native':
return instanceEb(
nodeFactory.aRC4Decode({
wtype: bytesPType.wtype,
value: this.resolve(),
sourceLocation,
}),
bytesPType,
)
}
return super.memberAccess(name, sourceLocation)
}
}
export class StaticBytesExpressionBuilder extends StaticArrayExpressionBuilder {
memberAccess(name: string, sourceLocation: SourceLocation): NodeBuilder {
switch (name) {
case 'native':
return instanceEb(this.toBytes(sourceLocation), bytesPType)
}
return super.memberAccess(name, sourceLocation)
}
}

export class AddressExpressionBuilder extends ArrayExpressionBuilder<StaticArrayType> {
constructor(expr: Expression, ptype: PType) {
invariant(ptype instanceof StaticArrayType, 'ptype must be instance of StaticArrayType')
Expand Down
Loading

0 comments on commit 607d15f

Please sign in to comment.