jade_node.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. package jade
  2. import (
  3. "bytes"
  4. "fmt"
  5. "go/parser"
  6. "html"
  7. "io"
  8. "log"
  9. "regexp"
  10. "strings"
  11. )
  12. type TagNode struct {
  13. NodeType
  14. Pos
  15. tr *Tree
  16. Nodes []Node
  17. AttrName []string
  18. AttrCode []string
  19. TagName string
  20. tagType itemType
  21. tab int
  22. }
  23. func (t *Tree) newTag(pos Pos, name string, tagType itemType) *TagNode {
  24. return &TagNode{tr: t, NodeType: NodeTag, Pos: pos, TagName: name, tagType: tagType, tab: t.tab}
  25. }
  26. func (l *TagNode) append(n Node) {
  27. l.Nodes = append(l.Nodes, n)
  28. }
  29. func (l *TagNode) tree() *Tree {
  30. return l.tr
  31. }
  32. func (l *TagNode) attr(a, b string) {
  33. for k, v := range l.AttrName {
  34. if v == a {
  35. l.AttrCode[k] = fmt.Sprintf(tag__arg_add, l.AttrCode[k], b)
  36. return
  37. }
  38. }
  39. l.AttrName = append(l.AttrName, a)
  40. l.AttrCode = append(l.AttrCode, b)
  41. }
  42. func codeStrFmt(a string) (string, bool) {
  43. var (
  44. str = []rune(a)
  45. lng = len(str)
  46. first = str[0]
  47. last = str[lng-1]
  48. unesc = false
  49. )
  50. if first == 'ߐ' { // FIXME temporarily ߐ - [AttrEqualUn] Unescaped flag set in parseAttributes()
  51. str = append(str[:0], str[1:]...)
  52. lng -= 1
  53. first = str[0]
  54. last = str[lng-1]
  55. unesc = true
  56. }
  57. switch first {
  58. case '"', '\'':
  59. if first == last {
  60. for k, v := range str[1 : lng-1] {
  61. if v == first && str[k] != '\\' {
  62. return "", false
  63. }
  64. }
  65. if unesc {
  66. return string(str[1 : lng-1]), true
  67. }
  68. return html.EscapeString(string(str[1 : lng-1])), true
  69. }
  70. case '`':
  71. if first == last {
  72. if !strings.ContainsAny(string(str[1:lng-1]), "`") {
  73. if unesc {
  74. return string(str[1 : lng-1]), true
  75. }
  76. return html.EscapeString(string(str[1 : lng-1])), true
  77. }
  78. }
  79. }
  80. return "", false
  81. }
  82. func query(a string) (string, bool) {
  83. var (
  84. re = regexp.MustCompile(`^(.+)\?(.+):(.+)$`)
  85. match = re.FindStringSubmatch(a)
  86. )
  87. if len(match) == 4 {
  88. for _, v := range match[1:4] {
  89. if _, err := parser.ParseExpr(v); err != nil {
  90. return "", false
  91. }
  92. }
  93. return "qf(" + match[1] + ", " + match[2] + ", " + match[3] + ")", true
  94. }
  95. return "", false
  96. }
  97. func (l *TagNode) String() string {
  98. var b = new(bytes.Buffer)
  99. l.WriteIn(b)
  100. return b.String()
  101. }
  102. func (l *TagNode) WriteIn(b io.Writer) {
  103. var (
  104. attr = new(bytes.Buffer)
  105. )
  106. if len(l.AttrName) > 0 {
  107. fmt.Fprint(attr, tag__arg_bgn)
  108. for k, name := range l.AttrName {
  109. if arg, ok := codeStrFmt(l.AttrCode[k]); ok {
  110. fmt.Fprintf(attr, tag__arg_str, name, arg)
  111. } else if !golang_mode {
  112. fmt.Fprintf(attr, tag__arg, name, l.AttrCode[k])
  113. } else if _, err := parser.ParseExpr(l.AttrCode[k]); err == nil {
  114. fmt.Fprintf(attr, tag__arg, name, l.Pos, l.AttrCode[k])
  115. } else if arg, ok := query(l.AttrCode[k]); ok {
  116. fmt.Fprintf(attr, tag__arg, name, l.Pos, arg)
  117. } else {
  118. log.Fatalln("Error tag attribute value ==> ", l.AttrCode[k])
  119. }
  120. }
  121. fmt.Fprint(attr, tag__arg_end)
  122. }
  123. switch l.tagType {
  124. case itemTagVoid:
  125. fmt.Fprintf(b, tag__void, l.TagName, attr)
  126. case itemTagVoidInline:
  127. fmt.Fprintf(b, tag__void, l.TagName, attr)
  128. default:
  129. fmt.Fprintf(b, tag__bgn, l.TagName, attr)
  130. for _, inner := range l.Nodes {
  131. inner.WriteIn(b)
  132. }
  133. fmt.Fprintf(b, tag__end, l.TagName)
  134. }
  135. }
  136. func (l *TagNode) CopyTag() *TagNode {
  137. if l == nil {
  138. return l
  139. }
  140. n := l.tr.newTag(l.Pos, l.TagName, l.tagType)
  141. n.tab = l.tab
  142. n.AttrCode = l.AttrCode
  143. n.AttrName = l.AttrName
  144. for _, elem := range l.Nodes {
  145. n.append(elem.Copy())
  146. }
  147. return n
  148. }
  149. func (l *TagNode) Copy() Node {
  150. return l.CopyTag()
  151. }
  152. //
  153. //
  154. type CondNode struct {
  155. NodeType
  156. Pos
  157. tr *Tree
  158. Nodes []Node
  159. cond string
  160. condType itemType
  161. tab int
  162. }
  163. func (t *Tree) newCond(pos Pos, cond string, condType itemType) *CondNode {
  164. return &CondNode{tr: t, NodeType: NodeCond, Pos: pos, cond: cond, condType: condType, tab: t.tab}
  165. }
  166. func (l *CondNode) append(n Node) {
  167. l.Nodes = append(l.Nodes, n)
  168. }
  169. func (l *CondNode) tree() *Tree {
  170. return l.tr
  171. }
  172. func (l *CondNode) String() string {
  173. var b = new(bytes.Buffer)
  174. l.WriteIn(b)
  175. return b.String()
  176. }
  177. func (l *CondNode) WriteIn(b io.Writer) {
  178. switch l.condType {
  179. case itemIf:
  180. fmt.Fprintf(b, cond__if, l.cond)
  181. case itemUnless:
  182. fmt.Fprintf(b, cond__unless, l.cond)
  183. case itemCase:
  184. fmt.Fprintf(b, cond__case, l.cond)
  185. case itemWhile:
  186. fmt.Fprintf(b, cond__while, l.cond)
  187. case itemFor, itemEach:
  188. if k, v, name, ok := l.parseForArgs(); ok {
  189. fmt.Fprintf(b, cond__for, k, v, name)
  190. } else {
  191. fmt.Fprintf(b, "\n{{ Error malformed each: %s }}", l.cond)
  192. }
  193. case itemForIfNotContain:
  194. if k, v, name, ok := l.parseForArgs(); ok {
  195. fmt.Fprintf(b, cond__for_if, name, k, v, name)
  196. } else {
  197. fmt.Fprintf(b, "\n{{ Error malformed each: %s }}", l.cond)
  198. }
  199. default:
  200. fmt.Fprintf(b, "{{ Error Cond %s }}", l.cond)
  201. }
  202. for _, n := range l.Nodes {
  203. n.WriteIn(b)
  204. }
  205. fmt.Fprint(b, cond__end)
  206. }
  207. func (l *CondNode) parseForArgs() (k, v, name string, ok bool) {
  208. sp := strings.SplitN(l.cond, " in ", 2)
  209. if len(sp) != 2 {
  210. return
  211. }
  212. name = strings.Trim(sp[1], " ")
  213. re := regexp.MustCompile(`^(\w+)\s*,\s*(\w+)$`)
  214. kv := re.FindAllStringSubmatch(strings.Trim(sp[0], " "), -1)
  215. if len(kv) == 1 && len(kv[0]) == 3 {
  216. k = kv[0][2]
  217. v = kv[0][1]
  218. ok = true
  219. return
  220. }
  221. r2 := regexp.MustCompile(`^\w+$`)
  222. kv2 := r2.FindAllString(strings.Trim(sp[0], " "), -1)
  223. if len(kv2) == 1 {
  224. k = "_"
  225. v = kv2[0]
  226. ok = true
  227. return
  228. }
  229. return
  230. }
  231. func (l *CondNode) CopyCond() *CondNode {
  232. if l == nil {
  233. return l
  234. }
  235. n := l.tr.newCond(l.Pos, l.cond, l.condType)
  236. n.tab = l.tab
  237. for _, elem := range l.Nodes {
  238. n.append(elem.Copy())
  239. }
  240. return n
  241. }
  242. func (l *CondNode) Copy() Node {
  243. return l.CopyCond()
  244. }
  245. //
  246. //
  247. type CodeNode struct {
  248. NodeType
  249. Pos
  250. tr *Tree
  251. codeType itemType
  252. Code []byte // The text; may span newlines.
  253. tab int
  254. }
  255. func (t *Tree) newCode(pos Pos, text string, codeType itemType) *CodeNode {
  256. return &CodeNode{tr: t, NodeType: NodeCode, Pos: pos, Code: []byte(text), codeType: codeType, tab: t.tab}
  257. }
  258. func (t *CodeNode) String() string {
  259. var b = new(bytes.Buffer)
  260. t.WriteIn(b)
  261. return b.String()
  262. }
  263. func (t *CodeNode) WriteIn(b io.Writer) {
  264. switch t.codeType {
  265. case itemCode:
  266. fmt.Fprintf(b, code__longcode, t.Code)
  267. case itemCodeBuffered:
  268. if !golang_mode {
  269. fmt.Fprintf(b, code__buffered, t.Code)
  270. } else if cb, ok := codeStrFmt(string(t.Code)); ok {
  271. fmt.Fprintf(b, code__buffered, t.Pos, `"`+cb+`"`)
  272. } else {
  273. fmt.Fprintf(b, code__buffered, t.Pos, t.Code)
  274. }
  275. case itemCodeUnescaped:
  276. fmt.Fprintf(b, code__unescaped, t.Code)
  277. case itemElse:
  278. fmt.Fprintf(b, code__else)
  279. case itemElseIf:
  280. fmt.Fprintf(b, code__else_if, t.Code)
  281. case itemForElse:
  282. fmt.Fprintf(b, code__for_else)
  283. case itemCaseWhen:
  284. fmt.Fprintf(b, code__case_when, t.Code)
  285. case itemCaseDefault:
  286. fmt.Fprintf(b, code__case_def)
  287. case itemMixinBlock:
  288. fmt.Fprintf(b, code__mix_block)
  289. default:
  290. fmt.Fprintf(b, "{{ Error Code %s }}", t.Code)
  291. }
  292. }
  293. func (t *CodeNode) tree() *Tree {
  294. return t.tr
  295. }
  296. func (t *CodeNode) Copy() Node {
  297. return &CodeNode{tr: t.tr, NodeType: NodeCode, Pos: t.Pos, codeType: t.codeType, Code: append([]byte{}, t.Code...), tab: t.tab}
  298. }
  299. //
  300. //
  301. type BlockNode struct {
  302. NodeType
  303. Pos
  304. tr *Tree
  305. blockType itemType
  306. Name string
  307. tab int
  308. }
  309. func (t *Tree) newBlock(pos Pos, name string, textType itemType) *BlockNode {
  310. return &BlockNode{tr: t, NodeType: NodeBlock, Pos: pos, Name: name, blockType: textType, tab: t.tab}
  311. }
  312. func (t *BlockNode) String() string {
  313. var b = new(bytes.Buffer)
  314. t.WriteIn(b)
  315. return b.String()
  316. }
  317. func (t *BlockNode) WriteIn(b io.Writer) {
  318. var (
  319. out_blk = t.tr.block[t.Name]
  320. out_pre, ok_pre = t.tr.block[t.Name+"_prepend"]
  321. out_app, ok_app = t.tr.block[t.Name+"_append"]
  322. )
  323. if ok_pre {
  324. out_pre.WriteIn(b)
  325. }
  326. out_blk.WriteIn(b)
  327. if ok_app {
  328. out_app.WriteIn(b)
  329. }
  330. }
  331. func (t *BlockNode) tree() *Tree {
  332. return t.tr
  333. }
  334. func (t *BlockNode) Copy() Node {
  335. return &BlockNode{tr: t.tr, NodeType: NodeBlock, Pos: t.Pos, blockType: t.blockType, Name: t.Name, tab: t.tab}
  336. }
  337. //
  338. //
  339. type TextNode struct {
  340. NodeType
  341. Pos
  342. tr *Tree
  343. textType itemType
  344. Text []byte // The text; may span newlines.
  345. tab int
  346. }
  347. func (t *Tree) newText(pos Pos, text string, textType itemType) *TextNode {
  348. return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text), textType: textType, tab: t.tab}
  349. }
  350. func (t *TextNode) String() string {
  351. var b = new(bytes.Buffer)
  352. t.WriteIn(b)
  353. return b.String()
  354. }
  355. func (t *TextNode) WriteIn(b io.Writer) {
  356. switch t.textType {
  357. case itemComment:
  358. fmt.Fprintf(b, text__comment, t.Text)
  359. default:
  360. fmt.Fprintf(b, text__str, t.Text)
  361. }
  362. }
  363. func (t *TextNode) tree() *Tree {
  364. return t.tr
  365. }
  366. func (t *TextNode) Copy() Node {
  367. return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, textType: t.textType, Text: append([]byte{}, t.Text...), tab: t.tab}
  368. }
  369. //
  370. //
  371. type MixinNode struct {
  372. NodeType
  373. Pos
  374. tr *Tree
  375. Nodes []Node
  376. AttrName []string
  377. AttrCode []string
  378. AttrRest []string
  379. MixinName string
  380. block string
  381. tagType itemType
  382. tab int
  383. }
  384. func (t *Tree) newMixin(pos Pos) *MixinNode {
  385. return &MixinNode{tr: t, NodeType: NodeMixin, Pos: pos, tab: t.tab}
  386. }
  387. func (l *MixinNode) append(n Node) {
  388. l.Nodes = append(l.Nodes, n)
  389. }
  390. func (l *MixinNode) attr(a, b string) {
  391. l.AttrName = append(l.AttrName, a)
  392. l.AttrCode = append(l.AttrCode, b)
  393. }
  394. func (l *MixinNode) tree() *Tree {
  395. return l.tr
  396. }
  397. func (l *MixinNode) String() string {
  398. var b = new(bytes.Buffer)
  399. l.WriteIn(b)
  400. return b.String()
  401. }
  402. func (l *MixinNode) WriteIn(b io.Writer) {
  403. var (
  404. attr = new(bytes.Buffer)
  405. an = len(l.AttrName)
  406. rest = len(l.AttrRest)
  407. )
  408. if an > 0 {
  409. fmt.Fprintf(attr, mixin__var_bgn)
  410. fmt.Fprintf(attr, mixin__var_block, l.block)
  411. if rest > 0 {
  412. fmt.Fprintf(attr, mixin__var_rest, strings.TrimLeft(l.AttrName[an-1], "."), l.AttrRest)
  413. l.AttrName = l.AttrName[:an-1]
  414. }
  415. for k, name := range l.AttrName {
  416. fmt.Fprintf(attr, mixin__var, name, l.AttrCode[k])
  417. }
  418. fmt.Fprintf(attr, mixin__var_end)
  419. }
  420. fmt.Fprintf(b, mixin__bgn, attr)
  421. for _, n := range l.Nodes {
  422. n.WriteIn(b)
  423. }
  424. fmt.Fprintf(b, mixin__end)
  425. }
  426. func (l *MixinNode) CopyMixin() *MixinNode {
  427. if l == nil {
  428. return l
  429. }
  430. n := l.tr.newMixin(l.Pos)
  431. n.tab = l.tab
  432. for _, elem := range l.Nodes {
  433. n.append(elem.Copy())
  434. }
  435. return n
  436. }
  437. func (l *MixinNode) Copy() Node {
  438. return l.CopyMixin()
  439. }
  440. //
  441. //
  442. type DoctypeNode struct {
  443. NodeType
  444. Pos
  445. tr *Tree
  446. doctype string
  447. }
  448. func (t *Tree) newDoctype(pos Pos, text string) *DoctypeNode {
  449. doc := ""
  450. txt := strings.Trim(text, " ")
  451. if len(txt) > 0 {
  452. sls := strings.SplitN(txt, " ", 2)
  453. switch sls[0] {
  454. case "5", "html":
  455. doc = `<!DOCTYPE html%s>`
  456. case "xml":
  457. doc = `<?xml version="1.0" encoding="utf-8"%s ?>`
  458. case "1.1", "xhtml":
  459. doc = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"%s>`
  460. case "basic":
  461. doc = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"%s>`
  462. case "strict":
  463. doc = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"%s>`
  464. case "frameset":
  465. doc = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"%s>`
  466. case "transitional":
  467. doc = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"%s>`
  468. case "mobile":
  469. doc = `<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"%s>`
  470. case "4", "4strict":
  471. doc = `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"%s>`
  472. case "4frameset":
  473. doc = `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"%s>`
  474. case "4transitional":
  475. doc = `<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"%s>`
  476. }
  477. if doc == "" {
  478. doc = fmt.Sprintf("<!DOCTYPE %s>", txt)
  479. } else if doc != "" && len(sls) == 2 {
  480. doc = fmt.Sprintf(doc, " "+sls[1])
  481. } else {
  482. doc = fmt.Sprintf(doc, "")
  483. }
  484. } else {
  485. doc = `<!DOCTYPE html>`
  486. }
  487. return &DoctypeNode{tr: t, NodeType: NodeDoctype, Pos: pos, doctype: doc}
  488. }
  489. func (d *DoctypeNode) String() string {
  490. return fmt.Sprintf(text__str, d.doctype)
  491. }
  492. func (d *DoctypeNode) WriteIn(b io.Writer) {
  493. b.Write([]byte(d.doctype))
  494. }
  495. func (d *DoctypeNode) tree() *Tree {
  496. return d.tr
  497. }
  498. func (d *DoctypeNode) Copy() Node {
  499. return &DoctypeNode{tr: d.tr, NodeType: NodeDoctype, Pos: d.Pos, doctype: d.doctype}
  500. }