Go: use slices for Handler results
This commit is contained in:
parent
f4f03d1737
commit
fb143f4d27
153
ell/ell.go
153
ell/ell.go
|
@ -545,7 +545,7 @@ func (p *Parser) Run() (result *V, err error) {
|
||||||
// --- Runtime -----------------------------------------------------------------
|
// --- Runtime -----------------------------------------------------------------
|
||||||
|
|
||||||
// Handler is a Go handler for an Ell function.
|
// Handler is a Go handler for an Ell function.
|
||||||
type Handler func(*Ell, []V, **V) bool
|
type Handler func(*Ell, []V, *[]V) bool
|
||||||
|
|
||||||
// Ell is an interpreter context.
|
// Ell is an interpreter context.
|
||||||
type Ell struct {
|
type Ell struct {
|
||||||
|
@ -656,6 +656,15 @@ error:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sliceToSeq(slice []V) (res *V) {
|
||||||
|
out := &res
|
||||||
|
for _, v := range slice {
|
||||||
|
*out = v.Clone()
|
||||||
|
out = &(*out).Next
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (ell *Ell) evalNative(name string, args *V, result **V) bool {
|
func (ell *Ell) evalNative(name string, args *V, result **V) bool {
|
||||||
fn := ell.Native[name]
|
fn := ell.Native[name]
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
|
@ -674,7 +683,12 @@ func (ell *Ell) evalNative(name string, args *V, result **V) bool {
|
||||||
singledOut.Next = nil
|
singledOut.Next = nil
|
||||||
sliced = append(sliced, singledOut)
|
sliced = append(sliced, singledOut)
|
||||||
}
|
}
|
||||||
return fn(ell, sliced, result)
|
var res []V
|
||||||
|
if !fn(ell, sliced, &res) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*result = sliceToSeq(res)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ell *Ell) evalResolved(body *V, args *V, result **V) bool {
|
func (ell *Ell) evalResolved(body *V, args *V, result **V) bool {
|
||||||
|
@ -778,13 +792,22 @@ func (ell *Ell) EvalBlock(body *V, args *V, result **V) bool {
|
||||||
|
|
||||||
// --- Standard library --------------------------------------------------------
|
// --- Standard library --------------------------------------------------------
|
||||||
|
|
||||||
// EvalAny evaluates any value.
|
// EvalAny evaluates any value and appends to the result.
|
||||||
func EvalAny(ell *Ell, body *V, arg *V, result **V) bool {
|
func EvalAny(ell *Ell, body *V, arg *V, result *[]V) bool {
|
||||||
if body.Type == VTypeString {
|
if body.Type == VTypeString {
|
||||||
*result = body.Clone()
|
*result = []V{*body.Clone()}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return ell.EvalBlock(body.Head, arg.Clone(), result)
|
var res *V
|
||||||
|
if !ell.EvalBlock(body.Head, arg.Clone(), &res) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for ; res != nil; res = res.Next {
|
||||||
|
singledOut := *res
|
||||||
|
singledOut.Next = nil
|
||||||
|
*result = append(*result, singledOut)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNumber creates a new string value containing a number.
|
// NewNumber creates a new string value containing a number.
|
||||||
|
@ -815,7 +838,7 @@ func NewBoolean(b bool) *V {
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
func fnLocal(ell *Ell, args []V, result **V) bool {
|
func fnLocal(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) == 0 || args[0].Type != VTypeList {
|
if len(args) == 0 || args[0].Type != VTypeList {
|
||||||
return ell.Errorf("first argument must be a list")
|
return ell.Errorf("first argument must be a list")
|
||||||
}
|
}
|
||||||
|
@ -833,46 +856,37 @@ func fnLocal(ell *Ell, args []V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnSet(ell *Ell, args []V, result **V) bool {
|
func fnSet(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) == 0 || args[0].Type != VTypeString {
|
if len(args) == 0 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
*result = args[1].Clone()
|
*result = []V{*args[1].Clone()}
|
||||||
ell.Set(args[0].String, *result)
|
ell.Set(args[0].String, &(*result)[0])
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// We return an empty list for a nil value.
|
// We return an empty list for a nil value.
|
||||||
if v := ell.Get(args[0].String); v != nil {
|
if v := ell.Get(args[0].String); v != nil {
|
||||||
*result = v.Clone()
|
*result = []V{*v.Clone()}
|
||||||
} else {
|
} else {
|
||||||
*result = NewList(nil)
|
*result = []V{*NewList(nil)}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func sliceToSeq(slice []V) (res *V) {
|
func fnList(ell *Ell, args []V, result *[]V) bool {
|
||||||
out := &res
|
*result = []V{*NewList(sliceToSeq(args))}
|
||||||
for _, v := range slice {
|
|
||||||
*out = v.Clone()
|
|
||||||
out = &(*out).Next
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func fnList(ell *Ell, args []V, result **V) bool {
|
|
||||||
*result = NewList(sliceToSeq(args))
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnValues(ell *Ell, args []V, result **V) bool {
|
func fnValues(ell *Ell, args []V, result *[]V) bool {
|
||||||
*result = sliceToSeq(args)
|
*result = args
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnIf(ell *Ell, args []V, result **V) bool {
|
func fnIf(ell *Ell, args []V, result *[]V) bool {
|
||||||
var cond, body, keyword int
|
var cond, body, keyword int
|
||||||
for cond = 0; ; cond = keyword + 1 {
|
for cond = 0; ; cond = keyword + 1 {
|
||||||
if cond >= len(args) {
|
if cond >= len(args) {
|
||||||
|
@ -882,11 +896,11 @@ func fnIf(ell *Ell, args []V, result **V) bool {
|
||||||
return ell.Errorf("missing body")
|
return ell.Errorf("missing body")
|
||||||
}
|
}
|
||||||
|
|
||||||
var res *V
|
var res []V
|
||||||
if !EvalAny(ell, &args[cond], nil, &res) {
|
if !EvalAny(ell, &args[cond], nil, &res) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if Truthy(res) {
|
if len(res) > 0 && Truthy(&res[0]) {
|
||||||
return EvalAny(ell, &args[body], nil, result)
|
return EvalAny(ell, &args[body], nil, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +925,7 @@ func fnIf(ell *Ell, args []V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMap(ell *Ell, args []V, result **V) bool {
|
func fnMap(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return ell.Errorf("first argument must be a function")
|
return ell.Errorf("first argument must be a function")
|
||||||
}
|
}
|
||||||
|
@ -921,22 +935,17 @@ func fnMap(ell *Ell, args []V, result **V) bool {
|
||||||
|
|
||||||
body, values := &args[0], &args[1]
|
body, values := &args[0], &args[1]
|
||||||
|
|
||||||
var res *V
|
var res []V
|
||||||
out := &res
|
|
||||||
|
|
||||||
for v := values.Head; v != nil; v = v.Next {
|
for v := values.Head; v != nil; v = v.Next {
|
||||||
if !EvalAny(ell, body, v, out) {
|
if !EvalAny(ell, body, v, &res) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for *out != nil {
|
|
||||||
out = &(*out).Next
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*result = NewList(res)
|
*result = []V{*NewList(sliceToSeq(res))}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnPrint(ell *Ell, args []V, result **V) bool {
|
func fnPrint(ell *Ell, args []V, result *[]V) bool {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if arg.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
PrintV(os.Stdout, &arg)
|
PrintV(os.Stdout, &arg)
|
||||||
|
@ -947,7 +956,7 @@ func fnPrint(ell *Ell, args []V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnCat(ell *Ell, args []V, result **V) bool {
|
func fnCat(ell *Ell, args []V, result *[]V) bool {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if arg.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
|
@ -956,11 +965,11 @@ func fnCat(ell *Ell, args []V, result **V) bool {
|
||||||
buf.WriteString(arg.String)
|
buf.WriteString(arg.String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result = NewString(buf.String())
|
*result = []V{*NewString(buf.String())}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnSystem(ell *Ell, args []V, result **V) bool {
|
func fnSystem(ell *Ell, args []V, result *[]V) bool {
|
||||||
var argv []string
|
var argv []string
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if arg.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
|
@ -979,16 +988,16 @@ func fnSystem(ell *Ell, args []V, result **V) bool {
|
||||||
|
|
||||||
// Approximation of system(3) return value to match C ell at least a bit.
|
// Approximation of system(3) return value to match C ell at least a bit.
|
||||||
if err := cmd.Run(); err == nil {
|
if err := cmd.Run(); err == nil {
|
||||||
*result = NewNumber(0)
|
*result = []V{*NewNumber(0)}
|
||||||
} else if _, ok := err.(*exec.Error); ok {
|
} else if _, ok := err.(*exec.Error); ok {
|
||||||
return ell.Errorf("%s", err)
|
return ell.Errorf("%s", err)
|
||||||
} else {
|
} else {
|
||||||
*result = NewNumber(1)
|
*result = []V{*NewNumber(1)}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnParse(ell *Ell, args []V, result **V) bool {
|
func fnParse(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -997,11 +1006,11 @@ func fnParse(ell *Ell, args []V, result **V) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ell.Errorf("%s", err)
|
return ell.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
*result = NewList(res)
|
*result = []V{*NewList(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnTry(ell *Ell, args []V, result **V) bool {
|
func fnTry(ell *Ell, args []V, result *[]V) bool {
|
||||||
var body, handler *V
|
var body, handler *V
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return ell.Errorf("first argument must be a function")
|
return ell.Errorf("first argument must be a function")
|
||||||
|
@ -1021,14 +1030,14 @@ func fnTry(ell *Ell, args []V, result **V) bool {
|
||||||
return EvalAny(ell, handler, msg, result)
|
return EvalAny(ell, handler, msg, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnThrow(ell *Ell, args []V, result **V) bool {
|
func fnThrow(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
return ell.Errorf("%s", args[0].String)
|
return ell.Errorf("%s", args[0].String)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnPlus(ell *Ell, args []V, result **V) bool {
|
func fnPlus(ell *Ell, args []V, result *[]V) bool {
|
||||||
res := 0.
|
res := 0.
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if arg.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
|
@ -1040,11 +1049,11 @@ func fnPlus(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
res += value
|
res += value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = []V{*NewNumber(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMinus(ell *Ell, args []V, result **V) bool {
|
func fnMinus(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1067,11 +1076,11 @@ func fnMinus(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
res -= value
|
res -= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = []V{*NewNumber(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMultiply(ell *Ell, args []V, result **V) bool {
|
func fnMultiply(ell *Ell, args []V, result *[]V) bool {
|
||||||
res := 1.
|
res := 1.
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if arg.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
|
@ -1083,11 +1092,11 @@ func fnMultiply(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
res *= value
|
res *= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = []V{*NewNumber(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnDivide(ell *Ell, args []V, result **V) bool {
|
func fnDivide(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1106,21 +1115,21 @@ func fnDivide(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
res /= value
|
res /= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = []V{*NewNumber(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnNot(ell *Ell, args []V, result **V) bool {
|
func fnNot(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return ell.Errorf("missing argument")
|
return ell.Errorf("missing argument")
|
||||||
}
|
}
|
||||||
*result = NewBoolean(!Truthy(&args[0]))
|
*result = []V{*NewBoolean(!Truthy(&args[0]))}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnAnd(ell *Ell, args []V, result **V) bool {
|
func fnAnd(ell *Ell, args []V, result *[]V) bool {
|
||||||
if args == nil {
|
if args == nil {
|
||||||
*result = NewBoolean(true)
|
*result = []V{*NewBoolean(true)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
|
@ -1128,29 +1137,29 @@ func fnAnd(ell *Ell, args []V, result **V) bool {
|
||||||
if !EvalAny(ell, &arg, nil, result) {
|
if !EvalAny(ell, &arg, nil, result) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !Truthy(*result) {
|
if len(*result) < 1 || !Truthy(&(*result)[0]) {
|
||||||
*result = NewBoolean(false)
|
*result = []V{*NewBoolean(false)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnOr(ell *Ell, args []V, result **V) bool {
|
func fnOr(ell *Ell, args []V, result *[]V) bool {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if !EvalAny(ell, &arg, nil, result) {
|
if !EvalAny(ell, &arg, nil, result) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if Truthy(*result) {
|
if len(*result) > 0 && Truthy(&(*result)[0]) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
*result = nil
|
*result = nil
|
||||||
}
|
}
|
||||||
*result = NewBoolean(false)
|
*result = []V{*NewBoolean(false)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnEq(ell *Ell, args []V, result **V) bool {
|
func fnEq(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1163,11 +1172,11 @@ func fnEq(ell *Ell, args []V, result **V) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result = NewBoolean(res)
|
*result = []V{*NewBoolean(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnLt(ell *Ell, args []V, result **V) bool {
|
func fnLt(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1181,11 +1190,11 @@ func fnLt(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
etalon = arg.String
|
etalon = arg.String
|
||||||
}
|
}
|
||||||
*result = NewBoolean(res)
|
*result = []V{*NewBoolean(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnEquals(ell *Ell, args []V, result **V) bool {
|
func fnEquals(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1206,11 +1215,11 @@ func fnEquals(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
first = second
|
first = second
|
||||||
}
|
}
|
||||||
*result = NewBoolean(res)
|
*result = []V{*NewBoolean(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnLess(ell *Ell, args []V, result **V) bool {
|
func fnLess(ell *Ell, args []V, result *[]V) bool {
|
||||||
if len(args) < 1 || args[0].Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
@ -1231,7 +1240,7 @@ func fnLess(ell *Ell, args []V, result **V) bool {
|
||||||
}
|
}
|
||||||
first = second
|
first = second
|
||||||
}
|
}
|
||||||
*result = NewBoolean(res)
|
*result = []V{*NewBoolean(res)}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue