mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
Refine compiler's error reporting.
This commit is contained in:
parent
b2dbfaee39
commit
2b1b57f0aa
|
@ -51,22 +51,23 @@ func compileDel(cp *compiler, fn *parse.Form) Op {
|
|||
// ensuring that variables can be resolved
|
||||
var names, envNames []string
|
||||
for _, cn := range fn.Args {
|
||||
cp.compiling(cn)
|
||||
qname := mustString(cp, cn, "should be a literal variable name")
|
||||
splice, ns, name := parseVariable(qname)
|
||||
if splice {
|
||||
cp.errorf(cn.Begin(), "removing spliced variable makes no sense")
|
||||
cp.errorf("removing spliced variable makes no sense")
|
||||
}
|
||||
switch ns {
|
||||
case "", "local":
|
||||
if !cp.thisScope()[name] {
|
||||
cp.errorf(cn.Begin(), "variable $%s not found on current local scope", name)
|
||||
cp.errorf("variable $%s not found on current local scope", name)
|
||||
}
|
||||
delete(cp.thisScope(), name)
|
||||
names = append(names, name)
|
||||
case "env":
|
||||
envNames = append(envNames, name)
|
||||
default:
|
||||
cp.errorf(cn.Begin(), "can only delete a variable in local: or env:")
|
||||
cp.errorf("can only delete a variable in local: or env:")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -98,20 +99,23 @@ func makeFnOp(op Op) Op {
|
|||
// fn f []{foobar} is a shorthand for set '&'f = []{foobar}.
|
||||
func compileFn(cp *compiler, fn *parse.Form) Op {
|
||||
if len(fn.Args) == 0 {
|
||||
cp.errorf(fn.End(), "should be followed by function name")
|
||||
end := fn.End()
|
||||
cp.errorpf(end, end, "should be followed by function name")
|
||||
}
|
||||
fnName := mustString(cp, fn.Args[0], "must be a literal string")
|
||||
varName := FnPrefix + fnName
|
||||
|
||||
if len(fn.Args) == 1 {
|
||||
cp.errorf(fn.Args[0].End(), "should be followed by a lambda")
|
||||
end := fn.Args[0].End()
|
||||
cp.errorpf(end, end, "should be followed by a lambda")
|
||||
}
|
||||
pn := mustPrimary(cp, fn.Args[1], "should be a lambda")
|
||||
if pn.Type != parse.Lambda {
|
||||
cp.errorf(pn.Begin(), "should be a lambda")
|
||||
cp.compiling(pn)
|
||||
cp.errorf("should be a lambda")
|
||||
}
|
||||
if len(fn.Args) > 2 {
|
||||
cp.errorf(fn.Args[2].Begin(), "superfluous argument")
|
||||
cp.errorpf(fn.Args[2].Begin(), fn.Args[len(fn.Args)-1].End(), "superfluous argument(s)")
|
||||
}
|
||||
|
||||
cp.registerVariableSet(":" + varName)
|
||||
|
@ -136,7 +140,8 @@ func compileUse(cp *compiler, fn *parse.Form) Op {
|
|||
|
||||
switch len(fn.Args) {
|
||||
case 0:
|
||||
cp.errorf(fn.Head.End(), "should be module name")
|
||||
end := fn.Head.End()
|
||||
cp.errorpf(end, end, "lack module name")
|
||||
case 2:
|
||||
filenameOp = cp.compound(fn.Args[1])
|
||||
filenameBegin = fn.Args[1].Begin()
|
||||
|
@ -144,7 +149,7 @@ func compileUse(cp *compiler, fn *parse.Form) Op {
|
|||
case 1:
|
||||
modname = mustString(cp, fn.Args[0], "should be a literal module name")
|
||||
default:
|
||||
cp.errorf(fn.Args[2].Begin(), "superfluous argument")
|
||||
cp.errorpf(fn.Args[2].Begin(), fn.Args[len(fn.Args)-1].End(), "superfluous argument(s)")
|
||||
}
|
||||
|
||||
return func(ec *EvalCtx) {
|
||||
|
|
|
@ -134,7 +134,7 @@ func (cp *compiler) pipeline(n *parse.Pipeline) Op {
|
|||
func (cp *compiler) form(n *parse.Form) Op {
|
||||
if len(n.Assignments) > 0 {
|
||||
if n.Head != nil {
|
||||
cp.errorf(n.Begin(), "temporary assignments not yet supported")
|
||||
cp.errorpf(n.Assignments[0].Begin(), n.Assignments[len(n.Assignments)-1].End(), "temporary assignments not yet supported")
|
||||
}
|
||||
ops := cp.assignments(n.Assignments)
|
||||
return func(ec *EvalCtx) {
|
||||
|
@ -146,7 +146,7 @@ func (cp *compiler) form(n *parse.Form) Op {
|
|||
|
||||
if n.Control != nil {
|
||||
if len(n.Args) > 0 {
|
||||
cp.errorf(n.Args[0].Begin(), "control structure takes no arguments")
|
||||
cp.errorpf(n.Args[0].Begin(), n.Args[len(n.Args)-1].End(), "control structure takes no arguments")
|
||||
}
|
||||
redirOps := cp.redirs(n.Redirs)
|
||||
controlOp := cp.control(n.Control)
|
||||
|
@ -259,7 +259,7 @@ func (cp *compiler) control(n *parse.Control) Op {
|
|||
case parse.BeginControl:
|
||||
return cp.chunk(n.Body)
|
||||
default:
|
||||
cp.errorf(n.Begin(), "unknown ControlKind %s, compiler bug", n.Kind)
|
||||
cp.errorpf(n.Begin(), n.End(), "unknown ControlKind %s, compiler bug", n.Kind)
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
@ -285,11 +285,12 @@ func (cp *compiler) multiVariable(n *parse.Indexing) []VariableOp {
|
|||
indexings := make([]*parse.Indexing, len(compounds))
|
||||
for i, cn := range compounds {
|
||||
if len(cn.Indexings) != 1 {
|
||||
cp.errorf(cn.Begin(), "must be a variable spec")
|
||||
cp.compiling(cn)
|
||||
cp.errorf("must be a variable spec")
|
||||
}
|
||||
indexings[i] = cn.Indexings[0]
|
||||
}
|
||||
variableOps = cp.singleVariables(indexings, "must be a variable spc")
|
||||
variableOps = cp.singleVariables(indexings, "must be a variable spec")
|
||||
} else {
|
||||
variableOps = []VariableOp{cp.singleVariable(n, "must be a variable spec or a braced list of those")}
|
||||
}
|
||||
|
@ -384,7 +385,8 @@ func (cp *compiler) literal(n *parse.Primary, msg string) string {
|
|||
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
|
||||
return n.Value
|
||||
default:
|
||||
cp.errorf(n.Begin(), msg)
|
||||
cp.compiling(n)
|
||||
cp.errorf(msg)
|
||||
return "" // not reached
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,13 +226,14 @@ func variable(qname string, p int) ValuesOp {
|
|||
}
|
||||
|
||||
func (cp *compiler) primary(n *parse.Primary) ValuesOp {
|
||||
cp.compiling(n)
|
||||
switch n.Type {
|
||||
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
|
||||
return literalStr(n.Value)
|
||||
case parse.Variable:
|
||||
qname := n.Value
|
||||
if !cp.registerVariableGet(qname) {
|
||||
cp.errorf(n.Begin(), "variable $%s not found", n.Value)
|
||||
cp.errorf("variable $%s not found", n.Value)
|
||||
}
|
||||
return variable(qname, n.Begin())
|
||||
case parse.Wildcard:
|
||||
|
@ -242,7 +243,7 @@ func (cp *compiler) primary(n *parse.Primary) ValuesOp {
|
|||
return vs
|
||||
}
|
||||
case parse.Tilde:
|
||||
cp.errorf(n.Begin(), "compiler bug: Tilde not handled in .compound")
|
||||
cp.errorf("compiler bug: Tilde not handled in .compound")
|
||||
return literalStr("~")
|
||||
case parse.ErrorCapture:
|
||||
return cp.errorCapture(n.Chunk)
|
||||
|
@ -260,7 +261,7 @@ func (cp *compiler) primary(n *parse.Primary) ValuesOp {
|
|||
case parse.Braced:
|
||||
return cp.braced(n)
|
||||
default:
|
||||
cp.errorf(n.Begin(), "bad PrimaryType; parser bug")
|
||||
cp.errorf("bad PrimaryType; parser bug")
|
||||
return literalStr(n.SourceText())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,16 +26,26 @@ type compiler struct {
|
|||
scopes []scope
|
||||
// Variables captured from outer scopes.
|
||||
capture scope
|
||||
// Position of what is being compiled.
|
||||
begin, end int
|
||||
}
|
||||
|
||||
func compile(sc scope, n *parse.Chunk) (op Op, err error) {
|
||||
cp := &compiler{[]scope{sc}, scope{}}
|
||||
cp := &compiler{[]scope{sc}, scope{}, 0, 0}
|
||||
defer util.Catch(&err)
|
||||
return cp.chunk(n), nil
|
||||
}
|
||||
|
||||
func (cp *compiler) errorf(p int, format string, args ...interface{}) {
|
||||
throw(&util.PosError{p, p, fmt.Errorf(format, args...)})
|
||||
func (cp *compiler) compiling(n parse.Node) {
|
||||
cp.begin, cp.end = n.Begin(), n.End()
|
||||
}
|
||||
|
||||
func (cp *compiler) errorpf(begin, end int, format string, args ...interface{}) {
|
||||
throw(&util.PosError{begin, end, fmt.Errorf(format, args...)})
|
||||
}
|
||||
|
||||
func (cp *compiler) errorf(format string, args ...interface{}) {
|
||||
cp.errorpf(cp.begin, cp.end, format, args...)
|
||||
}
|
||||
|
||||
func (cp *compiler) thisScope() scope {
|
||||
|
|
|
@ -95,7 +95,7 @@ func oneString(cn *parse.Compound) (string, bool) {
|
|||
func mustPrimary(cp *compiler, cn *parse.Compound, msg string) *parse.Primary {
|
||||
p := onePrimary(cn)
|
||||
if p == nil {
|
||||
cp.errorf(cn.Begin(), msg)
|
||||
cp.errorpf(cn.Begin(), cn.End(), msg)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func mustPrimary(cp *compiler, cn *parse.Compound, msg string) *parse.Primary {
|
|||
func mustString(cp *compiler, cn *parse.Compound, msg string) string {
|
||||
s, ok := oneString(cn)
|
||||
if !ok {
|
||||
cp.errorf(cn.Begin(), msg)
|
||||
cp.errorpf(cn.Begin(), cn.End(), msg)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user