Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work #22

Merged
merged 25 commits into from
Oct 16, 2024
Merged

Work #22

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
929e47b
fix: wtype for box_resize
tristanmenzel Oct 11, 2024
b0034ef
fix: Make all tuples immutable for now to match puya
tristanmenzel Oct 15, 2024
b5e75e4
refactor: Remove superfluous source location param
tristanmenzel Oct 15, 2024
f2862b3
fix: not node still requires int to be cast to bool
tristanmenzel Oct 15, 2024
a181cce
fix: Ensure nested assignments use correct lvalue logic
tristanmenzel Oct 15, 2024
103f372
fix: Use platform agnostic command name
tristanmenzel Oct 15, 2024
d12456e
refactor: Rename fatal log to critical to match puya and improve log …
tristanmenzel Oct 15, 2024
80ddc85
test: Check for general error log messages without a source location …
tristanmenzel Oct 15, 2024
a2bdce1
feat: Add hooks to compile process for consumers to manipulate TS AST…
tristanmenzel Oct 15, 2024
98336dc
feat: Include --isolated-files option to compile each individual file…
tristanmenzel Oct 15, 2024
29b11a4
test: Have approval tests invoke puya compiler to provide additional …
tristanmenzel Oct 15, 2024
980d792
fix: Patched awst serializer to work with puya's simplified approach …
tristanmenzel Oct 15, 2024
3100c50
refactor: Use unreachable exception
tristanmenzel Oct 15, 2024
c5e8005
fix: Builder can be returned as is if ptype is an exact match
tristanmenzel Oct 15, 2024
28b68ca
fix: Use correct node type for local state expressions
tristanmenzel Oct 15, 2024
ba8c399
test: Add some additional approvals and regenerate
tristanmenzel Oct 15, 2024
7b39597
feat: Error when attemping to mutate an immutable tuple type
tristanmenzel Oct 16, 2024
eb1cea4
feat: Introduce a logging context which holds logs and source lines …
tristanmenzel Oct 16, 2024
bd7eb84
docs: Drop tealscript example - it's not very useful
tristanmenzel Oct 16, 2024
89bba6e
fix: Remove circular dependencies and ensure build fails in future if…
tristanmenzel Oct 16, 2024
2e2021e
chore: Change approvals script to use puya for additional verificatio…
tristanmenzel Oct 16, 2024
19520b1
test: Include the details of any logs which are found
tristanmenzel Oct 16, 2024
4cd3c2c
build: Install puya compiler before testing
tristanmenzel Oct 16, 2024
8946292
build: Configure python version in CI
tristanmenzel Oct 16, 2024
7a19f23
build: Specify python version for pipx install
tristanmenzel Oct 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ jobs:
audit-script: npm run audit
upload-artifact-name: puya-ts
upload-artifact-path: ./dist
python-version: 3.12.6
pre-test-script: |
pipx install puyapy --python 3.12.6
9 changes: 9 additions & 0 deletions .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
required: false
type: string
default: 18.x
python-version:
required: false
type: string
working-directory:
required: false
type: string
Expand Down Expand Up @@ -110,6 +113,12 @@ jobs:
cache: 'npm'
cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json

