// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n");
fmt.Fprintf(fgo1, "//line %s:1\n", srcfile);
- printer.Fprint(fgo1, p.AST, 0, 8, nil);
+ printer.Fprint(fgo1, p.AST);
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
for name, def := range p.Typedef {
fmt.Fprintf(fgo2, "type %s ", name);
- printer.Fprint(fgo2, def, 0, 8, nil);
+ printer.Fprint(fgo2, def);
fmt.Fprintf(fgo2, "\n");
}
fmt.Fprintf(fgo2, "type _C_void [0]byte\n");
for name, def := range p.Vardef {
fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s/%s_%s.so\"\n", p.Package, name, name, pkgroot, p.PackagePath, base);
fmt.Fprintf(fgo2, "var _C_%s ", name);
- printer.Fprint(fgo2, &ast.StarExpr{X: def.Go}, 0, 8, nil);
+ printer.Fprint(fgo2, &ast.StarExpr{X: def.Go});
fmt.Fprintf(fgo2, "\n");
}
fmt.Fprintf(fc, "\n");
Name: &ast.Ident{Value: "_C_"+name},
Type: def.Go,
};
- printer.Fprint(fgo2, d, 0, 8, nil);
+ printer.Fprint(fgo2, d);
fmt.Fprintf(fgo2, "\n");
if name == "CString" || name == "GoString" {
)
-// Printing is controlled with these flags supplied
-// to Fprint via the mode parameter.
-//
-const (
- GenHTML uint = 1 << iota; // generate HTML
- RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
- UseSpaces; // use spaces instead of tabs for indentation and alignment
-)
-
-
type whiteSpace int
const (
var noPos token.Position
-// An HtmlTag specifies a start and end tag.
-type HtmlTag struct {
- Start, End string; // empty if tags are absent
-}
-
-
-// A Styler specifies the formatting line tags and elementary Go words.
-// A format consists of text and a (possibly empty) surrounding HTML tag.
-type Styler interface {
- LineTag(line int) ([]byte, HtmlTag);
- Comment(c *ast.Comment, line []byte) ([]byte, HtmlTag);
- BasicLit(x *ast.BasicLit) ([]byte, HtmlTag);
- Ident(id *ast.Ident) ([]byte, HtmlTag);
- Token(tok token.Token) ([]byte, HtmlTag);
-}
-
-
type printer struct {
// Configuration (does not change after initialization)
output io.Writer;
- mode uint;
- tabwidth int;
- style Styler;
+ Config;
errors chan os.Error;
// Current state
}
-func (p *printer) init(output io.Writer, mode uint, tabwidth int, style Styler) {
+func (p *printer) init(output io.Writer, cfg *Config) {
p.output = output;
- p.mode = mode;
- p.tabwidth = tabwidth;
- p.style = style;
+ p.Config = *cfg;
p.errors = make(chan os.Error);
p.buffer = make([]whiteSpace, 0, 16); // whitespace sequences are short
}
i0 = i+1;
case '&', '<', '>':
- if p.mode & GenHTML != 0 {
+ if p.Mode & GenHTML != 0 {
// write segment ending in b
p.write0(data[i0 : i]);
// do not update p.pos - use write0
p.write0(strings.Bytes(fmt.Sprintf("[%d:%d]", pos.Line, pos.Column)));
}
- if p.mode & GenHTML != 0 {
+ if p.Mode & GenHTML != 0 {
// write line tag if on a new line
// TODO(gri): should write line tags on each line at the start
// will be more useful (e.g. to show line numbers)
- if p.style != nil && pos.Line > p.lastTaggedLine {
- p.writeTaggedItem(p.style.LineTag(pos.Line));
+ if p.Styler != nil && pos.Line > p.lastTaggedLine {
+ p.writeTaggedItem(p.Styler.LineTag(pos.Line));
p.lastTaggedLine = pos.Line;
}
p.writeTaggedItem(data, tag);
// by the printer, reducing tab sequences to single tabs will yield the
// original comment again after reformatting via the tabwriter.
text := comment.Text;
- if p.mode & RawFormat == 0 {
+ if p.Mode & RawFormat == 0 {
// tabwriter is used
text = collapseTabs(comment.Text);
}
// write comment
var tag HtmlTag;
- if p.style != nil {
- text, tag = p.style.Comment(comment, text);
+ if p.Styler != nil {
+ text, tag = p.Styler.Comment(comment, text);
}
p.writeItem(comment.Pos(), text, tag);
}
// handles comments correctly
data = strings.Bytes(x);
case *ast.Ident:
- if p.style != nil {
- data, tag = p.style.Ident(x);
+ if p.Styler != nil {
+ data, tag = p.Styler.Ident(x);
} else {
data = strings.Bytes(x.Value);
}
case *ast.BasicLit:
- if p.style != nil {
- data, tag = p.style.BasicLit(x);
+ if p.Styler != nil {
+ data, tag = p.Styler.BasicLit(x);
} else {
data = x.Value;
}
// TODO(gri): this this more efficiently.
data = strings.Bytes("\xff" + string(data) + "\xff");
case token.Token:
- if p.style != nil {
- data, tag = p.style.Token(x);
+ if p.Styler != nil {
+ data, tag = p.Styler.Token(x);
} else {
data = strings.Bytes(x.String());
}
// test-print the statement and see if it would fit
var buf bytes.Buffer;
- _, err := Fprint(&buf, b.List[0], p.mode, p.tabwidth, p.style);
+ _, err := p.Config.Fprint(&buf, b.List[0]);
if err != nil {
return false; // don't try
}
// ----------------------------------------------------------------------------
// Public interface
-var inf = token.Position{Offset: 1<<30, Line: 1<<30}
+// General printing is controlled with these Config.Mode flags.
+const (
+ GenHTML uint = 1 << iota; // generate HTML
+ RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
+ UseSpaces; // use spaces instead of tabs for indentation and alignment
+)
+
+
+// An HtmlTag specifies a start and end tag.
+type HtmlTag struct {
+ Start, End string; // empty if tags are absent
+}
+
+
+// A Styler specifies formatting of line tags and elementary Go words.
+// A format consists of text and a (possibly empty) surrounding HTML tag.
+//
+type Styler interface {
+ LineTag(line int) ([]byte, HtmlTag);
+ Comment(c *ast.Comment, line []byte) ([]byte, HtmlTag);
+ BasicLit(x *ast.BasicLit) ([]byte, HtmlTag);
+ Ident(id *ast.Ident) ([]byte, HtmlTag);
+ Token(tok token.Token) ([]byte, HtmlTag);
+}
-// Fprint "pretty-prints" an AST node to output and returns the number of
-// bytes written, and an error, if any. The node type must be *ast.File,
-// or assignment-compatible to ast.Expr, ast.Decl, or ast.Stmt. Printing
-// is controlled by the mode and tabwidth parameters.
+// A Config node controls the output of Fprint.
+type Config struct {
+ Mode uint; // default: 0
+ Tabwidth int; // default: 8
+ Styler Styler; // default: nil
+}
+
+
+// Fprint "pretty-prints" an AST node to output and returns the number
+// of bytes written and an error (if any) for a given configuration cfg.
+// The node type must be *ast.File, or assignment-compatible to ast.Expr,
+// ast.Decl, or ast.Stmt.
//
-func Fprint(output io.Writer, node interface{}, mode uint, tabwidth int, style Styler) (int, os.Error) {
+func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
// redirect output through a trimmer to eliminate trailing whitespace
// (Input to a tabwriter must be untrimmed since trailing tabs provide
// formatting information. The tabwriter could provide trimming
// setup tabwriter if needed and redirect output
var tw *tabwriter.Writer;
- if mode & RawFormat == 0 {
+ if cfg.Mode & RawFormat == 0 {
padchar := byte('\t');
- if mode & UseSpaces != 0 {
+ if cfg.Mode & UseSpaces != 0 {
padchar = ' ';
}
twmode := tabwriter.DiscardEmptyColumns;
- if mode & GenHTML != 0 {
+ if cfg.Mode & GenHTML != 0 {
twmode |= tabwriter.FilterHTML;
}
- tw = tabwriter.NewWriter(output, tabwidth, 1, padchar, twmode);
+ tw = tabwriter.NewWriter(output, cfg.Tabwidth, 1, padchar, twmode);
output = tw;
}
// setup printer and print node
var p printer;
- p.init(output, mode, tabwidth, style);
+ p.init(output, cfg);
go func() {
switch n := node.(type) {
case ast.Expr:
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n));
runtime.Goexit();
}
- p.flush(inf);
+ p.flush(token.Position{Offset: 1<<30, Line: 1<<30}); // flush to "infinity"
p.errors <- nil; // no errors
}();
err := <-p.errors; // wait for completion of goroutine
return p.written, err;
}
+
+
+// Fprint "pretty-prints" an AST node to output.
+// It calls Config.Fprint with default settings.
+//
+func Fprint(output io.Writer, node interface{}) os.Error {
+ _, err := (&Config{Tabwidth: 8}).Fprint(output, node); // don't care about number of bytes written
+ return err;
+}