diff --git a/cmd/protoscope/main.go b/cmd/protoscope/main.go index b1c1394..507eea3 100644 --- a/cmd/protoscope/main.go +++ b/cmd/protoscope/main.go @@ -54,13 +54,13 @@ var ( ) func main() { - if err := Main(); err != nil { + if err := realMain(); err != nil { fmt.Fprintln(os.Stderr, "protoscope:", err) os.Exit(1) } } -func Main() error { +func realMain() error { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [-s] [OPTION...] [INPUT]\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Assemble a Protoscope file to binary, or inspect binary data as Protoscope text.\n") @@ -154,8 +154,7 @@ func Main() error { outBytes, err = scanner.Exec() if err != nil { - return fmt.Errorf("syntax error: %s\n", err) - os.Exit(1) + return fmt.Errorf("syntax error: %s", err) } } else { outBytes = []byte(protoscope.Write(inBytes, protoscope.WriterOptions{ diff --git a/internal/print/print.go b/internal/print/print.go index cee0725..7a69042 100644 --- a/internal/print/print.go +++ b/internal/print/print.go @@ -40,7 +40,7 @@ func (s *Stack[T]) Pop() T { return popped } -// Pop pops the top n elements off the stack and returns a slice containing +// PopN pops the top n elements off the stack and returns a slice containing // copies. Panics if the stack is too small func (s *Stack[T]) PopN(n int) []T { popped := make([]T, n) @@ -58,7 +58,7 @@ func (s *Stack[T]) Peek() *T { return &s.PeekN(1)[0] } -// Peek returns the top n elements of the stack as another stack. +// PeekN returns the top n elements of the stack as another stack. // // Returns nil if the stack is too small. func (s *Stack[T]) PeekN(n int) Stack[T] { @@ -96,19 +96,22 @@ func (p *Printer) Current() *Line { return p.Prev(0) } -// Discards the current line +// DiscardLine discards the current line func (p *Printer) DiscardLine() { p.lines.Pop() } +// A Mark is a mark in a Printer that can be used to discard all lines that follow it. +// +// See Printer.Reset(). type Mark int -// Makes a mark on the line buffer. +// Mark returns a mark on the line buffer. func (p *Printer) Mark() Mark { return Mark(len(p.lines)) } -// Discards all lines after the mark. +// Reset discards all lines after the mark. func (p *Printer) Reset(m Mark) { p.lines = p.lines[:m] } @@ -130,18 +133,18 @@ func (p *Printer) Write(args ...any) { fmt.Fprint(p.Current(), args...) } -// Writes to the current line's buffer with Fprintf. +// Writef writes to the current line's buffer with Fprintf. func (p *Printer) Writef(f string, args ...any) { fmt.Fprintf(p.Current(), f, args...) } -// Adds a new remark made from stringifying args. +// Remark adds a new remark made by calling Fprint. func (p *Printer) Remark(args ...any) { l := p.Current() l.remarks = append(l.remarks, fmt.Sprint(args...)) } -// Adds a new remark made from stringifying args. +// Remarkf adds a new remark made by calling Fprintf. func (p *Printer) Remarkf(f string, args ...any) { l := p.Current() l.remarks = append(l.remarks, fmt.Sprintf(f, args...)) @@ -214,6 +217,7 @@ func (p *Printer) Finish() []byte { return out.Bytes() } +// A BlockInfo is configuration options for a block. type BlockInfo struct { // Whether this block will start and end with delimiters that do not need to // have spaces placed before/after them, allowing for output like {x} instead @@ -229,7 +233,7 @@ type BlockInfo struct { start int } -// Starts a new indentation block. +// StartBlock starts a new indentation block. func (p *Printer) StartBlock(bi BlockInfo) { if p.Current().indent != 0 { panic("called StartBlock() too many times; this is a bug") @@ -239,7 +243,7 @@ func (p *Printer) StartBlock(bi BlockInfo) { p.Current().indent++ } -// Discards the current block and undoes its indentation. +// DropBlock discards the current block and undoes its indentation. func (p *Printer) DropBlock() *Line { bi := p.blocks.Pop() start := &p.lines[bi.start] @@ -247,7 +251,7 @@ func (p *Printer) DropBlock() *Line { return start } -// Finishes an indentation block; a call to this function must match up to +// EndBlock finishes an indentation block; a call to this function must match up to // a corresponding previous StartBlock() call. Returns the starting line for the // block. // @@ -308,7 +312,7 @@ func (p *Printer) EndBlock() *Line { return start } -// Folds the last count lines into lines with `cols` columns each. +// FoldIntoColumns folds the last count lines into lines with `cols` columns each. func (p *Printer) FoldIntoColumns(cols, count int) { toFold := p.lines.PopN(count) widths := make([]int, cols) diff --git a/scanner.go b/scanner.go index 0f4cb4f..d0f6e4a 100644 --- a/scanner.go +++ b/scanner.go @@ -12,7 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// package protoscope ... +// package protoscope implements an assembler and disassembler for the Protoscope language. +// This language is specified in language.txt. +// +// The assembler consumes a string containing Protoscope tokens and outputs a Protobuf-encoded +// binary blob based on those tokens. The entry point for the assembler is the Scanner type. +// +// The disassembler consumes a binary blob and attempts to produce reasonable Protoscope tokens that +// can be reassembled into the original binary. It uses a number of heuristics to accomplish this, +// optionally incorporating a message descriptor to aid with disassembly. The entry point for the +// disassembler is the Write function. + package protoscope import ( @@ -28,7 +38,7 @@ import ( _ "embed" ) -// The contents of language.text. +// LanguageTxt contains the contents of language.txt, which specifies the Protoscope language. // //go:embed language.txt var LanguageTxt string @@ -116,6 +126,7 @@ var ( // 3: The wire type, including the colon, if this is a tag. // 4: The wire type expression, which may be empty if it is inferred. regexpIntOrTag = regexp.MustCompile(`^-?([0-9]+|0x[0-9a-fA-F]+)(z|i32|i64)?(:(\w*))?$`) + regexpDecFp = regexp.MustCompile(`^(-?[0-9]+\.[0-9]+(?:[eE]-?[0-9]+)?)(i32|i64)?$`) regexpHexFp = regexp.MustCompile(`^(-?0x[0-9a-fA-F]+\.[0-9a-fA-F]+(?:[pP]-?[0-9]+)?)(i32|i64)?$`) regexpLongForm = regexp.MustCompile(`^long-form:([0-9]+)$`) @@ -421,7 +432,7 @@ loop: } if value>>61 != 0 && value>>61 != -1 { - return token{}, &ParseError{start, errors.New("field number too large for three extra bits for the wire type.")} + return token{}, &ParseError{start, errors.New("field number too large for three extra bits for the wire type")} } fieldNumber = value