Spracherkennung für: .go vermutete Sprache: Abap {ABAP[55] Algol[45] Delphi[38]} [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 parser
import (
"fmt"
"strconv"
"strings"
"text/scanner"
"unicode"
)
var noPos scanner.
Position
type printer struct {
defs []
Definition
comments []
*CommentGroup
curComment int
pos scanner.
Position
pendingSpace bool
pendingNewline int
output []byte
indentList []int
wsBuf []byte
skippedComments []
*CommentGroup
}
func newPrinter(
file *File) *printer {
return &printer{
defs:
file.Defs,
comments:
file.Comments,
indentList: []int{
0},
// pendingNewLine
is initialized
to -
1 to eat
initial spaces
if the first token
is a
comment
pendingNewline: -
1,
pos: scanner.
Position{
Line:
1,
},
}
}
func
Print(
file *File) ([]byte, error) {
p := newPrinter(
file)
for _, def := range p.defs {
p.printDef(def)
}
p.flush()
return p.output, nil
}
func PrintExpression(expression Expression) ([]byte, error) {
dummyFile := &
File{}
p := newPrinter(dummyFile)
p.printExpression(expression)
p.flush()
return p.output, nil
}
func (p
*printer) Print() ([]byte, error) {
for _, def := range p.defs {
p.printDef(def)
}
p.flush()
return p.output, nil
}
func (p
*printer) printDef(def Definition) {
if assignment, ok := def.(
*Assignment); ok {
p.printAssignment(assignment)
}
else if module, ok := def.(
*Module); ok {
p.printModule(
module)
}
else {
panic(
"Unknown definition")
}
}
func (p
*printer) printAssignment(assignment *Assignment) {
p.printToken(assignment.Name, assignment.NamePos)
p.requestSpace()
p.printToken(assignment.Assigner, assignment.EqualsPos)
p.requestSpace()
p.printExpression(assignment.Value)
p.requestNewline()
}
func (p
*printer) printModule(module *Module) {
p.printToken(
module.
Type,
module.TypePos)
p.printMap(&
module.Map)
p.requestDoubleNewline()
}
func (p
*printer) printExpression(value Expression) {
switch v := value.(
type) {
case *Variable:
p.printToken(v.Name, v.NamePos)
case *Operator:
p.printOperator(v)
case *Bool:
var s
string
if v.Value {
s =
"true"
}
else {
s =
"false"
}
p.printToken(s, v.LiteralPos)
case *Int64:
p.printToken(strconv.FormatInt(v.Value,
10), v.LiteralPos)
case *String:
p.printToken(strconv.Quote(v.Value), v.LiteralPos)
case *List:
p.printList(v.Values, v.LBracePos, v.RBracePos)
case *Map:
p.printMap(v)
case *Select:
p.printSelect(v)
default:
panic(fmt.Errorf(
"bad property type: %v", value))
}
}
func (p
*printer) printSelect(s *Select) {
print_append := func() {
if s.
Append != nil {
p.requestSpace()
p.printToken(
"+", s.RBracePos)
p.requestSpace()
p.printExpression(s.
Append)
}
}
if len(s.Cases) ==
0 {
print_append()
return
}
if len(s.Cases) ==
1 && len(s.Cases[
0].Patterns) ==
1 {
if str, ok := s.Cases[
0].Patterns[
0].Value.(
*String); ok && str.Value == default_select_branch_name {
p.printExpression(s.Cases[
0].Value)
p.pos = s.RBracePos
print_append()
return
}
}
if len(s.Cases) ==
1 && len(s.Cases[
0].Patterns) ==
0 {
p.printExpression(s.Cases[
0].Value)
p.pos = s.RBracePos
print_append()
return
}
p.requestSpace()
p.printToken(
"select(", s.KeywordPos)
multilineConditions := false
if len(s.Conditions) >
1 {
p.printToken(
"(", s.KeywordPos)
if s.Conditions[len(s.Conditions)-
1].
position.
Line > s.KeywordPos.
Line {
multilineConditions = true
p.requestNewline()
p.indent(p.curIndent() +
4)
}
}
for i, c := range s.Conditions {
p.printToken(c.FunctionName, c.
position)
p.printToken(
"(", c.
position)
for i, arg := range c.Args {
p.printToken(strconv.Quote(arg.Value), arg.LiteralPos)
if i < len(c.Args)-
1 {
p.printToken(
",", arg.LiteralPos)
p.requestSpace()
}
}
p.printToken(
")", p.pos)
if len(s.Conditions) >
1 {
if multilineConditions {
p.printToken(
",", p.pos)
p.requestNewline()
}
else if i < len(s.Conditions)-
1 {
p.printToken(
",", p.pos)
p.requestSpace()
}
}
}
if len(s.Conditions) >
1 {
if multilineConditions {
p.unindent(p.pos)
}
p.printToken(
")", p.pos)
}
p.printToken(
", {", s.LBracePos)
p.requestNewline()
p.indent(p.curIndent() +
4)
for _, c := range s.Cases {
p.requestNewline()
if len(c.Patterns) >
1 {
p.printToken(
"(", p.pos)
}
for i, pat := range c.Patterns {
p.printSelectPattern(pat)
if i < len(c.Patterns)-
1 {
p.printToken(
",", p.pos)
p.requestSpace()
}
}
if len(c.Patterns) >
1 {
p.printToken(
")", p.pos)
}
p.printToken(
":", c.ColonPos)
p.requestSpace()
if unset, ok := c.Value.(
*UnsetProperty); ok {
p.printToken(unset.
String(), unset.Pos())
}
else {
p.printExpression(c.Value)
}
p.printToken(
",", c.Value.End())
}
p.requestNewline()
p.unindent(s.RBracePos)
p.printToken(
"})", s.RBracePos)
print_append()
}
func (p
*printer) printSelectPattern(pat SelectPattern) {
switch pat := pat.Value.(
type) {
case *String:
if pat.Value == default_select_branch_name {
p.printToken(
"default", pat.LiteralPos)
}
else if pat.Value == any_select_branch_name {
p.printToken(
"any", pat.LiteralPos)
}
else {
p.printToken(strconv.Quote(pat.Value), pat.LiteralPos)
}
case *Bool:
s :=
"false"
if pat.Value {
s =
"true"
}
p.printToken(s, pat.LiteralPos)
default:
panic(
"Unhandled case")
}
if pat.Binding.Name !=
"" {
p.requestSpace()
p.printToken(
"@", pat.Binding.Pos())
p.requestSpace()
p.printExpression(&pat.Binding)
}
}
func (p
*printer) printList(list []Expression, pos, endPos scanner.Position) {
p.requestSpace()
p.printToken(
"[", pos)
if len(list) >
1 || pos.
Line != endPos.
Line || listHasMap(list) {
p.requestNewline()
p.indent(p.curIndent() +
4)
for _, value := range list {
if sv, ok := value.(
*String); ok && sv.Deleted {
p.pos = sv.LiteralPos
continue
}
p.printExpression(value)
p.printToken(
",", noPos)
p.requestNewline()
}
p.unindent(endPos)
}
else {
for _, value := range list {
if sv, ok := value.(
*String); ok && sv.Deleted {
p.pos = sv.LiteralPos
continue
}
p.printExpression(value)
}
}
p.printToken(
"]", endPos)
}
func (p
*printer) printMap(m *Map) {
p.requestSpace()
p.printToken(
"{", m.LBracePos)
if len(m.Properties) >
0 || m.LBracePos.
Line != m.RBracePos.
Line {
p.requestNewline()
p.indent(p.curIndent() +
4)
for _, prop := range m.Properties {
if prop.Deleted {
p.pos = prop.End()
continue
}
p.printProperty(prop)
p.printToken(
",", noPos)
p.requestNewline()
}
p.unindent(m.RBracePos)
}
p.printToken(
"}", m.RBracePos)
}
func (p
*printer) printOperator(operator *Operator) {
p.printOperatorInternal(operator, true)
}
func (p
*printer) printOperatorInternal(operator *Operator, allowIndent bool) {
p.printExpression(operator.Args[
0])
p.requestSpace()
p.printToken(
string(operator.Operator), operator.OperatorPos)
indented := false
if operator.Args[
0].End().
Line == operator.Args[
1].Pos().
Line {
p.requestSpace()
}
else {
if allowIndent {
indented = true
p.indent(p.curIndent() +
4)
}
p.requestNewline()
}
if op, isOp := operator.Args[
1].(
*Operator); isOp {
p.printOperatorInternal(op, false)
}
else {
p.printExpression(operator.Args[
1])
}
if indented {
p.unindent(p.pos)
}
}
func (p
*printer) printProperty(property *Property) {
p.printToken(
property.Name,
property.NamePos)
p.printToken(
":",
property.ColonPos)
p.requestSpace()
p.printExpression(
property.Value)
}
//
Print a
single token, including
any necessary comments
or whitespace
between
// this token
and the previously printed token
func (p
*printer) printToken(s string, pos scanner.Position) {
newline := p.pendingNewline !=
0
if pos == noPos {
pos = p.pos
}
if newline {
p.printEndOfLineCommentsBefore(pos)
p.requestNewlinesForPos(pos)
}
p.printInLineCommentsBefore(pos)
p.flushSpace()
p.output =
append(p.output, s...)
p.pos = pos
}
//
Print any in-
line (
single line /* */) comments that appear _before_ pos
func (p
*printer) printInLineCommentsBefore(pos scanner.Position) {
for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().Offset < pos.Offset {
c := p.comments[p.curComment]
if c.Comments[
0].
Comment[
0][
0:
2] ==
"//" || len(c.Comments[
0].
Comment) >
1 {
p.skippedComments =
append(p.skippedComments, c)
}
else {
p.printComment(c)
p.requestSpace()
}
p.curComment++
}
}
//
Print any comments, including end
of line comments, that appear _before_ the
line specified
//
by pos
func (p
*printer) printEndOfLineCommentsBefore(pos scanner.Position) {
if len(p.skippedComments) >
0 {
for _, c := range p.skippedComments {
p.printComment(c)
p._requestNewline()
}
p.skippedComments = nil
}
for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().
Line < pos.
Line {
c := p.comments[p.curComment]
p.printComment(c)
p._requestNewline()
p.curComment++
}
}
// Compare the
line numbers
of the previous
and current positions
to determine whether extra
// newlines should be inserted. A second newline
is allowed anywhere requestNewline()
is call
ed.
func (p *printer) requestNewlinesForPos(pos scanner.Position) bool {
if pos.Line > p.pos.Line {
p._requestNewline()
if pos.Line > p.pos.Line+1 {
p.pendingNewline = 2
}
return true
}
return false
}
func (p *printer) requestSpace() {
p.pendingSpace = true
}
// Ask for a newline to be inserted before the next token, but do not insert any comments. Used
// by the comment printers.
func (p *printer) _requestNewline() {
if p.pendingNewline == 0 {
p.pendingNewline = 1
}
}
// Ask for a newline to be inserted before the next token. Also inserts any end-of line comments
// for the current line
func (p *printer) requestNewline() {
pos := p.pos
pos.Line++
p.printEndOfLineCommentsBefore(pos)
p._requestNewline()
}
// Ask for two newlines to be inserted before the next token. Also inserts any end-of line comments
// for the current line
func (p *printer) requestDoubleNewline() {
p.requestNewline()
p.pendingNewline = 2
}
// Flush any pending whitespace, ignoring pending spaces if there is a pending newline
func (p *printer) flushSpace() {
if p.pendingNewline == 1 {
p.output = append(p.output, '\n')
p.pad(p.curIndent())
} else if p.pendingNewline == 2 {
p.output = append(p.output, "\n\n"...)
p.pad(p.curIndent())
} else if p.pendingSpace == true && p.pendingNewline != -1 {
p.output = append(p.output, ' ')
}
p.pendingSpace = false
p.pendingNewline = 0
}
// Print a single comment, which may be a multi-line comment
func (p *printer) printComment(cg *CommentGroup) {
for _, comment := range cg.Comments {
if !p.requestNewlinesForPos(comment.Pos()) {
p.requestSpace()
}
for i, line := range comment.Comment {
line = strings.TrimRightFunc(line, unicode.IsSpace)
p.flushSpace()
if i != 0 {
lineIndent := strings.IndexFunc(line, func(r rune) bool { return !unicode.IsSpace(r) })
lineIndent = max(lineIndent, p.curIndent())
p.pad(lineIndent - p.curIndent())
}
p.output = append(p.output, strings.TrimSpace(line)...)
if i < len(comment.Comment)-1 {
p._requestNewline()
}
}
if p.pos.Offset < comment.End().Offset {
p.pos = comment.End()
}
}
}
// Print any comments that occur after the last token, and a trailing newline
func (p *printer) flush() {
for _, c := range p.skippedComments {
if !p.requestNewlinesForPos(c.Pos()) {
p.requestSpace()
}
p.printComment(c)
}
for p.curComment < len(p.comments) {
p.printComment(p.comments[p.curComment])
p.curComment++
}
p.output = append(p.output, '\n')
}
// Print whitespace to pad from column l to column max
func (p *printer) pad(l int) {
if l > len(p.wsBuf) {
p.wsBuf = make([]byte, l)
for i := range p.wsBuf {
p.wsBuf[i] = ' '
}
}
p.output = append(p.output, p.wsBuf[0:l]...)
}
func (p *printer) indent(i int) {
p.indentList = append(p.indentList, i)
}
func (p *printer) unindent(pos scanner.Position) {
p.printEndOfLineCommentsBefore(pos)
p.indentList = p.indentList[0 : len(p.indentList)-1]
}
func (p *printer) curIndent() int {
return p.indentList[len(p.indentList)-1]
}
func max(a, b int) int {
if a > b {
return a
} else {
return b
}
}
func listHasMap(list []Expression) bool {
for _, value := range list {
if _, ok := value.(*Map); ok {
return true
}
}
return false
}