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

Macro support #49

Open
bbroder-algo opened this issue Jan 26, 2023 · 3 comments
Open

Macro support #49

bbroder-algo opened this issue Jan 26, 2023 · 3 comments

Comments

@bbroder-algo
Copy link

algorand/go-algorand#4737 is introducing support for macros in TEAL.

One useful thing to do with macros is use them to define the constants Tealish supports.

I believe the following patch will enable that:

diff --git a/tealish/expression_nodes.py b/tealish/expression_nodes.py
index 4b365ac..409daca 100644
--- a/tealish/expression_nodes.py
+++ b/tealish/expression_nodes.py
@@ -78,9 +78,9 @@ class Constant(BaseNode):
 
     def write_teal(self, writer):
         if self.type == "int":
-            writer.write(self, f"pushint {self.value} // {self.name}")
+            writer.write(self, f"pushint {self.name} // {self.value}")
         elif self.type == "bytes":
-            writer.write(self, f"pushbytes {self.value} // {self.name}")
+            writer.write(self, f"pushbytes {self.name} // {self.value}")
 
     def _tealish(self, formatter=None):
         return f"{self.name}"
diff --git a/tealish/nodes.py b/tealish/nodes.py
index 62f9ce1..d5a53d9 100644
--- a/tealish/nodes.py
+++ b/tealish/nodes.py
@@ -334,6 +334,7 @@ class Const(LineStatement):
         scope["consts"][self.name] = [self.type, self.expression.value]
 
     def write_teal(self, writer):
+        writer.write (self, f"#define {self.name} {self.expression.value}")
         pass
 
     def _tealish(self, formatter=None):

this will result in tealish that goes from

#pragma version 8

struct Item:
    id: int
    foo: int
    name: bytes[10]
end

const int KNOWN_ID = 64738
const bytes BOX_NAME = "tealishbox"
const bytes KNOWN_ITEM = "fearghal"


box<Item> item1 = CreateBox(BOX_NAME)
item1.id = KNOWN_ID
item1.foo = KNOWN_ID + 1
item1.name = KNOWN_ITEM

log(itob(item1.id))
log(itob(item1.foo))
log(item1.name)

to TEAL

#pragma version 8


#define KNOWN_ID 64738
#define BOX_NAME "tealishbox"
#define KNOWN_ITEM "fearghal"


// box<Item> item1 = CreateBox(BOX_NAME) [slot 0]
pushbytes BOX_NAME // "tealishbox"
dup
pushint 26
box_create
assert // assert created
store 0 // item1
// item1.id = KNOWN_ID [box]
load 0 // box key item1
pushint 0 // offset
pushint KNOWN_ID // 64738
itob
box_replace // item1.id
// item1.foo = KNOWN_ID + 1 [box]
load 0 // box key item1
pushint 8 // offset
pushint KNOWN_ID // 64738
pushint 1
+
itob
box_replace // item1.foo
// item1.name = KNOWN_ITEM [box]
load 0 // box key item1
pushint 16 // offset
pushbytes KNOWN_ITEM // "fearghal"
box_replace // item1.name

// log(itob(item1.id))
load 0 // box key item1
pushint 0 // offset
pushint 8 // size
box_extract // item1.id
btoi
itob
log
// log(itob(item1.foo))
load 0 // box key item1
pushint 8 // offset
pushint 8 // size
box_extract // item1.foo
btoi
itob
log
// log(item1.name)
load 0 // box key item1
pushint 16 // offset
pushint 10 // size
box_extract // item1.name
log
@bbroder-algo
Copy link
Author

Most of the constraints regarding macro names in TEAL are resolved by the Tealish Const pattern (?P<name>[A-Z][a-zA-Z0-9_]*), particularly the requirement for an initial uppercase letter, including the requirement for a non-digit leading character, support for the underscore, and not collide with any branch labels. Also, since consts are either integers or quoted strings (which are treated as one token by the AVM), there will be no inception-style macro expansion, as in

#pragma version 8

struct Item:
    id: int
    foo: int
    name: bytes[10]
end

const int KNOWN_ID = 64738
const bytes BOX_NAME = "tealishbox"
const bytes KNOWN_ITEM = "macro BOX_NAME macro"

would not expand known_item to "macro tealishbox macro".

TEAL macros can not, however, be named after field names, stuch as "ApplicationID", or "RekeyTo", or "VoteLast", or "Sender", or a dozen or so others. One way around this might be to detect them using the TEAL langspec.json and erroring out or possibly postfixing the name automatically with one of the allowable TEAL special characters disallowed in Tealish consts (like %).

@fergalwalsh
Copy link
Collaborator

This looks great! It definitely improves the Teal output and is a very simple change.
I think the const pattern can be updated to only allow uppercase and digits. That was my intention and usage until now so allowing lowercase seems like it was a mistake: (?P<name>[A-Z][A-Z0-9_]*). It's also documented as such actually.

If there is still a possibility for conflicts still we can definitely make use of the langspec.

Before opening a PR for this I'll warn you there is significant work on the develop branch for some internal refactoring (mostly by Barnji). I'd like to merge that (#47) first to avoid unnecessary conflicts. I can't make promises on when but I've been aiming to do it this week so let's see if it happens today :)

@bbroder-algo
Copy link
Author

Nice! I did notice the inconsistency between the code and the docs but I went with the code. There are no all-cap field names at the moment (although TxID comes close), and I suppose there is no guarantee there won't be in the future, but that solution (all caps + numbers + underscore) is workable at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants