From 11f2531da631f25437216a051be7699ff2d4663a Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 21 Mar 2014 18:18:42 -0700 Subject: [PATCH] pkg/dockerscript: expose a simple, clean API with a single Parse method Docker-DCO-1.1-Signed-off-by: Solomon Hykes (github: shykes) --- pkg/beam/examples/beamsh/beamsh.go | 102 +-------------------- pkg/dockerscript/dockerscript.go | 107 ++++++++++++++++++++++ pkg/dockerscript/{ => scanner}/extra.go | 0 pkg/dockerscript/{ => scanner}/scanner.go | 0 4 files changed, 112 insertions(+), 97 deletions(-) create mode 100644 pkg/dockerscript/dockerscript.go rename pkg/dockerscript/{ => scanner}/extra.go (100%) rename pkg/dockerscript/{ => scanner}/scanner.go (100%) diff --git a/pkg/beam/examples/beamsh/beamsh.go b/pkg/beam/examples/beamsh/beamsh.go index 77678d285a..ddce5103cd 100644 --- a/pkg/beam/examples/beamsh/beamsh.go +++ b/pkg/beam/examples/beamsh/beamsh.go @@ -3,109 +3,17 @@ package main import ( "fmt" "os" - scanner "github.com/dotcloud/docker/pkg/dockerscript" - "strings" + "github.com/dotcloud/docker/pkg/dockerscript" ) func main() { - s := &scanner.Scanner{} - s.Init(os.Stdin) - s.Whitespace = 1<<'\t' | 1<<' ' - //s.Mode = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments - s.Mode = scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanIdents - expr, err := parse(s, "") + script, err := dockerscript.Parse(os.Stdin) if err != nil { - fmt.Fprintf(os.Stderr, "line %d:%d: %v\n", s.Pos().Line, s.Pos().Column, err) + fmt.Fprintf(os.Stderr, "parse error: %v\n", err) os.Exit(1) } - fmt.Printf("%d commands:\n", len(expr)) - for i, cmd := range expr { + fmt.Printf("%d commands:\n", len(script)) + for i, cmd := range script { fmt.Printf("%%%d: %s\n", i, cmd) } } - -type Command struct { - Args []string - Children []*Command -} - -func (cmd *Command) subString(depth int) string { - var prefix string - for i:=0; i 0 { - s += " {\n" - for _, subcmd := range cmd.Children { - s += subcmd.subString(depth + 1) - } - s += prefix + "}" - } - s += "\n" - return s -} - -func (cmd *Command) String() string { - return cmd.subString(0) -} - -func parseArgs(s *scanner.Scanner) ([]string, rune, error) { - var parseError error - // FIXME: we overwrite previously set error - s.Error = func(s *scanner.Scanner, msg string) { - parseError = fmt.Errorf(msg) - // parseError = fmt.Errorf("line %d:%d: %s\n", s.Pos().Line, s.Pos().Column, msg) - } - var args []string - tok := s.Scan() - for tok != scanner.EOF { - if parseError != nil { - return args, tok, parseError - } - text := s.TokenText() - //fmt.Printf("--> [%s]\n", text) - if text == "{" || text == "}" || text == "\n" || text == "\r" || text == ";" { - return args, tok, nil - } - args = append(args, text) - tok = s.Scan() - } - return args, tok, nil -} - -func parse(s *scanner.Scanner, opener string) (expr []*Command, err error) { - defer func() { - fmt.Printf("parse() returned %d commands:\n", len(expr)) - for _, c := range expr { - fmt.Printf("\t----> %s\n", c) - } - }() - for { - args, tok, err := parseArgs(s) - if err != nil { - return nil, err - } - cmd := &Command{Args: args} - fmt.Printf("---> args=%v finished by %s\n", args, s.TokenText()) - afterArgs := s.TokenText() - if afterArgs == "{" { - fmt.Printf("---> therefore calling parse() of sub-expression\n") - children, err := parse(s, "{") - fmt.Printf("---> parse() of sub-epxression returned %d commands (ended by %s) and error=%v\n", children, s.TokenText(), err) - if err != nil { - return nil, err - } - cmd.Children = children - } else if afterArgs == "}" && opener != "{" { - return nil, fmt.Errorf("unexpected end of block '}'") - } - if len(cmd.Args) > 0 || len(cmd.Children) > 0 { - expr = append(expr, cmd) - } - if tok == scanner.EOF || afterArgs == "}" { - break - } - } - return expr, nil -} diff --git a/pkg/dockerscript/dockerscript.go b/pkg/dockerscript/dockerscript.go new file mode 100644 index 0000000000..7bc9ebbc29 --- /dev/null +++ b/pkg/dockerscript/dockerscript.go @@ -0,0 +1,107 @@ +package dockerscript + +import ( + "github.com/dotcloud/docker/pkg/dockerscript/scanner" + "fmt" + "io" + "strings" +) + +type Command struct { + Args []string + Children []*Command +} + +func Parse(src io.Reader) ([]*Command, error) { + s := &scanner.Scanner{} + s.Init(src) + s.Whitespace = 1<<'\t' | 1<<' ' + //s.Mode = ScanIdents | ScanFloats | ScanChars | ScanStrings | ScanRawStrings | ScanComments | SkipComments + s.Mode = scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanIdents + expr, err := parse(s, "") + if err != nil { + return nil, fmt.Errorf("line %d:%d: %v\n", s.Pos().Line, s.Pos().Column, err) + } + return expr, nil +} + +func (cmd *Command) subString(depth int) string { + var prefix string + for i:=0; i 0 { + s += " {\n" + for _, subcmd := range cmd.Children { + s += subcmd.subString(depth + 1) + } + s += prefix + "}" + } + s += "\n" + return s +} + +func (cmd *Command) String() string { + return cmd.subString(0) +} + +func parseArgs(s *scanner.Scanner) ([]string, rune, error) { + var parseError error + // FIXME: we overwrite previously set error + s.Error = func(s *scanner.Scanner, msg string) { + parseError = fmt.Errorf(msg) + // parseError = fmt.Errorf("line %d:%d: %s\n", s.Pos().Line, s.Pos().Column, msg) + } + var args []string + tok := s.Scan() + for tok != scanner.EOF { + if parseError != nil { + return args, tok, parseError + } + text := s.TokenText() + //fmt.Printf("--> [%s]\n", text) + if text == "{" || text == "}" || text == "\n" || text == "\r" || text == ";" { + return args, tok, nil + } + args = append(args, text) + tok = s.Scan() + } + return args, tok, nil +} + +func parse(s *scanner.Scanner, opener string) (expr []*Command, err error) { + defer func() { + fmt.Printf("parse() returned %d commands:\n", len(expr)) + for _, c := range expr { + fmt.Printf("\t----> %s\n", c) + } + }() + for { + args, tok, err := parseArgs(s) + if err != nil { + return nil, err + } + cmd := &Command{Args: args} + fmt.Printf("---> args=%v finished by %s\n", args, s.TokenText()) + afterArgs := s.TokenText() + if afterArgs == "{" { + fmt.Printf("---> therefore calling parse() of sub-expression\n") + children, err := parse(s, "{") + fmt.Printf("---> parse() of sub-epxression returned %d commands (ended by %s) and error=%v\n", children, s.TokenText(), err) + if err != nil { + return nil, err + } + cmd.Children = children + } else if afterArgs == "}" && opener != "{" { + return nil, fmt.Errorf("unexpected end of block '}'") + } + if len(cmd.Args) > 0 || len(cmd.Children) > 0 { + expr = append(expr, cmd) + } + if tok == scanner.EOF || afterArgs == "}" { + break + } + } + return expr, nil +} diff --git a/pkg/dockerscript/extra.go b/pkg/dockerscript/scanner/extra.go similarity index 100% rename from pkg/dockerscript/extra.go rename to pkg/dockerscript/scanner/extra.go diff --git a/pkg/dockerscript/scanner.go b/pkg/dockerscript/scanner/scanner.go similarity index 100% rename from pkg/dockerscript/scanner.go rename to pkg/dockerscript/scanner/scanner.go