Skip to content

Commit

Permalink
Merge pull request #242 from algorandfoundation/feat/do_while
Browse files Browse the repository at this point in the history
feat: do while loop
  • Loading branch information
joe-p authored Nov 23, 2023
2 parents b998508 + f1cbf13 commit 713249f
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/lib/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export default class Compiler {

private whileCount: number = 0;

private doWhileCount: number = 0;

private forCount: number = 0;

filename: string;
Expand Down Expand Up @@ -1973,6 +1975,13 @@ export default class Compiler {
else this.pushVoid(node, 'err');
}

private processDoStatement(node: ts.DoStatement) {
this.pushVoid(node, `do_while_${this.doWhileCount}:`);
this.processNode(node.statement);
this.processNode(node.expression);
this.pushVoid(node, `bnz do_while_${this.doWhileCount}`);
}

private processWhileStatement(node: ts.WhileStatement) {
this.pushVoid(node, `while_${this.whileCount}:`);
this.processNode(node.expression);
Expand Down Expand Up @@ -2039,6 +2048,7 @@ export default class Compiler {
else if (ts.isThrowStatement(node)) this.processThrowStatement(node);
else if (ts.isWhileStatement(node)) this.processWhileStatement(node);
else if (ts.isForStatement(node)) this.processForStatement(node);
else if (ts.isDoStatement(node)) this.processDoStatement(node);
// Vars/Consts
else if (ts.isIdentifier(node)) this.processIdentifier(node);
else if (ts.isVariableDeclarationList(node)) this.processVariableDeclaration(node);
Expand Down
42 changes: 41 additions & 1 deletion tests/contracts/artifacts/LoopsTest.approval.teal
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,45 @@ for_0_end:
log
retsub

// doWhileLoop()uint64
abi_route_doWhileLoop:
byte 0x // push empty bytes to fill the stack frame for this subroutine's local variables

// execute doWhileLoop()uint64
callsub doWhileLoop
int 1
return

doWhileLoop:
proto 1 0

// tests/contracts/loops.algo.ts:26
// i = 0
int 0
frame_bury -1 // i: uint64

do_while_0:
// tests/contracts/loops.algo.ts:29
// i = i + 1
frame_dig -1 // i: uint64
int 1
+
frame_bury -1 // i: uint64
frame_dig -1 // i: uint64
int 10
<
bnz do_while_0

// tests/contracts/loops.algo.ts:32
// return i;
frame_dig -1 // i: uint64
itob
byte 0x151f7c75
swap
concat
log
retsub

abi_route_createApplication:
int 1
return
Expand All @@ -131,6 +170,7 @@ create_NoOp:
call_NoOp:
method "whileLoop()uint64"
method "forLoop()uint64"
method "doWhileLoop()uint64"
txna ApplicationArgs 0
match abi_route_whileLoop abi_route_forLoop
match abi_route_whileLoop abi_route_forLoop abi_route_doWhileLoop
err
16 changes: 15 additions & 1 deletion tests/contracts/artifacts/LoopsTest.arc32.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
"no_op": "CALL"
}
},
"doWhileLoop()uint64": {
"call_config": {
"no_op": "CALL"
}
},
"createApplication()void": {
"call_config": {
"no_op": "CREATE"
Expand Down Expand Up @@ -44,7 +49,7 @@
}
},
"source": {
"approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjMuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIHdoaWxlTG9vcCgpdWludDY0CmFiaV9yb3V0ZV93aGlsZUxvb3A6CglieXRlIDB4IC8vIHB1c2ggZW1wdHkgYnl0ZXMgdG8gZmlsbCB0aGUgc3RhY2sgZnJhbWUgZm9yIHRoaXMgc3Vicm91dGluZSdzIGxvY2FsIHZhcmlhYmxlcwoKCS8vIGV4ZWN1dGUgd2hpbGVMb29wKCl1aW50NjQKCWNhbGxzdWIgd2hpbGVMb29wCglpbnQgMQoJcmV0dXJuCgp3aGlsZUxvb3A6Cglwcm90byAxIDAKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czo2CgkvLyBpID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0Cgp3aGlsZV8wOgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgk8CglieiB3aGlsZV8wX2VuZAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjkKCS8vIGkgPSBpICsgMQoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0CgliIHdoaWxlXzAKCndoaWxlXzBfZW5kOgoJLy8gdGVzdHMvY29udHJhY3RzL2xvb3BzLmFsZ28udHM6MTIKCS8vIHJldHVybiBpOwoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgovLyBmb3JMb29wKCl1aW50NjQKYWJpX3JvdXRlX2Zvckxvb3A6CglieXRlIDB4OyBkdXAgLy8gcHVzaCBlbXB0eSBieXRlcyB0byBmaWxsIHRoZSBzdGFjayBmcmFtZSBmb3IgdGhpcyBzdWJyb3V0aW5lJ3MgbG9jYWwgdmFyaWFibGVzCgoJLy8gZXhlY3V0ZSBmb3JMb29wKCl1aW50NjQKCWNhbGxzdWIgZm9yTG9vcAoJaW50IDEKCXJldHVybgoKZm9yTG9vcDoKCXByb3RvIDIgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjE2CgkvLyBpID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0CgoJLy8gdGVzdHMvY29udHJhY3RzL2xvb3BzLmFsZ28udHM6MTgKCS8vIGogPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAtMiAvLyBqOiB1aW50NjQKCmZvcl8wOgoJZnJhbWVfZGlnIC0yIC8vIGo6IHVpbnQ2NAoJaW50IDEwCgk8CglieiBmb3JfMF9lbmQKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czoxOQoJLy8gaSA9IGkgKyAxCglmcmFtZV9kaWcgLTEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAtMSAvLyBpOiB1aW50NjQKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czoxOAoJLy8gaiA9IGogKyAxCglmcmFtZV9kaWcgLTIgLy8gajogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAtMiAvLyBqOiB1aW50NjQKCWIgZm9yXzAKCmZvcl8wX2VuZDoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjIyCgkvLyByZXR1cm4gaTsKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJaW50IDEKCXJldHVybgoKY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCmNhbGxfTm9PcDoKCW1ldGhvZCAid2hpbGVMb29wKCl1aW50NjQiCgltZXRob2QgImZvckxvb3AoKXVpbnQ2NCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV93aGlsZUxvb3AgYWJpX3JvdXRlX2Zvckxvb3AKCWVycg==",
"approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjMuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIHdoaWxlTG9vcCgpdWludDY0CmFiaV9yb3V0ZV93aGlsZUxvb3A6CglieXRlIDB4IC8vIHB1c2ggZW1wdHkgYnl0ZXMgdG8gZmlsbCB0aGUgc3RhY2sgZnJhbWUgZm9yIHRoaXMgc3Vicm91dGluZSdzIGxvY2FsIHZhcmlhYmxlcwoKCS8vIGV4ZWN1dGUgd2hpbGVMb29wKCl1aW50NjQKCWNhbGxzdWIgd2hpbGVMb29wCglpbnQgMQoJcmV0dXJuCgp3aGlsZUxvb3A6Cglwcm90byAxIDAKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czo2CgkvLyBpID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0Cgp3aGlsZV8wOgoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgk8CglieiB3aGlsZV8wX2VuZAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjkKCS8vIGkgPSBpICsgMQoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEKCSsKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0CgliIHdoaWxlXzAKCndoaWxlXzBfZW5kOgoJLy8gdGVzdHMvY29udHJhY3RzL2xvb3BzLmFsZ28udHM6MTIKCS8vIHJldHVybiBpOwoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaXRvYgoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgovLyBmb3JMb29wKCl1aW50NjQKYWJpX3JvdXRlX2Zvckxvb3A6CglieXRlIDB4OyBkdXAgLy8gcHVzaCBlbXB0eSBieXRlcyB0byBmaWxsIHRoZSBzdGFjayBmcmFtZSBmb3IgdGhpcyBzdWJyb3V0aW5lJ3MgbG9jYWwgdmFyaWFibGVzCgoJLy8gZXhlY3V0ZSBmb3JMb29wKCl1aW50NjQKCWNhbGxzdWIgZm9yTG9vcAoJaW50IDEKCXJldHVybgoKZm9yTG9vcDoKCXByb3RvIDIgMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjE2CgkvLyBpID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgLTEgLy8gaTogdWludDY0CgoJLy8gdGVzdHMvY29udHJhY3RzL2xvb3BzLmFsZ28udHM6MTgKCS8vIGogPSAwCglpbnQgMAoJZnJhbWVfYnVyeSAtMiAvLyBqOiB1aW50NjQKCmZvcl8wOgoJZnJhbWVfZGlnIC0yIC8vIGo6IHVpbnQ2NAoJaW50IDEwCgk8CglieiBmb3JfMF9lbmQKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czoxOQoJLy8gaSA9IGkgKyAxCglmcmFtZV9kaWcgLTEgLy8gaTogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAtMSAvLyBpOiB1aW50NjQKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czoxOAoJLy8gaiA9IGogKyAxCglmcmFtZV9kaWcgLTIgLy8gajogdWludDY0CglpbnQgMQoJKwoJZnJhbWVfYnVyeSAtMiAvLyBqOiB1aW50NjQKCWIgZm9yXzAKCmZvcl8wX2VuZDoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjIyCgkvLyByZXR1cm4gaTsKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKLy8gZG9XaGlsZUxvb3AoKXVpbnQ2NAphYmlfcm91dGVfZG9XaGlsZUxvb3A6CglieXRlIDB4IC8vIHB1c2ggZW1wdHkgYnl0ZXMgdG8gZmlsbCB0aGUgc3RhY2sgZnJhbWUgZm9yIHRoaXMgc3Vicm91dGluZSdzIGxvY2FsIHZhcmlhYmxlcwoKCS8vIGV4ZWN1dGUgZG9XaGlsZUxvb3AoKXVpbnQ2NAoJY2FsbHN1YiBkb1doaWxlTG9vcAoJaW50IDEKCXJldHVybgoKZG9XaGlsZUxvb3A6Cglwcm90byAxIDAKCgkvLyB0ZXN0cy9jb250cmFjdHMvbG9vcHMuYWxnby50czoyNgoJLy8gaSA9IDAKCWludCAwCglmcmFtZV9idXJ5IC0xIC8vIGk6IHVpbnQ2NAoKZG9fd2hpbGVfMDoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjI5CgkvLyBpID0gaSArIDEKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWludCAxCgkrCglmcmFtZV9idXJ5IC0xIC8vIGk6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGk6IHVpbnQ2NAoJaW50IDEwCgk8CglibnogZG9fd2hpbGVfMAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9sb29wcy5hbGdvLnRzOjMyCgkvLyByZXR1cm4gaTsKCWZyYW1lX2RpZyAtMSAvLyBpOiB1aW50NjQKCWl0b2IKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJaW50IDEKCXJldHVybgoKY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCmNhbGxfTm9PcDoKCW1ldGhvZCAid2hpbGVMb29wKCl1aW50NjQiCgltZXRob2QgImZvckxvb3AoKXVpbnQ2NCIKCW1ldGhvZCAiZG9XaGlsZUxvb3AoKXVpbnQ2NCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV93aGlsZUxvb3AgYWJpX3JvdXRlX2Zvckxvb3AgYWJpX3JvdXRlX2RvV2hpbGVMb29wCgllcnI=",
"clear": "I3ByYWdtYSB2ZXJzaW9uIDk="
},
"contract": {
Expand All @@ -69,6 +74,15 @@
"desc": ""
}
},
{
"name": "doWhileLoop",
"args": [],
"desc": "",
"returns": {
"type": "uint64",
"desc": ""
}
},
{
"name": "createApplication",
"desc": "",
Expand Down
9 changes: 9 additions & 0 deletions tests/contracts/artifacts/LoopsTest.arc4.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@
"desc": ""
}
},
{
"name": "doWhileLoop",
"args": [],
"desc": "",
"returns": {
"type": "uint64",
"desc": ""
}
},
{
"name": "createApplication",
"desc": "",
Expand Down
10 changes: 10 additions & 0 deletions tests/contracts/loops.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ class LoopsTest extends Contract {

return i;
}

doWhileLoop(): uint64 {
let i = 0;

do {
i = i + 1;
} while (i < 10);

return i;
}
}
5 changes: 5 additions & 0 deletions tests/loops.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ describe('Loops', function () {
const ret = await appClient.call({ method: 'forLoop', methodArgs: [], sendParams: { suppressLog: true } });
expect(ret.return?.returnValue).toEqual(BigInt(10));
});

test('doWhileLoop', async function () {
const ret = await appClient.call({ method: 'doWhileLoop', methodArgs: [], sendParams: { suppressLog: true } });
expect(ret.return?.returnValue).toEqual(BigInt(10));
});
});

0 comments on commit 713249f

Please sign in to comment.