From 9acd2a973153cd98888429191c7c6ee5497efbab Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 6 Feb 2009 15:26:30 -0800 Subject: [PATCH] snapshot: - first stab at a Go Documentation Server (gds) - various fixes to make initial version of gds work R=r OCL=24588 CL=24588 --- usr/gri/pretty/Makefile | 9 +++- usr/gri/pretty/compilation.go | 10 +---- usr/gri/pretty/gds.go | 83 +++++++++++++++++++++++++++++++++++ usr/gri/pretty/pretty.go | 28 ++++++------ usr/gri/pretty/printer.go | 67 ++++++++++++++++++---------- 5 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 usr/gri/pretty/gds.go diff --git a/usr/gri/pretty/Makefile b/usr/gri/pretty/Makefile index ebf75218ed..a3b99ef928 100644 --- a/usr/gri/pretty/Makefile +++ b/usr/gri/pretty/Makefile @@ -5,11 +5,14 @@ G=6g L=6l -all: untab pretty +all: untab gds pretty untab: untab.6 $(L) -o untab untab.6 - + +gds: gds.6 + $(L) -o gds gds.6 + pretty: pretty.6 $(L) -o pretty pretty.6 @@ -25,6 +28,8 @@ install: pretty clean: rm -f pretty *.6 *.a *~ +gds.6: utils.6 platform.6 compilation.6 printer.6 + pretty.6: platform.6 printer.6 compilation.6 compilation.6: platform.6 scanner.6 parser.6 ast.6 typechecker.6 diff --git a/usr/gri/pretty/compilation.go b/usr/gri/pretty/compilation.go index fa87d28d1b..498175cad4 100644 --- a/usr/gri/pretty/compilation.go +++ b/usr/gri/pretty/compilation.go @@ -9,6 +9,7 @@ import ( "utf8"; "fmt"; "os"; + Utils "utils"; Platform "platform"; Scanner "scanner"; Parser "parser"; @@ -205,16 +206,9 @@ func addDeps(globalset map [string] bool, wset *array.Array, src_file string, fl func ComputeDeps(src_file string, flags *Flags) { - // string ".go" extension, if any - { n := len(src_file); - if src_file[n-3 : n] == ".go" { - src_file = src_file[0 : n-3]; - } - } - // compute deps globalset := make(map [string] bool); wset := array.New(0); - wset.Push(src_file); + wset.Push(Utils.TrimExt(src_file, ".go")); for wset.Len() > 0 { addDeps(globalset, wset, wset.Pop().(string), flags); } diff --git a/usr/gri/pretty/gds.go b/usr/gri/pretty/gds.go new file mode 100644 index 0000000000..cdf2c7d1ab --- /dev/null +++ b/usr/gri/pretty/gds.go @@ -0,0 +1,83 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// GDS: Go Documentation Server + +package main + +import ( + "bufio"; + "flag"; + "fmt"; + "http"; + "io"; + "net"; + "os"; + + Utils "utils"; + Platform "platform"; + Compilation "compilation"; + Printer "printer"; +) + + +var urlPrefix = "/gds" // 6g BUG should be const + + +var ( + verbose = flag.Bool("v", false, "verbose mode"); + port = flag.String("port", "6060", "server port"); + //root = flag.String("root", Platform.GOROOT, "go root directory"); + root = &Platform.GOROOT; // TODO cannot change root w/ passing it to printer +) + + +// TODO should factor this out - also used by the parser +func getFilename(url string) string { + // strip URL prefix + if url[0 : len(urlPrefix)] != urlPrefix { + panic("server error - illegal URL prefix"); + } + url = url[len(urlPrefix) : len(url)]; + + // sanitize source file name + return *root + Utils.TrimExt(url, ".go") + ".go"; +} + + +func docServer(c *http.Conn, req *http.Request) { + if *verbose { + fmt.Printf("URL path = %s\n", req.Url.Path); + } + + filename := getFilename(req.Url.Path); + var flags Compilation.Flags; + prog, nerrors := Compilation.Compile(filename, &flags); + if nerrors > 0 { + c.WriteHeader(http.StatusNotFound); + fmt.Fprintf(c, "compilation errors: %s\n", filename); + return; + } + + c.SetHeader("content-type", "text/html; charset=utf-8"); + Printer.Print(c, true, prog); +} + + +func main() { + flag.Parse(); + + if *verbose { + fmt.Printf("Go Documentation Server\n"); + fmt.Printf("port = %s\n", *port); + fmt.Printf("root = %s\n", *root); + } + + http.Handle(urlPrefix + "/", http.HandlerFunc(docServer)); + err := http.ListenAndServe(":" + *port, nil); + if err != nil { + panic("ListenAndServe: ", err.String()) + } +} + diff --git a/usr/gri/pretty/pretty.go b/usr/gri/pretty/pretty.go index 96e57f7a9c..a61e4f980f 100644 --- a/usr/gri/pretty/pretty.go +++ b/usr/gri/pretty/pretty.go @@ -5,7 +5,8 @@ package main import ( - Flag "flag"; + "os"; + "flag"; Platform "platform"; Printer "printer"; Compilation "compilation"; @@ -14,35 +15,36 @@ import ( var ( flags Compilation.Flags; - silent = Flag.Bool("s", false, "silent mode: no pretty print output"); + silent = flag.Bool("s", false, "silent mode: no pretty print output"); + html = flag.Bool("html", false, "generate html"); ) func init() { - Flag.BoolVar(&flags.Verbose, "v", false, "verbose mode: trace parsing"); - Flag.BoolVar(&flags.Sixg, "6g", true, "6g compatibility mode"); - Flag.BoolVar(&flags.Deps, "d", false, "print dependency information only"); - Flag.BoolVar(&flags.Columns, "columns", Platform.USER == "gri", "print column info in error messages"); - Flag.BoolVar(&flags.Testmode, "t", false, "test mode: interprets /* ERROR */ and /* SYNC */ comments"); + flag.BoolVar(&flags.Verbose, "v", false, "verbose mode: trace parsing"); + flag.BoolVar(&flags.Sixg, "6g", true, "6g compatibility mode"); + flag.BoolVar(&flags.Deps, "d", false, "print dependency information only"); + flag.BoolVar(&flags.Columns, "columns", Platform.USER == "gri", "print column info in error messages"); + flag.BoolVar(&flags.Testmode, "t", false, "test mode: interprets /* ERROR */ and /* SYNC */ comments"); } func usage() { print("usage: pretty { flags } { files }\n"); - Flag.PrintDefaults(); + flag.PrintDefaults(); sys.Exit(0); } func main() { - Flag.Parse(); + flag.Parse(); - if Flag.NFlag() == 0 && Flag.NArg() == 0 { + if flag.NFlag() == 0 && flag.NArg() == 0 { usage(); } // process files - for i := 0; i < Flag.NArg(); i++ { - src_file := Flag.Arg(i); + for i := 0; i < flag.NArg(); i++ { + src_file := flag.Arg(i); if flags.Deps { Compilation.ComputeDeps(src_file, &flags); @@ -56,7 +58,7 @@ func main() { sys.Exit(1); } if !*silent && !flags.Testmode { - Printer.Print(prog); + Printer.Print(os.Stdout, *html, prog); } } } diff --git a/usr/gri/pretty/printer.go b/usr/gri/pretty/printer.go index d69833d94a..a985e6abc1 100644 --- a/usr/gri/pretty/printer.go +++ b/usr/gri/pretty/printer.go @@ -28,7 +28,6 @@ var ( maxnewlines = flag.Int("maxnewlines", 3, "max. number of consecutive newlines"); // formatting control - html = flag.Bool("html", false, "generate html"); comments = flag.Bool("comments", true, "print comments"); optsemicolons = flag.Bool("optsemicolons", false, "print optional semicolons"); ) @@ -79,6 +78,9 @@ const ( type Printer struct { // output text io.Write; + + // formatting control + html bool; // comments comments *array.Array; // the list of all comments @@ -118,9 +120,12 @@ func (P *Printer) NextComment() { } -func (P *Printer) Init(text io.Write, comments *array.Array) { +func (P *Printer) Init(text io.Write, html bool, comments *array.Array) { // writers P.text = text; + + // formatting control + P.html = html; // comments P.comments = comments; @@ -137,8 +142,8 @@ func (P *Printer) Init(text io.Write, comments *array.Array) { // ---------------------------------------------------------------------------- // Printing support -func htmlEscape(s string) string { - if *html { +func (P *Printer) htmlEscape(s string) string { + if P.html { var esc string; for i := 0; i < len(s); i++ { switch s[i] { @@ -146,7 +151,7 @@ func htmlEscape(s string) string { case '&': esc = "&"; default: continue; } - return s[0 : i] + esc + htmlEscape(s[i+1 : len(s)]); + return s[0 : i] + esc + P.htmlEscape(s[i+1 : len(s)]); } } return s; @@ -291,7 +296,7 @@ func (P *Printer) TaggedString(pos int, tag, s, endtag string) { } // calling untabify increases the change for idempotent output // since tabs in comments are also interpreted by tabwriter - P.Printf("%s", htmlEscape(untabify(ctext))); + P.Printf("%s", P.htmlEscape(untabify(ctext))); if ctext[1] == '/' { //-style comments must end in newline @@ -337,7 +342,7 @@ func (P *Printer) TaggedString(pos int, tag, s, endtag string) { if *debug { P.Printf("[%d]", pos); } - P.Printf("%s%s%s", tag, htmlEscape(s), endtag); + P.Printf("%s%s%s", tag, P.htmlEscape(s), endtag); // -------------------------------- // interpret state @@ -368,6 +373,7 @@ func (P *Printer) String(pos int, s string) { func (P *Printer) Token(pos int, tok int) { P.String(pos, Scanner.TokenString(tok)); + //P.TaggedString(pos, "", Scanner.TokenString(tok), ""); } @@ -381,12 +387,12 @@ func (P *Printer) Error(pos int, tok int, msg string) { // HTML support func (P *Printer) HtmlPrologue(title string) { - if *html { + if P.html { P.TaggedString(0, "\n" "\n" " \n" - " " + htmlEscape(title) + "\n" + " " + P.htmlEscape(title) + "\n" " \n" "\n" @@ -399,7 +405,7 @@ func (P *Printer) HtmlPrologue(title string) { func (P *Printer) HtmlEpilogue() { - if *html { + if P.html { P.TaggedString(0, "\n" "\n" @@ -412,7 +418,7 @@ func (P *Printer) HtmlEpilogue() { func (P *Printer) HtmlIdentifier(x *AST.Ident) { obj := x.Obj; - if *html && obj.Kind != SymbolTable.NONE { + if P.html && obj.Kind != SymbolTable.NONE { // depending on whether we have a declaration or use, generate different html // - no need to htmlEscape ident id := Utils.IntToString(obj.Id, 10); @@ -429,6 +435,17 @@ func (P *Printer) HtmlIdentifier(x *AST.Ident) { } +func (P *Printer) HtmlPackageName(pos int, name string) { + if P.html { + sname := name[1 : len(name)-1]; // strip quotes TODO do this elsewhere eventually + // TODO CAPITAL HACK BELOW FIX THIS + P.TaggedString(pos, `"`, sname, `"`); + } else { + P.String(pos, name); + } +} + + // ---------------------------------------------------------------------------- // Types @@ -841,12 +858,12 @@ func (P *Printer) ControlClause(isForStat bool, init AST.Stat, expr AST.Expr, po func (P *Printer) DoIfStat(s *AST.IfStat) { - P.String(s.Pos, "if"); + P.Token(s.Pos, Scanner.IF); P.ControlClause(false, s.Init, s.Cond, nil); P.Block(s.Body, true); if s.Else != nil { P.separator = blank; - P.String(0, "else"); + P.Token(0, Scanner.ELSE); P.separator = blank; P.Stat(s.Else); } @@ -854,7 +871,7 @@ func (P *Printer) DoIfStat(s *AST.IfStat) { func (P *Printer) DoForStat(s *AST.ForStat) { - P.String(s.Pos, "for"); + P.Token(s.Pos, Scanner.FOR); P.ControlClause(true, s.Init, s.Cond, s.Post); P.Block(s.Body, true); } @@ -862,11 +879,11 @@ func (P *Printer) DoForStat(s *AST.ForStat) { func (P *Printer) DoCaseClause(s *AST.CaseClause) { if s.Expr != nil { - P.String(s.Pos, "case"); + P.Token(s.Pos, Scanner.CASE); P.separator = blank; P.Expr(s.Expr); } else { - P.String(s.Pos, "default"); + P.Token(s.Pos, Scanner.DEFAULT); } // TODO: try to use P.Block instead // P.Block(s.Body, true); @@ -879,14 +896,14 @@ func (P *Printer) DoCaseClause(s *AST.CaseClause) { func (P *Printer) DoSwitchStat(s *AST.SwitchStat) { - P.String(s.Pos, "switch"); + P.Token(s.Pos, Scanner.SWITCH); P.ControlClause(false, s.Init, s.Tag, nil); P.Block(s.Body, false); } func (P *Printer) DoSelectStat(s *AST.SelectStat) { - P.String(s.Pos, "select"); + P.Token(s.Pos, Scanner.SELECT); P.separator = blank; P.Block(s.Body, false); } @@ -940,7 +957,13 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { P.String(d.Val.Pos(), ""); // flush pending ';' separator/newlines } P.separator = tab; - P.Expr(d.Val); + if lit, is_lit := d.Val.(*AST.BasicLit); is_lit && lit.Tok == Scanner.STRING { + P.HtmlPackageName(lit.Pos(), lit.Val); + } else { + // we should only reach here for strange imports + // import "foo" "bar" + P.Expr(d.Val); + } P.separator = semicolon; case Scanner.TYPE: @@ -1002,15 +1025,15 @@ func (P *Printer) Program(p *AST.Program) { // ---------------------------------------------------------------------------- // External interface -func Print(prog *AST.Program) { +func Print(writer io.Write, html bool, prog *AST.Program) { // setup var P Printer; padchar := byte(' '); if *usetabs { padchar = '\t'; } - text := tabwriter.New(os.Stdout, *tabwidth, 1, padchar, true, *html); - P.Init(text, prog.Comments); + text := tabwriter.New(writer, *tabwidth, 1, padchar, true, html); + P.Init(text, html, prog.Comments); // TODO would be better to make the name of the src file be the title P.HtmlPrologue("package " + prog.Ident.(*AST.Ident).Obj.Ident); -- 2.48.1