package eval
import (
)
type Exception interface {
error
diag.Shower
Reason() error
StackTrace() *StackTrace
isException()
}
func ( error, *StackTrace) Exception {
return &exception{, }
}
type exception struct {
reason error
stackTrace *StackTrace
}
type StackTrace struct {
Head *diag.Context
Next *StackTrace
}
func ( ...*diag.Context) *StackTrace {
var *StackTrace
for := len() - 1; >= 0; -- {
= &StackTrace{Head: [], Next: }
}
return
}
func ( error) error {
if , := .(*exception); {
return .reason
}
return
}
var OK = &exception{}
func ( *exception) () {}
func ( *exception) () error { return .reason }
func ( *exception) () *StackTrace { return .stackTrace }
func ( *exception) () string { return .reason.Error() }
func ( *exception) ( string) string {
:= new(bytes.Buffer)
var string
if , := .reason.(diag.Shower); {
= .Show()
} else if .reason == nil {
= "ok"
} else {
= "\033[31;1m" + .reason.Error() + "\033[m"
}
fmt.Fprintf(, "Exception: %s", )
if .stackTrace != nil {
.WriteString("\n")
if .stackTrace.Next == nil {
.WriteString(.stackTrace.Head.ShowCompact())
} else {
.WriteString( + "Traceback:")
for := .stackTrace; != nil; = .Next {
.WriteString("\n" + + " ")
.WriteString(.Head.Show( + " "))
}
}
}
if , := .reason.(PipelineError); {
.WriteString("\n" + + "Caused by:")
for , := range .Errors {
if == OK {
continue
}
.WriteString("\n" + + " " + .Show(+" "))
}
}
return .String()
}
func ( *exception) () string {
return "exception"
}
func ( *exception) ( int) string {
if .reason == nil {
return "$ok"
}
return "[&reason=" + vals.Repr(.reason, +1) + "]"
}
func ( *exception) ( interface{}) bool {
return ==
}
func ( *exception) () uint32 {
return hash.Pointer(unsafe.Pointer())
}
func ( *exception) () bool {
return .reason == nil
}
func ( *exception) () vals.StructMap { return excFields{} }
type excFields struct{ e *exception }
func (excFields) () {}
func ( excFields) () error { return .e.reason }
type PipelineError struct {
Errors []Exception
}
func ( PipelineError) () string {
:= new(bytes.Buffer)
.WriteString("(")
for , := range .Errors {
if > 0 {
.WriteString(" | ")
}
if == nil || .Reason() == nil {
.WriteString("<nil>")
} else {
.WriteString(.Error())
}
}
.WriteString(")")
return .String()
}
func ( []Exception) error {
:= make([]Exception, len())
, := 0, 0
for , := range {
if == nil {
[] = OK
} else {
[] =
if .Reason() != nil {
++
=
}
}
}
switch {
case 0:
return nil
case 1:
return []
default:
return PipelineError{}
}
}
func ( PipelineError) () vals.StructMap { return peFields{} }
type peFields struct{ pe PipelineError }
func (peFields) () {}
func ( peFields) () string { return "pipeline" }
func ( peFields) () vals.List {
:= vals.EmptyList
for , := range .pe.Errors {
= .Cons()
}
return
}
type Flow uint
const (
Return Flow = iota
Break
Continue
)
var flowNames = [...]string{
"return", "break", "continue",
}
func ( Flow) () string {
if >= Flow(len(flowNames)) {
return fmt.Sprintf("!(BAD FLOW: %d)", )
}
return flowNames[]
}
func ( Flow) (string) string {
return "\033[33;1m" + .Error() + "\033[m"
}
func ( Flow) () vals.StructMap { return flowFields{} }
type flowFields struct{ f Flow }
func (flowFields) () {}
func ( flowFields) () string { return "flow" }
func ( flowFields) () string { return .f.Error() }
type ExternalCmdExit struct {
syscall.WaitStatus
CmdName string
Pid int
}
func ( string, syscall.WaitStatus, int) error {
if .Exited() && .ExitStatus() == 0 {
return nil
}
return ExternalCmdExit{, , }
}
func ( ExternalCmdExit) () string {
:= .WaitStatus
:= parse.Quote(.CmdName)
switch {
case .Exited():
return + " exited with " + strconv.Itoa(.ExitStatus())
case .Signaled():
:= + " killed by signal " + .Signal().String()
if .CoreDump() {
+= " (core dumped)"
}
return
case .Stopped():
:= + " stopped by signal " + fmt.Sprintf("%s (pid=%d)", .StopSignal(), .Pid)
:= .TrapCause()
if != -1 {
+= fmt.Sprintf(" (trapped %v)", )
}
return
default:
return fmt.Sprint(, " has unknown WaitStatus ", )
}
}
func ( ExternalCmdExit) () vals.StructMap {
:= .WaitStatus
:= exitFieldsCommon{}
switch {
case .Exited():
return exitFieldsExited{}
case .Signaled():
return exitFieldsSignaled{}
case .Stopped():
return exitFieldsStopped{}
default:
return exitFieldsUnknown{}
}
}
type exitFieldsCommon struct{ e ExternalCmdExit }
func (exitFieldsCommon) () {}
func ( exitFieldsCommon) () string { return .e.CmdName }
func ( exitFieldsCommon) () string { return strconv.Itoa(.e.Pid) }
type exitFieldsExited struct{ exitFieldsCommon }
func (exitFieldsExited) () string { return "external-cmd/exited" }
func ( exitFieldsExited) () string { return strconv.Itoa(.e.ExitStatus()) }
type exitFieldsSignaled struct{ exitFieldsCommon }
func ( exitFieldsSignaled) () string { return "external-cmd/signaled" }
func ( exitFieldsSignaled) () string { return .e.Signal().String() }
func ( exitFieldsSignaled) () string { return strconv.Itoa(int(.e.Signal())) }
func ( exitFieldsSignaled) () bool { return .e.CoreDump() }
type exitFieldsStopped struct{ exitFieldsCommon }
func ( exitFieldsStopped) () string { return "external-cmd/stopped" }
func ( exitFieldsStopped) () string { return .e.StopSignal().String() }
func ( exitFieldsStopped) () string { return strconv.Itoa(int(.e.StopSignal())) }
func ( exitFieldsStopped) () int { return .e.TrapCause() }
type exitFieldsUnknown struct{ exitFieldsCommon }
func (exitFieldsUnknown) () string { return "external-cmd/unknown" }