mirror of
https://github.com/johnkerl/miller.git
synced 2026-01-23 02:14:13 +00:00
* Static-check fixes from @lespea #1657, batch 2/n * Static-check fixes from @lespea #1657, batch 3/n * Static-check fixes from @lespea #1657, batch 4/n * Static-check fixes from @lespea #1657, batch 5/n * Static-check fixes from @lespea #1657, batch 6/n
325 lines
7.4 KiB
Go
325 lines
7.4 KiB
Go
// ================================================================
|
|
// Print routines for AST and ASTNode
|
|
// ================================================================
|
|
|
|
package dsl
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ================================================================
|
|
// Print is indent-style multiline print.
|
|
// Example, given parse of '$y = 2 * $x + 1':
|
|
//
|
|
// * statement block
|
|
// * assignment "="
|
|
// * direct field value "y"
|
|
// * operator "+"
|
|
// * operator "*"
|
|
// * int literal "2"
|
|
// * direct field value "x"
|
|
// * int literal "1"
|
|
|
|
func (ast *AST) Print() {
|
|
ast.RootNode.Print()
|
|
}
|
|
|
|
// PrintParex is parenthesized-expression print.
|
|
// Example, given parse of '$y = 2 * $x + 1':
|
|
//
|
|
// (statement-block
|
|
// (=
|
|
// $y
|
|
// (+
|
|
// (* 2 $x)
|
|
// 1
|
|
// )
|
|
// )
|
|
// )
|
|
|
|
func (ast *AST) PrintParex() {
|
|
ast.RootNode.PrintParex()
|
|
}
|
|
|
|
// PrintParexOneLine is parenthesized-expression print, all on one line.
|
|
// Example, given parse of '$y = 2 * $x + 1':
|
|
//
|
|
// (statement-block (= $y (+ (* 2 $x) 1)))
|
|
|
|
func (ast *AST) PrintParexOneLine() {
|
|
ast.RootNode.PrintParexOneLine()
|
|
}
|
|
|
|
// ================================================================
|
|
|
|
// Print is indent-style multiline print.
|
|
func (node *ASTNode) Print() {
|
|
node.printAux(0)
|
|
}
|
|
|
|
// printAux is a recursion-helper for Print.
|
|
func (node *ASTNode) printAux(depth int) {
|
|
// Indent
|
|
for i := 0; i < depth; i++ {
|
|
fmt.Print(" ")
|
|
}
|
|
|
|
// Token text (if non-nil) and token type
|
|
tok := node.Token
|
|
fmt.Print("* " + node.Type)
|
|
if tok != nil {
|
|
fmt.Printf(" \"%s\"", string(tok.Lit))
|
|
}
|
|
fmt.Println()
|
|
|
|
// Children, indented one level further
|
|
for _, child := range node.Children {
|
|
child.printAux(depth + 1)
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// PrintParex is parenthesized-expression print.
|
|
func (node *ASTNode) PrintParex() {
|
|
node.printParexAux(0)
|
|
}
|
|
|
|
// printParexAux is a recursion-helper for PrintParex.
|
|
func (node *ASTNode) printParexAux(depth int) {
|
|
if node.IsLeaf() {
|
|
for i := 0; i < depth; i++ {
|
|
fmt.Print(" ")
|
|
}
|
|
fmt.Println(node.Text())
|
|
|
|
} else if node.ChildrenAreAllLeaves() {
|
|
// E.g. (= sum 0) or (+ 1 2)
|
|
for i := 0; i < depth; i++ {
|
|
fmt.Print(" ")
|
|
}
|
|
fmt.Print("(")
|
|
fmt.Print(node.Text())
|
|
|
|
for _, child := range node.Children {
|
|
fmt.Print(" ")
|
|
fmt.Print(child.Text())
|
|
}
|
|
fmt.Println(")")
|
|
|
|
} else {
|
|
// Parent and opening parenthesis on first line
|
|
for i := 0; i < depth; i++ {
|
|
fmt.Print(" ")
|
|
}
|
|
fmt.Print("(")
|
|
fmt.Println(node.Text())
|
|
|
|
// Children on their own lines
|
|
for _, child := range node.Children {
|
|
child.printParexAux(depth + 1)
|
|
}
|
|
|
|
// Closing parenthesis on last line
|
|
for i := 0; i < depth; i++ {
|
|
fmt.Print(" ")
|
|
}
|
|
fmt.Println(")")
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// PrintParexOneLine is parenthesized-expression print, all on one line.
|
|
func (node *ASTNode) PrintParexOneLine() {
|
|
node.printParexOneLineAux()
|
|
fmt.Println()
|
|
}
|
|
|
|
// printParexOneLineAux is a recursion-helper for PrintParexOneLine.
|
|
func (node *ASTNode) printParexOneLineAux() {
|
|
if node.IsLeaf() {
|
|
fmt.Print(node.Text())
|
|
} else {
|
|
fmt.Print("(")
|
|
fmt.Print(node.Text())
|
|
for _, child := range node.Children {
|
|
fmt.Print(" ")
|
|
child.printParexOneLineAux()
|
|
}
|
|
fmt.Print(")")
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// IsLeaf determines if an AST node is a leaf node.
|
|
func (node *ASTNode) IsLeaf() bool {
|
|
return len(node.Children) == 0
|
|
}
|
|
|
|
// ChildrenAreAllLeaves determines if an AST node's children are all leaf nodes.
|
|
func (node *ASTNode) ChildrenAreAllLeaves() bool {
|
|
for _, child := range node.Children {
|
|
if !child.IsLeaf() {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
// Text makes a human-readable, whitespace-free name for an AST node. Some
|
|
// nodes have non-nil tokens; other, nil. And token-types can have spaces in
|
|
// them. In this method we use custom mappings to always get a whitespace-free
|
|
// representation of the content of a single AST node.
|
|
func (node *ASTNode) Text() string {
|
|
tokenText := ""
|
|
if node.Token != nil {
|
|
tokenText = string(node.Token.Lit)
|
|
}
|
|
|
|
switch node.Type {
|
|
|
|
case NodeTypeStringLiteral:
|
|
return "\"" + strings.ReplaceAll(tokenText, "\"", "\\\"") + "\""
|
|
case NodeTypeIntLiteral:
|
|
return tokenText
|
|
case NodeTypeFloatLiteral:
|
|
return tokenText
|
|
case NodeTypeBoolLiteral:
|
|
return tokenText
|
|
case NodeTypeNullLiteral:
|
|
return tokenText
|
|
case NodeTypeArrayLiteral:
|
|
return tokenText
|
|
case NodeTypeMapLiteral:
|
|
return tokenText
|
|
case NodeTypeMapLiteralKeyValuePair:
|
|
return tokenText
|
|
|
|
case NodeTypeArrayOrMapIndexAccess:
|
|
return "[]"
|
|
case NodeTypeArraySliceAccess:
|
|
return "[:]"
|
|
case NodeTypeArraySliceEmptyLowerIndex:
|
|
return "array-slice-empty-lower-index"
|
|
case NodeTypeArraySliceEmptyUpperIndex:
|
|
return "array-slice-empty-upper-index"
|
|
case NodeTypeContextVariable:
|
|
return tokenText
|
|
case NodeTypeConstant:
|
|
return tokenText
|
|
case NodeTypeEnvironmentVariable:
|
|
return "ENV[\"" + tokenText + "\"]"
|
|
|
|
case NodeTypeDirectFieldValue:
|
|
return "$" + tokenText
|
|
case NodeTypeIndirectFieldValue:
|
|
return "$[" + tokenText + "]"
|
|
case NodeTypeFullSrec:
|
|
return tokenText
|
|
case NodeTypeDirectOosvarValue:
|
|
return "@" + tokenText
|
|
case NodeTypeIndirectOosvarValue:
|
|
return "@[" + tokenText + "]"
|
|
case NodeTypeFullOosvar:
|
|
return tokenText
|
|
case NodeTypeLocalVariable:
|
|
return tokenText
|
|
case NodeTypeTypedecl:
|
|
return tokenText
|
|
|
|
case NodeTypeStatementBlock:
|
|
return "statement-block"
|
|
case NodeTypeAssignment:
|
|
return tokenText
|
|
case NodeTypeUnset:
|
|
return tokenText
|
|
|
|
case NodeTypeBareBoolean:
|
|
return "bare-boolean"
|
|
case NodeTypeFilterStatement:
|
|
return tokenText
|
|
case NodeTypeEmit1Statement:
|
|
return tokenText
|
|
case NodeTypeEmitStatement:
|
|
return tokenText
|
|
case NodeTypeEmitPStatement:
|
|
return tokenText
|
|
case NodeTypeEmitFStatement:
|
|
return tokenText
|
|
case NodeTypeDumpStatement:
|
|
return tokenText
|
|
case NodeTypeEdumpStatement:
|
|
return tokenText
|
|
case NodeTypePrintStatement:
|
|
return tokenText
|
|
case NodeTypeEprintStatement:
|
|
return tokenText
|
|
case NodeTypePrintnStatement:
|
|
return tokenText
|
|
case NodeTypeEprintnStatement:
|
|
return tokenText
|
|
|
|
case NodeTypeNoOp:
|
|
return "no-op"
|
|
|
|
case NodeTypeOperator:
|
|
return tokenText
|
|
case NodeTypeDotOperator:
|
|
return tokenText
|
|
case NodeTypeFunctionCallsite:
|
|
return tokenText
|
|
|
|
case NodeTypeBeginBlock:
|
|
return "begin"
|
|
case NodeTypeEndBlock:
|
|
return "end"
|
|
case NodeTypeIfChain:
|
|
return "if-chain"
|
|
case NodeTypeIfItem:
|
|
return tokenText
|
|
case NodeTypeCondBlock:
|
|
return "cond"
|
|
case NodeTypeWhileLoop:
|
|
return tokenText
|
|
case NodeTypeDoWhileLoop:
|
|
return tokenText
|
|
case NodeTypeForLoopOneVariable:
|
|
return tokenText
|
|
case NodeTypeForLoopTwoVariable:
|
|
return tokenText
|
|
case NodeTypeForLoopMultivariable:
|
|
return tokenText
|
|
case NodeTypeTripleForLoop:
|
|
return tokenText
|
|
case NodeTypeBreak:
|
|
return tokenText
|
|
case NodeTypeContinue:
|
|
return tokenText
|
|
|
|
case NodeTypeNamedFunctionDefinition:
|
|
return "named-udf"
|
|
case NodeTypeUnnamedFunctionDefinition:
|
|
return "unnamed-udf"
|
|
case NodeTypeSubroutineDefinition:
|
|
return "subr"
|
|
case NodeTypeParameterList:
|
|
return "parameters"
|
|
case NodeTypeParameter:
|
|
return "parameter"
|
|
case NodeTypeParameterName:
|
|
return tokenText
|
|
case NodeTypeReturn:
|
|
return tokenText
|
|
|
|
case NodeTypePanic:
|
|
return tokenText
|
|
|
|
}
|
|
return "[ERROR]"
|
|
}
|