From d2dd036d67a4630b8f413ea8982a21489ff47207 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Mon, 7 Mar 2022 22:22:55 -0500 Subject: [PATCH 1/8] Start prototype of PC source map --- cmd/goal/clerk.go | 29 +++++++++++++++++++-- data/transactions/logic/assembler.go | 38 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index 5359c372ff..3695f3f750 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -18,6 +18,7 @@ package main import ( "encoding/base64" + "encoding/json" "fmt" "io" "os" @@ -49,6 +50,7 @@ var ( rejectsFilename string closeToAddress string noProgramOutput bool + writeSourceMap bool signProgram bool programSource string argB64Strings []string @@ -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") compileCmd.Flags().BoolVarP(&signProgram, "sign", "s", false, "sign program, output is a binary signed LogicSig record") compileCmd.Flags().StringVarP(&outFilename, "outfile", "o", "", "Filename to write program bytes or signed LogicSig to") compileCmd.Flags().StringVarP(&account, "account", "a", "", "Account address to sign the program (If not specified, uses default account)") @@ -927,7 +930,7 @@ func mustReadFile(fname string) []byte { return contents } -func assembleFile(fname string) (program []byte) { +func assembleFileImpl(fname string) *logic.OpStream { text, err := readFile(fname) if err != nil { reportErrorf("%s: %s", fname, err) @@ -948,9 +951,19 @@ func assembleFile(fname string) (program []byte) { } } + return ops +} + +func assembleFile(fname string) []byte { + ops := assembleFileImpl(fname) return ops.Program } +func assembleFileWithMap(fname string) ([]byte, logic.AssemblyMap) { + ops := assembleFileImpl(fname) + return ops.Program, ops.GetAssemblyMap() +} + func disassembleFile(fname, outname string) { program, err := readFile(fname) if err != nil { @@ -997,7 +1010,7 @@ var compileCmd = &cobra.Command{ disassembleFile(fname, outFilename) continue } - program := assembleFile(fname) + program, sourceMap := assembleFileWithMap(fname) outblob := program outname := outFilename if outname == "" { @@ -1036,6 +1049,18 @@ var compileCmd = &cobra.Command{ reportErrorf("%s: %s", outname, err) } } + if writeSourceMap { + mapname := fname + ".map.json" // TODO: naming? + sourceMap.SourceName = fname + pcblob, err := json.Marshal(sourceMap) + if err != nil { + reportErrorf("%s: %s", mapname, err) + } + err = writeFile(mapname, pcblob, 0666) + if err != nil { + reportErrorf("%s: %s", mapname, err) + } + } if !signProgram && outname != stdoutFilenameValue { pd := logic.HashProgram(program) addr := basics.Address(pd) diff --git a/data/transactions/logic/assembler.go b/data/transactions/logic/assembler.go index 8202af0bcf..e94524a8df 100644 --- a/data/transactions/logic/assembler.go +++ b/data/transactions/logic/assembler.go @@ -272,6 +272,34 @@ func (ops *OpStream) ReferToLabel(pc int, label string) { ops.labelReferences = append(ops.labelReferences, labelReference{ops.sourceLine, pc, label}) } +// GetAssemblyMap returns a struct containing details about +// the assembled file and mappings to the source file +func (ops *OpStream) GetAssemblyMap() AssemblyMap { + maxPC := 0 + for pc := range ops.OffsetToLine { + if pc > maxPC { + maxPC = pc + } + } + + // Array where index is the PC and value is the line. + pcToLine := make([]string, maxPC+1) + for pc := range pcToLine { + if line, ok := ops.OffsetToLine[pc]; ok { + pcToLine[pc] = strconv.Itoa(line) + } else { + pcToLine[pc] = "" + } + } + + // Encode the source map into a string + encodedMapping := strings.Join(pcToLine, ";") + + return AssemblyMap{ + Mapping: encodedMapping, + } +} + type opTypeFunc func(ops *OpStream, immediates []string) (StackTypes, StackTypes) // returns allows opcodes like `txn` to be specific about their return @@ -2742,3 +2770,13 @@ func HasStatefulOps(program []byte) (bool, error) { _, ds, err := disassembleInstrumented(program, nil) return ds.hasStatefulOps, err } + +// TODO: Consider haing a SourceMapper interface... +// AssemblyMap contains details from the source to assembly process +// currently contains map of TEAL source line number to assembled bytecode position +// and details about the template varirables contained in the source file +type AssemblyMap struct { + SourceName string `json:"source_name"` + Mapping string `json:"mapping"` + SourceMap []int `json:"source_map"` +} From f00862f30f5160525d0116a99b1e5ee7e07639c4 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Thu, 17 Mar 2022 14:55:57 -0400 Subject: [PATCH 2/8] Refactor source map struct --- cmd/goal/clerk.go | 7 ++- data/transactions/logic/assembler.go | 40 +--------------- data/transactions/logic/sourcemap.go | 68 ++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 43 deletions(-) create mode 100644 data/transactions/logic/sourcemap.go diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index 3695f3f750..7224a1ab87 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -959,9 +959,9 @@ func assembleFile(fname string) []byte { return ops.Program } -func assembleFileWithMap(fname string) ([]byte, logic.AssemblyMap) { +func assembleFileWithMap(fname string) ([]byte, logic.SourceMap) { ops := assembleFileImpl(fname) - return ops.Program, ops.GetAssemblyMap() + return ops.Program, logic.GetSourceMap([]string{fname}, ops.OffsetToLine) } func disassembleFile(fname, outname string) { @@ -1050,8 +1050,7 @@ var compileCmd = &cobra.Command{ } } if writeSourceMap { - mapname := fname + ".map.json" // TODO: naming? - sourceMap.SourceName = fname + mapname := fname + ".map" pcblob, err := json.Marshal(sourceMap) if err != nil { reportErrorf("%s: %s", mapname, err) diff --git a/data/transactions/logic/assembler.go b/data/transactions/logic/assembler.go index e94524a8df..4c09f57030 100644 --- a/data/transactions/logic/assembler.go +++ b/data/transactions/logic/assembler.go @@ -267,39 +267,11 @@ func (ops *OpStream) RecordSourceLine() { ops.OffsetToLine[ops.pending.Len()] = ops.sourceLine - 1 } -// ReferToLabel records an opcode label refence to resolve later +// ReferToLabel records an opcode label reference to resolve later func (ops *OpStream) ReferToLabel(pc int, label string) { ops.labelReferences = append(ops.labelReferences, labelReference{ops.sourceLine, pc, label}) } -// GetAssemblyMap returns a struct containing details about -// the assembled file and mappings to the source file -func (ops *OpStream) GetAssemblyMap() AssemblyMap { - maxPC := 0 - for pc := range ops.OffsetToLine { - if pc > maxPC { - maxPC = pc - } - } - - // Array where index is the PC and value is the line. - pcToLine := make([]string, maxPC+1) - for pc := range pcToLine { - if line, ok := ops.OffsetToLine[pc]; ok { - pcToLine[pc] = strconv.Itoa(line) - } else { - pcToLine[pc] = "" - } - } - - // Encode the source map into a string - encodedMapping := strings.Join(pcToLine, ";") - - return AssemblyMap{ - Mapping: encodedMapping, - } -} - type opTypeFunc func(ops *OpStream, immediates []string) (StackTypes, StackTypes) // returns allows opcodes like `txn` to be specific about their return @@ -2770,13 +2742,3 @@ func HasStatefulOps(program []byte) (bool, error) { _, ds, err := disassembleInstrumented(program, nil) return ds.hasStatefulOps, err } - -// TODO: Consider haing a SourceMapper interface... -// AssemblyMap contains details from the source to assembly process -// currently contains map of TEAL source line number to assembled bytecode position -// and details about the template varirables contained in the source file -type AssemblyMap struct { - SourceName string `json:"source_name"` - Mapping string `json:"mapping"` - SourceMap []int `json:"source_map"` -} diff --git a/data/transactions/logic/sourcemap.go b/data/transactions/logic/sourcemap.go new file mode 100644 index 0000000000..db4af93704 --- /dev/null +++ b/data/transactions/logic/sourcemap.go @@ -0,0 +1,68 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package logic + +import ( + "strconv" + "strings" +) + +const sourceMapVersion = 3 + +// 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 { + Version int `json:"version"` + File string `json:"file"` + SourceRoot string `json:"sourceRoot"` + Sources []string `json:"sources"` + Names []string `json:"names"` + Mapping string `json:"mapping"` +} + +// GetSourceMap returns a struct containing details about +// the assembled file and mappings to the source file. +func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { + maxPC := 0 + for pc := range offsetToLine { + if pc > maxPC { + maxPC = pc + } + } + + // Array where index is the PC and value is the line. + pcToLine := make([]string, maxPC+1) + for pc := range pcToLine { + if line, ok := offsetToLine[pc]; ok { + pcToLine[pc] = strconv.Itoa(line) + } else { + pcToLine[pc] = "" + } + } + + // Encode the source map into a string + encodedMapping := strings.Join(pcToLine, ";") + + return SourceMap{ + Version: sourceMapVersion, + File: "", // Assembled file does not have a name. + Sources: sourceNames, + Names: []string{}, // TEAL code does not generate any names + Mapping: encodedMapping, + } +} From 9279f9cae2c2e7da8954f031c3400df256cf5a65 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Mon, 28 Mar 2022 14:29:58 -0400 Subject: [PATCH 3/8] Add some tests for source maps --- data/transactions/logic/sourcemap.go | 34 ++++++++++-- data/transactions/logic/sourcemap_test.go | 63 +++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 data/transactions/logic/sourcemap_test.go diff --git a/data/transactions/logic/sourcemap.go b/data/transactions/logic/sourcemap.go index db4af93704..1e5277c5fe 100644 --- a/data/transactions/logic/sourcemap.go +++ b/data/transactions/logic/sourcemap.go @@ -17,11 +17,13 @@ package logic import ( - "strconv" + "bytes" "strings" ) +// sourceMapVersion is currently 3: https://sourcemaps.info/spec.html const sourceMapVersion = 3 +const b64table string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" // SourceMap contains details from the source to assembly process // currently contains map of TEAL source line to assembled bytecode position @@ -36,7 +38,7 @@ type SourceMap struct { } // GetSourceMap returns a struct containing details about -// the assembled file and mappings to the source file. +// the assembled file and encoded mappings to the source file. func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { maxPC := 0 for pc := range offsetToLine { @@ -49,7 +51,7 @@ func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { pcToLine := make([]string, maxPC+1) for pc := range pcToLine { if line, ok := offsetToLine[pc]; ok { - pcToLine[pc] = strconv.Itoa(line) + pcToLine[pc] = MakeSourceMapLine(0, 0, line, 0) } else { pcToLine[pc] = "" } @@ -62,7 +64,31 @@ func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { Version: sourceMapVersion, File: "", // Assembled file does not have a name. Sources: sourceNames, - Names: []string{}, // TEAL code does not generate any names + Names: []string{}, // TEAL code does not generate any names. Mapping: encodedMapping, } } + +// IntToVLQ writes out value to bytes.Buffer +func IntToVLQ(v int, buf *bytes.Buffer) { + v <<= 1 + if v < 0 { + v = -v + v |= 1 + } + for v >= 32 { + buf.WriteByte(b64table[32|(v&31)]) + v >>= 5 + } + buf.WriteByte(b64table[v]) +} + +// MakeSourceMapLine creates source map mapping's line entry +func MakeSourceMapLine(tcol, sindex, sline, scol int) string { + buf := bytes.NewBuffer(nil) + IntToVLQ(tcol, buf) + IntToVLQ(sindex, buf) + IntToVLQ(sline, buf) + IntToVLQ(scol, buf) + return buf.String() +} diff --git a/data/transactions/logic/sourcemap_test.go b/data/transactions/logic/sourcemap_test.go new file mode 100644 index 0000000000..a60f00c23e --- /dev/null +++ b/data/transactions/logic/sourcemap_test.go @@ -0,0 +1,63 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package logic + +import ( + "strings" + "testing" + + "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/require" +) + +func TestGetSourceMap(t *testing.T) { + partitiontest.PartitionTest(t) + a := require.New(t) + + sourceNames := []string{"test.teal"} + offsetToLine := map[int]int{ + 1: 1, + 2: 2, + 3: 5, + } + actualSourceMap := GetSourceMap(sourceNames, offsetToLine) + + a.Equal(sourceMapVersion, actualSourceMap.Version) + a.Equal("", actualSourceMap.File) + a.Equal(sourceNames, actualSourceMap.Sources) + a.Equal([]string{}, actualSourceMap.Names) + + // Check encoding for each line. + splitMapping := strings.Split(actualSourceMap.Mapping, ";") + for pc := range splitMapping { + if line, ok := offsetToLine[pc]; ok { + a.Equal(MakeSourceMapLine(0, 0, line, 0), splitMapping[pc]) + } + } +} + +func TestVLQ(t *testing.T) { + partitiontest.PartitionTest(t) + a := require.New(t) + + a.Equal("AAAA", MakeSourceMapLine(0, 0, 0, 0)) + a.Equal("AACA", MakeSourceMapLine(0, 0, 1, 0)) + a.Equal("AAEA", MakeSourceMapLine(0, 0, 2, 0)) + a.Equal("AAgBA", MakeSourceMapLine(0, 0, 16, 0)) + a.Equal("AAggBA", MakeSourceMapLine(0, 0, 512, 0)) + a.Equal("ADggBD", MakeSourceMapLine(0, -1, 512, -1)) +} From bf9fc027cfee9e5775035da31074fa3b2f6a680a Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Thu, 14 Apr 2022 16:36:07 -0400 Subject: [PATCH 4/8] Move VLQ encoding into logic package and delete in tealdbg dir --- cmd/tealdbg/util.go | 26 ++++++-------------------- cmd/tealdbg/util_test.go | 36 ------------------------------------ 2 files changed, 6 insertions(+), 56 deletions(-) delete mode 100644 cmd/tealdbg/util_test.go diff --git a/cmd/tealdbg/util.go b/cmd/tealdbg/util.go index 6a7f880efb..40c1c85060 100644 --- a/cmd/tealdbg/util.go +++ b/cmd/tealdbg/util.go @@ -20,6 +20,8 @@ import ( "bytes" "strconv" "sync/atomic" + + "github.com/algorand/go-algorand/data/transactions/logic" ) type atomicString struct { @@ -101,28 +103,12 @@ func IsTextFile(data []byte) bool { return printable } -const b64table string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - -// IntToVLQ writes out value to bytes.Buffer -func IntToVLQ(v int, buf *bytes.Buffer) { - v <<= 1 - if v < 0 { - v = -v - v |= 1 - } - for v >= 32 { - buf.WriteByte(b64table[32|(v&31)]) - v >>= 5 - } - buf.WriteByte(b64table[v]) -} - // MakeSourceMapLine creates source map mapping's line entry func MakeSourceMapLine(tcol, sindex, sline, scol int) string { buf := bytes.NewBuffer(nil) - IntToVLQ(tcol, buf) - IntToVLQ(sindex, buf) - IntToVLQ(sline, buf) - IntToVLQ(scol, buf) + logic.IntToVLQ(tcol, buf) + logic.IntToVLQ(sindex, buf) + logic.IntToVLQ(sline, buf) + logic.IntToVLQ(scol, buf) return buf.String() } diff --git a/cmd/tealdbg/util_test.go b/cmd/tealdbg/util_test.go deleted file mode 100644 index 85de0747dd..0000000000 --- a/cmd/tealdbg/util_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2019-2022 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// go-algorand is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with go-algorand. If not, see . - -package main - -import ( - "testing" - - "github.com/algorand/go-algorand/test/partitiontest" - "github.com/stretchr/testify/require" -) - -func TestVLQ(t *testing.T) { - partitiontest.PartitionTest(t) - a := require.New(t) - - a.Equal("AAAA", MakeSourceMapLine(0, 0, 0, 0)) - a.Equal("AACA", MakeSourceMapLine(0, 0, 1, 0)) - a.Equal("AAEA", MakeSourceMapLine(0, 0, 2, 0)) - a.Equal("AAgBA", MakeSourceMapLine(0, 0, 16, 0)) - a.Equal("AAggBA", MakeSourceMapLine(0, 0, 512, 0)) - a.Equal("ADggBD", MakeSourceMapLine(0, -1, 512, -1)) -} From 6ddc4d11f2e65262f2d942ef3c36057ff98f5164 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Thu, 14 Apr 2022 17:05:40 -0400 Subject: [PATCH 5/8] Remove redundant function in tealdbg --- cmd/tealdbg/debugger.go | 6 +++--- cmd/tealdbg/util.go | 13 ------------- data/transactions/logic/sourcemap.go | 12 ++++++------ 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/cmd/tealdbg/debugger.go b/cmd/tealdbg/debugger.go index 34957f2c7b..b9b8995609 100644 --- a/cmd/tealdbg/debugger.go +++ b/cmd/tealdbg/debugger.go @@ -368,14 +368,14 @@ func (s *session) GetSourceMap() ([]byte, error) { prevSourceLine := 0 // the very first entry is needed by CDT - lines[0] = MakeSourceMapLine(targetCol, sourceIdx, 0, sourceCol) + lines[0] = logic.MakeSourceMapLine(targetCol, sourceIdx, 0, sourceCol) for targetLine := 1; targetLine < len(s.lines); targetLine++ { if pc, ok := s.pcOffset[targetLine]; ok && pc != 0 { sourceLine, ok = s.offsetToLine[pc] if !ok { lines[targetLine] = "" } else { - lines[targetLine] = MakeSourceMapLine(targetCol, sourceIdx, sourceLine-prevSourceLine, sourceCol) + lines[targetLine] = logic.MakeSourceMapLine(targetCol, sourceIdx, sourceLine-prevSourceLine, sourceCol) prevSourceLine = sourceLine } } else { @@ -384,7 +384,7 @@ func (s *session) GetSourceMap() ([]byte, error) { if targetLine == len(s.lines)-1 { delta = 1 } - lines[targetLine] = MakeSourceMapLine(targetCol, sourceIdx, delta, sourceCol) + lines[targetLine] = logic.MakeSourceMapLine(targetCol, sourceIdx, delta, sourceCol) } } diff --git a/cmd/tealdbg/util.go b/cmd/tealdbg/util.go index 40c1c85060..d611c7bcb1 100644 --- a/cmd/tealdbg/util.go +++ b/cmd/tealdbg/util.go @@ -17,11 +17,8 @@ package main import ( - "bytes" "strconv" "sync/atomic" - - "github.com/algorand/go-algorand/data/transactions/logic" ) type atomicString struct { @@ -102,13 +99,3 @@ func IsTextFile(data []byte) bool { } return printable } - -// MakeSourceMapLine creates source map mapping's line entry -func MakeSourceMapLine(tcol, sindex, sline, scol int) string { - buf := bytes.NewBuffer(nil) - logic.IntToVLQ(tcol, buf) - logic.IntToVLQ(sindex, buf) - logic.IntToVLQ(sline, buf) - logic.IntToVLQ(scol, buf) - return buf.String() -} diff --git a/data/transactions/logic/sourcemap.go b/data/transactions/logic/sourcemap.go index 1e5277c5fe..c8b0270cf9 100644 --- a/data/transactions/logic/sourcemap.go +++ b/data/transactions/logic/sourcemap.go @@ -69,8 +69,8 @@ func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { } } -// IntToVLQ writes out value to bytes.Buffer -func IntToVLQ(v int, buf *bytes.Buffer) { +// intToVLQ writes out value to bytes.Buffer +func intToVLQ(v int, buf *bytes.Buffer) { v <<= 1 if v < 0 { v = -v @@ -86,9 +86,9 @@ func IntToVLQ(v int, buf *bytes.Buffer) { // MakeSourceMapLine creates source map mapping's line entry func MakeSourceMapLine(tcol, sindex, sline, scol int) string { buf := bytes.NewBuffer(nil) - IntToVLQ(tcol, buf) - IntToVLQ(sindex, buf) - IntToVLQ(sline, buf) - IntToVLQ(scol, buf) + intToVLQ(tcol, buf) + intToVLQ(sindex, buf) + intToVLQ(sline, buf) + intToVLQ(scol, buf) return buf.String() } From 6645cb5eebaecb7476ff4849ad6573d25f8c74c5 Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Fri, 15 Apr 2022 14:39:10 -0400 Subject: [PATCH 6/8] Fix some tests and mark some fields as optional --- cmd/goal/clerk.go | 2 +- data/transactions/logic/sourcemap.go | 15 ++++++++------- data/transactions/logic/sourcemap_test.go | 5 +++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index dac6f639e1..987c14a316 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -125,7 +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") + compileCmd.Flags().BoolVarP(&writeSourceMap, "map", "m", false, "write out source map") compileCmd.Flags().BoolVarP(&signProgram, "sign", "s", false, "sign program, output is a binary signed LogicSig record") compileCmd.Flags().StringVarP(&outFilename, "outfile", "o", "", "Filename to write program bytes or signed LogicSig to") compileCmd.Flags().StringVarP(&account, "account", "a", "", "Account address to sign the program (If not specified, uses default account)") diff --git a/data/transactions/logic/sourcemap.go b/data/transactions/logic/sourcemap.go index c8b0270cf9..3ffafd5e50 100644 --- a/data/transactions/logic/sourcemap.go +++ b/data/transactions/logic/sourcemap.go @@ -21,17 +21,19 @@ import ( "strings" ) -// sourceMapVersion is currently 3: https://sourcemaps.info/spec.html +// sourceMapVersion is currently 3. +// Refer to the full specs of sourcemap here: https://sourcemaps.info/spec.html const sourceMapVersion = 3 const b64table string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" -// 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 +// SourceMap contains details from the source to assembly process. +// Currently contains the map between TEAL source line to +// the assembled bytecode position and details about +// the template variables contained in the source file. type SourceMap struct { Version int `json:"version"` - File string `json:"file"` - SourceRoot string `json:"sourceRoot"` + File string `json:"file,omitempty"` + SourceRoot string `json:"sourceRoot,omitempty"` Sources []string `json:"sources"` Names []string `json:"names"` Mapping string `json:"mapping"` @@ -62,7 +64,6 @@ func GetSourceMap(sourceNames []string, offsetToLine map[int]int) SourceMap { return SourceMap{ Version: sourceMapVersion, - File: "", // Assembled file does not have a name. Sources: sourceNames, Names: []string{}, // TEAL code does not generate any names. Mapping: encodedMapping, diff --git a/data/transactions/logic/sourcemap_test.go b/data/transactions/logic/sourcemap_test.go index a60f00c23e..718535ec44 100644 --- a/data/transactions/logic/sourcemap_test.go +++ b/data/transactions/logic/sourcemap_test.go @@ -32,12 +32,11 @@ func TestGetSourceMap(t *testing.T) { offsetToLine := map[int]int{ 1: 1, 2: 2, - 3: 5, + 5: 3, } actualSourceMap := GetSourceMap(sourceNames, offsetToLine) a.Equal(sourceMapVersion, actualSourceMap.Version) - a.Equal("", actualSourceMap.File) a.Equal(sourceNames, actualSourceMap.Sources) a.Equal([]string{}, actualSourceMap.Names) @@ -46,6 +45,8 @@ func TestGetSourceMap(t *testing.T) { for pc := range splitMapping { if line, ok := offsetToLine[pc]; ok { a.Equal(MakeSourceMapLine(0, 0, line, 0), splitMapping[pc]) + } else { + a.Equal("", splitMapping[pc]) } } } From 17d9b9c7f7eeb9c3c2503912bd3815062514948f Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Tue, 19 Apr 2022 18:08:33 -0400 Subject: [PATCH 7/8] Add e2e shell test and fix typo in existing test --- data/transactions/logic/tlhc.py | 4 ++-- test/scripts/e2e_subs/e2e-teal.sh | 14 ++++++++++++++ test/scripts/e2e_subs/tealprogs/quine.map | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 test/scripts/e2e_subs/tealprogs/quine.map diff --git a/data/transactions/logic/tlhc.py b/data/transactions/logic/tlhc.py index f436b78100..ce8c8d793e 100755 --- a/data/transactions/logic/tlhc.py +++ b/data/transactions/logic/tlhc.py @@ -69,11 +69,11 @@ def main(): out.write(code) try: out.close() - except Exeption as e: + except Exception as e: print(e) try: secretout.close() - except Exeption as e: + except Exception as e: print(e) return diff --git a/test/scripts/e2e_subs/e2e-teal.sh b/test/scripts/e2e_subs/e2e-teal.sh index a71c78a10d..da13d30715 100755 --- a/test/scripts/e2e_subs/e2e-teal.sh +++ b/test/scripts/e2e_subs/e2e-teal.sh @@ -11,6 +11,8 @@ WALLET=$1 gcmd="goal -w ${WALLET}" +TEAL=test/scripts/e2e_subs/tealprogs + ACCOUNT=$(${gcmd} account list|awk '{ print $3 }') # prints: @@ -148,6 +150,18 @@ ${gcmd} clerk compile ${TEMPDIR}/true3.teal -o ${TEMPDIR}/true3.lsig cp ${TEMPDIR}/true3.lsig ${TEMPDIR}/true2.lsig printf '\x02' | dd of=${TEMPDIR}/true2.lsig bs=1 seek=0 count=1 conv=notrunc +# Try to compile with source map, and check that map is correct. +# Since the source map contains info about the file path, +# we need to do this in place and clean up the file later. +${gcmd} clerk compile ${TEAL}/quine.teal -m +if ! diff ${TEAL}/quine.map ${TEAL}/quine.teal.map > /dev/null; then + rm ${TEAL}/quine.teal.* + echo "produced source maps do not match" + exit 1 +fi +# Clean up generated source map +rm ${TEAL}/quine.teal.* + # compute the escrow account for the frankenstein program ACCOUNT_TRUE=$(python -c 'import algosdk, sys; print(algosdk.logic.address(sys.stdin.buffer.read()))' < ${TEMPDIR}/true2.lsig) # fund that escrow account diff --git a/test/scripts/e2e_subs/tealprogs/quine.map b/test/scripts/e2e_subs/tealprogs/quine.map new file mode 100644 index 0000000000..02e426d14b --- /dev/null +++ b/test/scripts/e2e_subs/tealprogs/quine.map @@ -0,0 +1 @@ +{"version":3,"sources":["test/scripts/e2e_subs/tealprogs/quine.teal"],"names":[],"mapping":";AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA;AASA;;;AAUA;;;AAWA;AAYA;;AAaA;AAcA;;;AAeA;AAgBA;AAiBA;;AAkBA;;AAmBA;AAoBA;AAqBA"} \ No newline at end of file From 21aa4a13d2b48f01558773fec1a2035317a856ae Mon Sep 17 00:00:00 2001 From: algochoi <86622919+algochoi@users.noreply.github.com> Date: Wed, 20 Apr 2022 10:41:32 -0400 Subject: [PATCH 8/8] Retain diff and use trap to clean up test files --- test/scripts/e2e_subs/e2e-teal.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/scripts/e2e_subs/e2e-teal.sh b/test/scripts/e2e_subs/e2e-teal.sh index da13d30715..93cb408896 100755 --- a/test/scripts/e2e_subs/e2e-teal.sh +++ b/test/scripts/e2e_subs/e2e-teal.sh @@ -152,15 +152,13 @@ printf '\x02' | dd of=${TEMPDIR}/true2.lsig bs=1 seek=0 count=1 conv=notrunc # Try to compile with source map, and check that map is correct. # Since the source map contains info about the file path, -# we need to do this in place and clean up the file later. +# we do this in place and clean up the file later. ${gcmd} clerk compile ${TEAL}/quine.teal -m -if ! diff ${TEAL}/quine.map ${TEAL}/quine.teal.map > /dev/null; then - rm ${TEAL}/quine.teal.* +trap 'rm ${TEAL}/quine.teal.*' EXIT +if ! diff ${TEAL}/quine.map ${TEAL}/quine.teal.map; then echo "produced source maps do not match" exit 1 fi -# Clean up generated source map -rm ${TEAL}/quine.teal.* # compute the escrow account for the frankenstein program ACCOUNT_TRUE=$(python -c 'import algosdk, sys; print(algosdk.logic.address(sys.stdin.buffer.read()))' < ${TEMPDIR}/true2.lsig)