Skip to content

Commit

Permalink
Merge pull request #71 from algorand-devrel/dev
Browse files Browse the repository at this point in the history
0.25.0
  • Loading branch information
joe-p authored Jul 8, 2023
2 parents 6192801 + 529a1a6 commit 54d1d41
Show file tree
Hide file tree
Showing 17 changed files with 452 additions and 6 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@algorandfoundation/tealscript",
"version": "0.25.0",
"version": "0.26.0",
"description": "Enables Algorand smart contract development with native TypeScript syntax, tooling, and IDE support",
"homepage": "https://github.com/algorand-devrel/TEALScript",
"bugs": {
Expand Down
28 changes: 24 additions & 4 deletions src/lib/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ export default class Compiler {
type: 'any',
args: 2,
fn: (node: ts.Node) => {
this.maybeValue(node, 'app_global_get_ex', StackType.bytes);
this.maybeValue(node, 'app_global_get_ex', StackType.any);
},
},
],
Expand Down Expand Up @@ -1552,8 +1552,6 @@ export default class Compiler {
const length = parseInt(typeHintNode.argumentExpression.getText(), 10);
const type = typeHintNode.expression.getText().replace(/\[\]$/, '');

if (length && length !== elements) throw new Error(`Array length mismatch: ${length} !== ${elements}`);

return new Array(elements).fill(type);
}

