pkg/eval: Don't use panics for propagating compilation errors.

This also enables saving multiple compilation errors.
This commit is contained in:
Qi Xiao 2022-11-28 22:49:55 +00:00
parent ff0feb4311
commit 69715b05fe
4 changed files with 15 additions and 18 deletions

View File

@ -789,7 +789,7 @@ func compilePragma(cp *compiler, fn *parse.Form) effectOp {
args := getArgs(cp, fn)
name := args.get(0, "pragma name").stringLiteral()
eq := args.get(1, "literal =").stringLiteral()
if eq != "=" {
if args.has(1) && eq != "=" {
args.errorpf(fn.Args[1], "must be literal =")
}
valueNode := args.get(2, "pragma value").any()

View File

@ -38,6 +38,7 @@ func (cp *compiler) parseCompoundLValues(ns []*parse.Compound, f lvalueFlag) lva
for _, n := range ns {
if len(n.Indexings) != 1 {
cp.errorpf(n, "lvalue may not be composite expressions")
break
}
more := cp.parseIndexingLValue(n.Indexings[0], f)
if more.rest == -1 {

View File

@ -28,32 +28,27 @@ type compiler struct {
deprecations deprecationRegistry
// Information about the source.
srcMeta parse.Source
// Compilation errrors.
errors []*diag.Error
}
type scopePragma struct {
unknownCommandIsExternal bool
}
func compile(b, g *staticNs, tree parse.Tree, w io.Writer) (op nsOp, err error) {
func compile(b, g *staticNs, tree parse.Tree, w io.Writer) (nsOp, error) {
g = g.clone()
cp := &compiler{
b, []*staticNs{g}, []*staticUpNs{new(staticUpNs)},
[]*scopePragma{{unknownCommandIsExternal: true}},
w, newDeprecationRegistry(), tree.Source}
defer func() {
r := recover()
if r == nil {
return
} else if e := GetCompilationError(r); e != nil {
// Save the compilation error and stop the panic.
err = e
} else {
// Resume the panic; it is not supposed to be handled here.
panic(r)
}
}()
w, newDeprecationRegistry(), tree.Source, nil}
chunkOp := cp.chunkOp(tree.Root)
return nsOp{chunkOp, g}, nil
var err error
if len(cp.errors) > 0 {
// TODO: Preserve all compilation errors.
err = cp.errors[0]
}
return nsOp{chunkOp, g}, err
}
type nsOp struct {
@ -84,8 +79,7 @@ func (op nsOp) prepare(fm *Frame) (*Ns, func() Exception) {
const compilationErrorType = "compilation error"
func (cp *compiler) errorpf(r diag.Ranger, format string, args ...any) {
// The panic is caught by the recover in compile above.
panic(&diag.Error{
cp.errors = append(cp.errors, &diag.Error{
Type: compilationErrorType,
Message: fmt.Sprintf(format, args...),
Context: *diag.NewContext(cp.srcMeta.Name, cp.srcMeta.Code, r)})

View File

@ -0,0 +1,2 @@
go test fuzz v1
string("{}= 0")