diff --git a/main.go b/main.go index 850c98b..794a9c1 100644 --- a/main.go +++ b/main.go @@ -1,37 +1,37 @@ package main import ( + "encoding/json" "flag" "fmt" "io" "os" ) -func input() io.ReadCloser { - if flag.Arg(1) == "" { +func input(n int) io.ReadCloser { + if flag.Arg(n) == "" { return os.Stdin } else { - f, err := os.Open(flag.Arg(1)) + f, err := os.Open(flag.Arg(n)) if err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err) - os.Exit(1) + bail(1, "input error: %s", err) } return f } } func check() { - r := input() + r := input(1) defer r.Close() _, err := parse(r) if err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err) + bail(1, "parse error: %s", err) } } func lexx() { - r := input() + r := input(1) defer r.Close() c := lex(r) @@ -41,20 +41,65 @@ func lexx() { } func parsse() { - r := input() + r := input(1) defer r.Close() n, err := parse(r) if err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err) - os.Exit(1) + bail(1, "parse error: %s", err) } if err := n.pretty(os.Stdout, ""); err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err) + bail(1, "output error: %s", err) + } +} + +func eval(r io.Reader) (map[string]interface{}, error) { + n, err := parse(r) + if err != nil { + return nil, fmt.Errorf("parse error: %s\n", err) + } + + ctx := make(map[string]interface{}) + if err := n.eval(ctx); err != nil { + return nil, fmt.Errorf("eval error: %s\n", err) + } + return ctx, nil +} + +func to() { + switch flag.Arg(1) { + case "json": + to_json(2) + default: + fmt.Fprintf(os.Stderr, "%s is not a valid output format\n", flag.Arg(1)) + fmt.Fprintln(os.Stderr, "valid output formats: json") os.Exit(1) } } +func to_json(n int) { + v, err := eval(input(n)) + if err != nil { + bail(1, "input error: %s", err) + } + b, err := json.MarshalIndent(v, "", " ") + if err != nil { + bail(1, "encode error: %s", err) + } + os.Stdout.Write(b) +} + +func bail(status int, t string, args ...interface{}) { + var w io.Writer + if status == 0 { + w = os.Stdout + } else { + w = os.Stderr + } + fmt.Fprintf(w, t+"\n", args...) + os.Exit(status) +} + func main() { flag.Parse() switch flag.Arg(0) { @@ -64,11 +109,11 @@ func main() { lexx() case "parse": parsse() + case "to": + to() case "": - fmt.Fprintf(os.Stderr, "specify an action (check)\n") - os.Exit(1) + bail(1, "must specify an action.\nvalid actions: check lex parse to") default: - fmt.Fprintf(os.Stderr, "no such action: %s\n", flag.Arg(0)) - os.Exit(1) + bail(1, "no such action:%s", flag.Arg(0)) } } diff --git a/node.go b/node.go index 06b5170..204fa17 100644 --- a/node.go +++ b/node.go @@ -23,6 +23,7 @@ type node interface { Type() nodeType parse(*parser) error pretty(io.Writer, string) error + eval(map[string]interface{}) error } type rootNode struct { @@ -90,6 +91,15 @@ func (n *rootNode) pretty(w io.Writer, prefix string) error { return nil } +func (n *rootNode) eval(ctx map[string]interface{}) error { + for _, child := range n.children { + if err := child.eval(ctx); err != nil { + return err + } + } + return nil +} + type commentNode struct { body string } @@ -126,6 +136,10 @@ func (n *commentNode) pretty(w io.Writer, prefix string) error { return nil } +func (n *commentNode) eval(ctx map[string]interface{}) error { + return nil +} + type assignmentNode struct { name string value interface{} @@ -167,5 +181,13 @@ func (n *assignmentNode) pretty(w io.Writer, prefix string) error { return nil } +func (n *assignmentNode) eval(ctx map[string]interface{}) error { + if _, ok := ctx[n.name]; ok { + return fmt.Errorf("invalid re-declaration: %s", n.name) + } + ctx[n.name] = n.value + return nil +} + type list []interface{} type object map[string]interface{}