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