blob: 69c383434734557500aba905c0c9266eff72667c [file] [log] [blame]
// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
package ast
import (
t "github.com/google/wuffs/lang/token"
)
// Str returns a string form of n.
func (n *Expr) Str(tm *t.Map) string {
if n == nil {
return "«nilExpr»"
}
if n.id0 == 0 && n.id1 == 0 {
return tm.ByID(n.id2)
}
return string(n.appendStr(nil, tm, false, 0))
}
func (n *Expr) appendStr(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 {
return buf
}
if n.id0.IsXOp() {
switch {
case n.id0.IsXUnaryOp():
buf = append(buf, opString(n.id0)...)
buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)
case n.id0.IsXBinaryOp():
if parenthesize {
buf = append(buf, '(')
}
buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
buf = append(buf, opString(n.id0)...)
if n.id0 == t.IDXBinaryAs {
buf = append(buf, n.rhs.AsTypeExpr().Str(tm)...)
} else {
buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)
}
if parenthesize {
buf = append(buf, ')')
}
case n.id0.IsXAssociativeOp():
if parenthesize {
buf = append(buf, '(')
}
op := opString(n.id0)
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, op...)
}
buf = o.AsExpr().appendStr(buf, tm, true, depth)
}
if parenthesize {
buf = append(buf, ')')
}
}
} else {
switch n.id0 {
case 0:
if n.id1 != 0 {
buf = append(buf, tm.ByID(n.id1)...)
buf = append(buf, '.')
}
buf = append(buf, tm.ByID(n.id2)...)
case t.IDOpenParen:
buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
buf = append(buf, n.flags.AsEffect().String()...)
buf = append(buf, '(')
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, ", "...)
}
buf = append(buf, tm.ByID(o.AsArg().Name())...)
buf = append(buf, ": "...)
buf = o.AsArg().Value().appendStr(buf, tm, false, depth)
}
buf = append(buf, ')')
case t.IDOpenBracket:
buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
buf = append(buf, '[')
buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
buf = append(buf, ']')
case t.IDDotDot:
buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
buf = append(buf, '[')
if n.mhs != nil {
buf = n.mhs.AsExpr().appendStr(buf, tm, false, depth)
buf = append(buf, ' ')
}
buf = append(buf, ".."...)
if n.rhs != nil {
buf = append(buf, ' ')
buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
}
buf = append(buf, ']')
case t.IDDot:
buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
buf = append(buf, '.')
buf = append(buf, tm.ByID(n.id2)...)
case t.IDComma:
buf = append(buf, '[')
for i, o := range n.list0 {
if i != 0 {
buf = append(buf, ", "...)
}
buf = o.AsExpr().appendStr(buf, tm, false, depth)
}
buf = append(buf, ']')
}
}
return buf
}
func opString(x t.ID) string {
if x < t.ID(len(opStrings)) {
if s := opStrings[x]; s != "" {
return s
}
}
return " no_such_Wuffs_operator "
}
var opStrings = [...]string{
t.IDXBinaryPlus: " + ",
t.IDXBinaryMinus: " - ",
t.IDXBinaryStar: " * ",
t.IDXBinarySlash: " / ",
t.IDXBinaryShiftL: " << ",
t.IDXBinaryShiftR: " >> ",
t.IDXBinaryAmp: " & ",
t.IDXBinaryPipe: " | ",
t.IDXBinaryHat: " ^ ",
t.IDXBinaryPercent: " % ",
t.IDXBinaryTildeModPlus: " ~mod+ ",
t.IDXBinaryTildeModMinus: " ~mod- ",
t.IDXBinaryTildeModStar: " ~mod* ",
t.IDXBinaryTildeModShiftL: " ~mod<< ",
t.IDXBinaryTildeSatPlus: " ~sat+ ",
t.IDXBinaryTildeSatMinus: " ~sat- ",
t.IDXBinaryNotEq: " <> ",
t.IDXBinaryLessThan: " < ",
t.IDXBinaryLessEq: " <= ",
t.IDXBinaryEqEq: " == ",
t.IDXBinaryGreaterEq: " >= ",
t.IDXBinaryGreaterThan: " > ",
t.IDXBinaryAnd: " and ",
t.IDXBinaryOr: " or ",
t.IDXBinaryAs: " as ",
t.IDXAssociativePlus: " + ",
t.IDXAssociativeStar: " * ",
t.IDXAssociativeAmp: " & ",
t.IDXAssociativePipe: " | ",
t.IDXAssociativeHat: " ^ ",
t.IDXAssociativeAnd: " and ",
t.IDXAssociativeOr: " or ",
t.IDXUnaryPlus: "+",
t.IDXUnaryMinus: "-",
t.IDXUnaryNot: "not ",
}
// Str returns a string form of n.
func (n *TypeExpr) Str(tm *t.Map) string {
if n == nil {
return "«nilTypeExpr»"
}
if n.Decorator() == 0 && n.Min() == nil && n.Max() == nil {
return n.QID().Str(tm)
}
return string(n.appendStr(nil, tm, 0))
}
func (n *TypeExpr) appendStr(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 dec := n.Decorator(); dec {
case 0:
buf = append(buf, n.QID().Str(tm)...)
case t.IDNptr:
buf = append(buf, "nptr "...)
return n.Inner().appendStr(buf, tm, depth)
case t.IDPtr:
buf = append(buf, "ptr "...)
return n.Inner().appendStr(buf, tm, depth)
case t.IDArray, t.IDRoarray:
if dec == t.IDRoarray {
buf = append(buf, "ro"...)
}
buf = append(buf, "array["...)
buf = n.ArrayLength().appendStr(buf, tm, false, 0)
buf = append(buf, "] "...)
return n.Inner().appendStr(buf, tm, depth)
case t.IDRoslice, t.IDSlice:
if dec == t.IDRoslice {
buf = append(buf, "ro"...)
}
buf = append(buf, "slice "...)
return n.Inner().appendStr(buf, tm, depth)
case t.IDRotable, t.IDTable:
if dec == t.IDRotable {
buf = append(buf, "ro"...)
}
buf = append(buf, "table "...)
return n.Inner().appendStr(buf, tm, depth)
case t.IDFunc:
buf = append(buf, "func "...)
if r := n.Receiver(); r != nil {
buf = append(buf, '(')
buf = r.appendStr(buf, tm, depth)
buf = append(buf, ")."...)
}
return append(buf, n.FuncName().Str(tm)...)
default:
return append(buf, "!invalid_type!"...)
}
if n.Min() != nil || n.Max() != nil {
buf = append(buf, '[')
if n.Min() != nil {
buf = n.Min().appendStr(buf, tm, false, 0)
buf = append(buf, ' ')
}
buf = append(buf, "..="...)
if n.Max() != nil {
buf = append(buf, ' ')
buf = n.Max().appendStr(buf, tm, false, 0)
}
buf = append(buf, ']')
}
return buf
}