Spracherkennung für: .go vermutete Sprache: Abap {ABAP[56] SPS[52] Algol[45]} [Methode: maximale Elemente, drei Dimensionen]
// Copyright
2014 Google Inc. All rights reserved.
//
// 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 blueprint
import (
"io"
"strings"
"unicode"
)
const (
indentWidth =
4
maxIndentDepth =
2
lineWidth =
80
)
var indentString = strings.Repeat(
" ", indentWidth
*maxIndentDepth)
type StringWriterWriter
interface {
io.StringWriter
io.Writer
}
type ninjaWriter struct {
writer StringWriterWriter
justDidBlankLine bool // true
if the last operation was a BlankLine
}
func newNinjaWriter(writer StringWriterWriter)
*ninjaWriter {
return &ninjaWriter{
writer: writer,
}
}
func (n
*ninjaWriter) Comment(comment string) error {
n.justDidBlankLine = false
const lineHeaderLen = len(
"# ")
const maxLineLen = lineWidth - lineHeaderLen
var lineStart, lastSplitPoint int
for i, r := range
comment {
if unicode.IsSpace(r) {
// We know we can safely
split the
line here.
lastSplitPoint = i +
1
}
var
line string
var writeLine bool
switch {
case r ==
'\n':
// Output the
line without trimming the left so
as to allow comments
//
to contain their own indentation.
line = strings.TrimRightFunc(
comment[lineStart:i], unicode.IsSpace)
writeLine = true
case (i-lineStart > maxLineLen) && (lastSplitPoint > lineStart):
// The
line has grown too long
and is splittable.
Split it
at the
// last
split point.
line = strings.TrimSpace(
comment[lineStart:lastSplitPoint])
writeLine = true
}
if writeLine {
line = strings.TrimSpace(
"# "+
line) +
"\n"
_, err := n.writer.WriteString(
line)
if err != nil {
return err
}
lineStart = lastSplitPoint
}
}
if lineStart != len(
comment) {
line := strings.TrimSpace(
comment[lineStart:])
_, err := n.writer.WriteString(
"# ")
if err != nil {
return err
}
_, err = n.writer.WriteString(
line)
if err != nil {
return err
}
_, err = n.writer.WriteString(
"\n")
if err != nil {
return err
}
}
return nil
}
func (n
*ninjaWriter) Pool(name string) error {
n.justDidBlankLine = false
return n.writeStatement(
"pool", name)
}
func (n
*ninjaWriter) Rule(name string) error {
n.justDidBlankLine = false
return n.writeStatement(
"rule", name)
}
func (n
*ninjaWriter) Build(comment string, rule string, outputs, implicitOuts,
explicitDeps, implicitDeps, orderOnlyDeps, validations []
*ninjaString,
outputStrings, implicitOutStrings, explicitDepStrings,
implicitDepStrings, orderOnlyDepStrings, validationStrings []
string,
nameTracker
*nameTracker) error {
n.justDidBlankLine = false
const lineWrapLen = len(
" $")
const maxLineLen = lineWidth - lineWrapLen
wrapper := &ninjaWriterWithWrap{
ninjaWriter: n,
maxLineLen: maxLineLen,
}
if comment !=
"" {
err := wrapper.
Comment(
comment)
if err != nil {
return err
}
}
wrapper.WriteString(
"build")
for _, output := range outputStrings {
wrapper.Space()
outputEscaper.WriteString(wrapper, output)
}
for _, output := range outputs {
wrapper.Space()
output.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
}
if len(implicitOuts) >
0 || len(implicitOutStrings) >
0 {
wrapper.WriteStringWithSpace(
"|")
for _, out := range implicitOutStrings {
wrapper.Space()
outputEscaper.WriteString(wrapper, out)
}
for _, out := range implicitOuts {
wrapper.Space()
out.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
}
}
wrapper.WriteString(
":")
wrapper.WriteStringWithSpace(rule)
for _, dep := range explicitDepStrings {
wrapper.Space()
inputEscaper.WriteString(wrapper, dep)
}
for _, dep := range explicitDeps {
wrapper.Space()
dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
}
if len(implicitDeps) >
0 || len(implicitDepStrings) >
0 {
wrapper.WriteStringWithSpace(
"|")
for _, dep := range implicitDepStrings {
wrapper.Space()
inputEscaper.WriteString(wrapper, dep)
}
for _, dep := range implicitDeps {
wrapper.Space()
dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
}
}
if len(orderOnlyDeps) >
0 || len(orderOnlyDepStrings) >
0 {
wrapper.WriteStringWithSpace(
"||")
for _, dep := range orderOnlyDepStrings {
wrapper.Space()
inputEscaper.WriteString(wrapper, dep)
}
for _, dep := range orderOnlyDeps {
wrapper.Space()
dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
}
}
if len(validations) >
0 || len(validationStrings) >
0 {
wrapper.WriteStringWithSpace(
"|@")
for _, dep := range validationStrings {
wrapper.Space()
inputEscaper.WriteString(wrapper, dep)
}
for _, dep := range validations {
wrapper.Space()
dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper)
}
}
return wrapper.Flush()
}
func (n
*ninjaWriter) Assign(name, value string) error {
n.justDidBlankLine = false
_, err := n.writer.WriteString(name)
if err != nil {
return err
}
_, err = n.writer.WriteString(
" = ")
if err != nil {
return err
}
_, err = n.writer.WriteString(value)
if err != nil {
return err
}
_, err = n.writer.WriteString(
"\n")
if err != nil {
return err
}
return nil
}
func (n
*ninjaWriter) ScopedAssign(name, value string) error {
n.justDidBlankLine = false
_, err := n.writer.WriteString(indentString[:indentWidth])
if err != nil {
return err
}
_, err = n.writer.WriteString(name)
if err != nil {
return err
}
_, err = n.writer.WriteString(
" = ")
if err != nil {
return err
}
_, err = n.writer.WriteString(value)
if err != nil {
return err
}
_, err = n.writer.WriteString(
"\n")
if err != nil {
return err
}
return nil
}
func (n
*ninjaWriter) Default(nameTracker *nameTracker, targets []*ninjaString, targetStrings []string) error {
n.justDidBlankLine = false
const lineWrapLen = len(
" $")
const maxLineLen = lineWidth - lineWrapLen
wrapper := &ninjaWriterWithWrap{
ninjaWriter: n,
maxLineLen: maxLineLen,
}
wrapper.WriteString(
"default")
for _, target := range targetStrings {
wrapper.Space()
outputEscaper.WriteString(wrapper, target)
}
for _, target := range targets {
wrapper.Space()
target.ValueWithEscaper(wrapper, nameTracker, outputEscaper)
}
return wrapper.Flush()
}
func (n
*ninjaWriter) Subninja(file string) error {
n.justDidBlankLine = false
return n.writeStatement(
"subninja",
file)
}
func (n
*ninjaWriter) BlankLine() (err error) {
// We don
't output multiple blank lines in a row.
if !n.justDidBlankLine {
n.justDidBlankLine = true
_, err = n.writer.WriteString(
"\n")
}
return err
}
func (n
*ninjaWriter) writeStatement(directive, name string) error {
_, err := n.writer.WriteString(directive +
" ")
if err != nil {
return err
}
_, err = n.writer.WriteString(name)
if err != nil {
return err
}
_, err = n.writer.WriteString(
"\n")
if err != nil {
return err
}
return nil
}
// ninjaWriterWithWrap
is an io.StringWriter that writes through
to a ninjaWriter, but suppo
rts
// user-readable line wrapping on boundaries when ninjaWriterWithWrap.Space is called.
// It collects incoming calls to WriteString until either the line length is exceeded, in which case
// it inserts a wrap before the pending strings and then writes them, or the next call to Space, in
// which case it writes out the pending strings.
//
// WriteString never returns an error, all errors are held until Flush is called. Once an error has
// occurred all writes become noops.
type ninjaWriterWithWrap struct {
*ninjaWriter
// pending lists the strings that have been written since the last call to Space.
pending []string
// pendingLen accumulates the lengths of the strings in pending.
pendingLen int
// lineLen accumulates the number of bytes on the current line.
lineLen int
// maxLineLen is the length of the line before wrapping.
maxLineLen int
// space is true if the strings in pending should be preceded by a space.
space bool
// err holds any error that has occurred to return in Flush.
err error
}
// WriteString writes the string to buffer, wrapping on a previous Space call if necessary.
// It never returns an error, all errors are held until Flush is called.
func (n *ninjaWriterWithWrap) WriteString(s string) (written int, noError error) {
// Always return the full length of the string and a nil error.
// ninjaWriterWithWrap doesn't return errors to the caller, it saves them until Flush()
written = len(s)
if n.err != nil {
return
}
const spaceLen = 1
if !n.space {
// No space is pending, so a line wrap can't be inserted before this, so just write
// the string.
n.lineLen += len(s)
_, n.err = n.writer.WriteString(s)
} else if n.lineLen+len(s)+spaceLen > n.maxLineLen {
// A space is pending, and the pending strings plus the current string would exceed the
// maximum line length. Wrap and indent before the pending space and strings, then write
// the pending and current strings.
_, n.err = n.writer.WriteString(" $\n")
if n.err != nil {
return
}
_, n.err = n.writer.WriteString(indentString[:indentWidth*2])
if n.err != nil {
return
}
n.lineLen = indentWidth*2 + n.pendingLen
s = strings.TrimLeftFunc(s, unicode.IsSpace)
n.pending = append(n.pending, s)
n.lineLen += len(s)
n.writePending()
n.space = false
} else {
// A space is pending but the current string would not reach the maximum line length,
// add it to the pending list.
n.pending = append(n.pending, s)
n.pendingLen += len(s)
n.lineLen += len(s)
}
return
}
func (n *ninjaWriterWithWrap) Write(p []byte) (written int, noError error) {
// Write is rarely used, implement it via WriteString.
return n.WriteString(string(p))
}
// Space inserts a space that is also a possible wrapping point into the string.
func (n *ninjaWriterWithWrap) Space() {
if n.err != nil {
return
}
if n.space {
// A space was already pending, and the space plus any strings written after the space did
// not reach the maxmimum line length, so write out the old space and pending strings.
_, n.err = n.writer.WriteString(" ")
n.lineLen++
n.writePending()
}
n.space = true
}
// writePending writes out all the strings stored in pending and resets it.
func (n *ninjaWriterWithWrap) writePending() {
if n.err != nil {
return
}
for _, pending := range n.pending {
_, n.err = n.writer.WriteString(pending)
if n.err != nil {
return
}
}
// Reset the length of pending back to 0 without reducing its capacity to avoid reallocating
// the backing array.
n.pending = n.pending[:0]
n.pendingLen = 0
}
// WriteStringWithSpace is a helper that calls Space and WriteString.
func (n *ninjaWriterWithWrap) WriteStringWithSpace(s string) {
n.Space()
_, _ = n.WriteString(s)
}
// Flush writes out any pending space or strings and then a newline. It also returns any errors
// that have previously occurred.
func (n *ninjaWriterWithWrap) Flush() error {
if n.space {
_, n.err = n.writer.WriteString(" ")
}
n.writePending()
if n.err != nil {
return n.err
}
_, err := n.writer.WriteString("\n")
return err
}