blocktrans_scanner.erl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. % Module for extracting blocktrans blocks with original source formatting preserved.
  2. -module(blocktrans_scanner).
  3. -export([scan/1]).
  4. scan(Template) ->
  5. scan(Template, [], {1, 1}, in_text).
  6. scan([], Scanned, _, in_text) ->
  7. {ok, lists:reverse(lists:map(
  8. fun
  9. ({text, Pos, Text}) ->
  10. {text, Pos, lists:reverse(Text)};
  11. (Other) ->
  12. Other
  13. end, Scanned))};
  14. scan([], _Scanned, _, {in_comment, _}) ->
  15. {error, "Reached end of file inside a comment."};
  16. scan([], _Scanned, _, _) ->
  17. {error, "Reached end of file inside a code block."};
  18. scan("<!--{{" ++ T, Scanned, {Row, Column}, in_text) ->
  19. scan(T, append_text("<!--{{", {Row, Column}, Scanned), {Row, Column + length("<!--{{")}, {in_code, "}}-->"});
  20. scan("{{" ++ T, Scanned, {Row, Column}, in_text) ->
  21. scan(T, append_text("{{", {Row, Column}, Scanned), {Row, Column + 2}, {in_code, "}}"});
  22. scan("<!--{#" ++ T, Scanned, {Row, Column}, in_text) ->
  23. scan(T, append_text("<!--{#", {Row, Column}, Scanned), {Row, Column + length("<!--{#")}, {in_comment, "#}-->"});
  24. scan("{#" ++ T, Scanned, {Row, Column}, in_text) ->
  25. scan(T, append_text("{#", {Row, Column}, Scanned), {Row, Column + length("{#")}, {in_comment, "#}"});
  26. scan("#}-->" ++ T, Scanned, {Row, Column}, {in_comment, "#}-->"}) ->
  27. scan(T, append_text("#}-->", {Row, Column}, Scanned), {Row, Column + length("#}-->")}, in_text);
  28. scan("#}" ++ T, Scanned, {Row, Column}, {in_comment, "#}"}) ->
  29. scan(T, append_text("#}", {Row, Column}, Scanned), {Row, Column + length("#}")}, in_text);
  30. scan("<!--{% blocktrans " ++ T, Scanned, {Row, Column}, in_text) ->
  31. scan(T, [{open_blocktrans, {Row, Column}, ""} | Scanned],
  32. {Row, Column + length("<!--{% blocktrans ")}, {in_code, "%}-->"});
  33. scan("{% blocktrans " ++ T, Scanned, {Row, Column}, in_text) ->
  34. scan(T, [{open_blocktrans, {Row, Column}, ""} | Scanned],
  35. {Row, Column + length("{% blocktrans ")}, {in_code, "%}"});
  36. scan("{% endblocktrans %}" ++ T, Scanned, {Row, Column}, in_text) ->
  37. scan(T, [{close_blocktrans, {Row, Column}} | Scanned],
  38. {Row, Column + length("{% endblocktrans %}")}, in_text);
  39. scan("<!--{% endblocktrans %}-->" ++ T, Scanned, {Row, Column}, in_text) ->
  40. scan(T, [{close_blocktrans, {Row, Column}} | Scanned],
  41. {Row, Column + length("<!--{% endblocktrans %}-->")}, {in_text});
  42. scan("<!--{%" ++ T, Scanned, {Row, Column}, in_text) ->
  43. scan(T, append_text("<!--{%", {Row, Column}, Scanned),
  44. {Row, Column + length("<!--{%")}, {in_code, "%}-->"});
  45. scan("{%" ++ T, Scanned, {Row, Column}, in_text) ->
  46. scan(T, append_text("{%", {Row, Column}, Scanned),
  47. {Row, Column + length("{%")}, {in_code, "%}"});
  48. scan([H | T], Scanned, {Row, Column}, {in_comment, Closer}) ->
  49. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_comment, Closer});
  50. scan("\n" ++ T, Scanned, {Row, Column}, in_text) ->
  51. scan(T, append_text("\n", {Row, Column}, Scanned), {Row + 1, 1}, in_text);
  52. scan([H | T], Scanned, {Row, Column}, in_text) ->
  53. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, in_text);
  54. scan("\"" ++ T, Scanned, {Row, Column}, {in_code, Closer}) ->
  55. scan(T, append_text("\"", {Row, Column}, Scanned), {Row, Column + 1} , {in_double_quote, Closer});
  56. scan("\'" ++ T, Scanned, {Row, Column}, {in_code, Closer}) ->
  57. scan(T, append_text("\'", {Row, Column}, Scanned), {Row, Column + 1}, {in_single_quote, Closer});
  58. scan("\\" ++ T, Scanned, {Row, Column}, {in_double_quote, Closer}) ->
  59. scan(T, append_text("\\", {Row, Column}, Scanned), {Row, Column + 1}, {in_double_quote_slash, Closer});
  60. scan([H | T], Scanned, {Row, Column}, {in_double_quote_slash, Closer}) ->
  61. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_double_quote, Closer});
  62. scan("\\" ++ T, Scanned, {Row, Column}, {in_single_quote, Closer}) ->
  63. scan(T, append_text("\\", {Row, Column}, Scanned), {Row, Column + 1}, {in_single_quote_slash, Closer});
  64. scan([H | T], Scanned, {Row, Column}, {in_single_quote_slash, Closer}) ->
  65. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_single_quote, Closer});
  66. % end quote
  67. scan("\"" ++ T, Scanned, {Row, Column}, {in_double_quote, Closer}) ->
  68. scan(T, append_text("\"", {Row, Column}, Scanned), {Row, Column + 1}, {in_code, Closer});
  69. scan("\'" ++ T, Scanned, {Row, Column}, {in_single_quote, Closer}) ->
  70. scan(T, append_text("\'", {Row, Column}, Scanned), {Row, Column + 1}, {in_code, Closer});
  71. scan([H | T], Scanned, {Row, Column}, {in_double_quote, Closer}) ->
  72. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_double_quote, Closer});
  73. scan([H | T], Scanned, {Row, Column}, {in_single_quote, Closer}) ->
  74. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_single_quote, Closer});
  75. scan("}}-->" ++ T, Scanned, {Row, Column}, {_, "}}-->"}) ->
  76. scan(T, append_text("}}-->", {Row, Column}, Scanned),
  77. {Row, Column + length("}}-->")}, in_text);
  78. scan("}}" ++ T, Scanned, {Row, Column}, {_, "}}"}) ->
  79. scan(T, append_text("}}", {Row, Column}, Scanned), {Row, Column + length("}}")}, in_text);
  80. scan("%}-->" ++ T, Scanned, {Row, Column}, {_, "%}-->"}) ->
  81. scan(T, append_text("%}-->", {Row, Column}, Scanned),
  82. {Row, Column + length("%}-->")}, in_text);
  83. scan("%}" ++ T, Scanned, {Row, Column}, {_, "%}"}) ->
  84. scan(T, append_text("%}", {Row, Column}, Scanned),
  85. {Row, Column + length("%}")}, in_text);
  86. scan([H | T], Scanned, {Row, Column}, {in_code, Closer}) ->
  87. scan(T, append_text([H], {Row, Column}, Scanned), {Row, Column + 1}, {in_code, Closer}).
  88. % internal functions
  89. append_text(Text, Pos, []) ->
  90. [{text, Pos, Text}];
  91. append_text(Text, Pos, [{close_blocktrans, _}|_] = Scanned) ->
  92. [{text, Pos, Text}|Scanned];
  93. append_text([C], _Pos, [{open_blocktrans, BPos, ""}|Rest]) when ((C >= $a) and (C =< $z)) or ((C >= $A) and (C =< $Z)) or (C =:= $_) ->
  94. [{open_blocktrans, BPos, [C]}|Rest];
  95. append_text(" ", _Pos, [{open_blocktrans, BPos, ""}|Rest]) ->
  96. [{open_blocktrans, BPos, ""}|Rest];
  97. append_text([C], _Pos, [{open_blocktrans, BPos, Name}|Rest]) when ((C >= $a) and (C =< $z)) or ((C >= $A) and (C =< $Z)) or (C =:= $_) orelse (C >= $0 andalso C =< $9) ->
  98. [{open_blocktrans, BPos, [C|Name]}|Rest];
  99. append_text(" ", _Pos, [{open_blocktrans, BPos, Name}|Rest]) when is_list(Name) ->
  100. [{open_blocktrans, BPos, lists:reverse(Name)}|Rest];
  101. append_text("%}", {Row, Column}, [{open_blocktrans, _BPos, _Name}|_] = Scanned) ->
  102. [{text, {Row, Column + 2}, ""}|Scanned];
  103. append_text(_Chars, _Pos, [{open_blocktrans, _BPos, _Name}|_] = Scanned) ->
  104. Scanned;
  105. append_text(Chars, _Pos, [{text, TPos, TChars}|Rest]) ->
  106. [{text, TPos, lists:reverse(Chars, TChars)}|Rest].