Expand Down Expand Up @@ -1684,6 +1682,7 @@ export default class Compiler {
if (!this.getABIType(typeHint).includes(']')) typeHint = `${typeHint}[]`;

const types = this.getarrayElementTypes(node.elements.length);
const arrayTypeHint = typeHint;
node.elements.forEach((e, i) => {
this.typeHint = types[i];
this.processNode(e);
Expand All @@ -1692,6 +1691,19 @@ export default class Compiler {
if (i) this.pushVoid(node, 'concat');
});

const typeHintNode = stringToExpression(this.getABIType(arrayTypeHint));

if (ts.isElementAccessExpression(typeHintNode)) {
const length = parseInt(typeHintNode.argumentExpression.getText(), 10);

if (length && node.elements.length < length) {
const typeLength = this.getTypeLength(baseType);
this.pushVoid(node, `byte 0x${'00'.repeat(typeLength * (length - node.elements.length))}`);

if (node.elements.length > 0) this.pushVoid(node, 'concat');
}
}

this.lastType = this.getABIType(typeHint);
}

Expand Down Expand Up @@ -2452,6 +2464,8 @@ export default class Compiler {
this.typeHint = this.getABIType(node.type.getText());
this.processNode(node.expression);

if (this.lastType === 'any') return;

const type = this.getABIType(node.type.getText());
if ((type.match(/uint\d+$/) || type.match(/ufixed\d+x\d+$/)) && type !== this.lastType) {
const typeBitWidth = parseInt(type.replace('uint', ''), 10);
Expand Down Expand Up @@ -2787,6 +2801,8 @@ export default class Compiler {

this.updateValue(node.expression.expression);
this.lastType = `${elementType}[]`;
} else if (methodName === 'forEach') {
throw Error('forEach not yet supported. Use for loop instead');
} else if (node.expression.expression.kind === ts.SyntaxKind.ThisKeyword) {
const preArgsType = this.lastType;
this.pushVoid(node, `PENDING_DUPN: ${methodName}`);
Expand Down Expand Up @@ -3244,9 +3260,13 @@ export default class Compiler {
if (!ts.isPropertyAccessExpression(node.expression.expression)) throw new Error();

const op = node.expression.name.getText();
const { type } = this.storageProps[node.expression.expression.name.getText()];
const { type, valueType } = this.storageProps[node.expression.expression.name.getText()];

this.typeHint = valueType;

this.storageFunctions[type][op](node);

this.typeHint = undefined;
}

private processTransaction(node: ts.CallExpression) {
Expand Down
12 changes: 12 additions & 0 deletions tests/abi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,4 +589,16 @@ describe('ABI', function () {

expect(await runMethod(appClient, 'stringAccessor')).toEqual('e');
});

test.concurrent('emptyStaticArray', async () => {
const { appClient } = await compileAndCreate('emptyStaticArray');

expect(await runMethod(appClient, 'emptyStaticArray')).toEqual([0n, 0n, 0n]);
});

test.concurrent('partialStaticArray', async () => {
const { appClient } = await compileAndCreate('partialStaticArray');

expect(await runMethod(appClient, 'partialStaticArray')).toEqual([1n, 0n, 0n]);
});
});
26 changes: 26 additions & 0 deletions tests/contracts/abi.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -803,3 +803,29 @@ class ABITestStringAccessor extends Contract {
return s[1];
}
}

class ABITestEmptyStaticArray extends Contract {
emptyStaticArray(): StaticArray<uint<16>, 3> {
const a: StaticArray<uint<16>, 3> = [];

return a;
}
}

class ABITestPartialStaticArray extends Contract {
partialStaticArray(): StaticArray<uint<16>, 3> {
const a: StaticArray<uint<16>, 3> = [1];

return a;
}
}

class ABITestStorageTypeHint extends Contract {
gKey = new GlobalStateKey<StaticArray<uint<16>, 3>>();

partialStaticArray(): StaticArray<uint<16>, 3> {
this.gKey.set([1, 2, 3]);

return this.gKey.get();
}
}
15 changes: 15 additions & 0 deletions tests/contracts/artifacts/ABITestEmptyStaticArray.abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "ABITestEmptyStaticArray",
"desc": "",
"methods": [
{
"name": "emptyStaticArray",
"args": [],
"desc": "",
"returns": {
"type": "uint16[3]",
"desc": ""
}
}
]
}
53 changes: 53 additions & 0 deletions tests/contracts/artifacts/ABITestEmptyStaticArray.approval.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma version 8
b main

abi_route_emptyStaticArray:
txn OnCompletion
int NoOp
==
txn ApplicationID
int 0
!=
&&
assert
byte 0x
callsub emptyStaticArray
int 1
return

emptyStaticArray:
proto 1 0

// tests/contracts/abi.algo.ts:809
// a: StaticArray<uint<16>, 3> = []
byte 0x000000000000
frame_bury -1 // a: uint16[3]

// tests/contracts/abi.algo.ts:811
// return a;
frame_dig -1 // a: uint16[3]
byte 0x151f7c75
swap
concat
log
retsub

main:
txn NumAppArgs
bnz route_abi

// default createApplication
txn ApplicationID
int 0
==
txn OnCompletion
int NoOp
==
&&
return

route_abi:
method "emptyStaticArray()uint16[3]"
txna ApplicationArgs 0
match abi_route_emptyStaticArray
err
3 changes: 3 additions & 0 deletions tests/contracts/artifacts/ABITestEmptyStaticArray.clear.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma version 8
int 1
return
51 changes: 51 additions & 0 deletions tests/contracts/artifacts/ABITestEmptyStaticArray.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"hints": {
"emptyStaticArray()uint16[3]": {
"call_config": {
"no_op": "CALL"
}
}
},
"bare_call_config": {
"no_op": "CREATE"
},
"schema": {
"local": {
"declared": {},
"reserved": {}
},
"global": {
"declared": {},
"reserved": {}
}
},
"state": {
"global": {
"num_byte_slices": 0,
"num_uints": 0
},
"local": {
"num_byte_slices": 0,
"num_uints": 0
}
},
"source": {
"approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX2VtcHR5U3RhdGljQXJyYXk6Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCXR4biBBcHBsaWNhdGlvbklECglpbnQgMAoJIT0KCSYmCglhc3NlcnQKCWJ5dGUgMHgKCWNhbGxzdWIgZW1wdHlTdGF0aWNBcnJheQoJaW50IDEKCXJldHVybgoKZW1wdHlTdGF0aWNBcnJheToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4MDkKCS8vIGE6IFN0YXRpY0FycmF5PHVpbnQ8MTY+LCAzPiA9IFtdCglieXRlIDB4MDAwMDAwMDAwMDAwCglmcmFtZV9idXJ5IC0xIC8vIGE6IHVpbnQxNlszXQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4MTEKCS8vIHJldHVybiBhOwoJZnJhbWVfZGlnIC0xIC8vIGE6IHVpbnQxNlszXQoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgptYWluOgoJdHhuIE51bUFwcEFyZ3MKCWJueiByb3V0ZV9hYmkKCgkvLyBkZWZhdWx0IGNyZWF0ZUFwcGxpY2F0aW9uCgl0eG4gQXBwbGljYXRpb25JRAoJaW50IDAKCT09Cgl0eG4gT25Db21wbGV0aW9uCglpbnQgTm9PcAoJPT0KCSYmCglyZXR1cm4KCnJvdXRlX2FiaToKCW1ldGhvZCAiZW1wdHlTdGF0aWNBcnJheSgpdWludDE2WzNdIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2VtcHR5U3RhdGljQXJyYXkKCWVycg==",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu"
},
"contract": {
"name": "ABITestEmptyStaticArray",
"desc": "",
"methods": [
{
"name": "emptyStaticArray",
"args": [],
"desc": "",
"returns": {
"type": "uint16[3]",
"desc": ""
}
}
]
}
}
15 changes: 15 additions & 0 deletions tests/contracts/artifacts/ABITestPartialStaticArray.abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "ABITestPartialStaticArray",
"desc": "",
"methods": [
{
"name": "partialStaticArray",
"args": [],
"desc": "",
"returns": {
"type": "uint16[3]",
"desc": ""
}
}
]
}
57 changes: 57 additions & 0 deletions tests/contracts/artifacts/ABITestPartialStaticArray.approval.teal
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma version 8
b main

