Skip to content

Commit

Permalink
feat: Support as casting
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanmenzel committed Dec 10, 2024
1 parent f94d9f4 commit c6670f7
Show file tree
Hide file tree
Showing 8 changed files with 1,379 additions and 9 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/reserve-scratch.algo.ts --output-awst --output-awst-json --output-ssa-ir --log-level=info --out-dir out/[name] --optimization-level=0",
"dev:testing": "tsx src/cli.ts build tests/approvals/casting.algo.ts --output-awst --output-awst-json --output-ssa-ir --log-level=info --out-dir out/[name] --optimization-level=0",
"audit": "better-npm-audit audit",
"format": "prettier --write .",
"lint": "eslint \"src/**/*.ts\"",
Expand Down
29 changes: 21 additions & 8 deletions src/awst_build/ast-visitors/base-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import {
import type { Visitor } from '../../visitor/visitor'
import { accept } from '../../visitor/visitor'
import type { AwstBuildContext } from '../context/awst-build-context'
import type { InstanceBuilder } from '../eb'
import { NodeBuilder } from '../eb'
import { InstanceBuilder, NodeBuilder } from '../eb'
import { BooleanExpressionBuilder } from '../eb/boolean-expression-builder'
import { ArrayLiteralExpressionBuilder } from '../eb/literal/array-literal-expression-builder'
import { BigIntLiteralExpressionBuilder } from '../eb/literal/big-int-literal-expression-builder'
Expand Down Expand Up @@ -453,12 +452,26 @@ export abstract class BaseVisitor implements Visitor<Expressions, NodeBuilder> {
}

visitAsExpression(node: ts.AsExpression): NodeBuilder {
// TODO: Is this robust enough??
if (ts.isTypeReferenceNode(node.type) && ts.isIdentifier(node.type.typeName) && node.type.typeName.text === 'const') {
// TODO: Do we need to do resolveAsPType here to re-resolve the target expression
return this.baseAccept(node.expression)
}
throw new TodoError('AsExpression')
// if (ts.isTypeReferenceNode(node.type) && ts.isIdentifier(node.type.typeName) && node.type.typeName.text === 'const') {
// return this.baseAccept(node.expression)
// }
const outerType = this.context.getPTypeForNode(node)

const innerExpr = this.baseAccept(node.expression)
const sourceLocation = this.sourceLocation(node)
codeInvariant(
innerExpr instanceof InstanceBuilder,
`${innerExpr.typeDescription} is not a valid target for an as expression'`,
sourceLocation,
)

codeInvariant(
innerExpr.resolvableToPType(outerType),
`${innerExpr.typeDescription} cannot be resolved to type ${outerType}`,
sourceLocation,
)

return innerExpr.resolveToPType(outerType)
}

visitNonNullExpression(node: ts.NonNullExpression): NodeBuilder {
Expand Down
14 changes: 14 additions & 0 deletions tests/approvals/casting.algo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { uint64 } from '@algorandfoundation/algorand-typescript'
import { BaseContract } from '@algorandfoundation/algorand-typescript'

export class CastingAlgo extends BaseContract {
approvalProgram(): boolean {
const x = 123 as uint64

const y = [1, 2, 3] as [uint64, uint64, uint64]

const z = [1 as uint64, 2 as uint64, 3 as uint64] as const

return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
}
}
55 changes: 55 additions & 0 deletions tests/approvals/out/casting/CastingAlgo.approval.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma version 10

tests/approvals/casting.algo.ts::CastingAlgo.approvalProgram:
intcblock 1 2 3
txn ApplicationID
bnz main_after_if_else@2
callsub constructor

main_after_if_else@2:
// tests/approvals/casting.algo.ts:8
// const y = [1, 2, 3] as [uint64, uint64, uint64]
intc_0 // 1
intc_1 // 2
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
*
// tests/approvals/casting.algo.ts:8
// const y = [1, 2, 3] as [uint64, uint64, uint64]
intc_2 // 3
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
*
// tests/approvals/casting.algo.ts:10
// const z = [1 as uint64, 2 as uint64, 3 as uint64] as const
intc_0 // 1
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
*
// tests/approvals/casting.algo.ts:10
// const z = [1 as uint64, 2 as uint64, 3 as uint64] as const
intc_1 // 2
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
*
// tests/approvals/casting.algo.ts:10
// const z = [1 as uint64, 2 as uint64, 3 as uint64] as const
intc_2 // 3
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
*
// tests/approvals/casting.algo.ts:6
// const x = 123 as uint64
pushint 123 // 123
// tests/approvals/casting.algo.ts:12
// return x > y[0] * y[1] * y[2] * z[0] * z[1] * z[2]
<
return


// tests/approvals/casting.algo.ts::CastingAlgo.constructor() -> void:
constructor:
// tests/approvals/casting.algo.ts:4
// export class CastingAlgo extends BaseContract {
proto 0 0
retsub
5 changes: 5 additions & 0 deletions tests/approvals/out/casting/CastingAlgo.clear.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma version 10

tests/approvals/casting.algo.ts::CastingAlgo.clearStateProgram:
pushint 1 // 1
return
29 changes: 29 additions & 0 deletions tests/approvals/out/casting/CastingAlgo.ssa.ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
contract tests/approvals/casting.algo.ts::CastingAlgo:
program approval:
subroutine tests/approvals/casting.algo.ts::CastingAlgo.approvalProgram() -> bool:
block@0: // L5
let reinterpret_bool%0#0: bool = (txn ApplicationID)
goto reinterpret_bool%0#0 ? block@2 : block@1
block@1: // if_body_L1
tests/approvals/casting.algo.ts::CastingAlgo.constructor()
goto block@2
block@2: // after_if_else_L1
let x#0: uint64 = 123u
let (y.0#0: uint64, y.1#0: uint64, y.2#0: uint64) = (1u, 2u, 3u)
let (z.0#0: uint64, z.1#0: uint64, z.2#0: uint64) = (1u, 2u, 3u)
let tmp%0#0: uint64 = (* y.0#0 y.1#0)
let tmp%1#0: uint64 = (* tmp%0#0 y.2#0)
let tmp%2#0: uint64 = (* tmp%1#0 z.0#0)
let tmp%3#0: uint64 = (* tmp%2#0 z.1#0)
let tmp%4#0: uint64 = (* tmp%3#0 z.2#0)
let tmp%5#0: bool = (> x#0 tmp%4#0)
return tmp%5#0

subroutine tests/approvals/casting.algo.ts::CastingAlgo.constructor() -> void:
block@0: // L4
return

program clear-state:
subroutine @algorandfoundation/algorand-typescript/base-contract.d.ts::BaseContract.clearStateProgram() -> bool:
block@0: // L1
return 1u
28 changes: 28 additions & 0 deletions tests/approvals/out/casting/casting.awst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
contract CastingAlgo
{
approvalProgram(): bool
{
if (!Boolean(txn<ApplicationID>())) {
this.constructor()
}
x: uint64 = 123
y: readonlytuple[uint64, uint64, uint64] = <tuple>[1, 2, 3]
z: readonlytuple[uint64, uint64, uint64] = <tuple>[1, 2, 3]
return x > y.0 * y.1 * y.2 * z.0 * z.1 * z.2
}

clearProgram(): bool
{
return True
}

constructor(): void
{
void
}

BaseContract::constructor(): void
{
}

}
Loading

0 comments on commit c6670f7

Please sign in to comment.