Further bug fixes and tweaks when working with @ params

This commit is contained in:
sloum 2023-05-04 20:05:43 -07:00
parent d9aab155d8
commit 3b385c4314
2 changed files with 23 additions and 12 deletions

View File

@ -117,7 +117,7 @@ There are a number of special forms in the language that will allow, for example
- `lambda`
- The body of a lambda has an implied `(begin ...)` surrounding it. As such, you may place non-nested procedure calls or values inside of a lambda body and the last will be returned
- Variadic lambdas can be created by using the special param name `args-list` or `...` (which will be a list of all of the remaining arguments when accessed rom the lambda body). This param should be the last param in the lambda definition, as it will eat all arguments that come after its position. Any params defined after `args-list`/`...` have undefined behavior (they will generally not be created)
- A paramater symbol can include an `@` followed by the name of a procedure. For example: `(lambda (input@number?) (+ input input))`. If tha is done, the argument passed to the lambda will first be passed to the given procedure. This allows for a form of runtime type checking. Generally the procedure given should be a predicate, but any procedure will work (the return value will be coerced to a boolean value). This creates a flexible type checking system. To create a new "type" simply create a predicate that is capable of recognizing that type, then use the `@` paramater syntax to enforce it. Note: `@` paramaters do work with `...` at present.
- A paramater symbol can include an `@` followed by the name of a procedure. For example: `(lambda (input@number?) (+ input input))`. If tha is done, the argument passed to the lambda will first be passed to the given procedure. This allows for a form of runtime type checking. Generally the procedure given should be a predicate, but any procedure will work (the return value will be coerced to a boolean value). This creates a flexible type checking system. To create a new "type" simply create a predicate that is capable of recognizing that type, then use the `@` paramater syntax to enforce it. `@` paramaters _do_ work with `...`: they will pass the full list to the predicate, and will _not_ run the predicate on each list item.
- `load`
- Loads and executes a slope file. Absolute path to file must be used
- `load-mod`

View File

@ -741,7 +741,26 @@ func apply(procedure expression, args []expression, name expression) (value expr
return exception(fmt.Sprintf("Lambda %q expected %d argument(s) but received %d", String(name, false), len(params), len(args)))
}
for i, param := range params {
variadic := false
if param.(symbol) == symbol("args-list") || param.(symbol) == symbol("...") {
variadic = true
}
result := true
if v, ok := p.predicates[param.(symbol)]; ok {
if variadic {
r := apply(eval(v, p.en), []expression{args[i:]}, v)
result = AnythingToBool(r).(bool)
} else {
r := apply(eval(v, p.en), []expression{args[i]}, v)
result = AnythingToBool(r).(bool)
}
if !result {
return exception(fmt.Sprintf("Type Error: In call to %q argument %d failed to fulfill predicate %q", String(name, false), i+1, v))
}
}
if variadic {
if len(args) >= len(params) {
en.vars[param.(symbol)] = args[i:]
} else {
@ -749,20 +768,12 @@ func apply(procedure expression, args []expression, name expression) (value expr
}
break
}
if v, ok := p.predicates[param.(symbol)]; ok {
result := apply(eval(v, p.en), []expression{args[i]}, v)
if !AnythingToBool(result).(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))
}
}
// This wont come up with changes to how lambdas without a () structure work
// hint: they are given a ()
en.vars[params.(symbol)] = args
}
value = eval(p.body, en)