Skip to content

Commit

Permalink
Add more error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
peachpit-site committed Jan 31, 2025
1 parent e86a346 commit cbdde93
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 40 deletions.
6 changes: 3 additions & 3 deletions source/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context)
for i, pair := range indexSig {
_, exists := newEnv.GetVar(pair.VarName)
if exists {
cp.P.Throw("comp/for/index/exists", node.Initializer.GetToken())
cp.P.Throw("comp/for/exists/index", node.Initializer.GetToken(), pair.VarName)
return altType(values.COMPILE_TIME_ERROR)
}
cp.Reserve(values.UNDEFINED_TYPE, nil, tok)
Expand Down Expand Up @@ -1529,7 +1529,7 @@ func (cp *Compiler) resolveBreaksWithValue() {
// Compile a `continue` in a `for loop`.
func (cp *Compiler) emitContinue(tok *token.Token) {
if len(cp.forData) == 0 {
cp.P.Throw("comp/for/continue", tok)
cp.P.Throw("comp/continue", tok)
return
}
cp.addToForData(cp.vmContinue())
Expand Down Expand Up @@ -1704,7 +1704,7 @@ func (cp *Compiler) CompileGivenBlock(given ast.Node, ctxt Context) {
for _, pair := range lhsSig {
_, exists := ctxt.Env.GetVar(pair.VarName)
if exists {
cp.P.Throw("comp/given/exists", chunk.GetToken())
cp.P.Throw("comp/given/exists", chunk.GetToken(), pair.VarName)
return
}
nameToNode[pair.VarName] = assEx
Expand Down
167 changes: 132 additions & 35 deletions source/err/errorfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,16 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/continue": {
Message: func(tok *token.Token, args ...any) string {
return "'continue' outside of 'for' loop"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "The 'continue' keyword really has no meaning outside of a 'for' loop, " +
"since what it means is \"continue the 'for' loop we're in without changing the bound variables\"."
},
},

"comp/error/arg": {
Message: func(tok *token.Token, args ...any) string {
return "expression can only return error"
Expand Down Expand Up @@ -340,40 +350,6 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/given/cycle": {
Message: func(tok *token.Token, args ...any) string {
cycle := args[0].([]string)
var description string
if len(cycle) == 1 {
description = emph(cycle[0]) + " is defined in terms of itself"
} else {
sep := ""
for _, name := range cycle {
description = description + sep + emph(name)
if sep == "" {
sep = " is defined in terms of "
} else {
sep = ", which is defined in terms of "
}
}
description = description + ", which is defined in terms of " + emph(cycle[0])
}
return description + " in " + emph("given") + " block"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "It isn't possible to define variables in terms of each other because how would that even work?"
},
},

"comp/log/close": {
Message: func(tok *token.Token, args ...any) string {
return "unclosed " + emph("|") + " in logging expression"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish interprets " + emph("| <expression> |") + " in a logging expression as meaning that the expression should be evaluated and inserted into the string. It therefore expects the " + emph("|") + " symbols to come in matching pairs."
},
},

"comp/fcis": {
Message: func(tok *token.Token, args ...any) string {
return "imperative code in " + emph("def") + " section"
Expand Down Expand Up @@ -432,6 +408,7 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},


"comp/for/bound/present": {
Message: func(tok *token.Token, args ...any) string {
return "loop has no bound variables"
Expand All @@ -442,7 +419,7 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/for/exists/key": {
"comp/for/exists/index": {
Message: func(tok *token.Token, args ...any) string {
return "reassigning to variable " + emph(args[0])
},
Expand All @@ -451,6 +428,14 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/for/exists/key": {
Message: func(tok *token.Token, args ...any) string {
return "reassigning to variable " + emph(args[0])
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "The index variables of a 'for' loop cannot have already been declared in the scope."
},
},

"comp/for/exists/value": {
Message: func(tok *token.Token, args ...any) string {
Expand All @@ -461,6 +446,109 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/for/range/a": {
Message: func(tok *token.Token, args ...any) string {
return "malformed assignment of range"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish expect the range of a 'for' loop to be assigned to a pair of " +
"index variables separated by a '::' operator."
},
},

"comp/for/range/b": {
Message: func(tok *token.Token, args ...any) string {
return "malformed assignment of range"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish expect the range of a 'for' loop to be assigned to a pair of " +
"index variables separated by a '::' operator."
},
},

"comp/for/range/c": {
Message: func(tok *token.Token, args ...any) string {
return "malformed assignment of range"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish expect the range of a 'for' loop to be assigned to a pair of " +
"index variables separated by a '::' operator."
},
},

"comp/for/range/discard": {
Message: func(tok *token.Token, args ...any) string {
return "discarding both key and value of range"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish currently doesn't let you do this. It may be allowed in later " +
"versions, since there is a marginal use-case." // TODO.
},
},

"comp/for/range/types": {
Message: func(tok *token.Token, args ...any) string {
return "ranging over invalid type"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "The argument of 'range' should be a type you can in fact range over, such as a list or a set."
},
},

"comp/given/assign": {
Message: func(tok *token.Token, args ...any) string {
return "malformed expression in 'given' block"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish was expecting either a function declaration or an assignment, and " +
"this is neither."
},
},

"comp/given/cycle": {
Message: func(tok *token.Token, args ...any) string {
cycle := args[0].([]string)
var description string
if len(cycle) == 1 {
description = emph(cycle[0]) + " is defined in terms of itself"
} else {
sep := ""
for _, name := range cycle {
description = description + sep + emph(name)
if sep == "" {
sep = " is defined in terms of "
} else {
sep = ", which is defined in terms of "
}
}
description = description + ", which is defined in terms of " + emph(cycle[0])
}
return description + " in " + emph("given") + " block"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "It isn't possible to define variables in terms of each other because how would that even work?"
},
},

"comp/given/exists": {
Message: func(tok *token.Token, args ...any) string {
return "variable " + emph(args[0]) + " already exists"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish doesn't allow the variables declared in a 'given' block " +
"to \"shadow\" existing variables."
},
},

"comp/given/redeclared": {
Message: func(tok *token.Token, args ...any) string {
return "variable " + emph(args[0]) + " defined twice"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "You've tried to define the same variable twice on the left-hand side of the same assignment."
},
},

"comp/global/global": {
Message: func(tok *token.Token, args ...any) string {
return "identifier " + emph(tok.Literal) + " doesn't identify a global variable"
Expand Down Expand Up @@ -614,6 +702,15 @@ var ErrorCreatorMap = map[string]ErrorCreator{
},
},

"comp/log/close": {
Message: func(tok *token.Token, args ...any) string {
return "unclosed " + emph("|") + " in logging expression"
},
Explanation: func(errors Errors, pos int, tok *token.Token, args ...any) string {
return "Pipefish interprets " + emph("| <expression> |") + " in a logging expression as meaning that the expression should be evaluated and inserted into the string. It therefore expects the " + emph("|") + " symbols to come in matching pairs."
},
},

"comp/loop/body": {
Message: func(tok *token.Token, args ...any) string {
return "trying to return a value from an imperative loop"
Expand Down
4 changes: 3 additions & 1 deletion source/vm/descriptors.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ func (vm *Vm) toString(v values.Value, flavor descriptionFlavor) string {
return "nil error"
}
ob := v.V.(*err.Error)
ob = err.CreateErr(ob.ErrorId, ob.Token, ob.Args...)
if ob.ErrorId != "vm/user" {
ob = err.CreateErr(ob.ErrorId, ob.Token, ob.Args...)
}
return text.Pretty(text.RT_ERROR+ob.Message+text.DescribePos(ob.Token)+".", 0, 80)
case values.FLOAT:
return strconv.FormatFloat(v.V.(float64), 'f', 8, 64)
Expand Down
2 changes: 1 addition & 1 deletion source/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ loop:
case Logy:
vm.logging = true
case Mker:
vm.Mem[args[0]] = values.Value{values.ERROR, &err.Error{ErrorId: "eval/user", Message: vm.Mem[args[1]].V.(string), Token: vm.Tokens[args[2]]}}
vm.Mem[args[0]] = values.Value{values.ERROR, &err.Error{ErrorId: "vm/user", Message: vm.Mem[args[1]].V.(string), Token: vm.Tokens[args[2]]}}
case Mkfn:
lf := vm.LambdaFactories[args[1]]
newLambda := *lf.Model
Expand Down

0 comments on commit cbdde93

Please sign in to comment.