jade_parse.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. package jade
  2. import (
  3. "log"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. )
  8. func (t *Tree) topParse() {
  9. t.Root = t.newList(t.peek().pos)
  10. var (
  11. ext bool
  12. token = t.nextNonSpace()
  13. )
  14. if token.typ == itemExtends {
  15. ext = true
  16. t.Root.append(t.parseSubFile(token.val))
  17. token = t.nextNonSpace()
  18. }
  19. for {
  20. switch token.typ {
  21. case itemInclude:
  22. t.Root.append(t.parseInclude(token))
  23. case itemBlock, itemBlockPrepend, itemBlockAppend:
  24. if ext {
  25. t.parseBlock(token)
  26. } else {
  27. t.Root.append(t.parseBlock(token))
  28. }
  29. case itemMixin:
  30. t.mixin[token.val] = t.parseMixin(token)
  31. case itemEOF:
  32. return
  33. case itemExtends:
  34. t.errorf(`Declaration of template inheritance ("extends") should be the first thing in the file. There can only be one extends statement per file.`)
  35. case itemError:
  36. t.errorf("%s line: %d\n", token.val, token.line)
  37. default:
  38. if ext {
  39. t.errorf(`Only import, named blocks and mixins can appear at the top level of an extending template`)
  40. }
  41. t.Root.append(t.hub(token))
  42. }
  43. token = t.nextNonSpace()
  44. }
  45. }
  46. func (t *Tree) hub(token item) (n Node) {
  47. for {
  48. switch token.typ {
  49. case itemDiv:
  50. token.val = "div"
  51. fallthrough
  52. case itemTag, itemTagInline, itemTagVoid, itemTagVoidInline:
  53. return t.parseTag(token)
  54. case itemText, itemComment, itemHTMLTag:
  55. return t.newText(token.pos, []byte(token.val), token.typ)
  56. case itemCode, itemCodeBuffered, itemCodeUnescaped, itemMixinBlock:
  57. return t.newCode(token.pos, token.val, token.typ)
  58. case itemIf, itemUnless:
  59. return t.parseIf(token)
  60. case itemFor, itemEach, itemWhile:
  61. return t.parseFor(token)
  62. case itemCase:
  63. return t.parseCase(token)
  64. case itemBlock, itemBlockPrepend, itemBlockAppend:
  65. return t.parseBlock(token)
  66. case itemMixinCall:
  67. return t.parseMixinUse(token)
  68. case itemInclude:
  69. return t.parseInclude(token)
  70. case itemDoctype:
  71. return t.newDoctype(token.pos, token.val)
  72. case itemFilter:
  73. return t.parseFilter(token)
  74. case itemError:
  75. t.errorf("Error lex: %s line: %d\n", token.val, token.line)
  76. default:
  77. t.errorf(`Error hub(): unexpected token "%s" type "%s"`, token.val, token.typ)
  78. }
  79. }
  80. }
  81. func (t *Tree) parseFilter(tk item) Node {
  82. var subf, args, text string
  83. Loop:
  84. for {
  85. switch token := t.nextNonSpace(); token.typ {
  86. case itemFilterSubf:
  87. subf = token.val
  88. case itemFilterArgs:
  89. args = strings.Trim(token.val, " \t\r\n")
  90. case itemFilterText:
  91. text = strings.Trim(token.val, " \t\r\n")
  92. default:
  93. break Loop
  94. }
  95. }
  96. t.backup()
  97. switch tk.val {
  98. case "go":
  99. filterGo(subf, args, text)
  100. case "markdown", "markdown-it":
  101. // TODO: filterMarkdown(subf, args, text)
  102. }
  103. return t.newList(tk.pos) // for return nothing
  104. }
  105. func filterGo(subf, args, text string) {
  106. switch subf {
  107. case "func":
  108. Go.Name = ""
  109. switch args {
  110. case "name":
  111. Go.Name = text
  112. case "arg", "args":
  113. if Go.Args != "" {
  114. Go.Args += ", " + strings.Trim(text, "()")
  115. } else {
  116. Go.Args = strings.Trim(text, "()")
  117. }
  118. default:
  119. fn := strings.Split(text, "(")
  120. if len(fn) == 2 {
  121. Go.Name = strings.Trim(fn[0], " \t\n)")
  122. Go.Args = strings.Trim(fn[1], " \t\n)")
  123. } else {
  124. log.Fatal(":go:func filter error in " + text)
  125. }
  126. }
  127. case "import":
  128. Go.Import = text
  129. }
  130. }
  131. func (t *Tree) parseTag(tk item) Node {
  132. var (
  133. deep = tk.depth
  134. tag = t.newTag(tk.pos, tk.val, tk.typ)
  135. )
  136. Loop:
  137. for {
  138. switch token := t.nextNonSpace(); {
  139. case token.depth > deep:
  140. if tag.tagType == itemTagVoid || tag.tagType == itemTagVoidInline {
  141. break Loop
  142. }
  143. tag.append(t.hub(token))
  144. case token.depth == deep:
  145. switch token.typ {
  146. case itemClass:
  147. tag.attr("class", `"`+token.val+`"`, false)
  148. case itemID:
  149. tag.attr("id", `"`+token.val+`"`, false)
  150. case itemAttrStart:
  151. t.parseAttributes(tag, `"`)
  152. case itemTagEnd:
  153. tag.tagType = itemTagVoid
  154. return tag
  155. default:
  156. break Loop
  157. }
  158. default:
  159. break Loop
  160. }
  161. }
  162. t.backup()
  163. return tag
  164. }
  165. type pAttr interface {
  166. attr(string, string, bool)
  167. }
  168. func (t *Tree) parseAttributes(tag pAttr, qw string) {
  169. var (
  170. aname string
  171. equal bool
  172. unesc bool
  173. stack = make([]string, 0, 4)
  174. )
  175. for {
  176. switch token := t.next(); token.typ {
  177. case itemAttrSpace:
  178. // skip
  179. case itemAttr:
  180. switch {
  181. case aname == "":
  182. aname = token.val
  183. case aname != "" && !equal:
  184. tag.attr(aname, qw+aname+qw, unesc)
  185. aname = token.val
  186. case aname != "" && equal:
  187. stack = append(stack, token.val)
  188. }
  189. case itemAttrEqual, itemAttrEqualUn:
  190. if token.typ == itemAttrEqual {
  191. unesc = false
  192. } else {
  193. unesc = true
  194. }
  195. equal = true
  196. switch len_stack := len(stack); {
  197. case len_stack == 0 && aname != "":
  198. // skip
  199. case len_stack > 1 && aname != "":
  200. tag.attr(aname, strings.Join(stack[:len(stack)-1], " "), unesc)
  201. aname = stack[len(stack)-1]
  202. stack = stack[:0]
  203. case len_stack == 1 && aname == "":
  204. aname = stack[0]
  205. stack = stack[:0]
  206. default:
  207. t.errorf("unexpected '='")
  208. }
  209. case itemAttrComma:
  210. equal = false
  211. switch len_stack := len(stack); {
  212. case len_stack > 0 && aname != "":
  213. tag.attr(aname, strings.Join(stack, " "), unesc)
  214. aname = ""
  215. stack = stack[:0]
  216. case len_stack == 0 && aname != "":
  217. tag.attr(aname, qw+aname+qw, unesc)
  218. aname = ""
  219. }
  220. case itemAttrEnd:
  221. switch len_stack := len(stack); {
  222. case len_stack > 0 && aname != "":
  223. tag.attr(aname, strings.Join(stack, " "), unesc)
  224. case len_stack > 0 && aname == "":
  225. for _, a := range stack {
  226. tag.attr(a, a, unesc)
  227. }
  228. case len_stack == 0 && aname != "":
  229. tag.attr(aname, qw+aname+qw, unesc)
  230. }
  231. return
  232. default:
  233. t.errorf("unexpected %s", token.val)
  234. }
  235. }
  236. }
  237. func (t *Tree) parseIf(tk item) Node {
  238. var (
  239. deep = tk.depth
  240. cond = t.newCond(tk.pos, tk.val, tk.typ)
  241. )
  242. Loop:
  243. for {
  244. switch token := t.nextNonSpace(); {
  245. case token.depth > deep:
  246. cond.append(t.hub(token))
  247. case token.depth == deep:
  248. switch token.typ {
  249. case itemElse:
  250. ni := t.peek()
  251. if ni.typ == itemIf {
  252. token = t.next()
  253. cond.append(t.newCode(token.pos, token.val, itemElseIf))
  254. } else {
  255. cond.append(t.newCode(token.pos, token.val, token.typ))
  256. }
  257. default:
  258. break Loop
  259. }
  260. default:
  261. break Loop
  262. }
  263. }
  264. t.backup()
  265. return cond
  266. }
  267. func (t *Tree) parseFor(tk item) Node {
  268. var (
  269. deep = tk.depth
  270. cond = t.newCond(tk.pos, tk.val, tk.typ)
  271. )
  272. Loop:
  273. for {
  274. switch token := t.nextNonSpace(); {
  275. case token.depth > deep:
  276. cond.append(t.hub(token))
  277. case token.depth == deep:
  278. if token.typ == itemElse {
  279. cond.condType = itemForIfNotContain
  280. cond.append(t.newCode(token.pos, token.val, itemForElse))
  281. } else {
  282. break Loop
  283. }
  284. default:
  285. break Loop
  286. }
  287. }
  288. t.backup()
  289. return cond
  290. }
  291. func (t *Tree) parseCase(tk item) Node {
  292. var (
  293. deep = tk.depth
  294. iCase = t.newCond(tk.pos, tk.val, tk.typ)
  295. )
  296. for {
  297. if token := t.nextNonSpace(); token.depth > deep {
  298. switch token.typ {
  299. case itemCaseWhen, itemCaseDefault:
  300. iCase.append(t.newCode(token.pos, token.val, token.typ))
  301. default:
  302. iCase.append(t.hub(token))
  303. }
  304. } else {
  305. break
  306. }
  307. }
  308. t.backup()
  309. return iCase
  310. }
  311. func (t *Tree) parseMixin(tk item) *MixinNode {
  312. var (
  313. deep = tk.depth
  314. mixin = t.newMixin(tk.pos)
  315. )
  316. Loop:
  317. for {
  318. switch token := t.nextNonSpace(); {
  319. case token.depth > deep:
  320. mixin.append(t.hub(token))
  321. case token.depth == deep:
  322. if token.typ == itemAttrStart {
  323. t.parseAttributes(mixin, "")
  324. } else {
  325. break Loop
  326. }
  327. default:
  328. break Loop
  329. }
  330. }
  331. t.backup()
  332. return mixin
  333. }
  334. func (t *Tree) parseMixinUse(tk item) Node {
  335. tMix, ok := t.mixin[tk.val]
  336. if !ok {
  337. t.errorf(`Mixin "%s" must be declared before use.`, tk.val)
  338. }
  339. var (
  340. deep = tk.depth
  341. mixin = tMix.CopyMixin()
  342. )
  343. Loop:
  344. for {
  345. switch token := t.nextNonSpace(); {
  346. case token.depth > deep:
  347. mixin.appendToBlock(t.hub(token))
  348. case token.depth == deep:
  349. if token.typ == itemAttrStart {
  350. t.parseAttributes(mixin, "")
  351. } else {
  352. break Loop
  353. }
  354. default:
  355. break Loop
  356. }
  357. }
  358. t.backup()
  359. use := len(mixin.AttrName)
  360. tpl := len(tMix.AttrName)
  361. switch {
  362. case use < tpl:
  363. i := 0
  364. diff := tpl - use
  365. mixin.AttrCode = append(mixin.AttrCode, make([]string, diff)...) // Extend slice
  366. for index := 0; index < diff; index++ {
  367. i = tpl - index - 1
  368. if tMix.AttrName[i] != tMix.AttrCode[i] {
  369. mixin.AttrCode[i] = tMix.AttrCode[i]
  370. } else {
  371. mixin.AttrCode[i] = `""`
  372. }
  373. }
  374. mixin.AttrName = tMix.AttrName
  375. case use > tpl:
  376. if tpl <= 0 {
  377. break
  378. }
  379. if strings.HasPrefix(tMix.AttrName[tpl-1], "...") {
  380. mixin.AttrRest = mixin.AttrCode[tpl-1:]
  381. }
  382. mixin.AttrCode = mixin.AttrCode[:tpl]
  383. mixin.AttrName = tMix.AttrName
  384. case use == tpl:
  385. mixin.AttrName = tMix.AttrName
  386. }
  387. return mixin
  388. }
  389. func (t *Tree) parseBlock(tk item) *BlockNode {
  390. block := t.newList(tk.pos)
  391. for {
  392. token := t.nextNonSpace()
  393. if token.depth > tk.depth {
  394. block.append(t.hub(token))
  395. } else {
  396. break
  397. }
  398. }
  399. t.backup()
  400. var suf string
  401. switch tk.typ {
  402. case itemBlockPrepend:
  403. suf = "_prepend"
  404. case itemBlockAppend:
  405. suf = "_append"
  406. }
  407. t.block[tk.val+suf] = block
  408. return t.newBlock(tk.pos, tk.val, tk.typ)
  409. }
  410. func (t *Tree) parseInclude(tk item) *ListNode {
  411. switch ext := filepath.Ext(tk.val); ext {
  412. case ".jade", ".pug", "":
  413. return t.parseSubFile(tk.val)
  414. case ".js", ".css", ".tpl", ".md":
  415. ln := t.newList(tk.pos)
  416. ln.append(t.newText(tk.pos, t.read(tk.val), itemText))
  417. return ln
  418. default:
  419. t.errorf(`file extension is not supported`)
  420. return nil
  421. }
  422. }
  423. func (t *Tree) parseSubFile(path string) *ListNode {
  424. // log.Println("subtemplate: " + path)
  425. currentTmplDir, _ := filepath.Split(t.Name)
  426. var incTree = New(currentTmplDir + path)
  427. incTree.block = t.block
  428. incTree.mixin = t.mixin
  429. incTree.ReadFunc = t.ReadFunc
  430. _, err := incTree.Parse(t.read(path))
  431. if err != nil {
  432. d, _ := os.Getwd()
  433. t.errorf(`in '%s' subtemplate '%s': parseSubFile() error: %s`, d, path, err)
  434. }
  435. return incTree.Root
  436. }
  437. var extensions = [...]string{".jade", ".pug", ".js", ".css", ".tpl", ".md"}
  438. func (t *Tree) read(path string) []byte {
  439. currentTmplDir, _ := filepath.Split(t.Name)
  440. path = currentTmplDir + path
  441. var (
  442. bb []byte
  443. err error
  444. )
  445. ext := filepath.Ext(path)
  446. for _, s := range extensions {
  447. if s == ext {
  448. bb, err = t.ReadFunc(path)
  449. break
  450. }
  451. if bb, err = t.ReadFunc(path + s); err == nil {
  452. break
  453. }
  454. }
  455. if err != nil {
  456. wd, _ := os.Getwd()
  457. t.errorf(`%s work dir: %s `, err, wd)
  458. }
  459. return bb
  460. }