// SourceText evaluates a chunk of elvish source. func (ev *Evaler) SourceText(name, src, dir string) ([]Value, error) { n, err := parse.Parse(name, src) if err != nil { return nil, err } return ev.Eval(name, src, dir, n) }
func mustParse(name, text string) *parse.Chunk { n, e := parse.Parse(name, text) if e != nil { panic("parser error") } return n }
// UseForm = 'use' StringPrimary.modname Primary.fname // = 'use' StringPrimary.fname func compileUse(cc *compileCtx, fn *parse.Form) exitusOp { var fnameNode *parse.Compound var fname, modname string switch len(fn.Args.Nodes) { case 0: cc.errorf(fn.Args.Pos, "expect module name or file name") case 1, 2: fnameNode = fn.Args.Nodes[0] _, fname = ensureStringPrimary(cc, fnameNode, "expect string literal") if len(fn.Args.Nodes) == 2 { modnameNode := fn.Args.Nodes[1] _, modname = ensureStringPrimary( cc, modnameNode, "expect string literal") if modname == "" { cc.errorf(modnameNode.Pos, "module name is empty") } } else { modname = stem(fname) if modname == "" { cc.errorf(fnameNode.Pos, "stem of file name is empty") } } default: cc.errorf(fn.Args.Nodes[2].Pos, "superfluous argument") } switch { case strings.HasPrefix(fname, "/"): // Absolute file name, do nothing case strings.HasPrefix(fname, "./") || strings.HasPrefix(fname, "../"): // File name relative to current source fname = path.Clean(path.Join(cc.dir, fname)) default: // File name relative to data dir fname = path.Clean(path.Join(cc.dataDir, fname)) } src, err := readFileUTF8(fname) if err != nil { cc.errorf(fnameNode.Pos, "cannot read module: %s", err.Error()) } cn, err := parse.Parse(fname, src) if err != nil { // TODO(xiaq): Pretty print cc.errorf(fnameNode.Pos, "cannot parse module: %s", err.Error()) } newCc := &compileCtx{ cc.Compiler, fname, src, path.Dir(fname), []staticNS{staticNS{}}, staticNS{}, } op, err := newCc.compile(cn) if err != nil { // TODO(xiaq): Pretty print cc.errorf(fnameNode.Pos, "cannot compile module: %s", err.Error()) } cc.mod[modname] = newCc.scopes[0] return func(ec *evalCtx) exitus { // TODO(xiaq): Should handle failures when evaluting the module newEc := &evalCtx{ ec.Evaler, fname, src, "module " + modname, ns{}, ns{}, ec.ports, } op.f(newEc) ec.mod[modname] = newEc.local return ok } }
// TODO(xiaq): Currently only the editor deals with signals. func interact() { ev, st := newEvalerAndStore() datadir, err := store.EnsureDataDir() printError(err) if err == nil { // XXX vs, err := ev.Source(datadir + "/rc.elv") if err != nil && !os.IsNotExist(err) { printError(err) } eval.PrintExituses(vs) } cmdNum := 0 username := "******" user, err := user.Current() if err == nil { username = user.Username } hostname, err := os.Hostname() if err != nil { hostname = "???" } rpromptStr := username + "@" + hostname sigch := make(chan os.Signal, sigchSize) signal.Notify(sigch) defer signal.Stop(sigch) ed := edit.NewEditor(os.Stdin, sigch, st) for { cmdNum++ name := fmt.Sprintf("<tty %d>", cmdNum) prompt := func() string { return sysutil.Getwd() + "> " } rprompt := func() string { return rpromptStr } lr := ed.ReadLine(prompt, rprompt) if lr.EOF { break } else if lr.Err != nil { fmt.Println("Editor error:", lr.Err) fmt.Println("My pid is", os.Getpid()) } n, err := parse.Parse(name, lr.Line) printError(err) if err == nil { vs, err := ev.Eval(name, lr.Line, ".", n) printError(err) eval.PrintExituses(vs) } } }