-
Notifications
You must be signed in to change notification settings - Fork 493
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
Goal: Source mapping PC to TEAL #3726
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3726 +/- ##
==========================================
+ Coverage 50.10% 50.12% +0.02%
==========================================
Files 393 394 +1
Lines 68382 68409 +27
==========================================
+ Hits 34263 34292 +29
+ Misses 30420 30413 -7
- Partials 3699 3704 +5
Continue to review full report at Codecov.
|
@@ -0,0 +1,94 @@ | |||
// Copyright (C) 2019-2022 Algorand, Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also thought of putting this file in the tealdbg
package, but I don't think it can be exported from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! As you can see, all my suggestions are nits so feel free to resolve anything you don't think is worthwhile to address.
// SourceMap contains details from the source to assembly process | ||
// currently contains map of TEAL source line to assembled bytecode position | ||
// and details about the template variables contained in the source file | ||
type SourceMap struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I had to check the spec for some of the fields here so it might be useful to describe the fields in a comment.
Spec:
"Line 1: The entire file is a single JSON object
Line 2: File version (always the first entry in the object) and must be a positive integer.
Line 3: An optional name of the generated code that this source map is associated with.
Line 4: An optional source root, useful for relocating source files on a server or removing repeated values in the “sources” entry. This value is prepended to the individual entries in the “source” field.
Line 5: A list of original sources used by the “mappings” entry.
Line 6: A list of symbol names used by the “mappings” entry.
Line 7: A string with the encoded mapping data in base64 VLQ encoding. Each semicolon separates a line in the generated code. Note that multiple lines in the generated code may point to the same line in the source code."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point - I eventually settled on linking the sourcemap specs URL instead in the comments, so the interested user can look at the original doc in more detail. Linking to URLs also might
data/transactions/logic/sourcemap.go
Outdated
type SourceMap struct { | ||
Version int `json:"version"` | ||
File string `json:"file"` | ||
SourceRoot string `json:"sourceRoot"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we might want to make some of these fields optional in the json serialization depending on how closely we want to follow the spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, added omitempty
field for File
and SourceRoot
cmd/goal/clerk.go
Outdated
@@ -123,6 +125,7 @@ func init() { | |||
|
|||
compileCmd.Flags().BoolVarP(&disassemble, "disassemble", "D", false, "disassemble a compiled program") | |||
compileCmd.Flags().BoolVarP(&noProgramOutput, "no-out", "n", false, "don't write contract program binary") | |||
compileCmd.Flags().BoolVarP(&writeSourceMap, "map", "m", false, "write out assembly map") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think it'd be nice if the source map format version was included here or somewhere else in the documentation easily accessible to the user.
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGetSourceMap(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this test doesn't cover the (unlikely) edge case where the line number is large enough that a left shift turns it negative.
Looks pretty good to me, I'd be interested in a follow up pr to have the |
@@ -1056,6 +1069,17 @@ var compileCmd = &cobra.Command{ | |||
reportErrorf("%s: %s", outname, err) | |||
} | |||
} | |||
if writeSourceMap { | |||
mapname := fname + ".map" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@algochoi small question/request, was there a specific reason you chose fname + ".map"
for the map file name? With this the source map is given the name of the input file, which I think is less intuitive/accurate.
In JS it's common practice for the map file to be named after the produced output file, since that's the starting point from which you can go "backwards" with the map, so I was expecting outname + ".map"
here (idk what should happen when the output is stdout, maybe an error?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this the source map is given the name of the input file, which I think is less intuitive/accurate.
That is a fair point, and I can see the confusion. I can open up a PR to fix this.
idk what should happen when the output is stdout, maybe an error?
This what I initially thought, but after playing around with the commands, I think the source map should always be output to the file because the no-out
flag says don't write contract program binary
, and a source map isn't necessarily the binary.
But alternatively, we could also output the source map to stdout if the no output flag is raised. That sounds fine too, depending on how you interpret the no-out
flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a fair point, and I can see the confusion. I can open up a PR to fix this.
That would be great, thanks!
I think the source map should always be output to the file because the
no-out
flag saysdon't write contract program binary
, and a source map isn't necessarily the binary.
That's definitely a valid interpretation, but what do you name the source map file then? I think <input>.tok.map
would work.
Though to be fair, I think it's quite rare to use the no-out
flag, so failing in this case would not be that bad in my opinion.
Summary
This is a PR generates a PC to TEAL source map file when
goal clerk compile
with the-m
option is invoked.Mostly shamelessly taken from this PR.
The source map follows this spec used in JS. The mappings are encoded using base64 VLQ and should be compatible with most browsers, including the tealdbg on CDT.
Example
myprog.teal
myprog.teal.map
Example decoder here: https://github.com/algochoi/teal-sourcemap-decoder
myprog_annotated.teal
Test Plan
This also changes the
goal clerk compile
command, so any manual changes to documentation needs to be done as well.