- name: Set up Python
if: ${{ inputs.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}

- name: Download artifacts
if: ${{ inputs.download-artifact-name || inputs.download-artifact-pattern }}
uses: actions/download-artifact@v4
Expand Down
18 changes: 0 additions & 18 deletions examples/tealscript/example.algo.ts

This file was deleted.

24 changes: 0 additions & 24 deletions examples/tealscript/teal-script-base.algo.ts

This file was deleted.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
"dev:hello": "tsx src/cli.ts build examples/hello-world/contract.algo.ts --output-awst --output-awst-json",
"dev:hello-abi": "tsx src/cli.ts build examples/hello-world-abi ",
"dev:calculator": "tsx src/cli.ts build examples/calculator/contract.algo.ts",
"dev:tealscript": "tsx src/cli.ts build examples/tealscript/example.algo.ts",
"dev:approvals": "tsx src/cli.ts build tests/approvals --output-awst --output-awst-json --dry-run",
"dev:approvals": "tsx src/cli.ts build tests/approvals --output-awst --output-awst-json --no-output-teal --no-output-arc32",
"dev:expected-output": "tsx src/cli.ts build tests/expected-output --dry-run",
"dev:testing": "tsx src/cli.ts build tests/approvals/byte-expressions.algo.ts --output-awst --output-awst-json --log-level=info",
"audit": "better-npm-audit audit",
Expand Down
7 changes: 7 additions & 0 deletions rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ const config: RollupOptions = {
nodeResolve(),
json(),
],
onwarn(log, defaultHandler) {
if (log.code === 'CIRCULAR_DEPENDENCY') {
throw new Error(log.message)
} else {
defaultHandler(log)
}
},
}

export default config
7 changes: 3 additions & 4 deletions scripts/generate-op-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as fs from 'fs'
import { camelCase } from 'change-case'
import * as fs from 'fs'
import { enumerate, hasFlags } from '../src/util'
import type { OpFunction, OpGrouping, OpOverloadedFunction } from './build-op-module'
import { AlgoTsType, buildOpModule } from './build-op-module'
import { enumerate, hasFlags } from '../src/util'
import { it } from 'vitest'

const opModule = buildOpModule()

Expand Down Expand Up @@ -120,7 +119,7 @@ function mapReturnType(returnTypes: AlgoTsType[]) {
if (ptypes.length === 1) {
return ptypes[0]
}
return `new ptypes.TuplePType({items: [${ptypes.join(', ')}], immutable: true})`
return `new ptypes.TuplePType({items: [${ptypes.join(', ')}]})`
}

function* emitTypes() {
Expand Down
20 changes: 19 additions & 1 deletion src/awst/json-serialize-awst.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { snakeCase } from 'change-case'
import path from 'node:path'
import { Constants } from '../constants'
import { logger } from '../logger'
import { invariant } from '../util'
import { buildBase85Encoder } from '../util/base-85'
import { ContractReference, LogicSigReference } from './models'
import { ARC4ABIMethodConfig, ContractReference, LogicSigReference } from './models'
import type { RootNode } from './nodes'
import { SourceLocation } from './source-location'

Expand Down Expand Up @@ -73,6 +74,23 @@ export class AwstSerializer extends SnakeCaseSerializer<RootNode[]> {
file: filePath,
}
}
if (value instanceof ARC4ABIMethodConfig) {
// TODO: This can be removed once puya has been updated to support a more advanced default args schema
return {
_type: value.constructor.name,
...(super.serializerFunction(key, value) as object),
default_args: Object.fromEntries(
Object.entries(value.defaultArgs).flatMap(([key, v]) => {
if (v.source === 'constant') {
logger.warn(value.sourceLocation, `Ignoring constant default value for ${key} as puya does not support this yet`)
return []
} else {
return [[key, v.memberName]]
}
}),
),
}
}
if (value instanceof Uint8Array) {
return this.b85.encode(value)
}
Expand Down
2 changes: 1 addition & 1 deletion src/awst/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class LogicSigReference extends ModelBase {
return this.id
}
}
export type CompilationSet = ReadonlyArray<ContractReference | LogicSigReference>
export type CompilationSet = Array<ContractReference | LogicSigReference>

