erlydtl_scanner.erl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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 2015-10-17 21:30:29 UTC by slex 0.2.1-2-g7814678.
  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, format_error/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. return_error(Error, P, T, S, St) ->
  50. {error, {P, erlydtl_scanner, Error},
  51. #scanner_state{template = T,
  52. scanned = post_process(S, err), pos = P, state = St}}.
  53. return_error(Error, P) ->
  54. {error, {P, erlydtl_scanner, Error}}.
  55. to_atom(L) when is_list(L) -> list_to_atom(L).
  56. to_keyword(L, P) -> {to_atom(L ++ "_keyword"), P, L}.
  57. atomize(L, T) -> setelement(3, T, to_atom(L)).
  58. is_keyword(Class, {_, _, L} = T) ->
  59. L1 = lists:reverse(L),
  60. case is_keyword(Class, L1) of
  61. true -> to_keyword(L1, element(2, T));
  62. false -> atomize(L1, T)
  63. end;
  64. is_keyword([C | Cs], L) ->
  65. is_keyword(C, L) orelse is_keyword(Cs, L);
  66. is_keyword(all, L) -> is_keyword([any, open, close], L);
  67. is_keyword(open_tag, L) -> is_keyword([any, open], L);
  68. is_keyword(close_tag, L) -> is_keyword([any, close], L);
  69. is_keyword(any, "in") -> true;
  70. is_keyword(any, "not") -> true;
  71. is_keyword(any, "or") -> true;
  72. is_keyword(any, "and") -> true;
  73. is_keyword(any, "as") -> true;
  74. is_keyword(any, "by") -> true;
  75. is_keyword(any, "with") -> true;
  76. is_keyword(any, "from") -> true;
  77. is_keyword(any, "count") -> true;
  78. is_keyword(any, "context") -> true;
  79. is_keyword(any, "noop") -> true;
  80. is_keyword(any, "trimmed") -> true;
  81. is_keyword(close, "only") -> true;
  82. is_keyword(close, "parsed") -> true;
  83. is_keyword(close, "silent") -> true;
  84. is_keyword(close, "reversed") -> true;
  85. is_keyword(close, "openblock") -> true;
  86. is_keyword(close, "closeblock") -> true;
  87. is_keyword(close, "openvariable") -> true;
  88. is_keyword(close, "closevariable") -> true;
  89. is_keyword(close, "openbrace") -> true;
  90. is_keyword(close, "closebrace") -> true;
  91. is_keyword(close, "opencomment") -> true;
  92. is_keyword(close, "closecomment") -> true;
  93. is_keyword(open, "autoescape") -> true;
  94. is_keyword(open, "endautoescape") -> true;
  95. is_keyword(open, "block") -> true;
  96. is_keyword(open, "endblock") -> true;
  97. is_keyword(open, "language") -> true;
  98. is_keyword(open, "endlanguage") -> true;
  99. is_keyword(open, "comment") -> true;
  100. is_keyword(open, "endcomment") -> true;
  101. is_keyword(open, "cycle") -> true;
  102. is_keyword(open, "extends") -> true;
  103. is_keyword(open, "filter") -> true;
  104. is_keyword(open, "endfilter") -> true;
  105. is_keyword(open, "firstof") -> true;
  106. is_keyword(open, "for") -> true;
  107. is_keyword(open, "empty") -> true;
  108. is_keyword(open, "endfor") -> true;
  109. is_keyword(open, "if") -> true;
  110. is_keyword(open, "elif") -> true;
  111. is_keyword(open, "else") -> true;
  112. is_keyword(open, "endif") -> true;
  113. is_keyword(open, "ifchanged") -> true;
  114. is_keyword(open, "endifchanged") -> true;
  115. is_keyword(open, "ifequal") -> true;
  116. is_keyword(open, "endifequal") -> true;
  117. is_keyword(open, "ifnotequal") -> true;
  118. is_keyword(open, "endifnotequal") -> true;
  119. is_keyword(open, "include") -> true;
  120. is_keyword(open, "now") -> true;
  121. is_keyword(open, "regroup") -> true;
  122. is_keyword(open, "endregroup") -> true;
  123. is_keyword(open, "spaceless") -> true;
  124. is_keyword(open, "endspaceless") -> true;
  125. is_keyword(open, "ssi") -> true;
  126. is_keyword(open, "templatetag") -> true;
  127. is_keyword(open, "widthratio") -> true;
  128. is_keyword(open, "call") -> true;
  129. is_keyword(open, "endwith") -> true;
  130. is_keyword(open, "trans") -> true;
  131. is_keyword(open, "blocktrans") -> true;
  132. is_keyword(open, "endblocktrans") -> true;
  133. is_keyword(open, "load") -> true;
  134. is_keyword(open, "plural") -> true;
  135. is_keyword(_, _) -> false.
  136. format_error({illegal_char, C}) ->
  137. io_lib:format("Illegal character '~s'", [[C]]);
  138. format_error({eof, Where}) ->
  139. io_lib:format("Unexpected end of file ~s",
  140. [format_where(Where)]).
  141. format_where(in_comment) -> "in comment";
  142. format_where(in_code) -> "in code block".
  143. scan(Template) when is_list(Template) ->
  144. scan(Template, [], {1, 1}, in_text);
  145. scan(Template) when is_binary(Template) ->
  146. scan(binary_to_list(Template)).
  147. scan("{{" ++ T, S, {R, C} = P, in_text) ->
  148. scan(T,
  149. [{open_var, P, "{{"} | post_process(S, open_var)],
  150. {R, C + 2}, {in_code, "}}"});
  151. scan("{%" ++ T, S, {R, C} = P, in_text) ->
  152. scan(T,
  153. [{open_tag, P, "{%"} | post_process(S, open_tag)],
  154. {R, C + 2}, {in_code, "%}"});
  155. scan("<!--{{" ++ T, S, {R, C} = P, in_text) ->
  156. scan(T,
  157. [{open_var, P, "<!--{{"} | post_process(S, open_var)],
  158. {R, C + 6}, {in_code, "}}-->"});
  159. scan("<!--{%" ++ T, S, {R, C} = P, in_text) ->
  160. scan(T,
  161. [{open_tag, P, "<!--{%"} | post_process(S, open_tag)],
  162. {R, C + 6}, {in_code, "%}-->"});
  163. scan("{#" ++ T, S, {R, C}, in_text) ->
  164. scan(T, S, {R, C + 2}, {in_comment, "#}"});
  165. scan("<!--{#" ++ T, S, {R, C}, in_text) ->
  166. scan(T, S, {R, C + 6}, {in_comment, "#}-->"});
  167. scan("#}-->" ++ T, S, {R, C}, {_, "#}-->"}) ->
  168. scan(T, S, {R, C + 5}, in_text);
  169. scan("#}" ++ T, S, {R, C}, {_, "#}"}) ->
  170. scan(T, S, {R, C + 2}, in_text);
  171. scan([H | T], S, {R, C} = P, {in_comment, E} = St) ->
  172. scan(T,
  173. case S of
  174. [{comment_tag, _, L} = M | Ss] ->
  175. [setelement(3, M, [H | L]) | Ss];
  176. _ ->
  177. [{comment_tag, P, [H]} | post_process(S, comment_tag)]
  178. end,
  179. case H of
  180. $\n -> {R + 1, 1};
  181. _ -> {R, C + 1}
  182. end,
  183. St);
  184. scan([H | T], S, {R, C} = P, in_text = St) ->
  185. scan(T,
  186. case S of
  187. [{string, _, L} = M | Ss] ->
  188. [setelement(3, M, [H | L]) | Ss];
  189. _ -> [{string, P, [H]} | post_process(S, string)]
  190. end,
  191. case H of
  192. $\n -> {R + 1, 1};
  193. _ -> {R, C + 1}
  194. end,
  195. St);
  196. scan("\"" ++ T, S, {R, C} = P, {in_code, E}) ->
  197. scan(T,
  198. [{string_literal, P, "\""} | post_process(S,
  199. string_literal)],
  200. {R, C + 1}, {in_double_quote, E});
  201. scan("'" ++ T, S, {R, C} = P, {in_code, E}) ->
  202. scan(T,
  203. [{string_literal, P, "\""} | post_process(S,
  204. string_literal)],
  205. {R, C + 1}, {in_single_quote, E});
  206. scan("\"" ++ T, S, {R, C} = P, {in_double_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_code, E});
  216. scan("'" ++ T, S, {R, C} = P, {in_single_quote, E}) ->
  217. scan(T,
  218. case S of
  219. [{string_literal, _, L} = M | Ss] ->
  220. [setelement(3, M, "\"" ++ L) | Ss];
  221. _ ->
  222. [{string_literal, P, "\""} | post_process(S,
  223. string_literal)]
  224. end,
  225. {R, C + 1}, {in_code, E});
  226. scan("\\" ++ T, S, {R, C} = P, {in_double_quote, E}) ->
  227. scan(T,
  228. case S of
  229. [{string_literal, _, L} = M | Ss] ->
  230. [setelement(3, M, "\\" ++ L) | Ss];
  231. _ ->
  232. [{string_literal, P, "\\"} | post_process(S,
  233. string_literal)]
  234. end,
  235. {R, C + 1}, {in_double_quote_escape, E});
  236. scan("\\" ++ T, S, {R, C} = P, {in_single_quote, E}) ->
  237. scan(T,
  238. case S of
  239. [{string_literal, _, L} = M | Ss] ->
  240. [setelement(3, M, "\\" ++ L) | Ss];
  241. _ ->
  242. [{string_literal, P, "\\"} | post_process(S,
  243. string_literal)]
  244. end,
  245. {R, C + 1}, {in_single_quote_escape, E});
  246. scan([H | T], S, {R, C} = P,
  247. {in_double_quote, E} = St) ->
  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. St);
  261. scan([H | T], S, {R, C} = P,
  262. {in_single_quote, E} = St) ->
  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. St);
  276. scan([H | T], S, {R, C} = P,
  277. {in_double_quote_escape, E}) ->
  278. scan(T,
  279. case S of
  280. [{string_literal, _, L} = M | Ss] ->
  281. [setelement(3, M, [H | L]) | Ss];
  282. _ ->
  283. [{string_literal, P, [H]} | post_process(S,
  284. string_literal)]
  285. end,
  286. case H of
  287. $\n -> {R + 1, 1};
  288. _ -> {R, C + 1}
  289. end,
  290. {in_double_quote, E});
  291. scan([H | T], S, {R, C} = P,
  292. {in_single_quote_escape, E}) ->
  293. scan(T,
  294. case S of
  295. [{string_literal, _, L} = M | Ss] ->
  296. [setelement(3, M, [H | L]) | Ss];
  297. _ ->
  298. [{string_literal, P, [H]} | post_process(S,
  299. string_literal)]
  300. end,
  301. case H of
  302. $\n -> {R + 1, 1};
  303. _ -> {R, C + 1}
  304. end,
  305. {in_single_quote, E});
  306. scan("}}-->" ++ T, S, {R, C} = P, {_, "}}-->"}) ->
  307. scan(T,
  308. [{close_var, P, "}}-->"} | post_process(S, close_var)],
  309. {R, C + 5}, in_text);
  310. scan("%}-->" ++ T, S, {R, C} = P, {_, "%}-->"}) ->
  311. scan(T,
  312. [{close_tag, P, "%}-->"} | post_process(S, close_tag)],
  313. {R, C + 5}, in_text);
  314. scan("}}" ++ T, S, {R, C} = P, {_, "}}"}) ->
  315. scan(T,
  316. [{close_var, P, "}}"} | post_process(S, close_var)],
  317. {R, C + 2}, in_text);
  318. scan("%}" ++ T, S, {R, C} = P, {_, "%}"} = St) ->
  319. case S of
  320. [{identifier, _, "mitabrev"}, {open_tag, _, '{%'}
  321. | Ss] ->
  322. scan(T, [{string, {R, C + 2}, ""} | Ss], {R, C + 2},
  323. {in_verbatim, undefined});
  324. [{identifier, _, Tag}, {identifier, _, verbatim},
  325. {open_tag, _, '{%'}
  326. | Ss] ->
  327. scan(T, [{string, {R, C + 2}, ""} | Ss], {R, C + 2},
  328. {in_verbatim, Tag});
  329. _ ->
  330. scan(T,
  331. [{close_tag, P, "%}"} | post_process(S, close_tag)],
  332. {R, C + 2}, in_text)
  333. end;
  334. scan("{%" ++ T, S, {R, C} = P, {in_verbatim, E} = St) ->
  335. scan(T, S, {R, C + 2}, {in_verbatim_code, {E, "%{"}});
  336. scan(" " ++ T, S, {R, C} = P,
  337. {in_verbatim_code, E} = St) ->
  338. {Tag, Backtrack} = E,
  339. scan(T, S, {R, C + 1},
  340. {in_verbatim_code, {Tag, [$\s | Backtrack]}});
  341. scan("endverbatim%}" ++ T, S, {R, C} = P,
  342. {in_verbatim_code, E} = St)
  343. when element(1, E) =:= undefined ->
  344. scan(T, S, {R, C + 13}, in_text);
  345. scan("endverbatim " ++ T, S, {R, C} = P,
  346. {in_verbatim_code, E} = St) ->
  347. {Tag, Backtrack} = E,
  348. scan(T, S, {R, C + 12},
  349. {in_endverbatim_code,
  350. {Tag, lists:reverse("endverbatim ", Backtrack), ""}});
  351. scan(" " ++ T, S, {R, C} = P,
  352. {in_endverbatim_code, E} = St)
  353. when element(3, E) =:= "" ->
  354. {Tag, Backtrack, EndTag} = E,
  355. scan(T, S, {R, C + 1},
  356. {in_endverbatim_code,
  357. {Tag, [$\s | Backtrack], EndTag}});
  358. scan([H | T], S, {R, C} = P,
  359. {in_endverbatim_code, E} = St)
  360. when H >= $a andalso H =< $z orelse
  361. H >= $0 andalso H =< $9 orelse H =:= $_ ->
  362. {Tag, Backtrack, EndTag} = E,
  363. scan(T, S, {R, C + 1},
  364. {in_endverbatim_code,
  365. {Tag, [H | Backtrack], [H | EndTag]}});
  366. scan(" " ++ T, S, {R, C} = P,
  367. {in_endverbatim_code, E} = St)
  368. when element(1, E) =:= element(3, E) ->
  369. {Tag, Backtrack, Tag} = E,
  370. scan(T, S, {R, C + 1},
  371. {in_endverbatim_code, {Tag, [$\s | Backtrack], Tag}});
  372. scan("%}" ++ T, S, {R, C} = P,
  373. {in_endverbatim_code, E} = St)
  374. when element(1, E) =:= element(3, E) ->
  375. scan(T, S, {R, C + 2}, in_text);
  376. scan("%}" ++ T, S, {R, C} = P,
  377. {in_endverbatim_code, E} = St)
  378. when element(1, E) =:= undefined andalso
  379. element(3, E) =:= "" ->
  380. scan(T, S, {R, C + 2}, in_text);
  381. scan([H | T], S, {R, C} = P,
  382. {in_endverbatim_code, E} = St) ->
  383. {Tag, Backtrack, _} = E,
  384. scan(T,
  385. case S of
  386. [{string, _, L} = M | Ss] ->
  387. [setelement(3, M, [H | Backtrack] ++ L) | Ss];
  388. _ -> [{string, P, [H | Backtrack]} | S]
  389. end,
  390. case H of
  391. $\n -> {R + 1, 1};
  392. _ -> {R, C + 1}
  393. end,
  394. {in_verbatim, Tag});
  395. scan([H | T], S, {R, C} = P,
  396. {in_verbatim_code, E} = St) ->
  397. {Tag, Backtrack} = E,
  398. scan(T,
  399. case S of
  400. [{string, _, L} = M | Ss] ->
  401. [setelement(3, M, [H | Backtrack] ++ L) | Ss];
  402. _ -> [{string, P, [H | Backtrack]} | S]
  403. end,
  404. case H of
  405. $\n -> {R + 1, 1};
  406. _ -> {R, C + 1}
  407. end,
  408. {in_verbatim, Tag});
  409. scan([H | T], S, {R, C} = P, {in_verbatim, E} = St) ->
  410. scan(T,
  411. case S of
  412. [{string, _, L} = M | Ss] ->
  413. [setelement(3, M, [H | L]) | Ss];
  414. _ -> [{string, P, [H]} | S]
  415. end,
  416. case H of
  417. $\n -> {R + 1, 1};
  418. _ -> {R, C + 1}
  419. end,
  420. {in_verbatim, E});
  421. scan("==" ++ T, S, {R, C} = P, {_, E}) ->
  422. scan(T, [{'==', P} | post_process(S, '==')], {R, C + 2},
  423. {in_code, E});
  424. scan("!=" ++ T, S, {R, C} = P, {_, E}) ->
  425. scan(T, [{'!=', P} | post_process(S, '!=')], {R, C + 2},
  426. {in_code, E});
  427. scan(">=" ++ T, S, {R, C} = P, {_, E}) ->
  428. scan(T, [{'>=', P} | post_process(S, '>=')], {R, C + 2},
  429. {in_code, E});
  430. scan("<=" ++ T, S, {R, C} = P, {_, E}) ->
  431. scan(T, [{'<=', P} | post_process(S, '<=')], {R, C + 2},
  432. {in_code, E});
  433. scan(">" ++ T, S, {R, C} = P, {_, E}) ->
  434. scan(T, [{'>', P} | post_process(S, '>')], {R, C + 1},
  435. {in_code, E});
  436. scan("<" ++ T, S, {R, C} = P, {_, E}) ->
  437. scan(T, [{'<', P} | post_process(S, '<')], {R, C + 1},
  438. {in_code, E});
  439. scan("(" ++ T, S, {R, C} = P, {_, E}) ->
  440. scan(T, [{'(', P} | post_process(S, '(')], {R, C + 1},
  441. {in_code, E});
  442. scan(")" ++ T, S, {R, C} = P, {_, E}) ->
  443. scan(T, [{')', P} | post_process(S, ')')], {R, C + 1},
  444. {in_code, E});
  445. scan("," ++ T, S, {R, C} = P, {_, E}) ->
  446. scan(T, [{',', P} | post_process(S, ',')], {R, C + 1},
  447. {in_code, E});
  448. scan("|" ++ T, S, {R, C} = P, {_, E}) ->
  449. scan(T, [{'|', P} | post_process(S, '|')], {R, C + 1},
  450. {in_code, E});
  451. scan("=" ++ T, S, {R, C} = P, {_, E}) ->
  452. scan(T, [{'=', P} | post_process(S, '=')], {R, C + 1},
  453. {in_code, E});
  454. scan(":" ++ T, S, {R, C} = P, {_, E}) ->
  455. scan(T, [{':', P} | post_process(S, ':')], {R, C + 1},
  456. {in_code, E});
  457. scan("." ++ T, S, {R, C} = P, {_, E}) ->
  458. scan(T, [{'.', P} | post_process(S, '.')], {R, C + 1},
  459. {in_code, E});
  460. scan("_(" ++ T, S, {R, C} = P, {_, E}) ->
  461. scan(T, [{'(', P}, {'_', P} | post_process(S, '_')],
  462. {R, C + 2}, {in_code, E});
  463. scan(" " ++ T, S, {R, C}, {_, E}) ->
  464. scan(T, S, {R, C + 1}, {in_code, E});
  465. scan([H | T], S, {R, C} = P, {in_code, E})
  466. when H >= $a andalso H =< $z orelse
  467. H >= $A andalso H =< $Z orelse H == $_ ->
  468. scan(T,
  469. [{identifier, P, [H]} | post_process(S, identifier)],
  470. case H of
  471. $\n -> {R + 1, 1};
  472. _ -> {R, C + 1}
  473. end,
  474. {in_identifier, E});
  475. scan([H | T], S, {R, C} = P, {in_code, E})
  476. when H >= $0 andalso H =< $9 orelse H == $- ->
  477. scan(T,
  478. [{number_literal, P, [H]} | post_process(S,
  479. number_literal)],
  480. case H of
  481. $\n -> {R + 1, 1};
  482. _ -> {R, C + 1}
  483. end,
  484. {in_number, E});
  485. scan([H | T], S, {R, C} = P, {in_code, E} = St) ->
  486. return_error({illegal_char, H}, P, [H | T], S, St);
  487. scan([H | T], S, {R, C} = P, {in_number, E} = St)
  488. when H >= $0 andalso H =< $9 ->
  489. scan(T,
  490. case S of
  491. [{number_literal, _, L} = M | Ss] ->
  492. [setelement(3, M, [H | L]) | Ss];
  493. _ ->
  494. [{number_literal, P, [H]} | post_process(S,
  495. number_literal)]
  496. end,
  497. case H of
  498. $\n -> {R + 1, 1};
  499. _ -> {R, C + 1}
  500. end,
  501. St);
  502. scan([H | T], S, {R, C} = P, {in_number, E} = St) ->
  503. return_error({illegal_char, H}, P, [H | T], S, St);
  504. scan([H | T], S, {R, C} = P, {in_identifier, E})
  505. when H >= $a andalso H =< $z orelse
  506. H >= $A andalso H =< $Z orelse
  507. H >= $0 andalso H =< $9 orelse H == $_ ->
  508. scan(T,
  509. case S of
  510. [{identifier, _, L} = M | Ss] ->
  511. [setelement(3, M, [H | L]) | Ss];
  512. _ ->
  513. [{identifier, P, [H]} | post_process(S, identifier)]
  514. end,
  515. case H of
  516. $\n -> {R + 1, 1};
  517. _ -> {R, C + 1}
  518. end,
  519. {in_identifier, E});
  520. scan([H | T], S, {R, C} = P, {in_identifier, E} = St) ->
  521. return_error({illegal_char, H}, P, [H | T], S, St);
  522. scan([], S, {R, C} = P, in_text = St) ->
  523. {ok, lists:reverse(post_process(S, eof))};
  524. scan([], S, {R, C} = P, {in_comment, E} = St) ->
  525. return_error({eof, in_comment}, P);
  526. scan([], S, {R, C} = P, {_, E} = St) ->
  527. return_error({eof, in_code}, P).
  528. post_process(_, {string, _, L} = T, _) ->
  529. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  530. post_process(_, {string_literal, _, L} = T, _) ->
  531. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  532. post_process(_, {comment_tag, _, L} = T, _) ->
  533. setelement(3, T, begin L1 = lists:reverse(L), L1 end);
  534. post_process(_, {number_literal, _, L} = T, _) ->
  535. setelement(3, T,
  536. begin
  537. L1 = lists:reverse(L), L2 = list_to_integer(L1), L2
  538. end);
  539. post_process(_, {open_var, _, L} = T, _) ->
  540. setelement(3, T, begin L1 = to_atom(L), L1 end);
  541. post_process(_, {close_var, _, L} = T, _) ->
  542. setelement(3, T, begin L1 = to_atom(L), L1 end);
  543. post_process(_, {open_tag, _, L} = T, _) ->
  544. setelement(3, T, begin L1 = to_atom(L), L1 end);
  545. post_process(_, {close_tag, _, L} = T, _) ->
  546. setelement(3, T, begin L1 = to_atom(L), L1 end);
  547. post_process([{open_tag, _, _} | _],
  548. {identifier, _, L} = T, close_tag) ->
  549. is_keyword(all, T);
  550. post_process([{open_tag, _, _} | _],
  551. {identifier, _, L} = T, _) ->
  552. is_keyword(open_tag, T);
  553. post_process([{open_var, _, _} | _],
  554. {identifier, _, L} = T, _) ->
  555. setelement(3, T,
  556. begin L1 = lists:reverse(L), L2 = to_atom(L1), L2 end);
  557. post_process([{'.', _} | _], {identifier, _, L} = T,
  558. _) ->
  559. setelement(3, T,
  560. begin L1 = lists:reverse(L), L2 = to_atom(L1), L2 end);
  561. post_process(_, {identifier, _, L} = T, close_tag) ->
  562. is_keyword(close_tag, T);
  563. post_process(_, {identifier, _, L} = T, _) ->
  564. is_keyword(any, T);
  565. post_process(_, T, _) -> T.
  566. post_process([S | Ss], N) ->
  567. [post_process(Ss, S, N) | Ss];
  568. post_process(T, N) -> post_process(undefined, T, N).