abi_route_partialStaticArray:
txn OnCompletion
int NoOp
==
txn ApplicationID
int 0
!=
&&
assert
byte 0x
callsub partialStaticArray
int 1
return

partialStaticArray:
proto 1 0

// tests/contracts/abi.algo.ts:817
// a: StaticArray<uint<16>, 3> = [1]
int 1
itob
extract 6 0
byte 0x00000000
concat
frame_bury -1 // a: uint16[3]

// tests/contracts/abi.algo.ts:819
// return a;
frame_dig -1 // a: uint16[3]
byte 0x151f7c75
swap
concat
log
retsub

main:
txn NumAppArgs
bnz route_abi

// default createApplication
txn ApplicationID
int 0
==
txn OnCompletion
int NoOp
==
&&
return

route_abi:
method "partialStaticArray()uint16[3]"
txna ApplicationArgs 0
match abi_route_partialStaticArray
err
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma version 8
int 1
return
51 changes: 51 additions & 0 deletions tests/contracts/artifacts/ABITestPartialStaticArray.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"hints": {
"partialStaticArray()uint16[3]": {
"call_config": {
"no_op": "CALL"
}
}
},
"bare_call_config": {
"no_op": "CREATE"
},
"schema": {
"local": {
"declared": {},
"reserved": {}
},
"global": {
"declared": {},
"reserved": {}
}
},
"state": {
"global": {
"num_byte_slices": 0,
"num_uints": 0
},
"local": {
"num_byte_slices": 0,
"num_uints": 0
}
},
"source": {
"approval": "I3ByYWdtYSB2ZXJzaW9uIDgKCWIgbWFpbgoKYWJpX3JvdXRlX3BhcnRpYWxTdGF0aWNBcnJheToKCXR4biBPbkNvbXBsZXRpb24KCWludCBOb09wCgk9PQoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgkhPQoJJiYKCWFzc2VydAoJYnl0ZSAweAoJY2FsbHN1YiBwYXJ0aWFsU3RhdGljQXJyYXkKCWludCAxCglyZXR1cm4KCnBhcnRpYWxTdGF0aWNBcnJheToKCXByb3RvIDEgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czo4MTcKCS8vIGE6IFN0YXRpY0FycmF5PHVpbnQ8MTY+LCAzPiA9IFsxXQoJaW50IDEKCWl0b2IKCWV4dHJhY3QgNiAwCglieXRlIDB4MDAwMDAwMDAKCWNvbmNhdAoJZnJhbWVfYnVyeSAtMSAvLyBhOiB1aW50MTZbM10KCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6ODE5CgkvLyByZXR1cm4gYTsKCWZyYW1lX2RpZyAtMSAvLyBhOiB1aW50MTZbM10KCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKbWFpbjoKCXR4biBOdW1BcHBBcmdzCglibnogcm91dGVfYWJpCgoJLy8gZGVmYXVsdCBjcmVhdGVBcHBsaWNhdGlvbgoJdHhuIEFwcGxpY2F0aW9uSUQKCWludCAwCgk9PQoJdHhuIE9uQ29tcGxldGlvbgoJaW50IE5vT3AKCT09CgkmJgoJcmV0dXJuCgpyb3V0ZV9hYmk6CgltZXRob2QgInBhcnRpYWxTdGF0aWNBcnJheSgpdWludDE2WzNdIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX3BhcnRpYWxTdGF0aWNBcnJheQoJZXJy",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDgKaW50IDEKcmV0dXJu"
},
"contract": {
"name": "ABITestPartialStaticArray",
"desc": "",
"methods": [
{
"name": "partialStaticArray",
"args": [],
"desc": "",
"returns": {
"type": "uint16[3]",
"desc": ""
}
}
]
}
}
Loading

0 comments on commit 54d1d41

Please sign in to comment.