123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- package muesli
- import "fmt"
- /* Run time values */
- type Value interface {
- String() string
- Type() TypeValue
- // Convert the value to a different go value which must be passed
- // in as a pointer to which the value must be set,
- // or return an error if the conversion is not possible.
- Convert(to interface{}) error
- }
- type IntValue int64
- type FloatValue float64
- type StringValue string
- type BoolValue bool
- type WordValue string
- type TypeValue string
- type ErrorValue struct {
- error
- }
- type EmptyValue struct {
- }
- type ListValue struct {
- RedispatchCallable
- List []Value
- }
- type MapValue struct {
- Map map[Value]Value
- }
- // Values is simply a shorthand alias for []Value
- type Values = []Value
- const (
- TrueValue = BoolValue(true)
- FalseValue = BoolValue(false)
- IntType = TypeValue("Int")
- FloatType = TypeValue("Float")
- StringType = TypeValue("String")
- BoolType = TypeValue("Bool")
- WordType = TypeValue("Word")
- ErrorType = TypeValue("Error")
- TypeType = TypeValue("Type")
- EmptyType = TypeValue("Empty")
- ListType = TypeValue("List")
- MapType = TypeValue("Map")
- AnyType = TypeValue("Any")
- ZeroType = TypeValue("")
- )
- var NilValue = Value(nil)
- func (val IntValue) String() string {
- return fmt.Sprintf("%d", int64(val))
- }
- func (val FloatValue) String() string {
- return fmt.Sprintf("%f", float64(val))
- }
- func (val BoolValue) String() string {
- if bool(val) {
- return "true"
- } else {
- return "false"
- }
- }
- func (val StringValue) String() string {
- return string(val)
- }
- func (val WordValue) String() string {
- return string(val)
- }
- func (val TypeValue) String() string {
- return string(val)
- }
- func (val ErrorValue) String() string {
- return fmt.Sprintf("%s", val.Error())
- }
- func (val EmptyValue) String() string {
- return "<empty>"
- }
- func (val ListValue) String() string {
- res := "["
- sep := ""
- for _, elt := range val.List {
- if elt == nil {
- res = res + sep + "nil"
- } else {
- res = res + sep + elt.String()
- }
- sep = ", "
- }
- res += "]"
- return res
- }
- func (val MapValue) String() string {
- res := "{"
- sep := ""
- for k, v := range val.Map {
- res = res + sep + k.String() + "=>" + v.String()
- sep = ", "
- }
- res += "}"
- return res
- }
- func (v IntValue) Type() TypeValue { return IntType }
- func (v FloatValue) Type() TypeValue { return FloatType }
- func (v StringValue) Type() TypeValue { return StringType }
- func (v BoolValue) Type() TypeValue { return BoolType }
- func (v WordValue) Type() TypeValue { return WordType }
- func (v TypeValue) Type() TypeValue { return TypeType }
- func (v ErrorValue) Type() TypeValue { return ErrorType }
- func (v EmptyValue) Type() TypeValue { return EmptyType }
- func (v ListValue) Type() TypeValue { return ListType }
- func (v MapValue) Type() TypeValue { return MapType }
- func NewErrorValuef(format string, args ...interface{}) ErrorValue {
- err := fmt.Errorf(format, args...)
- return ErrorValue{err}
- }
- func NewListValue(elements ...Value) * ListValue {
- return &ListValue{ NewRedispatchCallable(), elements}
- }
- func (list *ListValue) Append(elements ...Value) {
- list.List = append(list.List, elements...)
- }
- func (list *ListValue) AppendList(toAppend ListValue) {
- list.List = append(list.List, toAppend.List...)
- }
- func (list ListValue) Length() int {
- return len(list.List)
- }
- func (list *ListValue) Fetch(i int) Value {
- if i >= len(list.List) {
- return NilValue
- }
- return list.List[i]
- }
- func (list *ListValue) Place(i int, v Value) Value {
- if i >= len(list.List) {
- return NilValue
- }
- list.List[i] = v
- return list.List[i]
- }
- func (list *ListValue) First() Value {
- return list.Fetch(0)
- }
- func (list *ListValue) Last() Value {
- return list.Fetch(list.Length()-1)
- }
- func EmptyListValue() ListValue {
- return ListValue{NewRedispatchCallable(), make([]Value, 0)}
- }
- func EmptyValueArray() []Value {
- return make([]Value, 0)
- }
- func NewValueArray(elements ...Value) []Value {
- return elements
- }
- func NewMapValue(elements map[Value]Value) * MapValue {
- return &MapValue{elements}
- }
- func (m *MapValue) Fetch(key Value) Value {
- var res Value
- var ok bool
- if res, ok = m.Map[key] ; !ok {
- return NilValue
- }
- return res
- }
- func (m *MapValue) Place(key Value, value Value) Value {
- m.Map[key] = value
- return m.Map[key]
- }
- func (from IntValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *int8:
- (*toPtr) = int8(from)
- case *int16:
- (*toPtr) = int16(from)
- case *int32:
- (*toPtr) = int32(from)
- case *int64:
- (*toPtr) = int64(from)
- case *int:
- (*toPtr) = int(from)
- case *bool:
- (*toPtr) = (from != 0)
- case *float32:
- (*toPtr) = float32(from)
- case *float64:
- (*toPtr) = float64(from)
- case *IntValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert IntValue value %v to %v", from, to)
- }
- return nil
- }
- func (from FloatValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *int8:
- (*toPtr) = int8(from)
- case *int16:
- (*toPtr) = int16(from)
- case *int32:
- (*toPtr) = int32(from)
- case *int64:
- (*toPtr) = int64(from)
- case *int:
- (*toPtr) = int(from)
- case *bool:
- (*toPtr) = (from != 0)
- case *float32:
- (*toPtr) = float32(from)
- case *float64:
- (*toPtr) = float64(from)
- case *FloatValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert FloatValue value %v to %v", from, to)
- }
- return nil
- }
-
- func (from StringValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *StringValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert StringValue %v to %v", from, to)
- }
- return nil
- }
- func (from WordValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *WordValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert WordValue %v to %v", from, to)
- }
- return nil
- }
- func (from TypeValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *TypeValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert value %v to %v", from, to)
- }
- return nil
- }
- func (from BoolValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *bool:
- (*toPtr) = bool(from)
- case *BoolValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert value %v to %v", from, to)
- }
- return nil
- }
- func (from ErrorValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *string:
- (*toPtr) = from.String()
- case *error:
- (*toPtr) = from.error
- case *ErrorValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert value %v to %v", from, to)
- }
- return nil
- }
- func (from EmptyValue) Convert(to interface{}) error {
- return NewErrorValuef("Cannot convert the empty value %v to %v", from, to)
- }
- func (from * ListValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *[]Value:
- (*toPtr) = from.List
- case **ListValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert value %v to %v", from, to)
- }
- return nil
- }
- func (from * MapValue) Convert(to interface{}) error {
- switch toPtr := to.(type) {
- case *map[Value]Value:
- (*toPtr) = from.Map
- case **MapValue:
- (*toPtr) = from
- case *Value:
- (*toPtr) = from
- default:
- return NewErrorValuef("Cannot convert value %v to %v", from, to)
- }
- return nil
- }
- /* Helpers to easily convert Muesli values to "normal" Go values. */
- func From(from Value, to interface{}) error {
- return from.Convert(to)
- }
- // ParseOptArgs is helper to easily convert Muesli value lists to "normal"
- // Go values. args is the input, required is the amount of required aruments,
- // and to are pointers to where to store the data. The args are converted by
- // calling the Convert() method on them.
- // The returned array contains the remaining unparsed arguments.
- func ParseOptArgs(args []Value, required int, to...interface{}) ([]Value, error) {
- if required > len(args) {
- return nil, NewErrorValuef("Too few arguments, expected %d, got %d", required, len(args))
- }
- stop := len(args)
- if len(to) < stop {
- stop = len(to)
- }
- i:= 0
- for ; i < stop ; i ++ {
- fromElt := args[i]
- toElt := to[i]
- if fromElt == nil {
- return nil, NewErrorValuef("Nil pointer to result %d", i)
- }
- err := fromElt.Convert(toElt)
- if err != nil {
- return nil, err
- }
- }
- rest := args[i:len(args)]
- return rest, nil
- }
- // ParseArgs is helper to easily convert Muesli value lists to "normal"
- // Go values. It is the same as ParseOptArgs(args, len(to), to...)
- func ParseArgs(args []Value, to...interface{}) ([]Value, error) {
- return ParseOptArgs(args, len(to), to...)
- }
- /* Helpers to easily convert Muesli value lists to "normal" Go values in slices. */
- func ParseArgsToIntSlice(args []Value) ([]int, error) {
- res := []int{}
- for _, arg := range args{
- value := int(0)
- err := arg.Convert(&value)
- if err != nil {
- return res, err
- }
- res = append(res, value)
- }
-
- return res, nil
- }
- /* Helpers to easily convert Muesli value lists to "normal" Go values in slices. */
- func ParseArgsToFloat64Slice(args []Value) ([]float64, error) {
- res := []float64{}
- for _, arg := range args{
- value := float64(0.0)
- err := arg.Convert(&value)
- if err != nil {
- return res, err
- }
- res = append(res, value)
- }
-
- return res, nil
- }
- /* Helpers to easily convert Muesli values from "normal" Go values. */
- func To(from interface{}) Value {
- switch val := from.(type) {
- case string:
- return StringValue(val)
- case int8:
- return IntValue(val)
- case int16:
- return IntValue(val)
- case int32:
- return IntValue(val)
- case int64:
- return IntValue(val)
- case int:
- return IntValue(val)
- case bool:
- return BoolValue(val)
- case float32:
- return FloatValue(val)
- case float64:
- return FloatValue(val)
- case error:
- return ErrorValue{val}
- case Value:
- return val
- default:
- return NewErrorValuef("Cannot convert value %v", from)
- }
- }
- func ListTo(froms ...interface{}) []Value {
- list := make([]Value, 0)
- for _, from := range froms {
- val := To(from)
- list = append(list, val)
- }
- return list
- }
- func ListFrom(froms []Value, tos ...interface{}) error {
- for i, from := range froms {
- if i >= len(tos) {
- break
- }
- err := From(from, tos[i])
- if err != nil {
- return err
- }
- }
- return nil
- }
- func ListFromList(froms []Value) []interface{} {
- res := make([]interface{}, len(froms))
- for i, from := range froms {
- res[i] = from
- }
- return res
- }
- func Return(args ... Value) []Value {
- return args
- }
- func ReturnEmpty() []Value {
- return []Value{EmptyValue{}}
- }
- func ReturnError(err error) []Value {
- return []Value{ErrorValue{err}}
- }
- func Ok(args ... Value) []Value {
- return args
- }
- func Fail(err error) []Value {
- return []Value{ErrorValue{err}}
- }
- func None() []Value {
- return []Value{EmptyValue{}}
- }
- func BoolOk(b bool) []Value{
- return []Value{BoolValue(b)}
- }
- func IntOk(i int) []Value{
- return []Value{IntValue(i)}
- }
- func FloatOk(f float64) []Value{
- return []Value{FloatValue(f)}
- }
- // CallableValue is is both a Value and a Callable.
- type CallableValue interface {
- Callable
- Value
- }
- // Redispath takes the first argument i args, and if that is a word,
- // calls the command named by that word, replacing the from CalableValue
- // as the first argument. This allows some OOP style trickery where
- // custom_value foo gets called as foo custom_value where custom_value is
- // of CustomType.
- // In this case foo should the be an overloaded command that takes CustomType.
- func Redispatch(from CallableValue, vm *VM, args...Value) []Value {
- if len(args) < 1 {
- return EmptyValueArray()
- }
- var word WordValue
- _, err := ParseOptArgs(args, 1, &word)
- if err != nil {
- return Fail(err)
- }
- args[0] = from
- return vm.CallNamed(string(word), args...)
- }
- // RedispatchCallable can be embedded into a type to allow it to
- // become redispatchable, that is, it can support OOP style
- // calling of pseudo methods by rearranging the command.
- type RedispatchCallable struct {
- BasicCallable
- }
- func (rc * RedispatchCallable) Call(vm *VM, args...Value) []Value {
- return Redispatch(rc, vm, args...)
- }
- var _ Callable = &RedispatchCallable{}
- func NewRedispatchCallable() RedispatchCallable {
- return RedispatchCallable{}
- }
- // Implement callable ...
- /*
- func (list * ListValue) Position() *Position {
- return &Position{"value.go", 572, 8}
- }
- func (list * ListValue) Call(vm *VM, args...Value) []Value {
- return Redispatch(list, vm, args...)
- }
- var listSignature = NewSignature(WordType, IntType)
- func (list * ListValue) Signature() Signature {
- return listSignature
- }
- */
- var _ Callable = &ListValue{}
|