Skip to content

Commit

Permalink
0.13.0 (#44)
Browse files Browse the repository at this point in the history
* storage prefix

* 0.13.0

* remove accidental import
  • Loading branch information
joe-p authored May 28, 2023
1 parent 7f1f5db commit 16226dc
Show file tree
Hide file tree
Showing 8 changed files with 869 additions and 730 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.12.1",
"version": "0.13.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
71 changes: 57 additions & 14 deletions src/lib/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ interface StorageProp {
keyType: string;
valueType: string;
dynamicSize?: boolean;
prefix?: string;
}

interface Subroutine {
Expand Down Expand Up @@ -183,6 +184,12 @@ export default class Compiler {

generatedClearTeal: string = '';

private mapKeyTypes: {
global: string[]
local: string[]
box: string[]
} = { global: [], local: [], box: [] };

private customTypes: {[name: string] : string} = {};

private scratch: {[name: string] :{index: number; type: string}} = {};
Expand Down Expand Up @@ -287,14 +294,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.push('app_global_get', valueType);
Expand All @@ -305,14 +314,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

if (node.arguments[key ? 0 : 1]) {
Expand All @@ -327,14 +338,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.pushVoid('app_global_del');
Expand All @@ -345,16 +358,18 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

this.pushVoid('txna Applications 0');

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.hasMaybeValue('app_global_get_ex');
Expand All @@ -367,16 +382,18 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

this.processNode(node.arguments[0]);

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[1]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.push('app_local_get', valueType);
Expand All @@ -387,16 +404,18 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

this.processNode(node.arguments[0]);

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[1]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

if (node.arguments[key ? 1 : 2]) {
Expand All @@ -411,16 +430,18 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

this.processNode(node.arguments[0]);

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[1]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.pushVoid('app_local_del');
Expand All @@ -431,16 +452,18 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];
this.processNode(node.arguments[0]);
this.pushVoid('txna Applications 0');

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[1]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.hasMaybeValue('app_local_get_ex');
Expand All @@ -453,14 +476,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.maybeValue('box_get', valueType);
Expand All @@ -472,14 +497,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key, dynamicSize,
valueType, keyType, key, dynamicSize, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

if (dynamicSize) this.pushLines('dup', 'box_del', 'pop');
Expand All @@ -498,14 +525,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.pushVoid('box_del');
Expand All @@ -516,14 +545,16 @@ export default class Compiler {
const name = node.expression.expression.name.getText();

const {
valueType, keyType, key,
valueType, keyType, key, prefix,
} = this.storageProps[name];

if (key) {
this.pushVoid(`byte "${key}"`);
} else {
if (prefix) this.pushVoid(`byte "${prefix}"`);
this.processNode(node.arguments[0]);
if (isNumeric(keyType)) this.pushVoid('itob');
if (prefix) this.pushVoid('concat');
}

this.hasMaybeValue('box_get');
Expand Down Expand Up @@ -2217,16 +2248,17 @@ export default class Compiler {

if (['BoxMap', 'GlobalMap', 'LocalMap', 'BoxReference', 'GlobalReference', 'LocalReference'].includes(klass)) {
let props: StorageProp;
const type = klass.toLocaleLowerCase().replace('map', '').replace('reference', '');

if (klass.includes('Map')) {
props = {
type: klass.toLocaleLowerCase().replace('map', ''),
type,
keyType: this.getABIType(node.initializer.typeArguments![0].getText()),
valueType: this.getABIType(node.initializer.typeArguments![1].getText()),
};
} else {
props = {
type: klass.toLocaleLowerCase().replace('map', '').replace('reference', ''),
type,
keyType: 'bytes',
valueType: this.getABIType(node.initializer.typeArguments![0].getText()),
};
Expand Down Expand Up @@ -2259,6 +2291,11 @@ export default class Compiler {

props.dynamicSize = p.initializer.getText() === 'true';
break;
case 'prefix':
if (!klass.includes('Map')) throw new Error(`${name} only applies to storage maps`);
if (!ts.isStringLiteral(p.initializer)) throw new Error('Storage prefix must be string');
props.prefix = p.initializer.text;
break;
default:
throw new Error(`Unknown property ${name}`);
}
Expand All @@ -2269,6 +2306,12 @@ export default class Compiler {
props.key = node.name.getText();
}

if (klass.includes('Map') && !props.prefix) {
const keyTypes = this.mapKeyTypes[type as ('box' | 'local' | 'global')];
if (keyTypes.includes(props.keyType)) throw Error(`Duplicate key type ${props.keyType} for ${type} map`);
keyTypes.push(props.keyType);
}

this.storageProps[node.name.getText()] = props;
} else {
throw new Error();
Expand Down
9 changes: 9 additions & 0 deletions tests/contracts/StorageTest.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
"name": "StorageTest",
"desc": "",
"methods": [
{
"name": "prefix",
"args": [],
"desc": "",
"returns": {
"type": "void",
"desc": ""
}
},
{
"name": "globalRefPut",
"args": [],
Expand Down
Loading

0 comments on commit 16226dc

Please sign in to comment.