github.com/masahide/goansible@v0.0.0-20160116054156-01eac649e9f2/lisp/cons.go (about)

     1  package lisp
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  )
     8  
     9  type Cons struct {
    10  	car *Value
    11  	cdr *Value
    12  }
    13  
    14  func (c Cons) Eval(scope ScopedVars) (val Value, err error) {
    15  	if c.List() {
    16  		if v, err := c.car.Eval(scope); err != nil {
    17  			return Nil, err
    18  		} else if *c.cdr == Nil {
    19  			return v, nil
    20  		} else {
    21  			return c.cdr.Cons().Eval(scope)
    22  		}
    23  	} else {
    24  		return Value{consValue, c}, nil
    25  	}
    26  }
    27  
    28  func (cons Cons) Execute(scope ScopedVars) (Value, error) {
    29  	if !cons.List() {
    30  		return Nil, fmt.Errorf("Combination must be a proper list: %v", cons)
    31  	}
    32  	switch cons.car.String() {
    33  	case "quote":
    34  		return cons.quoteForm(scope)
    35  	case "read":
    36  		return cons.readForm(scope)
    37  	case "if":
    38  		return cons.ifForm(scope)
    39  	case "or":
    40  		return cons.orForm(scope)
    41  	case "set!":
    42  		return cons.setForm(scope)
    43  	case "define":
    44  		return cons.defineForm(scope)
    45  	case "lambda":
    46  		return cons.lambdaForm(scope)
    47  	case "begin":
    48  		return cons.beginForm(scope)
    49  	default:
    50  		if cons.isBuiltin() {
    51  			return cons.runBuiltin(scope)
    52  		} else {
    53  			return cons.procForm(scope)
    54  		}
    55  	}
    56  }
    57  
    58  func (c Cons) List() bool {
    59  	return c.cdr.typ == consValue || c.cdr.typ == nilValue
    60  }
    61  
    62  func (c Cons) Map(f func(v Value) (Value, error)) ([]Value, error) {
    63  	result := make([]Value, 0)
    64  	if value, err := f(*c.car); err != nil {
    65  		return nil, err
    66  	} else {
    67  		result = append(result, value)
    68  	}
    69  	if *c.cdr != Nil {
    70  		if values, err := c.cdr.Cons().Map(f); err != nil {
    71  			return nil, err
    72  		} else {
    73  			result = append(result, values...)
    74  		}
    75  	}
    76  	return result, nil
    77  }
    78  
    79  func (c Cons) Len() int {
    80  	l := 0
    81  	if *c.car != Nil {
    82  		l++
    83  		if *c.cdr != Nil {
    84  			l += c.cdr.Cons().Len()
    85  		}
    86  	}
    87  	return l
    88  }
    89  
    90  func (c Cons) Vector() Vector {
    91  	v, _ := c.Map(func(v Value) (Value, error) {
    92  		return v, nil
    93  	})
    94  	return v
    95  }
    96  
    97  func (c Cons) String() string {
    98  	s := strings.Join(c.Stringify(), " ")
    99  	return fmt.Sprintf(`(%v)`, s)
   100  }
   101  
   102  func (c Cons) Stringify() []string {
   103  	result := make([]string, 0)
   104  	result = append(result, c.car.String())
   105  	switch c.cdr.typ {
   106  	case nilValue:
   107  	case consValue:
   108  		result = append(result, c.cdr.Cons().Stringify()...)
   109  	default:
   110  		result = append(result, ".", c.cdr.String())
   111  	}
   112  	return result
   113  }
   114  
   115  func (cons Cons) procForm(scope ScopedVars) (val Value, err error) {
   116  	if val, err = cons.car.Eval(scope); err == nil {
   117  		if val.typ == procValue {
   118  			var args Vector
   119  			if args, err = cons.cdr.Cons().Map(func(v Value) (Value, error) {
   120  				return v.Eval(scope)
   121  			}); err != nil {
   122  				return
   123  			} else {
   124  				val, err = val.val.(Proc).Call(scope, args)
   125  			}
   126  		} else {
   127  			err = fmt.Errorf("The object %v is not applicable", val)
   128  		}
   129  	}
   130  	return
   131  }
   132  
   133  func (cons Cons) beginForm(scope ScopedVars) (val Value, err error) {
   134  	return cons.cdr.Cons().Eval(scope)
   135  }
   136  
   137  func (cons Cons) setForm(scope ScopedVars) (val Value, err error) {
   138  	expr := cons.Vector()
   139  	if len(expr) == 3 {
   140  		key := expr[1].String()
   141  		if _, ok := scope.Get(key); ok {
   142  			val, err = expr[2].Eval(scope)
   143  			if err == nil {
   144  				scope.Set(key, val)
   145  			}
   146  		} else {
   147  			err = fmt.Errorf("Unbound variable: %v", key)
   148  		}
   149  	} else {
   150  		err = fmt.Errorf("Ill-formed special form: %v", cons)
   151  	}
   152  	return
   153  }
   154  
   155  func (cons Cons) ifForm(scope ScopedVars) (val Value, err error) {
   156  	expr := cons.Vector()
   157  	val = Nil
   158  	if len(expr) < 3 || len(expr) > 4 {
   159  		err = fmt.Errorf("Ill-formed special form: %v", expr)
   160  	} else {
   161  		r, err := expr[1].Eval(scope)
   162  		if err == nil {
   163  			if !(r.typ == symbolValue && r.String() == "false") && r != Nil && len(expr) > 2 {
   164  				val, err = expr[2].Eval(scope)
   165  			} else if len(expr) == 4 {
   166  				val, err = expr[3].Eval(scope)
   167  			}
   168  		}
   169  	}
   170  	return
   171  }
   172  
   173  func (cons Cons) orForm(scope ScopedVars) (val Value, err error) {
   174  	expr := cons.Vector()
   175  	val = Nil
   176  	if len(expr) < 1 {
   177  		err = fmt.Errorf("Ill-formed special form: %v", expr)
   178  	} else {
   179  		var r Value
   180  
   181  		for i := 1; i < len(expr); i++ {
   182  			r, err = expr[i].Eval(scope)
   183  			if err != nil {
   184  				return
   185  			}
   186  
   187  			if r.typ == symbolValue {
   188  				var ok bool
   189  
   190  				val, ok = scope.Get(r.String())
   191  
   192  				if ok {
   193  					return
   194  				}
   195  			} else {
   196  				val = r
   197  				return
   198  			}
   199  		}
   200  	}
   201  
   202  	return
   203  }
   204  
   205  func (cons Cons) lambdaForm(scope ScopedVars) (val Value, err error) {
   206  	if cons.cdr.typ == consValue {
   207  		lambda := cons.cdr.Cons()
   208  		if (lambda.car.typ == consValue || lambda.car.typ == nilValue) && lambda.cdr.typ == consValue {
   209  			params := lambda.car.Cons().Vector()
   210  			val = Value{procValue, Proc{params, lambda.cdr.Cons(), scope}}
   211  		} else {
   212  			err = fmt.Errorf("Ill-formed special form: %v", cons)
   213  		}
   214  	} else {
   215  		err = fmt.Errorf("Ill-formed special form: %v", cons)
   216  	}
   217  	return
   218  }
   219  
   220  func (cons Cons) quoteForm(scope ScopedVars) (val Value, err error) {
   221  	if cons.cdr != nil {
   222  		if *cons.cdr.Cons().cdr == Nil {
   223  			val = *cons.cdr.Cons().car
   224  		} else {
   225  			val = Value{consValue, cons}
   226  		}
   227  	} else {
   228  		err = fmt.Errorf("Ill-formed special form: %v", cons)
   229  	}
   230  	return
   231  }
   232  
   233  func (cons Cons) readForm(scope ScopedVars) (val Value, err error) {
   234  	val, err = cons.cdr.Cons().car.Eval(scope)
   235  	return val, err
   236  }
   237  
   238  func (cons Cons) defineForm(scope ScopedVars) (val Value, err error) {
   239  	expr := cons.Vector()
   240  	if len(expr) >= 2 && len(expr) <= 3 {
   241  		if expr[1].typ == symbolValue {
   242  			key := expr[1].String()
   243  			if len(expr) == 3 {
   244  				var i Value
   245  				if i, err = expr[2].Eval(scope); err == nil {
   246  					scope.Create(key, i)
   247  				}
   248  			} else {
   249  				scope.Create(key, Nil)
   250  			}
   251  			return expr[1], err
   252  		}
   253  	}
   254  	return Nil, fmt.Errorf("Ill-formed special form: %v", expr)
   255  }
   256  
   257  func (cons Cons) isBuiltin() bool {
   258  	s := cons.car.String()
   259  	if _, ok := builtin_commands[s]; ok {
   260  		return true
   261  	}
   262  	return false
   263  }
   264  
   265  func (cons Cons) runBuiltin(scope ScopedVars) (val Value, err error) {
   266  	cmd := builtin_commands[cons.car.String()]
   267  	vars, err := cons.cdr.Cons().Map(func(v Value) (Value, error) {
   268  		return v.Eval(scope)
   269  	})
   270  
   271  	if err != nil {
   272  		return Nil, err
   273  	}
   274  
   275  	values := []reflect.Value{}
   276  	for _, v := range vars {
   277  		values = append(values, reflect.ValueOf(v))
   278  	}
   279  	result := reflect.ValueOf(&builtin).MethodByName(cmd).Call(values)
   280  	val = result[0].Interface().(Value)
   281  	err, _ = result[1].Interface().(error)
   282  	return
   283  }