func main() { flag.Usage = usage flag.Parse() if *origin != 0 && *origin != 1 { fmt.Fprintf(os.Stderr, "ivy: illegal origin value %d\n", *origin) os.Exit(2) } if *gformat { *format = "%g" } conf.SetFormat(*format) conf.SetOrigin(*origin) conf.SetPrompt(*prompt) value.SetConfig(&conf) context := parse.NewContext() if *execute { runArgs(context) return } if flag.NArg() > 0 { for i := 0; i < flag.NArg(); i++ { name := flag.Arg(i) var fd io.Reader var err error interactive := false if name == "-" { interactive = true fd = os.Stdin } else { interactive = false fd, err = os.Open(name) } if err != nil { fmt.Fprintf(os.Stderr, "ivy: %s\n", err) os.Exit(1) } scanner := scan.New(&conf, name, bufio.NewReader(fd)) parser := parse.NewParser(&conf, name, scanner, context) if !run(parser, os.Stdout, context, interactive) { break } } return } scanner := scan.New(&conf, "<stdin>", bufio.NewReader(os.Stdin)) parser := parse.NewParser(&conf, "<stdin>", scanner, context) for !run(parser, os.Stdout, context, true) { } }
// runFromFile executes the contents of the named file. func (p *Parser) runFromFile(name string) { runDepth++ if runDepth > 10 { p.errorf("get %q nested too deep", name) } defer func() { runDepth-- err := recover() if err == nil { return } if err, ok := err.(value.Error); ok { fmt.Fprintf(os.Stderr, "%s: %s\n", p.Loc(), err) return } panic(err) }() fd, err := os.Open(name) if err != nil { p.errorf("%s", err) } scanner := scan.New(p.config, name, bufio.NewReader(fd)) parser := NewParser(p.config, name, scanner, p.context) for { value, ok := parser.Line() if value != nil { fmt.Fprintln(os.Stdout, value) } if !ok { return } } }
func runTest(t *testing.T, name string, lineNum int, input, output []string) bool { shouldFail := strings.HasSuffix(name, "_fail.ivy") initConf() scanner := scan.New(&conf, "", strings.NewReader(strings.Join(input, "\n")+"\n")) context := parse.NewContext() value.SetContext(context) parser := parse.NewParser(&conf, name, scanner, context) testBuf.Reset() if !run(parser, context, false) != shouldFail { if shouldFail { t.Fatalf("\nexpected execution failure at %s:%d:\n%s", name, lineNum, strings.Join(input, "\n")) } else { t.Fatalf("\nexecution failure at %s:%d:\n%s", name, lineNum, strings.Join(input, "\n")) } return false } if shouldFail { return true } result := testBuf.String() if !equal(strings.Split(result, "\n"), output) { t.Errorf("\n%s:%d:\n%s\ngot:\n%swant:\n%s", name, lineNum, strings.Join(input, "\n"), result, strings.Join(output, "\n")) return false } return true }
// runFromFile executes the contents of the named file. func (p *Parser) runFromFile(context value.Context, name string) { runDepth++ if runDepth > 10 { p.errorf("get %q nested too deep", name) } defer func() { runDepth-- err := recover() if err == nil { return } if err, ok := err.(value.Error); ok { fmt.Fprintf(p.context.Config().ErrOutput(), "%s%s\n", p.Loc(), err) return } panic(err) }() fd, err := os.Open(name) if err != nil { p.errorf("%s", err) } scanner := scan.New(context, name, bufio.NewReader(fd)) parser := NewParser(name, scanner, p.context) out := p.context.Config().Output() for { exprs, ok := parser.Line() for _, expr := range exprs { val := expr.Eval(p.context) if val == nil { continue } if _, ok := val.(Assignment); ok { continue } fmt.Fprintf(out, "%v\n", val.Sprint(context.Config())) } if !ok { return } } }
// Eval evaluates the input string and returns its output. // If execution caused errors, they will be returned concatenated // together in the error value returned. // TODO: Should it stop at first error? func Eval(expr string) (result string, errors error) { if !strings.HasSuffix(expr, "\n") { expr += "\n" } reader := strings.NewReader(expr) stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) conf.SetOutput(stdout) conf.SetErrOutput(stderr) scanner := scan.New(&conf, context, " ", reader) parser := parse.NewParser(&conf, " ", scanner, context) for !run.Run(parser, context, false) { } var err error if stderr.Len() > 0 { err = fmt.Errorf("%s", stderr) } return stdout.String(), err }
// IvyEval is the function called by value/unaryIvy to implement the ivy (eval) operation. // It is exported but is not intended to be used outside of ivy. func IvyEval(context value.Context, str string) value.Value { scanner := scan.New(context, "<ivy>", strings.NewReader(str)) parser := parse.NewParser("<ivy>", scanner, context) return eval(parser, context) }
func runArgs(context value.Context) { scanner := scan.New(&conf, "<args>", strings.NewReader(strings.Join(flag.Args(), " "))) parser := parse.NewParser(&conf, "<args>", scanner, context) run(parser, os.Stdout, context, false) }
func main() { flag.Usage = usage flag.Parse() if *origin != 0 && *origin != 1 { fmt.Fprintf(os.Stderr, "ivy: illegal origin value %d\n", *origin) os.Exit(2) } if *gformat { *format = "%.12g" } conf.SetFormat(*format) conf.SetMaxBits(*maxbits) conf.SetMaxDigits(*maxdigits) conf.SetOrigin(*origin) conf.SetPrompt(*prompt) if len(*debugFlag) > 0 { for _, debug := range strings.Split(*debugFlag, ",") { if !conf.SetDebug(debug, true) { fmt.Fprintf(os.Stderr, "ivy: unknown debug flag %q", debug) os.Exit(2) } } } value.SetConfig(&conf) context = parse.NewContext() value.SetContext(context) if *execute { runArgs(context) return } if flag.NArg() > 0 { for i := 0; i < flag.NArg(); i++ { name := flag.Arg(i) var fd io.Reader var err error interactive := false if name == "-" { interactive = true fd = os.Stdin } else { interactive = false fd, err = os.Open(name) } if err != nil { fmt.Fprintf(os.Stderr, "ivy: %s\n", err) os.Exit(1) } scanner := scan.New(&conf, name, bufio.NewReader(fd)) parser := parse.NewParser(&conf, name, scanner, context) if !run(parser, context, interactive) { break } } return } scanner := scan.New(&conf, "<stdin>", bufio.NewReader(os.Stdin)) parser := parse.NewParser(&conf, "<stdin>", scanner, context) for !run(parser, context, true) { } }