mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-26 12:57:26 +08:00
improve compile error feedback
This commit is contained in:
parent
3452677fbd
commit
fb83b08269
@ -7,6 +7,7 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
@ -268,3 +269,82 @@ func main(a, b uint64) uint64 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type parseErrorTestData struct {
|
||||
code string
|
||||
errorMessage string
|
||||
}
|
||||
|
||||
var compileErrorTests = []parseErrorTestData{
|
||||
{
|
||||
code: `packag main`,
|
||||
errorMessage: `Compile error [parse]: unexpected token 'packag': expected 'package', {data}:1:0
|
||||
packag main
|
||||
^`,
|
||||
},
|
||||
{
|
||||
code: `package mai`,
|
||||
errorMessage: `found packages mai and main`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
package main
|
||||
func main1(a, b int4) int4 {
|
||||
return Sum2(MinMax(a, b))
|
||||
}
|
||||
`,
|
||||
errorMessage: `no main function defined`,
|
||||
},
|
||||
{
|
||||
code: `
|
||||
package main
|
||||
fun main(a, b int4) int4 {
|
||||
return Sum2(MinMax(a, b))
|
||||
}`,
|
||||
errorMessage: `Compile error [parse]: unexpected token 'identifier', {data}:3:1
|
||||
fun main(a, b int4) int4 {
|
||||
^`,
|
||||
},
|
||||
{
|
||||
code: `package main
|
||||
func main(a, b) int4 {
|
||||
return Sum2(MinMax(a, b))
|
||||
}`,
|
||||
|
||||
errorMessage: `Compile error [parse]: unexpected token ')' while parsing type, {data}:2:16
|
||||
func main(a, b) int4 {
|
||||
^`,
|
||||
},
|
||||
{
|
||||
code: `package main
|
||||
func main(a, b int4 int4 {
|
||||
return Sum2(MinMax(a, b))
|
||||
}`,
|
||||
|
||||
errorMessage: `Compile error [parse]: unexpected token 'int4': expected ',', {data}:2:22
|
||||
func main(a, b int4 int4 {
|
||||
^`,
|
||||
},
|
||||
{
|
||||
code: `package main
|
||||
func main(a, b int4) int4 {
|
||||
a+b
|
||||
}`,
|
||||
|
||||
errorMessage: `missing return at the end of function`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestCompileErrorMessage(t *testing.T) {
|
||||
for idx, testData := range compileErrorTests {
|
||||
t.Run(fmt.Sprintf("test parse %d", idx), func(t *testing.T) {
|
||||
_, _, err := New(utils.NewParams()).Compile(testData.code, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Parse test %d failed: expected error", idx)
|
||||
}
|
||||
if err.Error() != testData.errorMessage {
|
||||
t.Fatalf("Parse test %d failed: expected error message %s, got %s", idx, testData.errorMessage, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
43
bedlam/compiler/errors.go
Normal file
43
bedlam/compiler/errors.go
Normal file
@ -0,0 +1,43 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
|
||||
)
|
||||
|
||||
type CompileError struct {
|
||||
Stage CompileStage // "parse", "compile", "circuit"
|
||||
SourcePos string
|
||||
Location *utils.Point
|
||||
Err error // origin error
|
||||
}
|
||||
|
||||
type CompileStage int
|
||||
|
||||
const (
|
||||
CompileStageParse CompileStage = iota
|
||||
CompileStageCompile
|
||||
CompileStageCircuit
|
||||
)
|
||||
|
||||
var stateName = map[CompileStage]string{
|
||||
CompileStageParse: "parse",
|
||||
CompileStageCompile: "compile",
|
||||
CompileStageCircuit: "circuit",
|
||||
}
|
||||
|
||||
func (cs CompileStage) String() string {
|
||||
return stateName[cs]
|
||||
}
|
||||
|
||||
func (e *CompileError) Error() string {
|
||||
msg := fmt.Sprintf("Compile error [%s]: %v", e.Stage, e.Err)
|
||||
if e.Location != nil {
|
||||
msg += fmt.Sprintf(", %s", e.Location)
|
||||
}
|
||||
if e.SourcePos != "" {
|
||||
msg += fmt.Sprintf("\n%s", e.SourcePos)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
36
bedlam/compiler/errors_test.go
Normal file
36
bedlam/compiler/errors_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"source.quilibrium.com/quilibrium/monorepo/bedlam/compiler/utils"
|
||||
)
|
||||
|
||||
func TestCompileError(t *testing.T) {
|
||||
t.Run("test compile error message without location", func(t *testing.T) {
|
||||
err := CompileError{
|
||||
Stage: CompileStageParse,
|
||||
SourcePos: "file:1:1",
|
||||
Err: fmt.Errorf("error message"),
|
||||
}
|
||||
want := "Compile error [parse]: error message\nfile:1:1"
|
||||
got := err.Error()
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
})
|
||||
t.Run("test compile error message with location", func(t *testing.T) {
|
||||
err := CompileError{
|
||||
Stage: CompileStageParse,
|
||||
SourcePos: "func main(a, b int4 int4",
|
||||
Location: &utils.Point{Source: "file", Line: 1, Col: 1},
|
||||
Err: fmt.Errorf("error message"),
|
||||
}
|
||||
want := "Compile error [parse]: error message, file:1:1\nfunc main(a, b int4 int4"
|
||||
got := err.Error()
|
||||
if got != want {
|
||||
t.Errorf("got %q, want %q", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -168,13 +168,26 @@ func (p *Parser) errf(loc utils.Point, format string, a ...interface{}) error {
|
||||
indicator = append(indicator, r)
|
||||
}
|
||||
indicator = append(indicator, '^')
|
||||
pos := fmt.Sprintf("%s\n%s", string(line), string(indicator))
|
||||
compilerError := &CompileError{
|
||||
Stage: CompileStageParse,
|
||||
SourcePos: pos,
|
||||
Location: &loc,
|
||||
Err: errors.New(msg),
|
||||
}
|
||||
p.logger.Errorf(loc, "%s\n%s\n%s\n",
|
||||
msg, string(line), string(indicator))
|
||||
|
||||
return errors.New(msg)
|
||||
return compilerError
|
||||
}
|
||||
p.logger.Errorf(loc, "%s", msg)
|
||||
return errors.New(msg)
|
||||
compilerError := &CompileError{
|
||||
Stage: CompileStageParse,
|
||||
SourcePos: fmt.Sprintf("%s:%d:%d", p.lexer.Source(), loc.Line, loc.Col),
|
||||
Location: &loc,
|
||||
Err: errors.New(msg),
|
||||
}
|
||||
return compilerError
|
||||
}
|
||||
|
||||
func (p *Parser) errUnexpected(offending *Token, expected TokenType) error {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user