// Copyright (c) 2016, Daniel Mart
// See LICENSE for licensing information
package syntax_test
import (
"fmt"
"os"
"strings"
"mvdan.cc/sh/v3/syntax"
)
func Example() {
r := strings.NewReader("{ foo; bar; }")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
return
}
syntax.NewPrinter().Print(os.Stdout, f)
// Output:
// {
// foo
// bar
// }
}
func ExampleWord() {
r := strings.NewReader("echo foo${bar}'baz'")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
return
}
printer := syntax.NewPrinter()
args := f.Stmts[0].Cmd.(*syntax.CallExpr).Args
for i, word := range args {
fmt.Printf("Word number %d:\n", i)
for _, part := range word.Parts {
fmt.Printf("%-20T - ", part)
printer.Print(os.Stdout, part)
fmt.Println()
}
fmt.Println()
}
// Output:
// Word number 0:
// *syntax.Lit - echo
//
// Word number 1:
// *syntax.Lit - foo
// *syntax.ParamExp - ${bar}
// *syntax.SglQuoted - 'baz'
}
func ExampleCommand() {
r := strings.NewReader("echo foo; if x; then y; fi; foo | bar")
f, err := syntax.NewParser().Parse(r, "")
if err != nil {
return
}
printer := syntax.NewPrinter()
for i, stmt := range f.Stmts {
fmt.Printf("Cmd %d: %-20T - ", i, stmt.Cmd)
printer.Print(os.Stdout, stmt.Cmd)
fmt.Println()
}
// Output:
// Cmd 0: *syntax.CallExpr - echo foo
// Cmd 1: *syntax.IfClause - if x; then y; fi
// Cmd 2: *syntax.BinaryCmd - foo | bar
}
func ExampleNewParser_options() {
src := "for ((i = 0; i < 5; i++)); do echo $i >f; done"
// LangBash is the default
r := strings.NewReader(src)
f, err := syntax.NewParser().Parse(r, "")
fmt.Println(err)
// Parser errors with LangPOSIX
r = strings.NewReader(src)
_, err = syntax.NewParser(syntax.Variant(syntax.LangPOSIX)).Parse(r, "")
fmt.Println(err)
syntax.NewPrinter().Print(os.Stdout, f)
syntax.NewPrinter(syntax.SpaceRedirects(true)).Print(os.Stdout, f)
// Output:
//
// 1:5: c-style fors are a bash/zsh feature; tried parsing as posix
// for ((i = 0; i < 5; i++)); do echo $i >f; done
// for ((i = 0; i < 5; i++)); do echo $i > f; done
}
// Keep in sync with FuzzQuote.
func ExampleQuote() {
for _, s := range []string{
"foo",
"bar $baz",
`"won't"`,
"~/home",
"#1304",
"name=value",
"for",
"glob-*",
"invalid-\xe2'",
"nonprint-\x0b\x1b",
} {
// We assume Bash syntax here.
// For general shell syntax quoting, use syntax.LangPOSIX.
quoted, err := syntax.Quote(s, syntax.LangBash)
if err != nil {
fmt.Printf("%q cannot be quoted: %v\n", s, err)
} else {
fmt.Printf("Quote(%17q): %s\n", s, quoted)
}
}
// Output:
// Quote( "foo"): foo
// Quote( "bar $baz"): 'bar $baz'
// Quote( "\"won't\""): "\"won't\""
// Quote( "~/home"): '~/home'
// Quote( "#1304"): '#1304'
// Quote( "name=value"): 'name=value'
// Quote( "for"): 'for'
// Quote( "glob-*"): 'glob-*'
// Quote( "invalid-\xe2'"): $'invalid-\xe2\''
// Quote("nonprint-\v\x1b"): $'nonprint-\v\x1b'
}
func ExampleWalk() {
in := strings.NewReader(`echo $foo "and $bar"`)
f, err := syntax.NewParser().Parse(in, "")
if err != nil {
return
}
syntax.Walk(f, func(node syntax.Node) bool {
switch node := node.(type) {
case *syntax.ParamExp:
node.Param.Value = strings.ToUpper(node.Param.Value)
}
return true
})
syntax.NewPrinter().Print(os.Stdout, f)
// Output: echo $FOO "and $BAR"
}
func ExampleDebugPrint() {
in := strings.NewReader(`echo 'foo'`)
f, err := syntax.NewParser().Parse(in, "")
if err != nil {
return
}
syntax.DebugPrint(os.Stdout, f)
// Output:
// *syntax.File {
// . Name: ""
// . Stmts: []*syntax.Stmt (len = 1) {
// . . 0: *syntax.Stmt {
// . . . Comments: []syntax.Comment (len = 0) {}
// . . . Cmd: *syntax.CallExpr {
// . . . . Assigns: []*syntax.Assign (len = 0) {}
// . . . . Args: []*syntax.Word (len = 2) {
// . . . . . 0: *syntax.Word {
// . . . . . . Parts: []syntax.WordPart (len = 1) {
// . . . . . . . 0: *syntax.Lit {
// . . . . . . . . ValuePos: 1:1
// . . . . . . . . ValueEnd: 1:5
// . . . . . . . . Value: "echo"
// . . . . . . . }
// . . . . . . }
// . . . . . }
// . . . . . 1: *syntax.Word {
// . . . . . . Parts: []syntax.WordPart (len = 1) {
// . . . . . . . 0: *syntax.SglQuoted {
// . . . . . . . . Left: 1:6
// . . . . . . . . Right: 1:10
// . . . . . . . . Dollar: false
// . . . . . . . . Value: "foo"
// . . . . . . . }
// . . . . . . }
// . . . . . }
// . . . . }
// . . . }
// . . . Position: 1:1
// . . . Semicolon: 0:0
// . . . Negated: false
// . . . Background: false
// . . . Coprocess: false
// . . . Disown: false
// . . . Redirs: []*syntax.Redirect (len = 0) {}
// . . }
// . }
// . Last: []syntax.Comment (len = 0) {}
// }
}