erlydtl_scanner.erl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. %%%%% THIS IS A SLEX GENERATED FILE %%%%%
  2. %%%-------------------------------------------------------------------
  3. %%% File: erlydtl_scanner.slex
  4. %%% @author Andreas Stenius <kaos@astekk.se>
  5. %%% @copyright 2013 Andreas Stenius
  6. %%% @doc
  7. %%% erlydtl scanner
  8. %%% @end
  9. %%%
  10. %%% The MIT License
  11. %%%
  12. %%% Copyright (c) 2013 Andreas Stenius
  13. %%%
  14. %%% Permission is hereby granted, free of charge, to any person obtaining a copy
  15. %%% of this software and associated documentation files (the "Software"), to deal
  16. %%% in the Software without restriction, including without limitation the rights
  17. %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  18. %%% copies of the Software, and to permit persons to whom the Software is
  19. %%% furnished to do so, subject to the following conditions:
  20. %%%
  21. %%% The above copyright notice and this permission notice shall be included in
  22. %%% all copies or substantial portions of the Software.
  23. %%%
  24. %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29. %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  30. %%% THE SOFTWARE.
  31. %%%
  32. %%% @since 2013-11-05 by Andreas Stenius
  33. %%%
  34. %%% Rules based on the original erlydtl_scanner by Robert Saccon and Evan Miller.
  35. %%%-------------------------------------------------------------------
  36. -module(erlydtl_scanner).
  37. %% This file was generated 2013-12-02 15:52:41 UTC by slex 0.1.0-2-gb81b78b.
  38. %% http://github.com/erlydtl/slex
  39. -slex_source("src/erlydtl_scanner.slex").
  40. -export([scan/1, scan/4]).
  41. -compile(nowarn_unused_vars).
  42. -export([resume/1]).
  43. -record(scanner_state,
  44. {template = [], scanned = [], pos = {1, 1},
  45. state = in_text}).
  46. resume(#scanner_state{template = Template,
  47. scanned = Scanned, pos = Pos, state = State}) ->
  48. scan(Template, Scanned, Pos, State).
  49. to_atom(L) when is_list(L) -> list_to_atom(L).
  50. to_keyword(L, P) -> {to_atom(L ++ "_keyword"), P, L}.
  51. atomize(L, T) -> setelement(3, T, to_atom(L)).
  52. is_keyword(Class, {_, _, L} = T) ->
  53. L1 = lists:reverse(L),
  54. case is_keyword(Class, L1) of
  55. true -> to_keyword(L1, element(2, T));
  56. false -> atomize(L1, T)
  57. end;
  58. is_keyword([C | Cs], L) ->
  59. is_keyword(C, L) orelse is_keyword(Cs, L);
  60. is_keyword(all, L) -> is_keyword([any, open, close], L);
  61. is_keyword(open_tag, L) -> is_keyword([any, open], L);
  62. is_keyword(close_tag, L) -> is_keyword([any, close], L);
  63. is_keyword(any, "in") -> true;
  64. is_keyword(any, "not") -> true;
  65. is_keyword(any, "or") -> true;
  66. is_keyword(any, "and") -> true;
  67. is_keyword(any, "as") -> true;
  68. is_keyword(any, "by") -> true;
  69. is_keyword(any, "with") -> true;
  70. is_keyword(close, "only") -> true;
  71. is_keyword(close, "parsed") -> true;
  72. is_keyword(close, "noop") -> true;
  73. is_keyword(close, "reversed") -> true;
  74. is_keyword(close, "openblock") -> true;
  75. is_keyword(close, "closeblock") -> true;
  76. is_keyword(close, "openvariable") -> true;
  77. is_keyword(close, "closevariable") -> true;
  78. is_keyword(close, "openbrace") -> true;
  79. is_keyword(close, "closebrace") -> true;
  80. is_keyword(close, "opencomment") -> true;
  81. is_keyword(close, "closecomment") -> true;
  82. is_keyword(open, "autoescape") -> true;
  83. is_keyword(open, "endautoescape") -> true;
  84. is_keyword(open, "block") -> true;
  85. is_keyword(open, "endblock") -> true;
  86. is_keyword(open, "comment") -> true;
  87. is_keyword(open, "endcomment") -> true;
  88. is_keyword(open, "cycle") -> true;
  89. is_keyword(open, "extends") -> true;
  90. is_keyword(open, "filter") -> true;
  91. is_keyword(open, "endfilter") -> true;
  92. is_keyword(open, "firstof") -> true;
  93. is_keyword(open, "for") -> true;
  94. is_keyword(open, "empty") -> true;
  95. is_keyword(open, "endfor") -> true;
  96. is_keyword(open, "if") -> true;
  97. is_keyword(open, "elif") -> true;
  98. is_keyword(open, "else") -> true;
  99. is_keyword(open, "endif") -> true;
  100. is_keyword(open, "ifchanged") -> true;
  101. is_keyword(open, "endifchanged") -> true;
  102. is_keyword(open, "ifequal") -> true;
  103. is_keyword(open, "endifequal") -> true;
  104. is_keyword(open, "ifnotequal") -> true;
  105. is_keyword(open, "endifnotequal") -> true;
  106. is_keyword(open, "include") -> true;
  107. is_keyword(open, "now") -> true;
  108. is_keyword(open, "regroup") -> true;
  109. is_keyword(open, "endregroup") -> true;
  110. is_keyword(open, "spaceless") -> true;
  111. is_keyword(open, "endspaceless") -> true;
  112. is_keyword(open, "ssi") -> true;
  113. is_keyword(open, "templatetag") -> true;
  114. is_keyword(open, "widthratio") -> true;
  115. is_keyword(open, "call") -> true;
  116. is_keyword(open, "endwith") -> true;
  117. is_keyword(open, "trans") -> true;
  118. is_keyword(open, "blocktrans") -> true;
  119. is_keyword(open, "endblocktrans") -> true;
  120. is_keyword(_, _) -> false.
  121. scan(Template) when is_list(Template) ->
  122. scan(Template, [], {1, 1}, in_text).
  123. scan("{{" ++ T, S, {R, C} = P, in_text) ->
  124. scan(T,
  125. [{open_var, P, "{{"} | post_process(S, open_var)],
  126. {R, C + 2}, {in_code, "}}"});
  127. scan("{%" ++ T, S, {R, C} = P, in_text) ->
  128. scan(T,
  129. [{open_tag, P, "{%"} | post_process(S, open_tag)],
  130. {R, C + 2}, {in_code, "%}"});
  131. scan("<!--{{" ++ T, S, {R, C} = P, in_text) ->
  132. scan(T,
  133. [{open_var, P, "<!--{{"} | post_process(S, open_var)],
  134. {R, C + 6}, {in_code, "}}-->"});
  135. scan("<!--{%" ++ T, S, {R, C} = P, in_text) ->
  136. scan(T,
  137. [{open_tag, P, "<!--{%"} | post_process(S, open_tag)],
  138. {R, C + 6}, {in_code, "%}-->"});
  139. scan("{#" ++ T, S, {R, C}, in_text) ->
  140. scan(T, S, {R, C + 2}, {in_comment, "#}"});
  141. scan("<!--{#" ++ T, S, {R, C}, in_text) ->
  142. scan(T, S, {R, C + 6}, {in_comment, "#}-->"});
  143. scan("#}-->" ++ T, S, {R, C}, {_, "#}-->"}) ->
  144. scan(T, S, {R, C + 5}, in_text);
  145. scan("#}" ++ T, S, {R, C}, {_, "#}"}) ->
  146. scan(T, S, {R, C + 2}, in_text);
  147. scan([H | T], S, {R, C}, {in_comment, E} = St) ->
  148. scan(T, S,
  149. case H of
  150. $\n -> {R + 1, 1};
  151. _ -> {R, C + 1}
  152. end,
  153. St);
  154. scan([H | T], S, {R, C} = P, in_text = St) ->
  155. scan(T,
  156. case S of
  157. [{string, _, L} = M | Ss] ->
  158. [setelement(3, M, [H | L]) | Ss];
  159. _ -> [{string, P, [H]} | post_process(S, string)]
  160. end,
  161. case H of
  162. $\n -> {R + 1, 1};
  163. _ -> {R, C + 1}
  164. end,
  165. St);
  166. scan("\"" ++ T, S, {R, C} = P, {in_code, E}) ->
  167. scan(T,
  168. [{string_literal, P, "\""} | post_process(S,
  169. string_literal)],
  170. {R, C + 1}, {in_double_quote, E});
  171. scan("'" ++ T, S, {R, C} = P, {in_code, E}) ->
  172. scan(T,
  173. [{string_literal, P, "\""} | post_process(S,
  174. string_literal)],
  175. {R, C + 1}, {in_single_quote, E});
  176. scan("\"" ++ T, S, {R, C} = P, {in_double_quote, E}) ->
  177. scan(T,
  178. case S of
  179. [{string_literal, _, L} = M | Ss] ->
  180. [setelement(3, M, "\"" ++ L) | Ss];
  181. _ ->
  182. [{string_literal, P, "\""} | post_process(S,
  183. string_literal)]
  184. end,
  185. {R, C + 1}, {in_code, E});
  186. scan("'" ++ T, S, {R, C} = P, {in_single_quote, E}) ->
  187. scan(T,
  188. case S of
  189. [{string_literal, _, L} = M | Ss] ->
  190. [setelement(3, M, "\"" ++ L) | Ss];
  191. _ ->
  192. [{string_literal, P, "\""} | post_process(S,
  193. string_literal)]
  194. end,
  195. {R, C + 1}, {in_code, E});
  196. scan("\\" ++ T, S, {R, C} = P, {in_double_quote, E}) ->
  197. scan(T,
  198. case S of
  199. [{string_literal, _, L} = M | Ss] ->
  200. [setelement(3, M, "\\" ++ L) | Ss];
  201. _ ->
  202. [{string_literal, P, "\\"} | post_process(S,
  203. string_literal)]
  204. end,
  205. {R, C + 1}, {in_double_quote_escape, E});
  206. scan("\\" ++ T, S, {R, C} = P, {in_single_quote, E}) ->
  207. scan(T,
  208. case S of
  209. [{string_literal, _, L} = M | Ss] ->
  210. [setelement(3, M, "\\" ++ L) | Ss];
  211. _ ->
  212. [{string_literal, P, "\\"} | post_process(S,
  213. string_literal)]
  214. end,
  215. {R, C + 1}, {in_single_quote_escape, E});
  216. scan([H | T], S, {R, C} = P,
  217. {in_double_quote, E} = St) ->
  218. scan(T,
  219. case S of
  220. [{string_literal, _, L} = M | Ss] ->
  221. [setelement(3, M, [H | L]) | Ss];
  222. _ ->
  223. [{string_literal, P, [H]} | post_process(S,
  224. string_literal)]
  225. end,
  226. case H of
  227. $\n -> {R + 1, 1};
  228. _ -> {R, C + 1}
  229. end,
  230. St);
  231. scan([H | T], S, {R, C} = P,
  232. {in_single_quote, E} = St) ->
  233. scan(T,
  234. case S of
  235. [{string_literal, _, L} = M | Ss] ->
  236. [setelement(3, M, [H | L]) | Ss];
  237. _ ->
  238. [{string_literal, P, [H]} | post_process(S,
  239. string_literal)]
  240. end,
  241. case H of
  242. $\n -> {R + 1, 1};
  243. _ -> {R, C + 1}
  244. end,
  245. St);
  246. scan([H | T], S, {R, C} = P,
  247. {in_double_quote_escape, E}) ->
  248. scan(T,
  249. case S of
  250. [{string_literal, _, L} = M | Ss] ->
  251. [setelement(3, M, [H | L]) | Ss];
  252. _ ->
  253. [{string_literal, P, [H]} | post_process(S,
  254. string_literal)]
  255. end,
  256. case H of
  257. $\n -> {R + 1, 1};
  258. _ -> {R, C + 1}
  259. end,
  260. {in_double_quote, E});
  261. scan([H | T], S, {R, C} = P,
  262. {in_single_quote_escape, E}) ->
  263. scan(T,
  264. case S of
  265. [{string_literal, _, L} = M | Ss] ->
  266. [setelement(3, M, [H | L]) | Ss];
  267. _ ->
  268. [{string_literal, P, [H]} | post_process(S,
  269. string_literal)]
  270. end,
  271. case H of
  272. $\n -> {R + 1, 1};
  273. _ -> {R, C + 1}
  274. end,
  275. {in_single_quote, E});
  276. scan("}}-->" ++ T, S, {R, C} = P, {_, "}}-->"}) ->
  277. scan(T,
  278. [{close_var, P, "}}-->"} | post_process(S, close_var)],
  279. {R, C + 5}, in_text);
  280. scan("%}-->" ++ T, S, {R, C} = P, {_, "%}-->"}) ->
  281. scan(T,
  282. [{close_tag, P, "%}-->"} | post_process(S, close_tag)],
  283. {R, C + 5}, in_text);
  284. scan("}}" ++ T, S, {R, C} = P, {_, "}}"}) ->
  285. scan(T,
  286. [{close_var, P, "}}"} | post_process(S, close_var)],
  287. {R, C + 2}, in_text);
  288. scan("%}" ++ T, S, {R, C} = P, {_, "%}"} = St) ->
  289. case S of
  290. [{identifier, _, "mitabrev"}, {open_tag, _, '{%'}
  291. | Ss] ->
  292. scan(T, [{string, {R, C + 2}, ""} | Ss], {R, C + 2},
  293. {in_verbatim, undefined});
  294. [{identifier, _, Tag}, {identifier, _, verbatim},
  295. {open_tag, _, '{%'}
  296. | Ss] ->
  297. scan(T, [{string, {R, C + 2}, ""} | Ss], {R, C + 2},
  298. {in_verbatim, Tag});
  299. _ ->
  300. scan(T,
  301. [{close_tag, P, "%}"} | post_process(S, close_tag)],
  302. {R, C + 2}, in_text)
  303. end;
  304. scan("{%" ++ T, S, {R, C} = P, {in_verbatim, E} = St) ->
  305. scan(T, S, {R, C + 2}, {in_verbatim_code, {E, "%{"}});
  306. scan(" " ++ T, S, {R, C} = P,
  307. {in_verbatim_code, E} = St) ->
  308. {Tag, Backtrack} = E,
  309. scan(T, S, {R, C + 1},
  310. {in_verbatim_code, {Tag, [$ | Backtrack]}});
  311. scan("endverbatim%}" ++ T, S, {R, C} = P,
  312. {in_verbatim_code, E} = St)
  313. when element(1, E) =:= undefined ->
  314. scan(T, S, {R, C + 13}, in_text);
  315. scan("endverbatim " ++ T, S, {R, C} = P,
  316. {in_verbatim_code, E} = St) ->
  317. {Tag, Backtrack} = E,
  318. scan(T, S, {R, C + 12},
  319. {in_endverbatim_code,
  320. {Tag, lists:reverse("endverbatim ", Backtrack), ""}});
  321. scan(" " ++ T, S, {R, C} = P,
  322. {in_endverbatim_code, E} = St)
  323. when element(3, E) =:= "" ->
  324. {Tag, Backtrack, EndTag} = E,
  325. scan(T, S, {R, C + 1},
  326. {in_endverbatim_code, {Tag, [$ | Backtrack], EndTag}});
  327. scan([H | T], S, {R, C} = P,
  328. {in_endverbatim_code, E} = St)
  329. when H >= $a andalso H =< $z orelse
  330. H >= $0 andalso H =< $9 orelse H =:= $_ ->
  331. {Tag, Backtrack, EndTag} = E,
  332. scan(T, S, {R, C + 1},
  333. {in_endverbatim_code,
  334. {Tag, [H | Backtrack], [H | EndTag]}});
  335. scan(" " ++ T, S, {R, C} = P,
  336. {in_endverbatim_code, E} = St)
  337. when element(1, E) =:= element(3, E) ->
  338. {Tag, Backtrack, Tag} = E,
  339. scan(T, S, {R, C + 1},
  340. {in_endverbatim_code, {Tag, [$ | Backtrack], Tag}});
  341. scan("%}" ++ T, S, {R, C} = P,
  342. {in_endverbatim_code, E} = St)
  343. when element(1, E) =:= element(3, E) ->
  344. scan(T, S, {R, C + 2}, in_text);
  345. scan("%}" ++ T, S, {R, C} = P,
  346. {in_endverbatim_code, E} = St)
  347. when element(1, E) =:= undefined andalso
  348. element(3, E) =:= "" ->
  349. scan(T, S, {R, C + 2}, in_text);
  350. scan([H | T], S, {R, C} = P,
  351. {in_endverbatim_code, E} = St) ->
  352. {Tag, Backtrack, _} = E,
  353. scan(T,
  354. case S of
  355. [{string, _, L} = M | Ss] ->
  356. [setelement(3, M, [H | Backtrack] ++ L) | Ss];
  357. _ -> [{string, P, [H | Backtrack]} | S]
  358. end,
  359. case H of
  360. $\n -> {R + 1, 1};
  361. _ -> {R, C + 1}
  362. end,
  363. {in_verbatim, Tag});
  364. scan([H | T], S, {R, C} = P,
  365. {in_verbatim_code, E} = St) ->
  366. {Tag, Backtrack} = E,
  367. scan(T,
  368. case S of
  369. [{string, _, L} = M | Ss] ->
  370. [setelement(3, M, [H | Backtrack] ++ L) | Ss];
  371. _ -> [{string, P, [H | Backtrack]} | S]
  372. end,
  373. case H of
  374. $\n -> {R + 1, 1};
  375. _ -> {R, C + 1}
  376. end,
  377. {in_verbatim, Tag});
  378. scan([H | T], S, {R, C} = P, {in_verbatim, E} = St) ->
  379. scan(T,
  380. case S of
  381. [{string, _, L} = M | Ss] ->
  382. [setelement(3, M, [H | L]) | Ss];
  383. _ -> [{string, P, [H]} | S]
  384. end,
  385. case H of
  386. $\n -> {R + 1, 1};
  387. _ -> {R, C + 1}
  388. end,
  389. {in_verbatim, E});
  390. scan("==" ++ T, S, {R, C} = P, {_, E}) ->
  391. scan(T, [{'==', P} | post_process(S, '==')], {R, C + 2},
  392. {in_code, E});
  393. scan("!=" ++ T, S, {R, C} = P, {_, E}) ->
  394. scan(T, [{'!=', P} | post_process(S, '!=')], {R, C + 2},
  395. {in_code, E});
  396. scan(">=" ++ T, S, {R, C} = P, {_, E}) ->
  397. scan(T, [{'>=', P} | post_process(S, '>=')], {R, C + 2},
  398. {in_code, E});
  399. scan("<=" ++ T, S, {R, C} = P, {_, E}) ->
  400. scan(T, [{'<=', P} | post_process(S, '<=')], {R, C + 2},
  401. {in_code, E});
  402. scan(">" ++ T, S, {R, C} = P, {_, E}) ->
  403. scan(T, [{'>', P} | post_process(S, '>')], {R, C + 1},
  404. {in_code, E});
  405. scan("<" ++ T, S, {R, C} = P, {_, E}) ->
  406. scan(T, [{'<', P} | post_process(S, '<')], {R, C + 1},
  407. {in_code, E});
  408. scan("(" ++ T, S, {R, C} = P, {_, E}) ->
  409. scan(T, [{'(', P} | post_process(S, '(')], {R, C + 1},
  410. {in_code, E});
  411. scan(")" ++ T, S, {R, C} = P, {_, E}) ->
  412. scan(T, [{')', P} | post_process(S, ')')], {R, C + 1},
  413. {in_code, E});
  414. scan("," ++ T, S, {R, C} = P, {_, E}) ->
  415. scan(T, [{',', P} | post_process(S, ',')], {R, C + 1},
  416. {in_code, E});
  417. scan("|" ++ T, S, {R, C} = P, {_, E}) ->
  418. scan(T, [{'|', P} | post_process(S, '|')], {R, C + 1},
  419. {in_code, E});
  420. scan("=" ++ T, S, {R, C} = P, {_, E}) ->
  421. scan(T, [{'=', P} | post_process(S, '=')], {R, C + 1},
  422. {in_code, E});
  423. scan(":" ++ T, S, {R, C} = P, {_, E}) ->
  424. scan(T, [{':', P} | post_process(S, ':')], {R, C + 1},
  425. {in_code, E});
  426. scan("." ++ T, S, {R, C} = P, {_, E}) ->
  427. scan(T, [{'.', P} | post_process(S, '.')], {R, C + 1},
  428. {in_code, E});
  429. scan("_(" ++ T, S, {R, C} = P, {_, E}) ->
  430. scan(T, [{'(', P}, {'_', P} | post_process(S, '_')],
  431. {R, C + 2}, {in_code, E});
  432. scan(" " ++ T, S, {R, C}, {_, E}) ->
  433. scan(T, S, {R, C + 1}, {in_code, E});
  434. scan([H | T], S, {R, C} = P, {in_code, E})
  435. when H >= $a andalso H =< $z orelse
  436. H >= $A andalso H =< $Z orelse H == $_ ->
  437. scan(T,
  438. [{identifier, P, [H]} | post_process(S, identifier)],
  439. case H of
  440. $\n -> {R + 1, 1};
  441. _ -> {R, C + 1}
  442. end,
  443. {in_identifier, E});
  444. scan([H | T], S, {R, C} = P, {in_code, E})
  445. when H >= $0 andalso H =< $9 orelse H == $- ->
  446. scan(T,
  447. [{number_literal, P, [H]} | post_process(S,
  448. number_literal)],
  449. case H of
  450. $\n -> {R + 1, 1};
  451. _ -> {R, C + 1}
  452. end,
  453. {in_number, E});
  454. scan([H | T], S, {R, C} = P, {in_code, E} = St) ->
  455. {error,
  456. {R, erlydtl_scanner,
  457. lists:concat(["Illegal character in column ", C])},
  458. #scanner_state{template = [H | T],
  459. scanned = post_process(S, err), pos = P, state = St}};
  460. scan([H | T], S, {R, C} = P, {in_number, E} = St)
  461. when H >= $0 andalso H =< $9 ->
  462. scan(T,
  463. case S of
  464. [{number_literal, _, L} = M | Ss] ->
  465. [setelement(3, M, [H | L]) | Ss];
  466. _ ->
  467. [{number_literal, P, [H]} | post_process(S,
  468. number_literal)]
  469. end,
  470. case H of
  471. $\n -> {R + 1, 1};
  472. _ -> {R, C + 1}
  473. end,
  474. St);
  475. scan([H | T], S, {R, C} = P, {in_number, E} = St) ->
  476. {error,
  477. {R, erlydtl_scanner,
  478. lists:concat(["Illegal character in column ", C])},
  479. #scanner_state{template = [H | T],
  480. scanned = post_process(S, err), pos = P,
  481. state = {in_code, E}}};
  482. scan([H | T], S, {R, C} = P, {in_identifier, E})
  483. when H >= $a andalso H =< $z orelse
  484. H >= $A andalso H =< $Z orelse
  485. H >= $0 andalso H =< $9 orelse H == $_ ->
  486. scan(T,
  487. case S of
  488. [{identifier, _, L} = M | Ss] ->
  489. [setelement(3, M, [H | L]) | Ss];
  490. _ ->
  491. [{identifier, P, [H]} | post_process(S, identifier)]
  492. end,
  493. case H of
  494. $\n -> {R + 1, 1};
  495. _ -> {R, C + 1}
  496. end,
  497. {in_identifier, E});
  498. scan([H | T], S, {R, C} = P, {in_identifier, E} = St) ->
  499. {error,
  500. {R, erlydtl_scanner,
  501. lists:concat(["Illegal character in column ", C])},
  502. #scanner_state{template = [H | T],
  503. scanned = post_process(S, err), pos = P,
  504. state = {in_code, E}}};
  505. scan([], S, {R, C} = P, in_text = St) ->
  506. {ok, lists:reverse(post_process(S, eof))};
  507. scan([], S, {R, C} = P, {in_comment, E} = St) ->
  508. {error, "Reached end of file inside a comment."};
  509. scan([], S, {R, C} = P, {_, E} = St) ->
  510. {error, "Reached end of file inside a code block."}.
  511. post_process(_, {string, _, L} = T, _) ->
  512. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  513. post_process(_, {string_literal, _, L} = T, _) ->
  514. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  515. post_process(_, {number_literal, _, L} = T, _) ->
  516. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  517. post_process(_, {open_var, _, L} = T, _) ->
  518. setelement(3, T, begin L1 = to_atom(L), L1 end);
  519. post_process(_, {close_var, _, L} = T, _) ->
  520. setelement(3, T, begin L1 = to_atom(L), L1 end);
  521. post_process(_, {open_tag, _, L} = T, _) ->
  522. setelement(3, T, begin L1 = to_atom(L), L1 end);
  523. post_process(_, {close_tag, _, L} = T, _) ->
  524. setelement(3, T, begin L1 = to_atom(L), L1 end);
  525. post_process([{open_tag, _, _} | _],
  526. {identifier, _, L} = T, close_tag) ->
  527. is_keyword(all, T);
  528. post_process([{open_tag, _, _} | _],
  529. {identifier, _, L} = T, _) ->
  530. is_keyword(open_tag, T);
  531. post_process(_, {identifier, _, L} = T, close_tag) ->
  532. is_keyword(close_tag, T);
  533. post_process(_, {identifier, _, L} = T, _) ->
  534. is_keyword(any, T);
  535. post_process(_, T, _) -> T.
  536. post_process([S | Ss], N) ->
  537. [post_process(Ss, S, N) | Ss];
  538. post_process(T, N) -> post_process(undefined, T, N).