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 }