1
0
Fork 0
Little S-Expression Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sxpf/form.go

88 lines
2.2 KiB

//-----------------------------------------------------------------------------
// Copyright (c) 2022 Detlef Stern
//
// This file is part of sxpf.
//
// sxpf is licensed under the latest version of the EUPL // (European Union
// Public License). Please see file LICENSE.txt for your rights and obligations
// under this license.
//-----------------------------------------------------------------------------
package sxpf
import (
"fmt"
"io"
)
// Form is a value that can be called. Depending on IsSpecial, the arguments
// are evaluated or not before calling the form.
type Form interface {
Value
Call(Environment, *Pair) (Value, error)
IsSpecial() bool
}
// Builtin is a wrapper for a builtin function.
type Builtin struct {
name string
fn BuiltinFn
minArity int
maxArity int // if maxArity < minArity ==> maxArity is unlimited
special bool
}
// BuiltinFn is a builtin form that is implemented in Go.
type BuiltinFn func(Environment, *Pair, int) (Value, error)
// NewBuiltin returns a new builtin form.
func NewBuiltin(name string, special bool, minArity, maxArity int, f BuiltinFn) *Builtin {
return &Builtin{name, f, minArity, maxArity, special}
}
func (b *Builtin) IsNil() bool { return b == nil }
func (b *Builtin) Equal(other Value) bool {
if b == nil || IsNil(other) {
return b == other
}
if o, ok := other.(*Builtin); ok {
return b.name == o.name
}
return false
}
func (b *Builtin) Print(w io.Writer) error {
_, err := w.Write([]byte{'#'})
if err == nil {
_, err = io.WriteString(w, b.name)
}
return err
}
func (b *Builtin) String() string { return "#" + b.name }
func (b *Builtin) IsSpecial() bool { return b != nil && b.special }
func (b *Builtin) Name() string {
if b == nil {
return ""
}
return b.name
}
func (b *Builtin) Call(env Environment, arg *Pair) (Value, error) {
arity := arg.Length()
if arity < b.minArity {
return nil, fmt.Errorf("not enough arguments (%d) for form %v (%d)", arity, b.name, b.minArity)
} else if b.minArity <= b.maxArity && b.maxArity < arity {
return nil, fmt.Errorf("too many arguments (%d) for form %v (%d)", arity, b.name, b.maxArity)
}
return b.fn(env, arg, arity)
}
func (b *Builtin) GetValue() BuiltinFn {
if b == nil {
return nil
}
return b.fn
}