]> Cypherpunks repositories - gostls13.git/commitdiff
snapshot:
authorRobert Griesemer <gri@golang.org>
Fri, 6 Feb 2009 23:26:30 +0000 (15:26 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 6 Feb 2009 23:26:30 +0000 (15:26 -0800)
- 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
usr/gri/pretty/compilation.go
usr/gri/pretty/gds.go [new file with mode: 0644]
usr/gri/pretty/pretty.go
usr/gri/pretty/printer.go

index ebf75218edad663da58030e16f08abd1450c6d96..a3b99ef928b98ee3ff1b32ea9c6d24306be31d1f 100644 (file)
@@ -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
index fa87d28d1b15c2b29128cadd574b2661f3c0d33b..498175cad486ef2bd086fda014ea96abf5e3bc97 100644 (file)
@@ -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 (file)
index 0000000..cdf2c7d
--- /dev/null
@@ -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())
+       }
+}
+
index 96e57f7a9c5653f636fd700be1132f113b9db9c9..a61e4f980ffa670c07dcded917b6e4401a67339f 100644 (file)
@@ -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);
                        }
                }
        }
index d69833d94a178860e959bbe4908f18ce6d319e83..a985e6abc11725486812e7336541a6f07baac17f 100644 (file)
@@ -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 = "&amp;";
                        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, "<b>", Scanner.TokenString(tok), "</b>");
 }
 
 
@@ -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,
                        "<html>\n"
                        "<head>\n"
                        "       <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">\n"
-                       "       <title>" + htmlEscape(title) + "</title>\n"
+                       "       <title>" + P.htmlEscape(title) + "</title>\n"
                        "       <style type=\"text/css\">\n"
                        "       </style>\n"
                        "</head>\n"
@@ -399,7 +405,7 @@ func (P *Printer) HtmlPrologue(title string) {
 
 
 func (P *Printer) HtmlEpilogue() {
-       if *html {
+       if P.html {
                P.TaggedString(0,
                        "</pre>\n"
                        "</body>\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, `"<a href="http://localhost:6060/gds/src/lib/` + sname + `.go">`, sname, `</a>"`);
+       } 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);