export enum TransactionKind {
pay = 1,
Expand Down
2 changes: 1 addition & 1 deletion src/awst/node-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ const explicitNodeFactory = {
tupleExpression(props: Omit<Props<TupleExpression>, 'wtype'>) {
return new TupleExpression({
...props,
wtype: new WTuple({ types: props.items.map((i) => i.wtype), immutable: false }),
wtype: new WTuple({ types: props.items.map((i) => i.wtype), immutable: true }),
})
},
methodDocumentation(props?: { description?: string | null; args?: Map<string, string>; returns?: string | null }) {
Expand Down
5 changes: 2 additions & 3 deletions src/awst_build/base-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ export abstract class BaseVisitor implements Visitor<Expressions, NodeBuilder> {
items: sourceType.items.map((item, index) =>
index < targetType.items.length ? this.buildAssignmentExpressionType(targetType.items[index], item, sourceLocation) : item,
),
immutable: sourceType.immutable,
})
} else if (targetType instanceof ArrayPType) {
// Narrow array literal types to array type
Expand Down Expand Up @@ -556,7 +555,7 @@ export abstract class BaseVisitor implements Visitor<Expressions, NodeBuilder> {
for (const [index, sourceItemType] of enumerate(assignmentType.items)) {
const targetItem = targetItems[index]
if (targetItem && !(targetItem instanceof OmittedExpressionBuilder)) {
targets.push(targetItem.resolveToPType(sourceItemType).resolveLValue())
targets.push(this.buildLValue(targetItem, sourceItemType, sourceLocation))
} else {
targets.push(
nodeFactory.varExpression({
Expand All @@ -575,7 +574,7 @@ export abstract class BaseVisitor implements Visitor<Expressions, NodeBuilder> {
const targets: LValue[] = []
for (const [propName, propType] of assignmentType.orderedProperties()) {
if (target.hasProperty(propName)) {
targets.push(target.memberAccess(propName, sourceLocation).resolveLValue())
targets.push(this.buildLValue(target.memberAccess(propName, sourceLocation), propType, sourceLocation))
} else {
targets.push(
nodeFactory.varExpression({
Expand Down
4 changes: 1 addition & 3 deletions src/awst_build/eb/arc4/arrays.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ class EntriesFunctionBuilder extends FunctionBuilder {

call(args: ReadonlyArray<InstanceBuilder>, typeArgs: ReadonlyArray<PType>, sourceLocation: SourceLocation): NodeBuilder {
parseFunctionArgs({ args, typeArgs, callLocation: sourceLocation, argSpec: (_) => [], genericTypeArgs: 0, funcName: 'entries' })
const iteratorType = IterableIteratorType.parameterise([
new TuplePType({ items: [uint64PType, this.arrayBuilder.ptype.elementType], immutable: true }),
])
const iteratorType = IterableIteratorType.parameterise([new TuplePType({ items: [uint64PType, this.arrayBuilder.ptype.elementType] })])
return new IterableIteratorExpressionBuilder(
nodeFactory.enumeration({
expr: this.arrayBuilder.iterate(sourceLocation),
Expand Down
2 changes: 1 addition & 1 deletion src/awst_build/eb/assert-match-function-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class AssertMatchFunctionBuilder extends NodeBuilder {
)
} else if (testProperty.hasProperty('between')) {
const range = requireInstanceBuilder(testProperty.memberAccess('between', sourceLocation)).singleEvaluation()
const rangePType = new TuplePType({ items: [subjectType, subjectType], immutable: true })
const rangePType = new TuplePType({ items: [subjectType, subjectType] })
codeInvariant(range.resolvableToPType(rangePType), 'Between range must be of type $')
const zeroIndex = instanceEb(nodeFactory.uInt64Constant({ value: 0n, sourceLocation }), uint64PType)
const gte = subjectProperty
Expand Down
5 changes: 3 additions & 2 deletions src/awst_build/eb/biguint-expression-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { logger } from '../../logger'
import { tryConvertEnum } from '../../util'
import type { InstanceType, PType } from '../ptypes'
import { BigUintFunction, biguintPType, boolPType, bytesPType, stringPType, uint64PType } from '../ptypes'
import { BooleanExpressionBuilder } from './boolean-expression-builder'
import { instanceEb } from '../type-registry'
import type { InstanceBuilder } from './index'
import { BuilderBinaryOp, BuilderComparisonOp, BuilderUnaryOp, FunctionBuilder, InstanceExpressionBuilder } from './index'
import { UInt64ExpressionBuilder } from './uint64-expression-builder'
Expand Down Expand Up @@ -94,13 +94,14 @@ export class BigUintExpressionBuilder extends InstanceExpressionBuilder<Instance
sourceLocation,
})
}
return new BooleanExpressionBuilder(
return instanceEb(
nodeFactory.numericComparisonExpression({
lhs: this._expr,
rhs: otherExpr,
operator: numComOp,
sourceLocation,
}),
boolPType,
)
}
boolEval(sourceLocation: SourceLocation, negate: boolean = false): Expression {
Expand Down
6 changes: 5 additions & 1 deletion src/awst_build/eb/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { awst } from '../../awst'
import { nodeFactory } from '../../awst/node-factory'
import type { Expression } from '../../awst/nodes'
import { TupleItemExpression } from '../../awst/nodes'
import type { SourceLocation } from '../../awst/source-location'
import { CodeError, NotSupported } from '../../errors'
import { logger } from '../../logger'
Expand Down Expand Up @@ -236,14 +237,17 @@ export function requireLValue(expr: awst.Expression): awst.LValue {
awst.AppAccountStateExpression,
awst.BoxValueExpression,
]
if (expr instanceof TupleItemExpression) {
throw new CodeError('Expression is not a valid assignment target - object is immutable', { sourceLocation: expr.sourceLocation })
}
if (!lValueNodes.some((l) => expr instanceof l)) {
throw new CodeError(`Expression is not a valid assignment target`, {
sourceLocation: expr.sourceLocation,
})
}
if (expr instanceof awst.IndexExpression || expr instanceof awst.FieldExpression) {
if (expr.base.wtype.immutable) {
throw new CodeError(`${expr.wtype} is not a valid assignment target as it is immutable`, {
throw new CodeError(`Expression is not a valid assignment target - object is immutable`, {
sourceLocation: expr.sourceLocation,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ import {
TransientType,
uint64PType,
} from '../../ptypes'
import { typeRegistry } from '../../type-registry'
import { BigUintExpressionBuilder } from '../biguint-expression-builder'
import { instanceEb, typeRegistry } from '../../type-registry'
import { foldBinaryOp, foldComparisonOp } from '../folding'
import type { BuilderBinaryOp, BuilderComparisonOp, InstanceBuilder } from '../index'
import { BuilderUnaryOp } from '../index'
import { LiteralExpressionBuilder } from '../literal-expression-builder'
import { UInt64ExpressionBuilder } from '../uint64-expression-builder'
import { isValidLiteralForPType } from '../util'

export class BigIntLiteralExpressionBuilder extends LiteralExpressionBuilder {
Expand Down Expand Up @@ -64,9 +62,9 @@ export class BigIntLiteralExpressionBuilder extends LiteralExpressionBuilder {

codeInvariant(isValidLiteralForPType(this.value, ptype), `${ptype.name} overflow or underflow: ${this.value}`, this.sourceLocation)
if (ptype.equals(uint64PType)) {
return new UInt64ExpressionBuilder(nodeFactory.uInt64Constant({ value: this.value, sourceLocation: this.sourceLocation }))
return instanceEb(nodeFactory.uInt64Constant({ value: this.value, sourceLocation: this.sourceLocation }), uint64PType)
} else if (ptype.equals(biguintPType)) {
return new BigUintExpressionBuilder(nodeFactory.bigUIntConstant({ value: this.value, sourceLocation: this.sourceLocation }))
return instanceEb(nodeFactory.bigUIntConstant({ value: this.value, sourceLocation: this.sourceLocation }), biguintPType)
}
throw new CodeError(`${this.value} cannot be converted to type ${ptype.name}`, { sourceLocation: this.sourceLocation })
}
Expand Down
3 changes: 3 additions & 0 deletions src/awst_build/eb/literal/object-expression-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class ObjectExpressionBuilder extends InstanceExpressionBuilder<ObjectPTy
}

resolveToPType(ptype: PTypeOrClass): InstanceBuilder {
if (ptype.equals(this.ptype)) {
return this
}
if (this.resolvableToPType(ptype)) {
const base = this.singleEvaluation()
return instanceEb(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class ObjectLiteralExpressionBuilder extends LiteralExpressionBuilder {

resolve(): Expression {
// Resolve object to a tuple using its own inferred types
return this.toTuple(this.ptype, this.sourceLocation)
return this.toTuple(this.ptype)
}
resolveLValue(): LValue {
return nodeFactory.tupleExpression({
Expand All @@ -65,7 +65,7 @@ export class ObjectLiteralExpressionBuilder extends LiteralExpressionBuilder {
return this.parts.some((part) => (part.type === 'properties' ? Object.hasOwn(part.properties, name) : part.obj.hasProperty(name)))
}

private toTuple(ptype: ObjectPType, sourceLocation: SourceLocation): Expression {
private toTuple(ptype: ObjectPType): Expression {
return nodeFactory.tupleExpression({
items: ptype
.orderedProperties()
Expand All @@ -86,7 +86,7 @@ export class ObjectLiteralExpressionBuilder extends LiteralExpressionBuilder {

resolveToPType(ptype: PTypeOrClass): InstanceBuilder {
codeInvariant(ptype instanceof ObjectPType, `Object literal cannot be resolved to type ${ptype}`, this.sourceLocation)
return new ObjectExpressionBuilder(this.toTuple(ptype, this.sourceLocation), ptype)
return new ObjectExpressionBuilder(this.toTuple(ptype), ptype)
}

assign(other: InstanceBuilder, sourceLocation: SourceLocation): InstanceBuilder {
Expand Down
2 changes: 1 addition & 1 deletion src/awst_build/eb/shared/at-function-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ 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'
import { getBigIntOrUint64Expr } from '../util/get-bigint-or-uint64-expr'

export class AtFunctionBuilder extends FunctionBuilder {
constructor(
Expand Down
8 changes: 4 additions & 4 deletions src/awst_build/eb/shared/slice-function-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ 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 { instanceEb } from '../../type-registry'
import type { NodeBuilder } from '../index'
import { FunctionBuilder, type InstanceBuilder } from '../index'
import { getBigIntOrUint64Expr } from '../util'
import { parseFunctionArgs } from '../util/arg-parsing'
import { getBigIntOrUint64Expr } from '../util/get-bigint-or-uint64-expr'

export class SliceFunctionBuilder extends FunctionBuilder {
constructor(
Expand All @@ -29,15 +29,15 @@ export class SliceFunctionBuilder extends FunctionBuilder {
funcName: 'slice',
argSpec: (a) => [a.optional(uint64PType, numberPType), a.optional(uint64PType, numberPType)],
})

return new BytesExpressionBuilder(
return instanceEb(
nodeFactory.intersectionSliceExpression({
base: this.base,
sourceLocation: sourceLocation,
beginIndex: start ? getBigIntOrUint64Expr(start) : null,
endIndex: stop ? getBigIntOrUint64Expr(stop) : null,
wtype: this.resultPType.wtype,
}),
this.resultPType,
)
}
}
2 changes: 1 addition & 1 deletion src/awst_build/eb/storage/box/box-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class BoxMapMaybeFunctionBuilder extends BoxMapFunctionBuilderBase {
genericTypeArgs: 0,
argSpec: (a) => [a.required(this.keyType)],
})
const type = new TuplePType({ items: [this.contentType, boolPType], immutable: true })
const type = new TuplePType({ items: [this.contentType, boolPType] })

return instanceEb(
nodeFactory.stateGetEx({
Expand Down
4 changes: 2 additions & 2 deletions src/awst_build/eb/storage/box/box-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,11 @@ export class BoxRefResizeFunctionBuilder extends BoxRefBaseFunctionBuilder {
nodeFactory.intrinsicCall({
opCode: 'box_resize',
stackArgs: [this.boxValue, size.resolve()],
wtype: boolWType,
wtype: voidWType,
immediates: [],
sourceLocation,
}),
boolPType,
voidPType,
)
}
}
Expand Down
Loading