cglsml.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*
  2. Tideland Common Go Library - Simple Markup Language
  3. Copyright (C) 2011 Frank Mueller / Oldenburg / Germany
  4. Redistribution and use in source and binary forms, with or
  5. modification, are permitted provided that the following conditions are
  6. met:
  7. Redistributions of source code must retain the above copyright notice, this
  8. list of conditions and the following disclaimer.
  9. Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. Neither the name of Tideland nor the names of its contributors may be
  13. used to endorse or promote products derived from this software without
  14. specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  25. THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. package cgl
  28. //--------------------
  29. // IMPORTS
  30. //--------------------
  31. import (
  32. "bufio"
  33. "bytes"
  34. "fmt"
  35. "io"
  36. "os"
  37. "strings"
  38. "unicode"
  39. )
  40. //--------------------
  41. // PROCESSOR
  42. //--------------------
  43. // Processor interface.
  44. type Processor interface {
  45. OpenTag(tag []string)
  46. CloseTag(tag []string)
  47. Text(text string)
  48. }
  49. //--------------------
  50. // NODE
  51. //--------------------
  52. // The node.
  53. type Node interface {
  54. Len() int
  55. ProcessWith(p Processor)
  56. }
  57. //--------------------
  58. // TAG NODE
  59. //--------------------
  60. // The tag node.
  61. type TagNode struct {
  62. tag []string
  63. children []Node
  64. }
  65. // Create a new tag node.
  66. func NewTagNode(tag string) *TagNode {
  67. tmp := strings.ToLower(tag)
  68. if !validIdentifier(tmp) {
  69. return nil
  70. }
  71. tn := &TagNode{
  72. tag: strings.Split(tmp, ":"),
  73. children: make([]Node, 0),
  74. }
  75. return tn
  76. }
  77. // Append a new tag.
  78. func (tn *TagNode) AppendTag(tag string) *TagNode {
  79. n := NewTagNode(tag)
  80. if n != nil {
  81. tn.children = append(tn.children, n)
  82. }
  83. return n
  84. }
  85. // Append a tag node.
  86. func (tn *TagNode) AppendTagNode(n *TagNode) *TagNode {
  87. tn.children = append(tn.children, n)
  88. return n
  89. }
  90. // Append a text node.
  91. func (tn *TagNode) AppendText(text string) *TextNode {
  92. n := NewTextNode(text)
  93. tn.children = append(tn.children, n)
  94. return n
  95. }
  96. // Append a tagged text node.
  97. func (tn *TagNode) AppendTaggedText(tag, text string) *TagNode {
  98. n := NewTagNode(tag)
  99. if n != nil {
  100. n.AppendText(text)
  101. tn.children = append(tn.children, n)
  102. }
  103. return n
  104. }
  105. // Append a text node.
  106. func (tn *TagNode) AppendTextNode(n *TextNode) *TextNode {
  107. tn.children = append(tn.children, n)
  108. return n
  109. }
  110. // Return the len of the tag node (aka number of children).
  111. func (tn *TagNode) Len() int {
  112. return len(tn.children)
  113. }
  114. // Process the node.
  115. func (tn *TagNode) ProcessWith(p Processor) {
  116. p.OpenTag(tn.tag)
  117. for _, child := range tn.children {
  118. child.ProcessWith(p)
  119. }
  120. p.CloseTag(tn.tag)
  121. }
  122. // Return the node as a string.
  123. func (tn *TagNode) String() string {
  124. buf := bytes.NewBufferString("")
  125. spp := NewSmlWriterProcessor(buf, true)
  126. tn.ProcessWith(spp)
  127. return buf.String()
  128. }
  129. //--------------------
  130. // TEXT NODE
  131. //--------------------
  132. // The text node.
  133. type TextNode struct {
  134. text string
  135. }
  136. // Create a new text node.
  137. func NewTextNode(text string) *TextNode {
  138. return &TextNode{text}
  139. }
  140. // Return the len of the text node.
  141. func (tn *TextNode) Len() int {
  142. return len(tn.text)
  143. }
  144. // Process the node.
  145. func (tn *TextNode) ProcessWith(p Processor) {
  146. p.Text(tn.text)
  147. }
  148. // Return the node as a string.
  149. func (tn *TextNode) String() string {
  150. return tn.text
  151. }
  152. //--------------------
  153. // PRIVATE FUNCTIONS
  154. //--------------------
  155. // Check an identifier (tag or id).
  156. func validIdentifier(id string) bool {
  157. for _, c := range id {
  158. if c < 'a' || c > 'z' {
  159. if c < '0' || c > '9' {
  160. if c != '-' && c != ':' {
  161. return false
  162. }
  163. }
  164. }
  165. }
  166. return true
  167. }
  168. //--------------------
  169. // SML READER
  170. //--------------------
  171. // Control values.
  172. const (
  173. ctrlText = iota
  174. ctrlSpace
  175. ctrlOpen
  176. ctrlClose
  177. ctrlEscape
  178. ctrlTag
  179. ctrlEOF
  180. ctrlInvalid
  181. )
  182. // Node read modes.
  183. const (
  184. modeInit = iota
  185. modeTag
  186. modeText
  187. )
  188. // Reader for SML.
  189. type SmlReader struct {
  190. reader *bufio.Reader
  191. index int
  192. root *TagNode
  193. error os.Error
  194. }
  195. // Create the reader.
  196. func NewSmlReader(reader io.Reader) *SmlReader {
  197. // Init the reader.
  198. sr := &SmlReader{
  199. reader: bufio.NewReader(reader),
  200. index: -1,
  201. }
  202. node, ctrl := sr.readNode()
  203. switch ctrl {
  204. case ctrlClose:
  205. sr.root = node
  206. sr.error = nil
  207. case ctrlEOF:
  208. msg := fmt.Sprintf("eof too early at index %v", sr.index)
  209. sr.error = os.NewError(msg)
  210. case ctrlInvalid:
  211. msg := fmt.Sprintf("invalid rune at index %v", sr.index)
  212. sr.error = os.NewError(msg)
  213. }
  214. return sr
  215. }
  216. // Return the root tag node.
  217. func (sr *SmlReader) RootTagNode() (*TagNode, os.Error) {
  218. return sr.root, sr.error
  219. }
  220. // Read a node.
  221. func (sr *SmlReader) readNode() (*TagNode, int) {
  222. var node *TagNode
  223. var buffer *bytes.Buffer
  224. mode := modeInit
  225. for {
  226. rune, ctrl := sr.readRune()
  227. sr.index++
  228. switch mode {
  229. case modeInit:
  230. // Before the first opening bracket.
  231. switch ctrl {
  232. case ctrlEOF:
  233. return nil, ctrlEOF
  234. case ctrlOpen:
  235. mode = modeTag
  236. buffer = bytes.NewBufferString("")
  237. }
  238. case modeTag:
  239. // Reading a tag.
  240. switch ctrl {
  241. case ctrlEOF:
  242. return nil, ctrlEOF
  243. case ctrlTag:
  244. buffer.WriteRune(rune)
  245. case ctrlSpace:
  246. if buffer.Len() == 0 {
  247. return nil, ctrlInvalid
  248. }
  249. node = NewTagNode(buffer.String())
  250. buffer = bytes.NewBufferString("")
  251. mode = modeText
  252. case ctrlClose:
  253. if buffer.Len() == 0 {
  254. return nil, ctrlInvalid
  255. }
  256. node = NewTagNode(buffer.String())
  257. return node, ctrlClose
  258. default:
  259. return nil, ctrlInvalid
  260. }
  261. case modeText:
  262. // Reading the text including the subnodes following
  263. // the space after the tag or id.
  264. switch ctrl {
  265. case ctrlEOF:
  266. return nil, ctrlEOF
  267. case ctrlOpen:
  268. text := strings.TrimSpace(buffer.String())
  269. if len(text) > 0 {
  270. node.AppendText(text)
  271. }
  272. buffer = bytes.NewBufferString("")
  273. sr.reader.UnreadRune()
  274. subnode, subctrl := sr.readNode()
  275. if subctrl == ctrlClose {
  276. // Correct closed subnode.
  277. node.AppendTagNode(subnode)
  278. } else {
  279. // Error while reading the subnode.
  280. return nil, subctrl
  281. }
  282. case ctrlClose:
  283. text := strings.TrimSpace(buffer.String())
  284. if len(text) > 0 {
  285. node.AppendText(text)
  286. }
  287. return node, ctrlClose
  288. case ctrlEscape:
  289. rune, ctrl = sr.readRune()
  290. if ctrl == ctrlOpen || ctrl == ctrlClose || ctrl == ctrlEscape {
  291. buffer.WriteRune(rune)
  292. sr.index++
  293. } else {
  294. return nil, ctrlInvalid
  295. }
  296. default:
  297. buffer.WriteRune(rune)
  298. }
  299. }
  300. }
  301. return nil, ctrlEOF
  302. }
  303. // Read a rune.
  304. func (sr *SmlReader) readRune() (rune, control int) {
  305. var size int
  306. rune, size, sr.error = sr.reader.ReadRune()
  307. switch {
  308. case size == 0:
  309. return rune, ctrlEOF
  310. case rune == '{':
  311. return rune, ctrlOpen
  312. case rune == '}':
  313. return rune, ctrlClose
  314. case rune == '^':
  315. return rune, ctrlEscape
  316. case rune >= 'a' && rune <= 'z':
  317. return rune, ctrlTag
  318. case rune >= 'A' && rune <= 'Z':
  319. return rune, ctrlTag
  320. case rune >= '0' && rune <= '9':
  321. return rune, ctrlTag
  322. case rune == '-':
  323. return rune, ctrlTag
  324. case rune == ':':
  325. return rune, ctrlTag
  326. case unicode.IsSpace(rune):
  327. return rune, ctrlSpace
  328. }
  329. return rune, ctrlText
  330. }
  331. //--------------------
  332. // SML WRITER PROCESSOR
  333. //--------------------
  334. // Processor for writing SML.
  335. type SmlWriterProcessor struct {
  336. writer *bufio.Writer
  337. prettyPrint bool
  338. indentLevel int
  339. }
  340. // Create a new SML writer processor.
  341. func NewSmlWriterProcessor(writer io.Writer, prettyPrint bool) *SmlWriterProcessor {
  342. swp := &SmlWriterProcessor{
  343. writer: bufio.NewWriter(writer),
  344. prettyPrint: prettyPrint,
  345. indentLevel: 0,
  346. }
  347. return swp
  348. }
  349. // Open a tag.
  350. func (swp *SmlWriterProcessor) OpenTag(tag []string) {
  351. swp.writeIndent(true)
  352. swp.writer.WriteString("{")
  353. swp.writer.WriteString(strings.Join(tag, ":"))
  354. }
  355. // Close a tag.
  356. func (swp *SmlWriterProcessor) CloseTag(tag []string) {
  357. swp.writer.WriteString("}")
  358. if swp.prettyPrint {
  359. swp.indentLevel--
  360. }
  361. swp.writer.Flush()
  362. }
  363. // Write a text.
  364. func (swp *SmlWriterProcessor) Text(text string) {
  365. ta := strings.Replace(text, "^", "^^", -1)
  366. tb := strings.Replace(ta, "{", "^{", -1)
  367. tc := strings.Replace(tb, "}", "^}", -1)
  368. swp.writeIndent(false)
  369. swp.writer.WriteString(tc)
  370. }
  371. // Write an indent in case of pretty print.
  372. func (swp *SmlWriterProcessor) writeIndent(increase bool) {
  373. if swp.prettyPrint {
  374. if swp.indentLevel > 0 {
  375. swp.writer.WriteString("\n")
  376. }
  377. for i := 0; i < swp.indentLevel; i++ {
  378. swp.writer.WriteString("\t")
  379. }
  380. if increase {
  381. swp.indentLevel++
  382. }
  383. } else {
  384. swp.writer.WriteString(" ")
  385. }
  386. }
  387. /*
  388. EOF
  389. */