1// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
2// See LICENSE for licensing information
3
4package syntax_test
5
6import (
7	"fmt"
8	"os"
9	"strings"
10
11	"mvdan.cc/sh/v3/syntax"
12)
13
14func Example() {
15	r := strings.NewReader("{ foo; bar; }")
16	f, err := syntax.NewParser().Parse(r, "")
17	if err != nil {
18		return
19	}
20	syntax.NewPrinter().Print(os.Stdout, f)
21	// Output:
22	// {
23	//	foo
24	//	bar
25	// }
26}
27
28func ExampleWord() {
29	r := strings.NewReader("echo foo${bar}'baz'")
30	f, err := syntax.NewParser().Parse(r, "")
31	if err != nil {
32		return
33	}
34
35	printer := syntax.NewPrinter()
36	args := f.Stmts[0].Cmd.(*syntax.CallExpr).Args
37	for i, word := range args {
38		fmt.Printf("Word number %d:\n", i)
39		for _, part := range word.Parts {
40			fmt.Printf("%-20T - ", part)
41			printer.Print(os.Stdout, part)
42			fmt.Println()
43		}
44		fmt.Println()
45	}
46
47	// Output:
48	// Word number 0:
49	// *syntax.Lit          - echo
50	//
51	// Word number 1:
52	// *syntax.Lit          - foo
53	// *syntax.ParamExp     - ${bar}
54	// *syntax.SglQuoted    - 'baz'
55}
56
57func ExampleCommand() {
58	r := strings.NewReader("echo foo; if x; then y; fi; foo | bar")
59	f, err := syntax.NewParser().Parse(r, "")
60	if err != nil {
61		return
62	}
63
64	printer := syntax.NewPrinter()
65	for i, stmt := range f.Stmts {
66		fmt.Printf("Cmd %d: %-20T - ", i, stmt.Cmd)
67		printer.Print(os.Stdout, stmt.Cmd)
68		fmt.Println()
69	}
70
71	// Output:
72	// Cmd 0: *syntax.CallExpr     - echo foo
73	// Cmd 1: *syntax.IfClause     - if x; then y; fi
74	// Cmd 2: *syntax.BinaryCmd    - foo | bar
75}
76
77func ExampleNewParser_options() {
78	src := "for ((i = 0; i < 5; i++)); do echo $i >f; done"
79
80	// LangBash is the default
81	r := strings.NewReader(src)
82	f, err := syntax.NewParser().Parse(r, "")
83	fmt.Println(err)
84
85	// Parser errors with LangPOSIX
86	r = strings.NewReader(src)
87	_, err = syntax.NewParser(syntax.Variant(syntax.LangPOSIX)).Parse(r, "")
88	fmt.Println(err)
89
90	syntax.NewPrinter().Print(os.Stdout, f)
91	syntax.NewPrinter(syntax.SpaceRedirects(true)).Print(os.Stdout, f)
92
93	// Output:
94	// <nil>
95	// 1:5: c-style fors are a bash feature
96	// for ((i = 0; i < 5; i++)); do echo $i >f; done
97	// for ((i = 0; i < 5; i++)); do echo $i > f; done
98}
99
100func ExampleWalk() {
101	in := strings.NewReader(`echo $foo "and $bar"`)
102	f, err := syntax.NewParser().Parse(in, "")
103	if err != nil {
104		return
105	}
106	syntax.Walk(f, func(node syntax.Node) bool {
107		switch x := node.(type) {
108		case *syntax.ParamExp:
109			x.Param.Value = strings.ToUpper(x.Param.Value)
110		}
111		return true
112	})
113	syntax.NewPrinter().Print(os.Stdout, f)
114	// Output: echo $FOO "and $BAR"
115}
116
117func ExampleDebugPrint() {
118	in := strings.NewReader(`echo 'foo'`)
119	f, err := syntax.NewParser().Parse(in, "")
120	if err != nil {
121		return
122	}
123	syntax.DebugPrint(os.Stdout, f)
124	// Output:
125	// *syntax.File {
126	// .  Name: ""
127	// .  Stmts: []*syntax.Stmt (len = 1) {
128	// .  .  0: *syntax.Stmt {
129	// .  .  .  Comments: []syntax.Comment (len = 0) {}
130	// .  .  .  Cmd: *syntax.CallExpr {
131	// .  .  .  .  Assigns: []*syntax.Assign (len = 0) {}
132	// .  .  .  .  Args: []*syntax.Word (len = 2) {
133	// .  .  .  .  .  0: *syntax.Word {
134	// .  .  .  .  .  .  Parts: []syntax.WordPart (len = 1) {
135	// .  .  .  .  .  .  .  0: *syntax.Lit {
136	// .  .  .  .  .  .  .  .  ValuePos: 1:1
137	// .  .  .  .  .  .  .  .  ValueEnd: 1:5
138	// .  .  .  .  .  .  .  .  Value: "echo"
139	// .  .  .  .  .  .  .  }
140	// .  .  .  .  .  .  }
141	// .  .  .  .  .  }
142	// .  .  .  .  .  1: *syntax.Word {
143	// .  .  .  .  .  .  Parts: []syntax.WordPart (len = 1) {
144	// .  .  .  .  .  .  .  0: *syntax.SglQuoted {
145	// .  .  .  .  .  .  .  .  Left: 1:6
146	// .  .  .  .  .  .  .  .  Right: 1:10
147	// .  .  .  .  .  .  .  .  Dollar: false
148	// .  .  .  .  .  .  .  .  Value: "foo"
149	// .  .  .  .  .  .  .  }
150	// .  .  .  .  .  .  }
151	// .  .  .  .  .  }
152	// .  .  .  .  }
153	// .  .  .  }
154	// .  .  .  Position: 1:1
155	// .  .  .  Semicolon: 0:0
156	// .  .  .  Negated: false
157	// .  .  .  Background: false
158	// .  .  .  Coprocess: false
159	// .  .  .  Redirs: []*syntax.Redirect (len = 0) {}
160	// .  .  }
161	// .  }
162	// .  Last: []syntax.Comment (len = 0) {}
163	// }
164}
165