-
Notifications
You must be signed in to change notification settings - Fork 125
feat(cli): support stdin/stdout I/O using the single hyphen convention #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ package main | |||||||||
| import ( | ||||||||||
| "flag" | ||||||||||
| "fmt" | ||||||||||
| "io" | ||||||||||
| "log" | ||||||||||
| "os" | ||||||||||
|
|
||||||||||
|
|
@@ -19,17 +20,17 @@ import ( | |||||||||
| var ( | ||||||||||
| Version = "dev" | ||||||||||
|
|
||||||||||
| inline = flag.Bool("inline", false, "parse rule inlining") | ||||||||||
| _switch = flag.Bool("switch", false, "replace if-else if-else like blocks with switch blocks") | ||||||||||
| // Avoid redefinition of built-in function print. | ||||||||||
| inline = flag.Bool("inline", false, "parse rule inlining") | ||||||||||
| switchFlag = flag.Bool("switch", false, "replace if-else if-else like blocks with switch blocks") | ||||||||||
| printFlag = flag.Bool("print", false, "directly dump the syntax tree") | ||||||||||
| syntax = flag.Bool("syntax", false, "print out the syntax tree") | ||||||||||
| noast = flag.Bool("noast", false, "disable AST") | ||||||||||
| strict = flag.Bool("strict", false, "treat compiler warnings as errors") | ||||||||||
| filename = flag.String("output", "", "specify name of output file") | ||||||||||
| outputFile = flag.String("output", "", "output to `FILE` (\"-\" for stdout)") | ||||||||||
| showVersion = flag.Bool("version", false, "print the version and exit") | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| // main is the entry point for the PEG compiler. | ||||||||||
| func main() { | ||||||||||
| flag.Parse() | ||||||||||
|
|
||||||||||
|
|
@@ -38,49 +39,84 @@ func main() { | |||||||||
| return | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if flag.NArg() != 1 { | ||||||||||
| flag.Usage() | ||||||||||
| log.Fatalf("FILE: the peg file to compile") | ||||||||||
| } | ||||||||||
| file := flag.Arg(0) | ||||||||||
| err := parse( | ||||||||||
| func(p *Peg[uint32], out io.Writer) error { | ||||||||||
| if *printFlag { | ||||||||||
| p.Print() | ||||||||||
| } | ||||||||||
| if *syntax { | ||||||||||
| p.PrintSyntaxTree() | ||||||||||
| } | ||||||||||
|
|
||||||||||
| buffer, err := os.ReadFile(file) | ||||||||||
| p.Strict = *strict | ||||||||||
| if err := p.Compile(*outputFile, os.Args, out); err != nil { | ||||||||||
| return err | ||||||||||
| } | ||||||||||
| return nil | ||||||||||
| }, | ||||||||||
| ) | ||||||||||
| if err != nil { | ||||||||||
| log.Fatal(err) | ||||||||||
| } | ||||||||||
|
|
||||||||||
| p := &Peg[uint32]{Tree: tree.New(*inline, *_switch, *noast), Buffer: string(buffer)} | ||||||||||
| _ = p.Init(Pretty[uint32](true), Size[uint32](1<<15)) | ||||||||||
| if err := p.Parse(); err != nil { | ||||||||||
| log.Fatal(err) | ||||||||||
| if *strict { | ||||||||||
| log.Fatal(err) | ||||||||||
| } | ||||||||||
| fmt.Fprintln(os.Stderr, "warning:", err) | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| p.Execute() | ||||||||||
| // getIO returns input and output streams based on command-line flags. | ||||||||||
| func getIO() (in io.ReadCloser, out io.WriteCloser, err error) { | ||||||||||
| in, out = os.Stdin, os.Stdout | ||||||||||
|
|
||||||||||
| if *printFlag { | ||||||||||
| p.Print() | ||||||||||
| } | ||||||||||
| if *syntax { | ||||||||||
| p.PrintSyntaxTree() | ||||||||||
| if flag.NArg() > 0 && flag.Arg(0) != "-" { | ||||||||||
| in, err = os.Open(flag.Arg(0)) | ||||||||||
| if err != nil { | ||||||||||
| return nil, nil, err | ||||||||||
| } | ||||||||||
| if *outputFile == "" { | ||||||||||
| *outputFile = flag.Arg(0) + ".go" | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if *filename == "" { | ||||||||||
| *filename = file + ".go" | ||||||||||
| if *outputFile != "" && *outputFile != "-" { | ||||||||||
| out, err = os.OpenFile(*outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o644) | ||||||||||
| if err != nil { | ||||||||||
| if in != nil && in != os.Stdin { | ||||||||||
| in.Close() | ||||||||||
| } | ||||||||||
|
Comment on lines
+83
to
+85
|
||||||||||
| if in != nil && in != os.Stdin { | |
| in.Close() | |
| } | |
| closeResource(in, os.Stdin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disagree with this suggestion: the reader would have to jump to another function containing only 2 lines of code and then jump back to resume reading.
So, adding closeResource is tedious for the reader and serves no functional benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error handling logic is incorrect. When
*strictis true, the code callslog.Fatal(err), but when false, it prints a warning. However, this happens outside the conditional check forerr != nil. Thelog.Fatal(err)should only be called when there's actually an error.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both logging statements are inside the conditional check for
err != nil. This looks like a Copilot mistake.