x/ref: Add vdl "file doc", used to insert the copyright header.
This fixes issue:
https://github.com/veyron/release-issues/issues/1599
Before this change, the vdl tool would automatically include the
vanadium copyright header in all generated files. This means
that users would also get the copyright header in their generated
files, which is wrong.
After this change, we introduce the notion of "file doc" in each
*.vdl file, which is the comment block that starts on line 1 of
the file, as long as it isn't the package doc. We require that
all files in a vdl package have the same file doc, otherwise we
return a compilation error. This makes it easier for java and
javascript, which generate files that don't match 1-to-1 with the
source *.vdl files.
The code generators have been updated to use this file doc when
generating their respective files.
Change-Id: Id53e1a37012d6ff29718753aa0ceb947c9ac43d8
diff --git a/lib/vdl/codegen/golang/gen.go b/lib/vdl/codegen/golang/gen.go
index 73a32eb..e7b3ff5 100644
--- a/lib/vdl/codegen/golang/gen.go
+++ b/lib/vdl/codegen/golang/gen.go
@@ -405,9 +405,7 @@
const genGo = `
{{$data := .}}
{{$file := $data.File}}
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
+{{$file.Package.FileDoc}}
// This file was auto-generated by the vanadium vdl tool.
// Source: {{$file.BaseName}}
diff --git a/lib/vdl/codegen/java/const.go b/lib/vdl/codegen/java/const.go
index 3ffbaec..f572908 100644
--- a/lib/vdl/codegen/java/const.go
+++ b/lib/vdl/codegen/java/const.go
@@ -4,10 +4,9 @@
package java
-const header = `
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
+// The data passed into every template must include a FileDoc field, which
+// contains the comment for each generated file; e.g. the boilerplate copyright
+// header.
+const header = `{{.FileDoc}}
// This file was auto-generated by the vanadium vdl tool.
`
diff --git a/lib/vdl/codegen/java/file_array.go b/lib/vdl/codegen/java/file_array.go
index 35e3330..4812cd1 100644
--- a/lib/vdl/codegen/java/file_array.go
+++ b/lib/vdl/codegen/java/file_array.go
@@ -62,6 +62,7 @@
elems := strings.TrimSuffix(strings.Repeat(javaZeroValue(tdef.Type.Elem(), env)+", ", tdef.Type.Len()), ", ")
zeroValue := fmt.Sprintf("new %s[] {%s}", elemType, elems)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
ElemType string
@@ -75,6 +76,7 @@
VdlTypeString string
ZeroValue string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
ElemType: elemType,
diff --git a/lib/vdl/codegen/java/file_client_factory.go b/lib/vdl/codegen/java/file_client_factory.go
index ecb90e2..626c5e0 100644
--- a/lib/vdl/codegen/java/file_client_factory.go
+++ b/lib/vdl/codegen/java/file_client_factory.go
@@ -37,12 +37,14 @@
func genJavaClientFactoryFile(iface *compile.Interface, env *compile.Env) JavaFileInfo {
javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
data := struct {
+ FileDoc string
AccessModifier string
Sources string
ServiceName string
PackagePath string
StubName string
}{
+ FileDoc: iface.File.Package.FileDoc,
AccessModifier: accessModifierForName(iface.Name),
Sources: iface.File.BaseName,
ServiceName: javaServiceName,
diff --git a/lib/vdl/codegen/java/file_client_interface.go b/lib/vdl/codegen/java/file_client_interface.go
index e504708..c71f60e 100644
--- a/lib/vdl/codegen/java/file_client_interface.go
+++ b/lib/vdl/codegen/java/file_client_interface.go
@@ -100,6 +100,7 @@
methods[i] = processClientInterfaceMethod(iface, method, env)
}
data := struct {
+ FileDoc string
AccessModifier string
Extends string
Methods []clientInterfaceMethod
@@ -108,6 +109,7 @@
ServiceName string
Source string
}{
+ FileDoc: iface.File.Package.FileDoc,
AccessModifier: accessModifierForName(iface.Name),
Extends: javaClientExtendsStr(iface.Embeds),
Methods: methods,
diff --git a/lib/vdl/codegen/java/file_client_stub.go b/lib/vdl/codegen/java/file_client_stub.go
index 9e3b6c4..a7275a2 100644
--- a/lib/vdl/codegen/java/file_client_stub.go
+++ b/lib/vdl/codegen/java/file_client_stub.go
@@ -252,6 +252,7 @@
}
javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
data := struct {
+ FileDoc string
AccessModifier string
EmbedMethods []clientStubEmbedMethod
Embeds []clientStubEmbed
@@ -262,6 +263,7 @@
Source string
VDLIfacePathName string
}{
+ FileDoc: iface.File.Package.FileDoc,
AccessModifier: accessModifierForName(iface.Name),
EmbedMethods: embedMethods,
Embeds: embeds,
diff --git a/lib/vdl/codegen/java/file_complex.go b/lib/vdl/codegen/java/file_complex.go
index 2f9a5a6..7d4e382 100644
--- a/lib/vdl/codegen/java/file_complex.go
+++ b/lib/vdl/codegen/java/file_complex.go
@@ -55,6 +55,7 @@
}
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
Name string
@@ -65,6 +66,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
Name: javaTypeName,
diff --git a/lib/vdl/codegen/java/file_constants.go b/lib/vdl/codegen/java/file_constants.go
index a4ba956..2ea6a90 100644
--- a/lib/vdl/codegen/java/file_constants.go
+++ b/lib/vdl/codegen/java/file_constants.go
@@ -76,11 +76,13 @@
}
data := struct {
+ FileDoc string
ClassName string
Source string
PackagePath string
Files []constFile
}{
+ FileDoc: pkg.FileDoc,
ClassName: className,
Source: javaFileNames(pkg.Files),
PackagePath: javaPath(javaGenPkgPath(pkg.GenPath)),
diff --git a/lib/vdl/codegen/java/file_enum.go b/lib/vdl/codegen/java/file_enum.go
index af2c036..50c9752 100644
--- a/lib/vdl/codegen/java/file_enum.go
+++ b/lib/vdl/codegen/java/file_enum.go
@@ -58,6 +58,7 @@
}
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
EnumLabels []string
Doc string
@@ -67,6 +68,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
EnumLabels: labels,
Doc: javaDocInComment(tdef.Doc),
diff --git a/lib/vdl/codegen/java/file_errors.go b/lib/vdl/codegen/java/file_errors.go
index b140d44..cd43dff 100644
--- a/lib/vdl/codegen/java/file_errors.go
+++ b/lib/vdl/codegen/java/file_errors.go
@@ -124,11 +124,13 @@
}
data := struct {
+ FileDoc string
ClassName string
Source string
PackagePath string
Files []errorFile
}{
+ FileDoc: pkg.FileDoc,
ClassName: className,
Source: javaFileNames(pkg.Files),
PackagePath: javaPath(javaGenPkgPath(pkg.GenPath)),
diff --git a/lib/vdl/codegen/java/file_list.go b/lib/vdl/codegen/java/file_list.go
index 79c409c..06d4c54 100644
--- a/lib/vdl/codegen/java/file_list.go
+++ b/lib/vdl/codegen/java/file_list.go
@@ -40,6 +40,7 @@
func genJavaListFile(tdef *compile.TypeDef, env *compile.Env) JavaFileInfo {
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
ElemType string
@@ -49,6 +50,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
ElemType: javaType(tdef.Type.Elem(), true, env),
diff --git a/lib/vdl/codegen/java/file_map.go b/lib/vdl/codegen/java/file_map.go
index bb506f8..073cebb 100644
--- a/lib/vdl/codegen/java/file_map.go
+++ b/lib/vdl/codegen/java/file_map.go
@@ -41,6 +41,7 @@
func genJavaMapFile(tdef *compile.TypeDef, env *compile.Env) JavaFileInfo {
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
ElemType string
@@ -51,6 +52,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
ElemType: javaType(tdef.Type.Elem(), true, env),
diff --git a/lib/vdl/codegen/java/file_package_info.go b/lib/vdl/codegen/java/file_package_info.go
index ac8c253..2e94276 100644
--- a/lib/vdl/codegen/java/file_package_info.go
+++ b/lib/vdl/codegen/java/file_package_info.go
@@ -31,10 +31,12 @@
generated = true
data := struct {
+ FileDoc string
Source string
PackagePath string
Doc string
}{
+ FileDoc: pkg.FileDoc,
Source: javaFileNames(pkg.Files),
PackagePath: javaPath(javaGenPkgPath(pkg.GenPath)),
Doc: javaDoc(file.PackageDef.Doc),
diff --git a/lib/vdl/codegen/java/file_primitive.go b/lib/vdl/codegen/java/file_primitive.go
index 295beef..cc167a6 100644
--- a/lib/vdl/codegen/java/file_primitive.go
+++ b/lib/vdl/codegen/java/file_primitive.go
@@ -73,6 +73,7 @@
func genJavaPrimitiveFile(tdef *compile.TypeDef, env *compile.Env) JavaFileInfo {
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
Name string
@@ -84,6 +85,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
Name: javaTypeName,
diff --git a/lib/vdl/codegen/java/file_server_interface.go b/lib/vdl/codegen/java/file_server_interface.go
index 6a9d3fc..04b9546 100644
--- a/lib/vdl/codegen/java/file_server_interface.go
+++ b/lib/vdl/codegen/java/file_server_interface.go
@@ -73,6 +73,7 @@
}
javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
data := struct {
+ FileDoc string
AccessModifier string
Extends string
Methods []serverInterfaceMethod
@@ -83,6 +84,7 @@
ServerWrapperPath string
Source string
}{
+ FileDoc: iface.File.Package.FileDoc,
AccessModifier: accessModifierForName(iface.Name),
Extends: javaServerExtendsStr(iface.Embeds),
Methods: methods,
diff --git a/lib/vdl/codegen/java/file_server_wrapper.go b/lib/vdl/codegen/java/file_server_wrapper.go
index e461085..401a864 100644
--- a/lib/vdl/codegen/java/file_server_wrapper.go
+++ b/lib/vdl/codegen/java/file_server_wrapper.go
@@ -247,6 +247,7 @@
}
javaServiceName := vdlutil.FirstRuneToUpper(iface.Name)
data := struct {
+ FileDoc string
AccessModifier string
EmbedMethods []serverWrapperEmbedMethod
Embeds []serverWrapperEmbed
@@ -258,6 +259,7 @@
Source string
Doc string
}{
+ FileDoc: iface.File.Package.FileDoc,
AccessModifier: accessModifierForName(iface.Name),
EmbedMethods: embedMethods,
Embeds: embeds,
diff --git a/lib/vdl/codegen/java/file_set.go b/lib/vdl/codegen/java/file_set.go
index 08e9c95..3547163 100644
--- a/lib/vdl/codegen/java/file_set.go
+++ b/lib/vdl/codegen/java/file_set.go
@@ -41,6 +41,7 @@
func genJavaSetFile(tdef *compile.TypeDef, env *compile.Env) JavaFileInfo {
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
KeyType string
@@ -50,6 +51,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
KeyType: javaType(tdef.Type.Key(), true, env),
diff --git a/lib/vdl/codegen/java/file_struct.go b/lib/vdl/codegen/java/file_struct.go
index 77a974f..e2083e2 100644
--- a/lib/vdl/codegen/java/file_struct.go
+++ b/lib/vdl/codegen/java/file_struct.go
@@ -166,6 +166,7 @@
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
Fields []structDefinitionField
@@ -176,6 +177,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
Fields: fields,
diff --git a/lib/vdl/codegen/java/file_union.go b/lib/vdl/codegen/java/file_union.go
index aca10b3..14b6d45 100644
--- a/lib/vdl/codegen/java/file_union.go
+++ b/lib/vdl/codegen/java/file_union.go
@@ -82,6 +82,7 @@
}
javaTypeName := vdlutil.FirstRuneToUpper(tdef.Name)
data := struct {
+ FileDoc string
AccessModifier string
Doc string
Fields []unionDefinitionField
@@ -91,6 +92,7 @@
VdlTypeName string
VdlTypeString string
}{
+ FileDoc: tdef.File.Package.FileDoc,
AccessModifier: accessModifierForName(tdef.Name),
Doc: javaDocInComment(tdef.Doc),
Fields: fields,
diff --git a/lib/vdl/codegen/javascript/gen.go b/lib/vdl/codegen/javascript/gen.go
index c213899..6403d4d 100644
--- a/lib/vdl/codegen/javascript/gen.go
+++ b/lib/vdl/codegen/javascript/gen.go
@@ -390,11 +390,7 @@
// complicated logic is delegated to the helper functions above.
//
// We try to generate code that has somewhat reasonable formatting.
-const genJS = `// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-{{with $data := .}}
+const genJS = `{{with $data := .}}{{$data.Pkg.FileDoc}}
// This file was auto-generated by the vanadium vdl tool.
{{generateSystemImports $data}}
diff --git a/lib/vdl/compile/compile.go b/lib/vdl/compile/compile.go
index 2ce4696..feab45f 100644
--- a/lib/vdl/compile/compile.go
+++ b/lib/vdl/compile/compile.go
@@ -123,6 +123,9 @@
// Compile our various structures. The order of these operations matters;
// e.g. we must compile types before consts, since consts may use a type
// defined in this package.
+ if compileFileDoc(pkg, pfiles, env); !env.Errors.IsEmpty() {
+ return nil
+ }
if compileImports(pkg, pfiles, env); !env.Errors.IsEmpty() {
return nil
}
@@ -141,6 +144,23 @@
return pkg
}
+func compileFileDoc(pkg *Package, pfiles []*parse.File, env *Env) {
+ for index := range pfiles {
+ file, pfile := pkg.Files[index], pfiles[index]
+ if index == 0 {
+ pkg.FileDoc = pfile.Doc
+ } else if pkg.FileDoc != pfile.Doc {
+ // We force all file-doc to be the same, since *.vdl files aren't 1-to-1
+ // with the generated files in each language, e.g. Java creates one file
+ // per class, while Javascript creates a single file for the entire
+ // package. For the common-case where we use file-doc for copyright
+ // headers, it also prevents the user from accidentally adding copyright
+ // headers to one file but not another, in the same package.
+ env.Errorf(file, parse.Pos{1, 1}, "all files in a package must have the same file doc (the comment on the first line of each *.vdl file that isn't package doc)")
+ }
+ }
+}
+
func compileImports(pkg *Package, pfiles []*parse.File, env *Env) {
for index := range pfiles {
file, pfile := pkg.Files[index], pfiles[index]
diff --git a/lib/vdl/compile/result.go b/lib/vdl/compile/result.go
index b30437e..3de65f8 100644
--- a/lib/vdl/compile/result.go
+++ b/lib/vdl/compile/result.go
@@ -257,6 +257,10 @@
GenPath string
// Files holds the files contained in the package.
Files []*File
+ // FileDoc holds the top-level file documentation, which must be the same for
+ // every file in the package. This is typically used to hold boilerplate that
+ // must appear in every generated file, e.g. a copyright notice.
+ FileDoc string
// Config holds the configuration for this package, specifying options used
// during compilation and code generation.
Config vdltool.Config
diff --git a/lib/vdl/parse/COPYRIGHT b/lib/vdl/parse/COPYRIGHT
deleted file mode 100644
index d3e8617..0000000
--- a/lib/vdl/parse/COPYRIGHT
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
diff --git a/lib/vdl/parse/grammar_gen.sh b/lib/vdl/parse/grammar_gen.sh
index a67ae64..dad7b5f 100755
--- a/lib/vdl/parse/grammar_gen.sh
+++ b/lib/vdl/parse/grammar_gen.sh
@@ -12,7 +12,12 @@
go tool yacc -o grammar.y.tmp.go -v grammar.y.debug.tmp grammar.y
gofmt -l -w grammar.y.tmp.go
-cat - COPYRIGHT grammar.y.tmp.go > grammar.y.go
+cat - grammar.y.tmp.go > grammar.y.go <<EOF
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+EOF
cat - grammar.y.debug.tmp > grammar.y.debug <<EOF
***** PLEASE READ THIS! DO NOT DELETE THIS BLOCK! *****
* The main reason this file has been generated and submitted is to try to ensure
diff --git a/lib/vdl/parse/parse.go b/lib/vdl/parse/parse.go
index aa38c43..ab74c83 100644
--- a/lib/vdl/parse/parse.go
+++ b/lib/vdl/parse/parse.go
@@ -65,6 +65,7 @@
}
config := &Config{
FileName: fileName,
+ Doc: file.Doc,
ConfigDef: file.PackageDef,
Imports: file.Imports,
Config: file.ConstDefs[0].Expr,
@@ -404,7 +405,7 @@
// getDocSuffix returns the suffix documentation associated with pos. Our rule
// is the first line of the documentation must be on the same line as pos. Once
-// a comment block as been returned it isn't eligible to be attached to any
+// a comment block has been returned it isn't eligible to be attached to any
// other item, and is deleted from the map.
//
// The returned string is either empty, or has a leading space.
@@ -419,6 +420,24 @@
return doc
}
+// getFileDoc returns the file documentation. Our rule is that the first line
+// of the documentation must occur on the first line of the file, and all other
+// comments must have already been attached. Once a comment block has been
+// returned it isn't eligible to be attached to any other item, and is deleted
+// from the map.
+//
+// The returned string is either empty, or is newline terminated.
+func (cm *commentMap) getFileDoc() string {
+ block := cm.byFirst[1]
+ if block.text == "" {
+ return ""
+ }
+ doc := block.text + "\n"
+ delete(cm.byFirst, block.firstLine)
+ delete(cm.byLast, block.lastLine)
+ return doc
+}
+
func attachTypeComments(t Type, cm *commentMap, suffix bool) {
switch tu := t.(type) {
case *TypeEnum:
@@ -518,6 +537,8 @@
y.Doc = l.comments.getDoc(y.Pos)
}
}
+ // Finally attach the top-level file doc - this occurs on the first line.
+ f.Doc = l.comments.getFileDoc()
}
// nextToken uses the text/scanner package to scan the input for the next token.
diff --git a/lib/vdl/parse/parse_test.go b/lib/vdl/parse/parse_test.go
index 1e6dcfa..0b84e89 100644
--- a/lib/vdl/parse/parse_test.go
+++ b/lib/vdl/parse/parse_test.go
@@ -174,11 +174,19 @@
`}},
nil},
{
- "NotPackageDoc",
- `// Extra newline, not package doc
+ "FileDocNoPackageDoc",
+ `// File doc, has extra newline so not package doc
package testpkg`,
- &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 3, 9)},
+ &parse.File{BaseName: "testfile", PackageDef: np("testpkg", 3, 9), Doc: "// File doc, has extra newline so not package doc\n"},
+ nil},
+ {
+ "FileDocAndPackageDoc",
+ `// File doc
+
+// Package doc
+package testpkg`,
+ &parse.File{BaseName: "testfile", PackageDef: parse.NamePos{Name: "testpkg", Pos: pos(4, 9), Doc: "// Package doc\n"}, Doc: "// File doc\n"},
nil},
{
"FAILUnterminatedComment",
@@ -1050,14 +1058,25 @@
Config: cn("true", 4, 10)},
nil},
{
- "NotConfigDoc",
- `// Extra newline, not config doc
+ "FileDocNoConfigDoc",
+ `// File doc, has extra newline so not config doc
config = true`,
&parse.Config{FileName: "testfile", ConfigDef: np("config", 3, 1),
+ Doc: "// File doc, has extra newline so not config doc\n",
Config: cn("true", 3, 10)},
nil},
{
+ "FileDocAndConfigDoc",
+ `// File doc
+
+// Config doc
+config = true`,
+ &parse.Config{FileName: "testfile", ConfigDef: parse.NamePos{Name: "config", Pos: pos(4, 1), Doc: "// Config doc\n"},
+ Doc: "// File doc\n",
+ Config: cn("true", 4, 10)},
+ nil},
+ {
"FAILUnterminatedComment",
`/* Unterminated
Another line
diff --git a/lib/vdl/parse/result.go b/lib/vdl/parse/result.go
index 234154f..bdb71bb 100644
--- a/lib/vdl/parse/result.go
+++ b/lib/vdl/parse/result.go
@@ -59,8 +59,9 @@
// File represents a parsed vdl file.
type File struct {
BaseName string // Base name of the vdl file, e.g. "foo.vdl"
+ Doc string // Top-level file documentation
PackageDef NamePos // Name, position and docs of the "package" clause
- Imports []*Import // Imports listed in this file.
+ Imports []*Import // Imports listed in this file
ErrorDefs []*ErrorDef // Errors defined in this file
TypeDefs []*TypeDef // Types defined in this file
ConstDefs []*ConstDef // Consts defined in this file
@@ -71,6 +72,7 @@
// vdl files, with similar concepts.
type Config struct {
FileName string // Config file name, e.g. "a/b/foo.config"
+ Doc string // Top-level config file documentation
ConfigDef NamePos // Name, position and docs of the "config" clause
Imports []*Import // Imports listed in this file.
Config ConstExpr // Const expression exported from this config.