// 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. // Format file for printing AST nodes. ast "ast"; token "token"; // ---------------------------------------------------------------------------- // Basic types, support rules array = *; ptr = *; string = "%s"; char = "%c"; bytes = {*}; empty = ; exists = *:empty; ast.Expr = *; ast.Stmt = *; ast.Decl = *; // ---------------------------------------------------------------------------- // Tokens and comments token.Token = @:string; ast.Comment = // TODO this doesn't indent properly after //-style comments because // the '\n'-char is printed as part of the comment - need to // address this Text:string [Text:isMultiLineComment "\n"]; ast.Comments = {*}; // ---------------------------------------------------------------------------- // Expressions & Types ast.Field = [Names:exists {Names / ", "} " "] Type; ast.BadExpr = "BAD EXPR"; ast.Ident = Value; ast.Ellipsis = "..."; ast.IntLit = Value:string; ast.FloatLit = Value:string; ast.CharLit = Value:string; ast.StringLit = Value:string; ast.StringList = {Strings / "\n"}; ast.FuncLit = Type " " Body @:clearOptSemi; // no optional ; after a func literal body ast.CompositeLit = Type "{" {Elts / ", "} "}"; ast.ParenExpr = "(" X ")"; ast.SelectorExpr = X "." Sel; ast.IndexExpr = X "[" Index [":" End] "]"; ast.TypeAssertExpr = X ".(" Type ")"; ast.CallExpr = Fun "(" {Args / ", "} ")"; ast.StarExpr = "*" X; ast.UnaryExpr = Op X; ast.BinaryExpr = X " " Op " " Y; ast.KeyValueExpr = Key ": " Value; ast.ArrayType = "[" [Len] "]" Elt; ast.StructType = "struct" [Lbrace:isValidPos " {"] [ Fields:exists ( "\t" >> "\n" {Fields / ";\n"} ) "\n" ] [Rbrace:isValidPos "}"]; signature = "(" {Params / ", "} ")" [Results:exists " (" {Results / ", "} ")"]; funcSignature = *:signature; ast.FuncType = [Position:isValidPos "func"] @:signature; ast.InterfaceType = "interface" [Lbrace:isValidPos " {"] [ Methods:exists ( "\t" >> "\n" {Methods / ";\n"} ) "\n" ] [Rbrace:isValidPos "}"]; ast.MapType = "map[" Key "]" Value; ast.ChanType = ( Dir:isSend Dir:isRecv "chan " | Dir:isSend "chan <- " | "<-chan " ) Value; // ---------------------------------------------------------------------------- // Statements ast.BadStmt = "BAD STMT"; ast.DeclStmt = Decl; ast.EmptyStmt = ; ast.LabeledStmt = Label ":\t" Stmt; ast.ExprStmt = X; ast.IncDecStmt = X Tok; ast.AssignStmt = {Lhs / ", "} " " Tok " " {Rhs / ", "}; ast.GoStmt = "go " Call; ast.DeferStmt = "defer " Call; ast.ReturnStmt = "return" {" " Results / ","}; ast.BranchStmt = Tok [" " Label]; stmtList = {@ / @:optSemi "\n"}; blockStmt = // like ast.BlockStmt but w/o indentation "{" [List:exists "\n" List:stmtList "\n" ] "}" @:setOptSemi; blockStmtPtr = *:blockStmt; ast.BlockStmt = "{" [List:exists ( "\t" >> "\n" List:stmtList ) "\n" ] "}" @:setOptSemi; ast.IfStmt = "if " [Init "; "] [Cond " "] Body [" else " Else]; ast.CaseClause = ( Values:exists "case " {Values / ", "} | "default" ) ":" [Body:exists ( "\t" >> "\n" Body:stmtList ) ]; ast.SwitchStmt = "switch " [Init "; "] [Tag " "] Body:blockStmtPtr; ast.TypeCaseClause = ( Type:exists "case " Type | "default" ) ":" [Body:exists ( "\t" >> "\n" Body:stmtList ) ]; ast.TypeSwitchStmt = "switch " Assign " " Body:blockStmtPtr; ast.CommClause = ( "case " [Lhs " " Tok " "] Rhs | "default" ) ":" [Body:exists ( "\t" >> "\n" Body:stmtList ) ]; ast.SelectStmt = "select " Body:blockStmtPtr; ast.ForStmt = "for " [ (Init:exists | Post:exists) [Init] "; " [Cond] "; " [Post " "] | Cond " " ] Body; ast.RangeStmt = "for " Key [", " Value] " " Tok " range " X " " Body; // ---------------------------------------------------------------------------- // Declarations ast.Spec = *; ast.ImportSpec = Doc [Name] "\t" {Path}; ast.ValueSpec = {Names / ", "} [" " Type] [Values:exists " = " {Values / ", "}]; ast.TypeSpec = Name " " // TODO using "\t" instead of " " screws up struct field alignment Type; ast.BadDecl = "BAD DECL"; ast.GenDecl = Doc Tok " " ( Lparen:isValidPos "(" [Specs:exists ( "\t" >> "\n" {Specs / ";\n"} ) "\n" ] ")" @:setOptSemi | {Specs / ";\n"} ); ast.FuncDecl = "func " ["(" Recv ") "] Name Type:funcSignature [" " Body] "\n"; // ---------------------------------------------------------------------------- // Program ast.Program = Doc "package " Name "\n\n" {Decls / "\n\n"};