func (r *Result) PrintWarnings(out io.Writer) {
	if len(r.Warnings) == 0 {
		return
	}
	fmt.Fprintf(out, strings.Join(r.Warnings, "\n")+"\n")
}
PrintWarnings to the writer
package parser
import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"unicode"
	"github.com/docker/docker/pkg/system"
	"github.com/openshift/imagebuilder/dockerfile/command"
	"github.com/pkg/errors"
)
type Node struct {
	Value      string           
	Next       *Node            
	Children   []*Node          
	Attributes map[string]bool  
	Original   string           
	Flags      []string         
	StartLine  int              
	EndLine    int              
}
func (node *Node) Dump() string {
	str := ""
	str += node.Value
	if len(node.Flags) > 0 {
		str += fmt.Sprintf(" %q", node.Flags)
	}
	for _, n := range node.Children {
		str += "(" + n.Dump() + ")\n"
	}
	for n := node.Next; n != nil; n = n.Next {
		if len(n.Children) > 0 {
			str += " " + n.Dump()
		} else {
			str += " " + strconv.Quote(n.Value)
		}
	}
	return strings.TrimSpace(str)
}
func (node *Node) lines(start, end int) {
	node.StartLine = start
	node.EndLine = end
}
func (node *Node) AddChild(child *Node, startLine, endLine int) {
	child.lines(startLine, endLine)
	if node.StartLine < 0 {
		node.StartLine = startLine
	}
	node.EndLine = endLine
	node.Children = append(node.Children, child)
}
var (
	dispatch             map[string]func(string, *Directive) (*Node, map[string]bool, error)
	tokenWhitespace      = regexp.MustCompile(`[\t\v\f\r ]+`)
	tokenEscapeCommand   = regexp.MustCompile(`^#[ \t]*escape[ \t]*=[ \t]*(?P<escapechar>.).*$`)
	tokenPlatformCommand = regexp.MustCompile(`^#[ \t]*platform[ \t]*=[ \t]*(?P<platform>.*)$`)
	tokenComment         = regexp.MustCompile(`^#.*$`)
)
const DefaultEscapeToken = '\\'
var defaultPlatformToken = runtime.GOOS
type Directive struct {
	escapeToken           rune            
	platformToken         string          
	lineContinuationRegex *regexp.Regexp  
	processingComplete    bool            
	escapeSeen            bool            
	platformSeen          bool            
}
func (d *Directive) setEscapeToken(s string) error {
	if s != "`" && s != "\\" {
		return fmt.Errorf("invalid ESCAPE '%s'. Must be ` or \\", s)
	}
	d.escapeToken = rune(s[0])
	d.lineContinuationRegex = regexp.MustCompile(`\` + s + `[ \t]*$`)
	return nil
}
func (d *Directive) setPlatformToken(s string) error {
	s = strings.ToLower(s)
	valid := []string{runtime.GOOS}
	if system.LCOWSupported() {
		valid = append(valid, "linux")
	}
	for _, item := range valid {
		if s == item {
			d.platformToken = s
			return nil
		}
	}
	return fmt.Errorf("invalid PLATFORM '%s'. Must be one of %v", s, valid)
}
func (d *Directive) possibleParserDirective(line string) error {
	if d.processingComplete {
		return nil
	}
	tecMatch := tokenEscapeCommand.FindStringSubmatch(strings.ToLower(line))
	if len(tecMatch) != 0 {
		for i, n := range tokenEscapeCommand.SubexpNames() {
			if n == "escapechar" {
				if d.escapeSeen == true {
					return errors.New("only one escape parser directive can be used")
				}
				d.escapeSeen = true
				return d.setEscapeToken(tecMatch[i])
			}
		}
	}
	if system.LCOWSupported() {
		tpcMatch := tokenPlatformCommand.FindStringSubmatch(strings.ToLower(line))
		if len(tpcMatch) != 0 {
			for i, n := range tokenPlatformCommand.SubexpNames() {
				if n == "platform" {
					if d.platformSeen == true {
						return errors.New("only one platform parser directive can be used")
					}
					d.platformSeen = true
					return d.setPlatformToken(tpcMatch[i])
				}
			}
		}
	}
	d.processingComplete = true
	return nil
}
func NewDefaultDirective() *Directive {
	directive := Directive{}
	directive.setEscapeToken(string(DefaultEscapeToken))
	directive.setPlatformToken(defaultPlatformToken)
	return &directive
}
func init() {
	dispatch = map[string]func(string, *Directive) (*Node, map[string]bool, error){
		command.Add:         parseMaybeJSONToList,
		command.Arg:         parseNameOrNameVal,
		command.Cmd:         parseMaybeJSON,
		command.Copy:        parseMaybeJSONToList,
		command.Entrypoint:  parseMaybeJSON,
		command.Env:         parseEnv,
		command.Expose:      parseStringsWhitespaceDelimited,
		command.From:        parseStringsWhitespaceDelimited,
		command.Healthcheck: parseHealthConfig,
		command.Label:       parseLabel,
		command.Maintainer:  parseString,
		command.Onbuild:     parseSubCommand,
		command.Run:         parseMaybeJSON,
		command.Shell:       parseMaybeJSON,
		command.StopSignal:  parseString,
		command.User:        parseString,
		command.Volume:      parseMaybeJSONToList,
		command.Workdir:     parseString,
	}
}
func newNodeFromLine(line string, directive *Directive) (*Node, error) {
	cmd, flags, args, err := splitCommand(line)
	if err != nil {
		return nil, err
	}
	fn := dispatch[cmd]
	if fn == nil {
		fn = parseIgnore
	}
	next, attrs, err := fn(args, directive)
	if err != nil {
		return nil, err
	}
	return &Node{
		Value:      cmd,
		Original:   line,
		Flags:      flags,
		Next:       next,
		Attributes: attrs,
	}, nil
}
type Result struct {
	AST         *Node
	EscapeToken rune
	Platform    string
	Warnings    []string
}