Merge branch 'predicate-types'

This commit is contained in:
sloum 2023-05-04 14:23:38 -07:00
commit 010451cfab
3 changed files with 76 additions and 3 deletions

21
gui.go
View File

@ -1130,7 +1130,26 @@ func String(v expression, rawString bool) string {
case proc:
var b strings.Builder
b.WriteString("(lambda ")
b.WriteString(String(v.params, true))
params, ok := v.params.([]expression)
if len(v.predicates) > 0 {
if ok {
newParams := make([]expression, len(params))
copy(newParams, params)
for i := range newParams {
if pred, ok := v.predicates[newParams[i].(symbol)]; ok {
newParams[i] = symbol(fmt.Sprintf("%s@%s", newParams[i].(symbol), pred))
}
}
b.WriteString(String(newParams, true))
} else {
val := String(v.params, false)
b.WriteString(val)
b.WriteString("@")
b.WriteString(string(v.predicates[symbol(val)]))
}
} else {
b.WriteString(String(v.params, true))
}
b.WriteRune(' ')
body := String(v.body, true)
if strings.HasPrefix(body, "(begin ") {

View File

@ -17,6 +17,7 @@ type proc struct {
params expression
body expression
en *env
predicates map[symbol]symbol
}
type macro struct {
@ -288,7 +289,31 @@ func eval(exp expression, en *env) (value expression) {
}
b := []expression{symbol("begin")}
b = append(b, e[2:]...)
value = proc{e[1], stringUnescapeEval(b), en}
predicates := make(map[symbol]symbol)
switch a := e[1].(type) {
case []expression:
for i, v := range a {
s := String(v, false)
ind := strings.LastIndex(s, "@")
if ind < 1 {
continue
}
a[i] = symbol(s[:ind])
predicates[a[i].(symbol)] = symbol(s[ind+1:])
}
e[1] = a
default:
s := String(e[1], false)
ind := strings.LastIndex(s, "@")
if ind < 1 {
e[1] = []expression{e[1]}
break
}
e[1] = symbol(s[:ind])
predicates[e[1].(symbol)] = symbol(s[ind+1:])
e[1] = []expression{e[1]}
}
value = proc{e[1], stringUnescapeEval(b), en, predicates}
case "macro":
if len(e) < 3 {
value = exception("'macro' expects at least three arguments")
@ -724,9 +749,19 @@ func apply(procedure expression, args []expression, name expression) (value expr
}
break
}
if v, ok := p.predicates[param.(symbol)]; ok {
if !AnythingToBool(eval([]expression{v, args[i]}, p.en)).(bool) {
return exception(fmt.Sprintf("Type Error: Lambda %q expected argument %d to pass predicate %q, it did not", String(name, false), i+1, v))
}
}
en.vars[param.(symbol)] = args[i]
}
default:
if v, ok := p.predicates[params.(symbol)]; ok {
if !AnythingToBool(eval([]expression{v, args[0]}, p.en)).(bool) {
return exception(fmt.Sprintf("Type Error: Lambda %q expected argument %d to pass predicate %q, it did not", String(name, false), 1, v))
}
}
en.vars[params.(symbol)] = args
}
value = eval(p.body, en)

View File

@ -35,7 +35,26 @@ func String(v expression, rawString bool) string {
case proc:
var b strings.Builder
b.WriteString("(lambda ")
b.WriteString(String(v.params, true))
params, ok := v.params.([]expression)
if len(v.predicates) > 0 {
if ok {
newParams := make([]expression, len(params))
copy(newParams, params)
for i := range newParams {
if pred, ok := v.predicates[newParams[i].(symbol)]; ok {
newParams[i] = symbol(fmt.Sprintf("%s@%s", newParams[i].(symbol), pred))
}
}
b.WriteString(String(newParams, true))
} else {
val := String(v.params, false)
b.WriteString(val)
b.WriteString("@")
b.WriteString(string(v.predicates[symbol(val)]))
}
} else {
b.WriteString(String(v.params, true))
}
b.WriteRune(' ')
body := String(v.body, true)
if strings.HasPrefix(body, "(begin ") {