Move all section handling to its own file automerge: f7e9207
automerge: e2cd612
* commit 'e2cd6126884f90ef06ad7c1d9de82da0e91a744c':
Move all section handling to its own file
diff --git a/tools/codergen/template/functions.go b/tools/codergen/template/functions.go
index 7be15dc..1771817 100644
--- a/tools/codergen/template/functions.go
+++ b/tools/codergen/template/functions.go
@@ -16,12 +16,9 @@
import (
"fmt"
- "io"
- "strconv"
"strings"
"android.googlesource.com/platform/tools/gpu/binary/schema"
- "android.googlesource.com/platform/tools/gpu/reflow"
)
type variable struct {
@@ -44,18 +41,6 @@
return "", tmpl.Execute(t.writer, arg)
}
-func (t *Templates) Section(name string) (string, error) {
- w, ok := t.writer.(*reflow.Writer)
- if !ok {
- return "", fmt.Errorf("Section called inside nested writer")
- }
- depth := strconv.Itoa(w.Depth)
- io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionStart, name, depth))
- err := t.execute(name, t.writer, t.File)
- io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionEnd, name, depth))
- return "", err
-}
-
func (*Templates) Lower(s interface{}) string {
return strings.ToLower(fmt.Sprint(s))
}
diff --git a/tools/codergen/template/section.go b/tools/codergen/template/section.go
new file mode 100644
index 0000000..b62e7b0
--- /dev/null
+++ b/tools/codergen/template/section.go
@@ -0,0 +1,123 @@
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "regexp"
+ "strconv"
+
+ "android.googlesource.com/platform/tools/gpu/reflow"
+)
+
+const (
+ sectionMarker = `<<<%s:%s:%s>>>`
+ sectionStart = `Start`
+ sectionEnd = `End`
+ sectionParameter = `([^\:>]+)`
+)
+
+var (
+ section = regexp.MustCompile(fmt.Sprintf(sectionMarker, sectionParameter, sectionParameter, sectionParameter))
+)
+
+// Section writes a new file section with associated templates.
+// It takes the name of the template to use to fill the section in, and wraps it
+// in the section markers.
+func (t *Templates) Section(name string) (string, error) {
+ w, ok := t.writer.(*reflow.Writer)
+ if !ok {
+ return "", fmt.Errorf("Section called inside nested writer")
+ }
+ depth := strconv.Itoa(w.Depth)
+ io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionStart, name, depth))
+ err := t.execute(name, t.writer, t.File)
+ io.WriteString(t.writer, fmt.Sprintf(sectionMarker, sectionEnd, name, depth))
+ return "", err
+}
+
+// Section represents a span of text in a file, segmented using SectionSplit.
+// If the section has a Name it will also have a StartMarker and EndMarker, otherwise
+// they will be empty.
+type Section struct {
+ Name string // The name the section was given.
+ Indentation int // The indentation level of the section.
+ StartMarker []byte // The bytes that marked the start of the section.
+ Body []byte // The content of the section.
+ EndMarker []byte // The bytes that marked the end of the section.
+}
+
+// SectionSplit breaks a file up into it's sections, and returns the slices with
+// the section header.
+// Named sections are delimited by <<<Start:name:depth>>> to <<<End:name:depth>>>
+// markers, areas between named sections are returned as unnamed sections.
+func SectionSplit(data []byte) ([]Section, error) {
+ matches := section.FindAllSubmatchIndex(data, -1)
+ if len(matches) == 0 {
+ return nil, nil
+ }
+ s := Section{}
+ sections := make([]Section, 0, len(matches)+1)
+ last := 0
+ // we are doing a partial update...
+ for _, match := range matches {
+ marker := data[match[0]:match[1]]
+ mode := string(data[match[2]:match[3]])
+ name := string(data[match[4]:match[5]])
+ level := string(data[match[6]:match[7]])
+ depth, err := strconv.Atoi(string(data[match[6]:match[7]]))
+ if err != nil {
+ return nil, fmt.Errorf("Indentation depth malformed, got %s in %s", level, name)
+ }
+ switch mode {
+ case sectionStart:
+ if s.Name != "" {
+ return nil, fmt.Errorf("Overlapping template %s found starting %s", s.Name, name)
+ }
+ // section start, add the prefix section
+ if last != match[0] {
+ s.Body = data[last:match[0]]
+ sections = append(sections, s)
+ }
+ // And prepare the section itself
+ s = Section{Name: name, Indentation: depth, StartMarker: marker}
+ last = match[1]
+ case sectionEnd:
+ // section end marker, check it matches
+ if name != s.Name {
+ return nil, fmt.Errorf("Invalid end %s found, expected %s", name, s.Name)
+ }
+ // write the end marker out throught the formatting writer
+ s.Body = data[last:match[0]]
+ s.EndMarker = marker
+ sections = append(sections, s)
+ // prepare for the next section
+ s = Section{}
+ last = match[1]
+ default:
+ return nil, fmt.Errorf("Invalid section marker %q", mode)
+ }
+ }
+ if s.Name != "" {
+ return nil, fmt.Errorf("Unclosed template %s found", s.Name)
+ }
+ // section start, add the prefix section
+ if last != len(data) {
+ s.Body = data[last:]
+ sections = append(sections, s)
+ }
+ return sections, nil
+}
diff --git a/tools/codergen/template/template.go b/tools/codergen/template/template.go
index 3db0c76..e5dd907 100644
--- a/tools/codergen/template/template.go
+++ b/tools/codergen/template/template.go
@@ -22,8 +22,6 @@
"os"
"path/filepath"
"reflect"
- "regexp"
- "strconv"
"strings"
"text/template"
"unicode"
@@ -92,13 +90,6 @@
return f
}
-var (
- sectionMarker = "<<<%s:%s:%s>>>"
- sectionStart = "Start"
- sectionEnd = "End"
- section = regexp.MustCompile(fmt.Sprintf(sectionMarker, "(.+)", "(.+)", "(.+)"))
-)
-
// Generate is an implementation of generate.Generator
func (t *Templates) Generate(g generate.Generate) (bool, error) {
t.File = g.Arg
@@ -107,52 +98,30 @@
buf := &bytes.Buffer{}
out := reflow.New(buf)
out.Indent = g.Indent
- matches := section.FindAllSubmatchIndex(old, -1)
- if len(matches) > 0 {
- last := 0
- tmpl := ""
+
+ sections, err := SectionSplit(old)
+ if err != nil {
+ return false, err
+ }
+ if len(sections) > 0 {
// we are doing a partial update...
- for _, match := range matches {
- mode := string(old[match[2]:match[3]])
- name := string(old[match[4]:match[5]])
- level := string(old[match[6]:match[7]])
- depth, err := strconv.Atoi(string(old[match[6]:match[7]]))
- if err != nil {
- return false, fmt.Errorf("Indentation depth malformed, got %s in %s", level, name)
- }
- switch mode {
- case sectionStart:
- if tmpl != "" {
- return false, fmt.Errorf("Overlapping template %s found starting %s", tmpl, name)
- }
- // section start, write the prefix
- buf.Write(old[last:match[1]])
- // now run the template
- tmpl = name
- out.Depth = depth
- if err := t.execute(tmpl, out, g.Arg); err != nil {
+ for _, s := range sections {
+ if s.Name == "" {
+ // copy the non template section straight to the underlying buf
+ buf.Write(s.Body)
+ } else {
+ // Write the start marker straight to the underlying buf
+ buf.Write(s.StartMarker)
+ out.Depth = s.Indentation
+ // Execute the template to generate a new body
+ if err := t.execute(s.Name, out, g.Arg); err != nil {
return false, err
}
- case sectionEnd:
- // section end marker, check it matches
- if name != tmpl {
- return false, fmt.Errorf("Invalid end %s found, expected %s", name, tmpl)
- }
- // write the end marker out throught the formatting writer
- out.Write(old[match[0]:match[1]])
+ // write the end marker out through the formatting writer
+ out.Write(s.EndMarker)
out.Flush()
- // set the markers ready for the next write
- tmpl = ""
- last = match[1]
- default:
- return false, fmt.Errorf("Invalid section marker %s:%s", mode, name)
}
}
- if tmpl != "" {
- return false, fmt.Errorf("Unclosed template %s found", tmpl)
- }
- // write the prefix
- buf.Write(old[last:])
} else {
if err := t.execute(g.Name, out, g.Arg); err != nil {
return false, err