blob: ce1605f471fef3955574d3f091511dc12c53cd46 [file] [log] [blame]
// Copyright 2017 The Puffs Authors.
//
// 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
//
// https://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 ast
import (
t "github.com/google/puffs/lang/token"
)
// String returns a string form of n.
func (n *Expr) String(tm *t.Map) string {
if n == nil {
return ""
}
if n.id0 == 0 {
return tm.ByID(n.id1)
}
return string(n.appendString(nil, tm, false, 0))
}
func (n *Expr) appendString(buf []byte, tm *t.Map, parenthesize bool, depth uint32) []byte {
if depth > MaxExprDepth {
return append(buf, "!expr_recursion_depth_too_large!"...)
}
depth++
if n != nil {
switch n.id0.Flags() & (t.FlagsUnaryOp | t.FlagsBinaryOp | t.FlagsAssociativeOp) {
case 0:
switch n.id0.Key() {
case 0:
buf = append(buf, tm.ByID(n.id1)...)
case t.KeyTry:
buf = append(buf, "try "...)
fallthrough
case t.KeyOpenParen:
buf = n.lhs.Expr().appendString(buf, tm, true, depth)
if n.flags&FlagsSuspendible != 0 {
buf = append(buf, '?')
}
buf = append(buf, '(')
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, ", "...)
}
buf = append(buf, tm.ByID(o.Arg().Name())...)
buf = append(buf, ':')
buf = o.Arg().Value().appendString(buf, tm, false, depth)
}
buf = append(buf, ')')
case t.KeyOpenBracket:
buf = n.lhs.Expr().appendString(buf, tm, true, depth)
buf = append(buf, '[')
buf = n.rhs.Expr().appendString(buf, tm, false, depth)
buf = append(buf, ']')
case t.KeyColon:
buf = n.lhs.Expr().appendString(buf, tm, true, depth)
buf = append(buf, '[')
buf = n.mhs.Expr().appendString(buf, tm, false, depth)
buf = append(buf, ':')
buf = n.rhs.Expr().appendString(buf, tm, false, depth)
buf = append(buf, ']')
case t.KeyDot:
buf = n.lhs.Expr().appendString(buf, tm, true, depth)
buf = append(buf, '.')
buf = append(buf, tm.ByID(n.id1)...)
case t.KeyDollar:
buf = append(buf, "$("...)
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, ", "...)
}
buf = o.Expr().appendString(buf, tm, false, depth)
}
buf = append(buf, ')')
}
case t.FlagsUnaryOp:
buf = append(buf, opStrings[0xFF&n.id0.Key()]...)
buf = n.rhs.Expr().appendString(buf, tm, true, depth)
case t.FlagsBinaryOp:
if parenthesize {
buf = append(buf, '(')
}
buf = n.lhs.Expr().appendString(buf, tm, true, depth)
buf = append(buf, opStrings[0xFF&n.id0.Key()]...)
if n.id0.Key() == t.KeyXBinaryAs {
buf = append(buf, n.rhs.TypeExpr().String(tm)...)
} else {
buf = n.rhs.Expr().appendString(buf, tm, true, depth)
}
if parenthesize {
buf = append(buf, ')')
}
case t.FlagsAssociativeOp:
if parenthesize {
buf = append(buf, '(')
}
op := opStrings[0xFF&n.id0.Key()]
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, op...)
}
buf = o.Expr().appendString(buf, tm, true, depth)
}
if parenthesize {
buf = append(buf, ')')
}
}
}
return buf
}
var opStrings = [256]string{
t.KeyXUnaryPlus: "+",
t.KeyXUnaryMinus: "-",
t.KeyXUnaryNot: "not ",
t.KeyXUnaryRef: "ref ",
t.KeyXUnaryDeref: "deref ",
t.KeyXBinaryPlus: " + ",
t.KeyXBinaryMinus: " - ",
t.KeyXBinaryStar: " * ",
t.KeyXBinarySlash: " / ",
t.KeyXBinaryShiftL: " << ",
t.KeyXBinaryShiftR: " >> ",
t.KeyXBinaryAmp: " & ",
t.KeyXBinaryAmpHat: " &^ ",
t.KeyXBinaryPipe: " | ",
t.KeyXBinaryHat: " ^ ",
t.KeyXBinaryNotEq: " != ",
t.KeyXBinaryLessThan: " < ",
t.KeyXBinaryLessEq: " <= ",
t.KeyXBinaryEqEq: " == ",
t.KeyXBinaryGreaterEq: " >= ",
t.KeyXBinaryGreaterThan: " > ",
t.KeyXBinaryAnd: " and ",
t.KeyXBinaryOr: " or ",
t.KeyXBinaryAs: " as ",
t.KeyXBinaryTildePlus: " ~+ ",
t.KeyXAssociativePlus: " + ",
t.KeyXAssociativeStar: " * ",
t.KeyXAssociativeAmp: " & ",
t.KeyXAssociativePipe: " | ",
t.KeyXAssociativeHat: " ^ ",
t.KeyXAssociativeAnd: " and ",
t.KeyXAssociativeOr: " or ",
}
// String returns a string form of n.
func (n *TypeExpr) String(tm *t.Map) string {
if n == nil {
return ""
}
if n.Decorator() == 0 && n.Min() == nil && n.Max() == nil {
return tm.ByID(n.Name())
}
return string(n.appendString(nil, tm, 0))
}
func (n *TypeExpr) appendString(buf []byte, tm *t.Map, depth uint32) []byte {
if depth > MaxTypeExprDepth {
return append(buf, "!type_expr_recursion_depth_too_large!"...)
}
depth++
if n == nil {
return append(buf, "!invalid_type!"...)
}
switch n.Decorator().Key() {
case 0:
buf = append(buf, tm.ByID(n.Name())...)
case t.KeyPtr:
buf = append(buf, "ptr "...)
return n.Inner().appendString(buf, tm, depth)
case t.KeyOpenBracket:
buf = append(buf, '[')
buf = n.ArrayLength().appendString(buf, tm, false, 0)
buf = append(buf, "] "...)
return n.Inner().appendString(buf, tm, depth)
case t.KeyColon:
buf = append(buf, "[] "...)
return n.Inner().appendString(buf, tm, depth)
default:
buf = append(buf, tm.ByID(n.Decorator())...)
buf = append(buf, '.')
buf = append(buf, tm.ByID(n.Name())...)
}
if n.Min() != nil || n.Max() != nil {
buf = append(buf, '[')
buf = n.Min().appendString(buf, tm, false, 0)
buf = append(buf, ".."...)
buf = n.Max().appendString(buf, tm, false, 0)
buf = append(buf, ']')
}
return buf
}