github.com/elves/Elvish@v0.12.0/eval/builtin_special.go (about) 1 package eval 2 3 // Builtin special forms. Special forms behave mostly like ordinary commands - 4 // they are valid commands syntactically, and can take part in pipelines - but 5 // they have special rules for the evaluation of their arguments and can affect 6 // the compilation phase (whereas ordinary commands can only affect the 7 // evaluation phase). 8 // 9 // For instance, the "and" special form evaluates its arguments from left to 10 // right, and stops as soon as one booleanly false value is obtained: the 11 // command "and $false (fail haha)" does not produce an exception. 12 // 13 // As another instance, the "del" special form removes a variable, affecting the 14 // compiler. 15 // 16 // Flow control structures are also implemented as special forms in elvish, with 17 // closures functioning as code blocks. 18 19 import ( 20 "errors" 21 "fmt" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/elves/elvish/eval/vals" 27 "github.com/elves/elvish/eval/vars" 28 "github.com/elves/elvish/parse" 29 ) 30 31 type compileBuiltin func(*compiler, *parse.Form) OpBody 32 33 var ( 34 // ErrRelativeUseNotFromMod is thrown by "use" when relative use is used 35 // not from a module 36 ErrRelativeUseNotFromMod = errors.New("Relative use not from module") 37 // ErrRelativeUseGoesOutsideLib is thrown when a relative use goes out of 38 // the library directory. 39 ErrRelativeUseGoesOutsideLib = errors.New("Module outside library directory") 40 ) 41 42 var builtinSpecials map[string]compileBuiltin 43 44 // IsBuiltinSpecial is the set of all names of builtin special forms. It is 45 // intended for external consumption, e.g. the syntax highlighter. 46 var IsBuiltinSpecial = map[string]bool{} 47 48 func init() { 49 // Needed to avoid initialization loop 50 builtinSpecials = map[string]compileBuiltin{ 51 "del": compileDel, 52 "fn": compileFn, 53 "use": compileUse, 54 "and": compileAnd, 55 "or": compileOr, 56 "if": compileIf, 57 "while": compileWhile, 58 "for": compileFor, 59 "try": compileTry, 60 } 61 for name := range builtinSpecials { 62 IsBuiltinSpecial[name] = true 63 } 64 } 65 66 const delArgMsg = "arguments to del must be variable or variable elements" 67 68 // DelForm = 'del' { VariablePrimary } 69 func compileDel(cp *compiler, fn *parse.Form) OpBody { 70 var ops []Op 71 for _, cn := range fn.Args { 72 cp.compiling(cn) 73 if len(cn.Indexings) != 1 { 74 cp.errorf(delArgMsg) 75 continue 76 } 77 head, indicies := cn.Indexings[0].Head, cn.Indexings[0].Indicies 78 if head.Type != parse.Bareword { 79 if head.Type == parse.Variable { 80 cp.errorf("arguments to del must drop $") 81 } else { 82 cp.errorf(delArgMsg) 83 } 84 continue 85 } 86 87 explode, ns, name := ParseVariableRef(head.Value) 88 if explode { 89 cp.errorf("arguments to del may be have a leading @") 90 continue 91 } 92 var f OpBody 93 if len(indicies) == 0 { 94 switch ns { 95 case "", "local": 96 if !cp.thisScope().has(name) { 97 cp.errorf("no variable $%s in local scope", name) 98 continue 99 } 100 cp.thisScope().del(name) 101 f = delLocalVarOp{name} 102 case "E": 103 f = delEnvVarOp{name} 104 default: 105 cp.errorf("only variables in local: or E: can be deleted") 106 continue 107 } 108 } else { 109 if !cp.registerVariableGet(ns, name) { 110 cp.errorf("no variable $%s", head.Value) 111 continue 112 } 113 f = newDelElementOp(ns, name, head.Begin(), head.End(), cp.arrayOps(indicies)) 114 } 115 ops = append(ops, Op{f, cn.Begin(), cn.End()}) 116 } 117 return seqOp{ops} 118 } 119 120 type delLocalVarOp struct{ name string } 121 122 func (op delLocalVarOp) Invoke(fm *Frame) error { 123 delete(fm.local, op.name) 124 return nil 125 } 126 127 type delEnvVarOp struct{ name string } 128 129 func (op delEnvVarOp) Invoke(*Frame) error { 130 return os.Unsetenv(op.name) 131 } 132 133 func newDelElementOp(ns, name string, begin, headEnd int, indexOps []ValuesOp) OpBody { 134 ends := make([]int, len(indexOps)+1) 135 ends[0] = headEnd 136 for i, op := range indexOps { 137 ends[i+1] = op.End 138 } 139 return &delElemOp{ns, name, indexOps, begin, ends} 140 } 141 142 type delElemOp struct { 143 ns string 144 name string 145 indexOps []ValuesOp 146 begin int 147 ends []int 148 } 149 150 func (op *delElemOp) Invoke(fm *Frame) error { 151 var indicies []interface{} 152 for _, indexOp := range op.indexOps { 153 indexValues, err := indexOp.Exec(fm) 154 if err != nil { 155 return err 156 } 157 if len(indexValues) != 1 { 158 fm.errorpf(indexOp.Begin, indexOp.End, "index must evaluate to a single value in argument to del") 159 } 160 indicies = append(indicies, indexValues[0]) 161 } 162 err := vars.DelElement(fm.ResolveVar(op.ns, op.name), indicies) 163 if err != nil { 164 if level := vars.ElementErrorLevel(err); level >= 0 { 165 fm.errorpf(op.begin, op.ends[level], "%s", err.Error()) 166 } 167 return err 168 } 169 return nil 170 } 171 172 // FnForm = 'fn' StringPrimary LambdaPrimary 173 // 174 // fn f []{foobar} is a shorthand for set '&'f = []{foobar}. 175 func compileFn(cp *compiler, fn *parse.Form) OpBody { 176 args := cp.walkArgs(fn) 177 nameNode := args.next() 178 varName := mustString(cp, nameNode, "must be a literal string") + FnSuffix 179 bodyNode := args.nextMustLambda() 180 args.mustEnd() 181 182 cp.registerVariableSetQname(":" + varName) 183 op := cp.lambda(bodyNode) 184 185 return fnOp{varName, op} 186 } 187 188 type fnOp struct { 189 varName string 190 lambdaOp ValuesOpBody 191 } 192 193 func (op fnOp) Invoke(fm *Frame) error { 194 // Initialize the function variable with the builtin nop function. This step 195 // allows the definition of recursive functions; the actual function will 196 // never be called. 197 fm.local[op.varName] = vars.NewAnyWithInit(NewBuiltinFn("<shouldn't be called>", nop)) 198 values, err := op.lambdaOp.Invoke(fm) 199 if err != nil { 200 return err 201 } 202 closure := values[0].(*Closure) 203 closure.Op = wrapFn(closure.Op) 204 return fm.local[op.varName].Set(closure) 205 } 206 207 func wrapFn(op Op) Op { 208 return Op{fnWrap{op}, op.Begin, op.End} 209 } 210 211 type fnWrap struct{ wrapped Op } 212 213 func (op fnWrap) Invoke(fm *Frame) error { 214 err := fm.Eval(op.wrapped) 215 if err != nil && err.(*Exception).Cause != Return { 216 // rethrow 217 return err 218 } 219 return nil 220 } 221 222 // UseForm = 'use' StringPrimary 223 func compileUse(cp *compiler, fn *parse.Form) OpBody { 224 if len(fn.Args) == 0 { 225 end := fn.Head.End() 226 cp.errorpf(end, end, "lack module name") 227 } else if len(fn.Args) >= 2 { 228 cp.errorpf(fn.Args[1].Begin(), fn.Args[len(fn.Args)-1].End(), "superfluous argument(s)") 229 } 230 231 spec := mustString(cp, fn.Args[0], "should be a literal string") 232 233 // When modspec = "a/b/c:d", modname is c:d, and modpath is a/b/c/d 234 modname := spec[strings.LastIndexByte(spec, '/')+1:] 235 modpath := strings.Replace(spec, ":", "/", -1) 236 cp.thisScope().set(modname + NsSuffix) 237 238 return useOp{modname, modpath} 239 } 240 241 type useOp struct{ modname, modpath string } 242 243 func (op useOp) Invoke(fm *Frame) error { 244 return use(fm, op.modname, op.modpath) 245 } 246 247 func use(fm *Frame, modname, modpath string) error { 248 resolvedPath := "" 249 if strings.HasPrefix(modpath, "./") || strings.HasPrefix(modpath, "../") { 250 if fm.srcMeta.typ != SrcModule { 251 return ErrRelativeUseNotFromMod 252 } 253 // Resolve relative modpath. 254 resolvedPath = filepath.Clean(filepath.Dir(fm.srcMeta.name) + "/" + modpath) 255 } else { 256 resolvedPath = filepath.Clean(modpath) 257 } 258 if strings.HasPrefix(resolvedPath, "../") { 259 return ErrRelativeUseGoesOutsideLib 260 } 261 262 // Put the just loaded module into local scope. 263 ns, err := loadModule(fm, resolvedPath) 264 if err != nil { 265 return err 266 } 267 fm.local.AddNs(modname, ns) 268 return nil 269 } 270 271 func loadModule(fm *Frame, name string) (Ns, error) { 272 if ns, ok := fm.Evaler.modules[name]; ok { 273 // Module already loaded. 274 return ns, nil 275 } 276 277 // Load the source. 278 src, err := getModuleSource(fm.Evaler, name) 279 if err != nil { 280 return nil, err 281 } 282 283 n, err := parse.Parse(name, src.code) 284 if err != nil { 285 return nil, err 286 } 287 288 // Make an empty scope to evaluate the module in. 289 modGlobal := Ns{} 290 291 newFm := &Frame{ 292 fm.Evaler, src, 293 modGlobal, make(Ns), 294 fm.ports, 295 0, len(src.code), fm.addTraceback(), false, 296 } 297 298 op, err := compile(newFm.Builtin.static(), modGlobal.static(), n, src) 299 if err != nil { 300 return nil, err 301 } 302 303 // Load the namespace before executing. This prevent circular "use"es from 304 // resulting in an infinite recursion. 305 fm.Evaler.modules[name] = modGlobal 306 err = newFm.Eval(op) 307 if err != nil { 308 // Unload the namespace. 309 delete(fm.modules, name) 310 return nil, err 311 } 312 return modGlobal, nil 313 } 314 315 func getModuleSource(ev *Evaler, name string) (*Source, error) { 316 // First try loading from file. 317 path := filepath.Join(ev.libDir, name+".elv") 318 if ev.libDir != "" { 319 _, err := os.Stat(path) 320 if err == nil { 321 code, err := readFileUTF8(path) 322 if err != nil { 323 return nil, err 324 } 325 return NewModuleSource(name, path, code), nil 326 } else if !os.IsNotExist(err) { 327 return nil, err 328 } 329 } 330 331 // Try loading bundled module. 332 if code, ok := ev.bundled[name]; ok { 333 return NewModuleSource(name, "", code), nil 334 } 335 336 return nil, fmt.Errorf("cannot load %s: %s does not exist", name, path) 337 } 338 339 // compileAnd compiles the "and" special form. 340 // 341 // The and special form evaluates arguments until a false-ish values is found 342 // and outputs it; the remaining arguments are not evaluated. If there are no 343 // false-ish values, the last value is output. If there are no arguments, it 344 // outputs $true, as if there is a hidden $true before actual arguments. 345 func compileAnd(cp *compiler, fn *parse.Form) OpBody { 346 return &andOrOp{cp.compoundOps(fn.Args), true, false} 347 } 348 349 // compileOr compiles the "or" special form. 350 // 351 // The or special form evaluates arguments until a true-ish values is found and 352 // outputs it; the remaining arguments are not evaluated. If there are no 353 // true-ish values, the last value is output. If there are no arguments, it 354 // outputs $false, as if there is a hidden $false before actual arguments. 355 func compileOr(cp *compiler, fn *parse.Form) OpBody { 356 return &andOrOp{cp.compoundOps(fn.Args), false, true} 357 } 358 359 type andOrOp struct { 360 argOps []ValuesOp 361 init bool 362 stopAt bool 363 } 364 365 func (op *andOrOp) Invoke(fm *Frame) error { 366 var lastValue interface{} = vals.Bool(op.init) 367 for _, argOp := range op.argOps { 368 values, err := argOp.Exec(fm) 369 if err != nil { 370 return err 371 } 372 for _, value := range values { 373 if vals.Bool(value) == op.stopAt { 374 fm.OutputChan() <- value 375 return nil 376 } 377 lastValue = value 378 } 379 } 380 fm.OutputChan() <- lastValue 381 return nil 382 } 383 384 func compileIf(cp *compiler, fn *parse.Form) OpBody { 385 args := cp.walkArgs(fn) 386 var condNodes []*parse.Compound 387 var bodyNodes []*parse.Primary 388 for { 389 condNodes = append(condNodes, args.next()) 390 bodyNodes = append(bodyNodes, args.nextMustLambda()) 391 if !args.nextIs("elif") { 392 break 393 } 394 } 395 elseNode := args.nextMustLambdaIfAfter("else") 396 args.mustEnd() 397 398 condOps := cp.compoundOps(condNodes) 399 bodyOps := cp.primaryOps(bodyNodes) 400 var elseOp ValuesOp 401 if elseNode != nil { 402 elseOp = cp.primaryOp(elseNode) 403 } 404 405 return &ifOp{condOps, bodyOps, elseOp} 406 } 407 408 type ifOp struct { 409 condOps []ValuesOp 410 bodyOps []ValuesOp 411 elseOp ValuesOp 412 } 413 414 func (op *ifOp) Invoke(fm *Frame) error { 415 bodies := make([]Callable, len(op.bodyOps)) 416 for i, bodyOp := range op.bodyOps { 417 bodies[i] = bodyOp.execlambdaOp(fm) 418 } 419 else_ := op.elseOp.execlambdaOp(fm) 420 for i, condOp := range op.condOps { 421 condValues, err := condOp.Exec(fm.fork("if cond")) 422 if err != nil { 423 return err 424 } 425 if allTrue(condValues) { 426 return bodies[i].Call(fm.fork("if body"), NoArgs, NoOpts) 427 } 428 } 429 if op.elseOp.Body != nil { 430 return else_.Call(fm.fork("if else"), NoArgs, NoOpts) 431 } 432 return nil 433 } 434 435 func compileWhile(cp *compiler, fn *parse.Form) OpBody { 436 args := cp.walkArgs(fn) 437 condNode := args.next() 438 bodyNode := args.nextMustLambda() 439 args.mustEnd() 440 441 return &whileOp{cp.compoundOp(condNode), cp.primaryOp(bodyNode)} 442 } 443 444 type whileOp struct { 445 condOp, bodyOp ValuesOp 446 } 447 448 func (op *whileOp) Invoke(fm *Frame) error { 449 body := op.bodyOp.execlambdaOp(fm) 450 451 for { 452 condValues, err := op.condOp.Exec(fm.fork("while cond")) 453 if err != nil { 454 return err 455 } 456 if !allTrue(condValues) { 457 break 458 } 459 err = fm.fork("while").Call(body, NoArgs, NoOpts) 460 if err != nil { 461 exc := err.(*Exception) 462 if exc.Cause == Continue { 463 // do nothing 464 } else if exc.Cause == Break { 465 break 466 } else { 467 return err 468 } 469 } 470 } 471 return nil 472 } 473 474 func compileFor(cp *compiler, fn *parse.Form) OpBody { 475 args := cp.walkArgs(fn) 476 varNode := args.next() 477 iterNode := args.next() 478 bodyNode := args.nextMustLambda() 479 elseNode := args.nextMustLambdaIfAfter("else") 480 args.mustEnd() 481 482 varOp, restOp := cp.lvaluesOp(varNode.Indexings[0]) 483 if restOp.Body != nil { 484 cp.errorpf(restOp.Begin, restOp.End, "rest not allowed") 485 } 486 487 iterOp := cp.compoundOp(iterNode) 488 bodyOp := cp.primaryOp(bodyNode) 489 var elseOp ValuesOp 490 if elseNode != nil { 491 elseOp = cp.primaryOp(elseNode) 492 } 493 494 return &forOp{varOp, iterOp, bodyOp, elseOp} 495 } 496 497 type forOp struct { 498 varOp LValuesOp 499 iterOp ValuesOp 500 bodyOp ValuesOp 501 elseOp ValuesOp 502 } 503 504 func (op *forOp) Invoke(fm *Frame) error { 505 variables, err := op.varOp.Exec(fm) 506 if err != nil { 507 return err 508 } 509 if len(variables) != 1 { 510 fm.errorpf(op.varOp.Begin, op.varOp.End, "only one variable allowed") 511 } 512 variable := variables[0] 513 iterable := fm.ExecAndUnwrap("value being iterated", op.iterOp).One().Any() 514 515 body := op.bodyOp.execlambdaOp(fm) 516 elseBody := op.elseOp.execlambdaOp(fm) 517 518 iterated := false 519 var errElement error 520 errIterate := vals.Iterate(iterable, func(v interface{}) bool { 521 iterated = true 522 err := variable.Set(v) 523 if err != nil { 524 errElement = err 525 return false 526 } 527 err = fm.fork("for").Call(body, NoArgs, NoOpts) 528 if err != nil { 529 exc := err.(*Exception) 530 if exc.Cause == Continue { 531 // do nothing 532 } else if exc.Cause == Break { 533 return false 534 } else { 535 errElement = err 536 return false 537 } 538 } 539 return true 540 }) 541 if errIterate != nil { 542 return errIterate 543 } 544 if errElement != nil { 545 return errElement 546 } 547 548 if !iterated && elseBody != nil { 549 return elseBody.Call(fm.fork("for else"), NoArgs, NoOpts) 550 } 551 return nil 552 } 553 554 func compileTry(cp *compiler, fn *parse.Form) OpBody { 555 logger.Println("compiling try") 556 args := cp.walkArgs(fn) 557 bodyNode := args.nextMustLambda() 558 logger.Printf("body is %q", bodyNode.SourceText()) 559 var exceptVarNode *parse.Indexing 560 var exceptNode *parse.Primary 561 if args.nextIs("except") { 562 logger.Println("except-ing") 563 n := args.peek() 564 // Is this a variable? 565 if len(n.Indexings) == 1 && n.Indexings[0].Head.Type == parse.Bareword { 566 exceptVarNode = n.Indexings[0] 567 args.next() 568 } 569 exceptNode = args.nextMustLambda() 570 } 571 elseNode := args.nextMustLambdaIfAfter("else") 572 finallyNode := args.nextMustLambdaIfAfter("finally") 573 args.mustEnd() 574 575 var exceptVarOp LValuesOp 576 var bodyOp, exceptOp, elseOp, finallyOp ValuesOp 577 bodyOp = cp.primaryOp(bodyNode) 578 if exceptVarNode != nil { 579 var restOp LValuesOp 580 exceptVarOp, restOp = cp.lvaluesOp(exceptVarNode) 581 if restOp.Body != nil { 582 cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in except variable") 583 } 584 } 585 if exceptNode != nil { 586 exceptOp = cp.primaryOp(exceptNode) 587 } 588 if elseNode != nil { 589 elseOp = cp.primaryOp(elseNode) 590 } 591 if finallyNode != nil { 592 finallyOp = cp.primaryOp(finallyNode) 593 } 594 595 return &tryOp{bodyOp, exceptVarOp, exceptOp, elseOp, finallyOp} 596 } 597 598 type tryOp struct { 599 bodyOp ValuesOp 600 exceptVarOp LValuesOp 601 exceptOp ValuesOp 602 elseOp ValuesOp 603 finallyOp ValuesOp 604 } 605 606 func (op *tryOp) Invoke(fm *Frame) error { 607 body := op.bodyOp.execlambdaOp(fm) 608 exceptVar := op.exceptVarOp.execMustOne(fm) 609 except := op.exceptOp.execlambdaOp(fm) 610 else_ := op.elseOp.execlambdaOp(fm) 611 finally := op.finallyOp.execlambdaOp(fm) 612 613 err := fm.fork("try body").Call(body, NoArgs, NoOpts) 614 if err != nil { 615 if except != nil { 616 if exceptVar != nil { 617 err := exceptVar.Set(err.(*Exception)) 618 if err != nil { 619 return err 620 } 621 } 622 err = fm.fork("try except").Call(except, NoArgs, NoOpts) 623 } 624 } else { 625 if else_ != nil { 626 err = fm.fork("try else").Call(else_, NoArgs, NoOpts) 627 } 628 } 629 if finally != nil { 630 errFinally := finally.Call(fm.fork("try finally"), NoArgs, NoOpts) 631 if errFinally != nil { 632 // TODO: If err is not nil, this discards err. Use something similar 633 // to pipeline exception to expose both. 634 return errFinally 635 } 636 } 637 return err 638 } 639 640 // execLambdaOp executes a ValuesOp that is known to yield a lambda and returns 641 // the lambda. If the ValuesOp is empty, it returns a nil. 642 func (op ValuesOp) execlambdaOp(fm *Frame) Callable { 643 if op.Body == nil { 644 return nil 645 } 646 647 values, err := op.Exec(fm) 648 if err != nil { 649 panic("must not be erroneous") 650 } 651 return values[0].(Callable) 652 } 653 654 // execMustOne executes the LValuesOp and raises an exception if it does not 655 // evaluate to exactly one Variable. If the given LValuesOp is empty, it returns 656 // nil. 657 func (op LValuesOp) execMustOne(fm *Frame) vars.Var { 658 if op.Body == nil { 659 return nil 660 } 661 variables, err := op.Exec(fm) 662 maybeThrow(err) 663 if len(variables) != 1 { 664 fm.errorpf(op.Begin, op.End, "should be one variable") 665 } 666 return variables[0] 667 }