Beispiel #1
0
func mustParse(t *testing.T, name, text string) *parse.Chunk {
	n, err := parse.Parse(text)
	if err != nil {
		t.Fatalf("Parser(%q) error: %s", text, err)
	}
	return n
}
Beispiel #2
0
// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(src string) error {
	n, err := parse.Parse(src)
	if err != nil {
		return err
	}
	return ev.EvalInteractive(src, n)
}
Beispiel #3
0
// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(name, src, dir string) error {
	n, err := parse.Parse(name, src)
	if err != nil {
		return err
	}
	return ev.Eval(name, src, dir, n)
}
Beispiel #4
0
func mustParse(name, text string) *parse.Chunk {
	n, e := parse.Parse(name, text)
	if e != nil {
		panic("parser error")
	}
	return n
}
Beispiel #5
0
// TODO(xiaq): Currently only the editor deals with signals.
func interact() {
	ev, st := newEvalerAndStore()
	datadir, err := store.EnsureDataDir()
	printError(err)
	if err == nil {
		// XXX
		err := ev.Source(datadir + "/rc.elv")
		if err != nil && !os.IsNotExist(err) {
			printError(err)
		}
	}

	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)

	ed := edit.NewEditor(os.Stdin, sigch, ev, st)

	for {
		cmdNum++
		name := fmt.Sprintf("<tty %d>", cmdNum)

		prompt := func() string {
			return osutil.Getwd() + "> "
		}
		rprompt := func() string {
			return rpromptStr
		}

		lr := ed.ReadLine(prompt, rprompt)
		// signal.Stop(sigch)

		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 {
			err := ev.Eval(name, lr.Line, n)
			printError(err)
		}
	}
}
Beispiel #6
0
func tokenize(src string) ([]Token, error) {
	lastEnd := 0
	n, err := parse.Parse("[interactive code]", src)
	if n == nil {
		return []Token{{ParserError, src, nil, ""}}, err
	}

	tokenCh := make(chan Token, tokensBufferSize)
	tokens := []Token{}
	tokensDone := make(chan bool)

	go func() {
		for token := range tokenCh {
			begin := token.Node.Begin()
			if begin > lastEnd {
				tokens = append(tokens, parserError(src[lastEnd:begin]))
			}
			tokens = append(tokens, token)
			lastEnd = token.Node.End()
		}
		tokensDone <- true
	}()
	produceTokens(n, tokenCh)
	close(tokenCh)

	<-tokensDone
	if lastEnd != len(src) {
		tokens = append(tokens, parserError(src[lastEnd:]))
	}
	return tokens, err
}
Beispiel #7
0
func interact(ev *eval.Evaler, st *store.Store) {
	// Build Editor.
	sigch := make(chan os.Signal)
	signal.Notify(sigch)
	ed := edit.NewEditor(os.Stdin, sigch, ev, st)

	// Source rc.elv.
	datadir, err := store.EnsureDataDir()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	} else {
		source(ev, datadir+"/rc.elv", true)
	}

	// Build readLine function.
	readLine := func() (string, error) {
		return ed.ReadLine()
	}

	cooldown := time.Second
	usingBasic := false
	cmdNum := 0

	for {
		cmdNum++
		// name := fmt.Sprintf("<tty %d>", cmdNum)

		line, err := readLine()

		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println("Editor error:", err)
			if !usingBasic {
				fmt.Println("Falling back to basic line editor")
				readLine = basicReadLine
				usingBasic = true
			} else {
				fmt.Println("Don't know what to do, pid is", os.Getpid())
				fmt.Println("Restarting editor in", cooldown)
				time.Sleep(cooldown)
				if cooldown < time.Minute {
					cooldown *= 2
				}
			}
			continue
		}

		// No error; reset cooldown.
		cooldown = time.Second

		n, err := parse.Parse(line)
		printError(err, "<interact>", "parse error", line)

		if err == nil {
			err := ev.EvalInteractive(line, n)
			printError(err, "<interact>", "eval error", line)
		}
	}
}
Beispiel #8
0
func (ed *Editor) refresh(fullRefresh bool) error {
	// Re-lex the line, unless we are in modeCompletion
	name := "[interacitve]"
	src := ed.line
	if ed.mode != modeCompletion {
		n, _ /*err*/ := parse.Parse(src)
		if n == nil {
			ed.tokens = []Token{{ParserError, src, nil, ""}}
		} else {
			ed.tokens = tokenize(src, n)
			_, err := ed.evaler.Compile(name, src, n)
			if err != nil {
				if err, ok := err.(*errutil.ContextualError); ok {
					ed.addTip("compiler error highlighted")
					p := err.Pos()
					for i, token := range ed.tokens {
						if token.Node.Begin() <= p && p < token.Node.End() {
							ed.tokens[i].MoreStyle += styleForCompilerError
							break
						}
					}
				}
			}
		}
		for i, t := range ed.tokens {
			for _, stylist := range stylists {
				ed.tokens[i].MoreStyle += stylist(t.Node, ed)
			}
		}
	}
	return ed.writer.refresh(&ed.editorState, fullRefresh)
}
Beispiel #9
0
func use(ec *EvalCtx, modname string, pfilename *string) {
	if _, ok := ec.Evaler.Modules[modname]; ok {
		// Module already loaded.
		return
	}

	// Load the source.
	var filename, source string

	if pfilename != nil {
		filename = *pfilename
		var err error
		source, err = readFileUTF8(filename)
		maybeThrow(err)
	} else {
		// No filename; defaulting to $datadir/$modname.elv.
		dataDir, err := store.DataDir()
		maybeThrow(err)
		filename = dataDir + "/" + modname + ".elv"
		if _, err := os.Stat(filename); os.IsNotExist(err) {
			// File does not exist. Try loading from the table of builtin
			// modules.
			var ok bool
			if source, ok = builtinModules[modname]; ok {
				// Source is loaded. Do nothing more.
				filename = "<builtin module>"
			} else {
				throw(fmt.Errorf("cannot load %s: %s does not exist", modname, filename))
			}
		} else {
			// File exists. Load it.
			source, err = readFileUTF8(filename)
			maybeThrow(err)
		}
	}

	// TODO(xiaq): Should handle failures when evaluting the module
	newEc := &EvalCtx{
		ec.Evaler,
		filename, source, "module " + modname,
		Namespace{}, Namespace{},
		ec.ports, nil,
		0, len(source),
	}

	n, err := parse.Parse(source)
	maybeThrow(err)

	op, err := newEc.Compile(n)
	// TODO the err originates in another source, should add appropriate information.
	maybeThrow(err)

	op.Exec(newEc)

	ec.Evaler.Modules[modname] = newEc.local
}
Beispiel #10
0
// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(name, src string) error {
	n, err := parse.Parse(name, src)
	if err != nil {
		return err
	}
	op, err := ev.Compile(n, name, src)
	if err != nil {
		return err
	}
	return ev.Eval(op, name, src)
}
Beispiel #11
0
func mustParseAndCompile(t *testing.T, ev *Evaler, name, text string) Op {
	n, err := parse.Parse(name, text)
	if err != nil {
		t.Fatalf("Parse(%q) error: %s", text, err)
	}
	op, err := ev.Compile(n, name, text)
	if err != nil {
		t.Fatalf("Compile(Parse(%q)) error: %s", text, err)
	}
	return op
}
Beispiel #12
0
// evalText is like eval.Evaler.SourceText except that it reports errors.
func evalText(ev *eval.Evaler, name, src string) bool {
	n, err := parse.Parse(name, src)
	if err != nil {
		printError(err, "Parse error")
		return false
	}

	op, err := ev.Compile(n, name, src)
	if err != nil {
		printError(err, "Compile error")
		return false
	}
	err = ev.Eval(op, name, src)
	if err != nil {
		printError(err, "Exception")
		return false
	}
	return true
}
Beispiel #13
0
func (ed *Editor) refresh(fullRefresh bool, tips bool) error {
	// Re-lex the line, unless we are in modeCompletion
	src := ed.line
	if ed.mode.Mode() != modeCompletion {
		n, err := parse.Parse("[interactive]", src)
		ed.parseErrorAtEnd = err != nil && atEnd(err, len(src))
		if err != nil {
			// If all the errors happen at the end, it is liekly complaining
			// about missing texts that will eventually be inserted. Don't show
			// such errors.
			// XXX We may need a more reliable criteria.
			if tips && !ed.parseErrorAtEnd {
				ed.addTip("parser error: %s", err)
			}
		}
		if n == nil {
			ed.tokens = []Token{parserError(src, 0, len(src))}
		} else {
			ed.tokens = tokenize(src, n)
			_, err := ed.evaler.Compile(n, "[interactive]", src)
			if err != nil {
				if tips && !atEnd(err, len(src)) {
					ed.addTip("compiler error: %s", err)
				}
				if err, ok := err.(*util.PosError); ok {
					p := err.Begin
					for i, token := range ed.tokens {
						if token.Node.Begin() <= p && p < token.Node.End() {
							ed.tokens[i].MoreStyle = joinStyles(ed.tokens[i].MoreStyle, styleForCompilerError)
							break
						}
					}
				}
			}
		}
		stylist := &Stylist{ed.tokens, ed, nil}
		stylist.do(n)
	}
	return ed.writer.refresh(&ed.editorState, fullRefresh)
}
Beispiel #14
0
// 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 install a failHandler that fails the use call
		newEc := &evalCtx{
			ec.Evaler,
			fname, src, "module " + modname,
			ns{}, ns{},
			ec.ports, nil,
		}
		op(newEc)
		ec.mod[modname] = newEc.local
		return success
	}
}
Beispiel #15
0
// TODO(xiaq): Currently only the editor deals with signals.
func interact() {
	ev, st := newEvalerAndStore()

	sigch := make(chan os.Signal, sigchSize)
	signal.Notify(sigch)

	ed := edit.NewEditor(os.Stdin, sigch, ev, st)

	datadir, err := store.EnsureDataDir()
	printError(err)
	if err == nil {
		// XXX
		err := ev.Source(datadir + "/rc.elv")
		if err != nil && !os.IsNotExist(err) {
			printError(err)
		}
	}

	cmdNum := 0

	username := "******"
	user, err := user.Current()
	if err == nil {
		username = user.Username
	}
	hostname, err := os.Hostname()
	if err != nil {
		hostname = "???"
	}
	rpromptStr := username + "@" + hostname
	prompt := func() string {
		return osutil.Getwd() + "> "
	}
	rprompt := func() string {
		return rpromptStr
	}

	readLine := func() edit.LineRead {
		return ed.ReadLine(prompt, rprompt)
	}

	usingBasic := false

	if !sys.IsATTY(0) {
		readLine = basicReadLine
		usingBasic = true
	}

	for {
		cmdNum++
		// name := fmt.Sprintf("<tty %d>", cmdNum)

		lr := readLine()
		// signal.Stop(sigch)

		if lr.EOF {
			break
		} else if lr.Err != nil {
			fmt.Println("Editor error:", lr.Err)
			if !usingBasic {
				fmt.Println("Falling back to basic line editor")
				readLine = basicReadLine
				usingBasic = true
			}
			continue
		}

		n, err := parse.Parse(lr.Line)
		printError(err)

		if err == nil {
			err := ev.EvalInteractive(lr.Line, n)
			printError(err)
		}
	}
}
Beispiel #16
0
func use(ec *EvalCtx, modname string, pfilename *string) {
	if _, ok := ec.Evaler.Modules[modname]; ok {
		// Module already loaded.
		return
	}

	// Load the source.
	var filename, source string

	if pfilename != nil {
		filename = *pfilename
		var err error
		source, err = readFileUTF8(filename)
		maybeThrow(err)
	} else {
		// No filename; defaulting to $datadir/$modname.elv.
		dataDir, err := store.DataDir()
		maybeThrow(err)
		filename = dataDir + "/" + strings.Replace(modname, ":", "/", -1) + ".elv"
		if _, err := os.Stat(filename); os.IsNotExist(err) {
			// File does not exist. Try loading from the table of builtin
			// modules.
			var ok bool
			if source, ok = builtinModules[modname]; ok {
				// Source is loaded. Do nothing more.
				filename = "<builtin module>"
			} else {
				throw(fmt.Errorf("cannot load %s: %s does not exist", modname, filename))
			}
		} else {
			// File exists. Load it.
			source, err = readFileUTF8(filename)
			maybeThrow(err)
		}
	}

	n, err := parse.Parse(filename, source)
	maybeThrow(err)

	// Make an empty namespace.
	local := Namespace{}

	// TODO(xiaq): Should handle failures when evaluting the module
	newEc := &EvalCtx{
		ec.Evaler, "module " + modname,
		filename, source,
		local, Namespace{},
		ec.ports, nil, true,
		0, len(source), ec.addTraceback(), false,
	}

	op, err := newEc.Compile(n, filename, source)
	// TODO the err originates in another source, should add appropriate information.
	maybeThrow(err)

	// Load the namespace before executing. This avoids mutual and self use's to
	// result in an infinite recursion.
	ec.Evaler.Modules[modname] = local
	err = newEc.PEval(op)
	if err != nil {
		// Unload the namespace.
		delete(ec.Modules, modname)
		throw(err)
	}
}