1// Copyright 2011 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Parse nodes. 6 7package mof 8 9import ( 10 "fmt" 11 "strconv" 12) 13 14// A Node is an element in the parse tree. The interface is trivial. 15// The interface contains an unexported method so that only 16// types local to this package can satisfy it. 17type node interface { 18 Type() nodeType 19 Value() interface{} 20 Position() pos // byte position of start of node in full original input string 21 // Make sure only functions in this package can create Nodes. 22 unexported() 23} 24 25// NodeType identifies the type of a parse tree node. 26type nodeType int 27 28// Pos represents a byte position in the original input text from which 29// this template was parsed. 30type pos int 31 32func (p pos) Position() pos { 33 return p 34} 35 36// unexported keeps Node implementations local to the package. 37// All implementations embed Pos, so this takes care of it. 38func (pos) unexported() { 39} 40 41// Type returns itself and provides an easy default implementation 42// for embedding in a Node. Embedded in all non-trivial Nodes. 43func (t nodeType) Type() nodeType { 44 return t 45} 46 47const ( 48 nodeClass nodeType = iota 49 nodeInstance 50 nodeArray 51 nodeString 52 nodeNumber 53 nodeBool 54 nodeNil 55) 56 57// Nodes. 58 59// NumberNode holds a number: signed or unsigned integer or float. 60// The value is parsed and stored under all the types that can represent the value. 61// This simulates in a small amount of code the behavior of Go's ideal constants. 62type numberNode struct { 63 nodeType 64 pos 65 IsInt bool // Number has an unsigned integral value. 66 IsFloat bool // Number has a floating-point value. 67 Int64 int64 // The unsigned integer value. 68 Float64 float64 // The floating-point value. 69 Text string // The original textual representation from the input. 70} 71 72func newNumber(pos pos, text string) (*numberNode, error) { 73 n := &numberNode{nodeType: nodeNumber, pos: pos, Text: text} 74 u, err := strconv.ParseInt(text, 0, 64) // will fail for -0. 75 if err == nil { 76 n.IsInt = true 77 n.Int64 = u 78 } 79 // If an integer extraction succeeded, promote the float. 80 if !n.IsInt { 81 f, err := strconv.ParseFloat(text, 64) 82 if err == nil { 83 n.IsFloat = true 84 n.Float64 = f 85 } 86 } 87 if !n.IsInt && !n.IsFloat { 88 return nil, fmt.Errorf("illegal number syntax: %q", text) 89 } 90 return n, nil 91} 92 93func (n *numberNode) Value() interface{} { 94 if n.IsInt { 95 return n.Int64 96 } 97 return n.Float64 98} 99 100// StringNode holds a string constant. The value has been "unquoted". 101type stringNode struct { 102 nodeType 103 pos 104 Quoted string // The original text of the string, with quotes. 105 Text string // The string, after quote processing. 106} 107 108func newString(pos pos, orig, text string) *stringNode { 109 return &stringNode{nodeType: nodeString, pos: pos, Quoted: orig, Text: text} 110} 111 112func (s *stringNode) Value() interface{} { 113 return s.Text 114} 115 116type boolNode struct { 117 nodeType 118 pos 119 Val bool 120} 121 122func newBool(pos pos, val bool) *boolNode { 123 return &boolNode{nodeType: nodeBool, pos: pos, Val: val} 124} 125 126func (b *boolNode) Value() interface{} { 127 return b.Val 128} 129 130type nilNode struct { 131 nodeType 132 pos 133} 134 135func newNil(pos pos) *nilNode { 136 return &nilNode{nodeType: nodeNil, pos: pos} 137} 138 139func (b *nilNode) Value() interface{} { 140 return nil 141} 142 143type classNode struct { 144 nodeType 145 pos 146 Members members 147} 148 149func newClass(pos pos) *classNode { 150 return &classNode{ 151 nodeType: nodeClass, 152 pos: pos, 153 Members: make(members), 154 } 155} 156 157type members map[string]node 158 159func (c *classNode) Value() interface{} { 160 return c.Members.Value() 161} 162 163func (m members) Value() interface{} { 164 r := make(map[string]interface{}, len(m)) 165 for k, v := range m { 166 r[k] = v.Value() 167 } 168 return r 169} 170 171type instanceNode struct { 172 nodeType 173 pos 174 Members members 175} 176 177func newInstance(pos pos) *instanceNode { 178 return &instanceNode{ 179 nodeType: nodeInstance, 180 pos: pos, 181 Members: make(members), 182 } 183} 184 185func (i *instanceNode) Value() interface{} { 186 return i.Members.Value() 187} 188 189type arrayNode struct { 190 nodeType 191 pos 192 Array []node 193} 194 195func newArray(pos pos) *arrayNode { 196 return &arrayNode{nodeType: nodeArray, pos: pos} 197} 198 199func (a *arrayNode) Value() interface{} { 200 r := make([]interface{}, len(a.Array)) 201 for i, v := range a.Array { 202 r[i] = v.Value() 203 } 204 return r 205} 206 207// Walk invokes f on n and sub-nodes of n. 208func walk(n node, f func(node)) { 209 f(n) 210 switch n := n.(type) { 211 case *arrayNode: 212 for _, a := range n.Array { 213 walk(a, f) 214 } 215 case *classNode: 216 for _, a := range n.Members { 217 walk(a, f) 218 } 219 case *numberNode, *stringNode: 220 // Ignore. 221 default: 222 panic(fmt.Errorf("other type: %T", n)) 223 } 224} 225