From f84b2a806f2330f675240ab80b013181fe2f50a8 Mon Sep 17 00:00:00 2001 From: Roberto Saccon Date: Sun, 18 Nov 2007 19:40:19 +0000 Subject: [PATCH] initial commit --- Emakefile | 2 + Makefile | 15 +++ demo/out/test_comment.html | 12 ++ demo/out/test_extend.html | 11 ++ demo/out/test_variable.html | 11 ++ demo/templates/base.html | 11 ++ demo/templates/test_comment.html | 12 ++ demo/templates/test_extend.html | 3 + demo/templates/test_variable.html | 11 ++ ebin/base.beam | Bin 0 -> 588 bytes ebin/erlydtl.beam | Bin 0 -> 6492 bytes ebin/erlydtl_api.beam | Bin 0 -> 6708 bytes ebin/erlydtl_demo.beam | Bin 0 -> 3264 bytes ebin/erlydtl_parser.beam | Bin 0 -> 3188 bytes ebin/erlydtl_scanner.beam | Bin 0 -> 7292 bytes ebin/erlydtl_tools.beam | Bin 0 -> 2968 bytes ebin/test_comment.beam | Bin 0 -> 736 bytes ebin/test_extend.beam | Bin 0 -> 628 bytes ebin/test_variable.beam | Bin 0 -> 764 bytes src/demo/erlydtl_demo.erl | 104 +++++++++++++++ src/erlydtl/erlydtl_api.erl | 175 +++++++++++++++++++++++++ src/erlydtl/erlydtl_parser.erl | 189 +++++++++++++++++++++++++++ src/erlydtl/erlydtl_parser.yrl | 66 ++++++++++ src/erlydtl/erlydtl_scanner.erl | 210 ++++++++++++++++++++++++++++++ src/erlydtl/erlydtl_tools.erl | 125 ++++++++++++++++++ 25 files changed, 957 insertions(+) create mode 100755 Emakefile create mode 100755 Makefile create mode 100644 demo/out/test_comment.html create mode 100644 demo/out/test_extend.html create mode 100644 demo/out/test_variable.html create mode 100755 demo/templates/base.html create mode 100755 demo/templates/test_comment.html create mode 100755 demo/templates/test_extend.html create mode 100755 demo/templates/test_variable.html create mode 100644 ebin/base.beam create mode 100644 ebin/erlydtl.beam create mode 100644 ebin/erlydtl_api.beam create mode 100644 ebin/erlydtl_demo.beam create mode 100644 ebin/erlydtl_parser.beam create mode 100644 ebin/erlydtl_scanner.beam create mode 100644 ebin/erlydtl_tools.beam create mode 100644 ebin/test_comment.beam create mode 100644 ebin/test_extend.beam create mode 100644 ebin/test_variable.beam create mode 100644 src/demo/erlydtl_demo.erl create mode 100755 src/erlydtl/erlydtl_api.erl create mode 100644 src/erlydtl/erlydtl_parser.erl create mode 100755 src/erlydtl/erlydtl_parser.yrl create mode 100755 src/erlydtl/erlydtl_scanner.erl create mode 100644 src/erlydtl/erlydtl_tools.erl diff --git a/Emakefile b/Emakefile new file mode 100755 index 0000000..c41e4eb --- /dev/null +++ b/Emakefile @@ -0,0 +1,2 @@ +{"src/erlydtl/*", [debug_info, {d, debug}, {outdir, "ebin"}]}. +{"src/demo/*", [debug_info, {d, debug}, {outdir, "ebin"}]}. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..acc2a9d --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +ERL=/Users/rsaccon/R11B/start.sh +#ERL=/usr/local/erlware/bin/erl +ERL=erl +NODENAME=skast + + +all: + $(ERL) -make + +run: + $(ERL) -pa `pwd`/ebin + +clean: + rm -fv ebin/* + rm -fv erl_crash.dump \ No newline at end of file diff --git a/demo/out/test_comment.html b/demo/out/test_comment.html new file mode 100644 index 0000000..7c69fba --- /dev/null +++ b/demo/out/test_comment.html @@ -0,0 +1,12 @@ + + + + + Test Comment + + + + bla + + + \ No newline at end of file diff --git a/demo/out/test_extend.html b/demo/out/test_extend.html new file mode 100644 index 0000000..2ad414d --- /dev/null +++ b/demo/out/test_extend.html @@ -0,0 +1,11 @@ +blastring + +base template + +replacing the base title + +more of base template + +replacing the base content + +end of base template \ No newline at end of file diff --git a/demo/out/test_variable.html b/demo/out/test_variable.html new file mode 100644 index 0000000..ae96900 --- /dev/null +++ b/demo/out/test_variable.html @@ -0,0 +1,11 @@ + + + + + Test variable + + + foostring + foostring + + \ No newline at end of file diff --git a/demo/templates/base.html b/demo/templates/base.html new file mode 100755 index 0000000..65c3fc1 --- /dev/null +++ b/demo/templates/base.html @@ -0,0 +1,11 @@ +{{ variable }} + +base template + +{% block title %}base title{% endblock %} + +more of base template + +{% block content %}base content{% endblock %} + +end of base template \ No newline at end of file diff --git a/demo/templates/test_comment.html b/demo/templates/test_comment.html new file mode 100755 index 0000000..925793b --- /dev/null +++ b/demo/templates/test_comment.html @@ -0,0 +1,12 @@ + + + + + Test Comment + + + {# comment1 #} + bla + {# comment2 #} + + \ No newline at end of file diff --git a/demo/templates/test_extend.html b/demo/templates/test_extend.html new file mode 100755 index 0000000..9954bc3 --- /dev/null +++ b/demo/templates/test_extend.html @@ -0,0 +1,3 @@ +{% extends base.html %} +{% block title %}replacing the base title{% endblock %} +{% block content %}replacing the base content{% endblock %} \ No newline at end of file diff --git a/demo/templates/test_variable.html b/demo/templates/test_variable.html new file mode 100755 index 0000000..e83f310 --- /dev/null +++ b/demo/templates/test_variable.html @@ -0,0 +1,11 @@ + + + + + Test variable + + + {{ variable }} + + + \ No newline at end of file diff --git a/ebin/base.beam b/ebin/base.beam new file mode 100644 index 0000000000000000000000000000000000000000..01d6270f0d1beba712125fe6b54c03f74109f32b GIT binary patch literal 588 zcmZWnyH3L}6m=ey$Q>|=Ktf`O+5raCfCOSdLM=2%NKg>ZvAB&(8xlK8OjTz7fG+^V z#KgqRz`_@F<2P8jPKyM>(uvPG_gp`c>>M1eAf(r~{Mvp^iWniZ1Tf7O%~&xO!F9x% zJ>C%omPV9cPF*tD{AF*8fI&V15P%vDz$C!Xh;G|NbBXmz>eeiB>TlL;*)Kaz-I}vX zBX)0XjIC+Q&zWyHhNCU(b_r?Ks%_!7GGae`+>J3pyK$n{p9kpbE&vmt{o=Ym$TN#$Pvum- z08m_wpC0Awd!nt@R355HnZmSq8^KfS>H#wP8P5eLD1Lbyo_(x8gkPKIpHJ`4VYt1^ zJCMA~^QOvAibVDV&r}ac%m#@_Ws^qH9}(u+K1(wQU!jTB%4%gzd8X{etXpWo#~RWi ywW&iF=!~iqGI5=@*%c~#rx`SQX-3=dHa(FrKB{@}H{1j=@+u+RrIkrI1o{Rf{e^%4 literal 0 HcmV?d00001 diff --git a/ebin/erlydtl.beam b/ebin/erlydtl.beam new file mode 100644 index 0000000000000000000000000000000000000000..14e2dd01869b541c660ef697a9c58fd2dfd28a41 GIT binary patch literal 6492 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 E0YJ85g8%>k literal 0 HcmV?d00001 diff --git a/ebin/erlydtl_demo.beam b/ebin/erlydtl_demo.beam new file mode 100644 index 0000000000000000000000000000000000000000..00c1a1c3856b3c7096cccb970a5c3e2acda67e09 GIT binary patch literal 3264 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 Fe*kW{mqY*n literal 0 HcmV?d00001 diff --git a/ebin/erlydtl_scanner.beam b/ebin/erlydtl_scanner.beam new file mode 100644 index 0000000000000000000000000000000000000000..e4895d341e208b166a22bd73598a9ad10582b9a6 GIT binary patch literal 7292 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 literal 0 HcmV?d00001 diff --git a/ebin/erlydtl_tools.beam b/ebin/erlydtl_tools.beam new file mode 100644 index 0000000000000000000000000000000000000000..52a9f206e82aa453fbb72b8abab918fe2515975d GIT binary patch literal 2968 zcmZuy2~-o;8lK5yBM_KmPzzNU4WL#96wr!TCXj%*02UM#YaEgRgGnY#62!GsmR9Lg zK)|O`1*8g!R0Wr+xI?v8A1>6T7ICk*KDVlf_TCWB>FMd5^UeM5zkdH+W}@OgAC4f- zg%N7yB&C%#A_$s{Ac(J&;SBS2R)faMvIdJ(%Q3W-(U@t@!f+pEMpkDtFam?#Vzr1; z4YbwDm_!_t$p9yeVN-=1V_<0=U(4zkf!W5TF+z})Hl?}Hpc2TefuX!1L!6#>{e7jXkx+%`uxtb0)nh%_4HdINABYq%vBk)ATUX%wcF9 z!#ROAIem)F%1D?jdoJ2waDk1$hG1jP4u8EVm32#FtRLdx9Ek*Lfgrr8V2yDA_{0MA z0dPWbo_qj;lDIewQHebfOht)32_e~x2J+-1NR%2i1#`hkir|ZIM1`D%xR8OA zf=>}3X&_#KtK!82U^<+_)fkUZ^9hhpgwLkj2{CCV(e0pD5pQ#l@aDh4EFb;(<^Jn1R${KU^io#lfIKUXa?!5EP`A2N9G46On}!-_EWB zu=6C*CsMqS1o3cDBp*i;YPc$rz6$W_rvNl7MoV!l6u{nR1cobyNO4F(fq^KvOngj? zZ^uzFj*AC@s_tSHL17A@22KA9m&|{1!3k6>17t`N70ab?e<(nuf3z%G;uS3!pjKdD z?Z8$X#?5#XMf8}SMq_FMGy;PO5bT4XVs}c8#p11~xEE9aM!n&V0UgDT)iH=FJrD@=Y2wG8{4iVT@_7Xi`$him~o)CLg5&V>c z__>H6*gx1m1iJC9dLuJOm;%=0BJE7eX@d5p2ip@^SR1Eh<|5$%Q@~%s65wDNz?vCT zkL|-z4EVR>Y5&u}lL>oKrdX_CnP26^BZy3yRlY500()~LUbf-#q*W&82es5!jZ~a- z^&Iwo!l)JBCH!{$<*bc?a$`)H@0zMo;f`m&jS2SU#$DM@ot=;(z5Dv~BE=`^U$>8m zTEFP&G%kwwDCyAm>+gQ2{=IeKgiq7{e=|SfoTTYdSgiiStOem^LtmBdd_MY?{@Jy= z^VgTHexjODb}z2-qUQE>zwayOnQD@khvy8q{A5sC<)34R#Nf9sdl&RtcK#Hpnf~*k z>=E6YPk8jXm#L_^88*Ab+}S6$v_$51O2?}nrdu3!zC8Eo_29c^n zvua_^>MN~-^Mq}@gseGy;rGzCYwyuxe}Ku*S9`lnxd~BQZ>7q=X3O$HA7Eq=^URV zxH2%~-sX&x-xuE=Syb4Vm%*yD@S@6d9!pnyG$tu8`ID`#r|(9XOIM$mw)75D15$LnjCLYJxZ+O?@FmUGcfyViJ;1_C}T`OZcX>~oHKM) z&f&9bUZKvfk;;LCde2Z3)6^+#7roGxwV9ta3u0~6wF%_7gR)m|wzr8FmQf*Ab>_l`>KRiJ*+^33+j%uR2`H-G)0<%YW6^Ulru*P)9wJ}zsg_nREEKgKKV z*LNYjZ~8u&JU0JeNPcQvz_*p`h+ZqJ4n1G6nisi?T+|rqZPvSmUX8S@J5s!_e}rjg zSLIhOPCk3K)%%xsE!{u5_a-**Uc20jR=$5MbzA4ZJNV>)FQ(->7g#-HZ?iTjXOCZ7 z99%WI->c71f9_me+E&SSJ&T3M}5l`wgEAyr%M=C6tixYO$FxkVXAFniN0wh!EC-X0!UoOgNU(MQo4 zi+nD6z6{ARzM?i)}a(xzMuaxWRAusgR&G$1hCXA>4QTL{+lx-hs)djwR*q zd|CGe_n>&L=xT;j@t&^Ljr&zus{-p6Xgdun3LB3)C5FyqiW);>&vh2~ge>+_=$XRC zVtq*T3-_shFRm@O3c?RdJ9bwyH9zKxuGhYu`DbOfQ|ys9=1Y|>nNx-PH+noU u3&$+pm4NLDTJgW*zL7IW<{mD;^j&vTuB*?CWz}OBZ7TfYX~1DmG5r^~V%i`8 literal 0 HcmV?d00001 diff --git a/ebin/test_comment.beam b/ebin/test_comment.beam new file mode 100644 index 0000000000000000000000000000000000000000..9c39cc8c5b8c478f4361cf7694d78368afea212a GIT binary patch literal 736 zcmY*X&2G~`5MDbWRZ=9ZMBF%RjSxX1-c}6~f+R}nBs5Z*M#T|uN;md4KefHap8Opv zu3X?@cma3^cnRKtS*MlCNS}A+n{Q^@N)h_TMVq~;7Ddc)Xyy|&iJmW-#&xnMI0{3=Tzp1WXq;F*m=O>vC^rL~#h zo^sF)1aPW4RK(}yd{sAX83K-=;%p;fQg;{CO%NMMo4%#)jK_(9`pD^4USr?156rjFT*j`rCQsQY!9o@%+{N2qG7{k~$M9utJ@A>e Mz<-$}fQKOe06Q+P82|tP literal 0 HcmV?d00001 diff --git a/ebin/test_extend.beam b/ebin/test_extend.beam new file mode 100644 index 0000000000000000000000000000000000000000..31f2fd77ccbec382493bd61a2329e9f77b33be4e GIT binary patch literal 628 zcmZuv%Wl&^6uq`XYE2|CwkQv=u*ib0;v&l4p$$?bD2T@nDNO8}#Hl@F&D>UjEq{Q- zn$O@P_yGQ*TUc_(4N@x@>DcF`BEGkOC;OEcUMs&dfi z^0dZTr53u6rj}}XV~I4oB*URDk#mL-G2A$2>@Wf^^5Z!2(kMKSj>26?j>3E4?r<_p znB5Kcx9mB2;)FB`0N#*!%j*~+c(bWq zq;qL8C2ZPS5*p-JQK@B0E4*kGTJgC^h(;UyCm_UsB2-b0LR^_y2!LtRy0z~!e0Nqx zkKtY7{$$g6_O_byxqhGFxEp^nPWPYd!p-S47!$cW-TPeg(_8r^1ZP%tg^D2m^!5F1 z?|XiI{QKK4`f8qWEW9*03wCK zoF^e4Mq+a+{hLS(!uU!SMH2CN{BSH_aF52Kmh=T~9AP5V>LS(=hGy!PWopzsvCMYK zB6i2H?KUl0l}^RZgVLYUBNZ98wyj$Z(GCtQqiYhahmonhKQL@XP}4xeH;{OQXlrFk z8*C{3RkPe+0ZgN2d86^PebMsX^*Z##J3phn{?XZKi#k=t-tM#*YkTcHQFpg%jCHyW zbpn9dOU4$9g}c~sWin>oWoB1rDJ0U3gA>ZRKI?MEd?18KG(8+Vy&HUk<>bcgqS<}# zdN=ZmZ{R#mr!$-fd4kXpYD5KucJHirmYHVjmQy;FFCx@gt-Bh<>t}MLJQYU{0TSG{ zK1KM|0^KLZJdLv;Hi`57%ih=8;MdO|AD@5I_g+sXt<(4lm7g+Y`N3J^|3P#ofe`pq}F#clqKKUSGyDsPgJxF!|W gPqC0CDIej~nVg9@&oO+oD<2}}PVg?n6!0g=KcV@uod5s; literal 0 HcmV?d00001 diff --git a/src/demo/erlydtl_demo.erl b/src/demo/erlydtl_demo.erl new file mode 100644 index 0000000..a3806a8 --- /dev/null +++ b/src/demo/erlydtl_demo.erl @@ -0,0 +1,104 @@ +%%%------------------------------------------------------------------- +%%% File: erlydtl_demo.erl +%%% @author Roberto Saccon [http://rsaccon.com] +%%% @copyright 2007 Roberto Saccon +%%% @doc +%%% +%%% @end +%%% +%%% The MIT License +%%% +%%% Copyright (c) 2007 Roberto Saccon +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in +%%% all copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%%% THE SOFTWARE. +%%% +%%% @since 2007-11-17 by Roberto Saccon +%%%------------------------------------------------------------------- +-module(erlydtl_demo). +-author('rsaccon@gmail.com'). + +%% API +-export([compile_templates/0, + render_html/0]). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% @spec () -> any() +%% @doc compiles the templates to beam files +%% @end +%%-------------------------------------------------------------------- +compile_templates() -> + DocRoot = filename:join([filename:dirname(code:which(?MODULE)),"..", "demo", "templates"]), + filelib:fold_files(DocRoot, + "\.", + true, + fun(Path, _Acc) -> + Name = filename:rootname(filename:basename(Path)), + erlydtl_api:compile(Path, Name, Name, DocRoot) + end, + []). + + +%%-------------------------------------------------------------------- +%% @spec () -> any() +%% @doc renders the templete to a file +%% @end +%%-------------------------------------------------------------------- +render_html() -> + OutDir = filename:join([filename:dirname(code:which(?MODULE)),"..", "demo", "out"]), + render(OutDir, test_variable, ".html", "foostring"), + render(OutDir, test_extend, ".html", "blastring"), + render(OutDir, test_comment, ".html"). + + +%%==================================================================== +%% Internal functions +%%==================================================================== + +render(OutDir, Name, Ext, Var) -> + case catch Name:Name(Var) of + {'EXIT', Reason} -> + io:format("TRACE ~p:~p ~p: rendering failure: ~n",[?MODULE, ?LINE, Reason]); + Val -> + case file:open(filename:join([OutDir, lists:concat([Name, Ext])]), [write]) of + {ok, IoDev} -> + file:write(IoDev, Val), + file:close(IoDev), + io:format("TRACE ~p:~p ~p: success~n",[?MODULE, ?LINE, Name]); + _ -> + io:format("TRACE ~p:~p ~p: file write failure~n",[?MODULE, ?LINE, Name]) + end + end. + +render(OutDir, Name, Ext) -> + case catch Name:Name() of + {'EXIT', Reason} -> + io:format("TRACE ~p:~p ~p: rendering failure: ~n",[?MODULE, ?LINE, Reason]); + Val -> + case file:open(filename:join([OutDir, lists:concat([Name, Ext])]), [write]) of + {ok, IoDev} -> + file:write(IoDev, Val), + file:close(IoDev), + io:format("TRACE ~p:~p ~p: success~n",[?MODULE, ?LINE, Name]); + _ -> + io:format("TRACE ~p:~p ~p: file write failure~n",[?MODULE, ?LINE, Name]) + end + end. diff --git a/src/erlydtl/erlydtl_api.erl b/src/erlydtl/erlydtl_api.erl new file mode 100755 index 0000000..8c0fc6e --- /dev/null +++ b/src/erlydtl/erlydtl_api.erl @@ -0,0 +1,175 @@ +%%%------------------------------------------------------------------- +%%% File: erlydtl_api.erl +%%% @author Roberto Saccon [http://rsaccon.com] +%%% @copyright 2007 Roberto Saccon +%%% @doc +%%% API for compiling ErlyDTL templeates +%%% @end +%%% +%%% The MIT License +%%% +%%% Copyright (c) 2007 Roberto Saccon +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in +%%% all copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%%% THE SOFTWARE. +%%% +%%% @since 2007-11-17 by Roberto Saccon +%%%------------------------------------------------------------------- +-module(erlydtl_api). +-author('rsaccon@gmail.com'). + +%% API +-export([compile/4]). + + +%%-------------------------------------------------------------------- +%% @spec (File:string(), ModuleName:string(), FunctionName:atom(), DocRoot:string()) -> +%% {Ok::atom, Ast::tuple() | {Error::atom(), Msg:string()} +%% @doc compiles a template to a beam file +%% @end +%%-------------------------------------------------------------------- +compile(File, ModuleName, FunctionName, DocRoot) -> + case parse(File) of + {ok, Ast} -> + RelDir = rel_dir(filename:dirname(File), DocRoot), + compile_reload(Ast, ModuleName, FunctionName, RelDir); + {error, Msg} = Err -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, File ++ " Parser failure:"]), + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, Msg]), + Err + end. + + +%%==================================================================== +%% Internal functions +%%==================================================================== + +rel_dir(Dir, DocRoot) when Dir =:= DocRoot -> + DocRoot; +rel_dir(Dir, DocRoot) -> + RelFile = string:substr(Dir, length(DocRoot)+2), + filename:join([DocRoot, RelFile]). + + +parse(File) -> + case file:read_file(File) of + {ok, B} -> + case erlydtl_scanner:scan(binary_to_list(B)) of + {ok, Tokens} -> + erlydtl_parser:parse(Tokens); + Err -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, File ++ " Scanner failure:"]), + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, Err]), + Err + end; + Err -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, "File read error"]), + Err + end. + + +compile_reload([H | T], ModuleName, FunctionName, RelDir) -> + {List, Args} = case transl(H, T, [], [], RelDir) of + {regular, List0, Args0} -> + {[inplace_block(X) || X <- List0], Args0}; + {inherited, List0, Arg0} -> + {List0, Arg0} + end, + Args2 = lists:reverse([{var, 1, Val} || {Val, _} <- Args]), + Cons = list_fold(lists:reverse(List)), + Ast2 = {function, 1, list_to_atom(FunctionName), length(Args2), + [{clause, 1, Args2, [], [Cons]}]}, + Ac = erlydtl_tools:create_module(Ast2 , ModuleName), + case compile:forms(Ac) of + {ok, Module, Bin} -> + case erlydtl_tools:reload(Module, Bin) of + ok -> + erlydtl_tools:write_beam(Module, Bin, "ebin"); + _ -> + {error, "reload failed"} + end; + _ -> + {error, "compilation failed"} + end. + + +list_fold([E]) -> + E; +list_fold([E1, E2]) -> + {cons, 1, E2, E1}; +list_fold([E1, E2 | Tail]) -> + lists:foldl(fun(X, T) -> + {cons, 1, X, T} + end, {cons, 1, E2, E1}, Tail). + + +transl(nil, [{extends, _, Name}], Out, Args, RelDir) -> + case parse(filename:join([RelDir, Name])) of + {ok, ParentAst} -> + [H|T]=ParentAst, + {_, List, Args1} = transl(H, T, [], [], RelDir), + {inherited, [replace_block(X, Out) || X <- List], Args1}; + {error, Msg} -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, Msg]), + io:format("TRACE ~p:~p Parent Parser failure: ~p~n",[?MODULE, ?LINE, Name]), + {regular, Out, Args} + end; + +transl(nil, [{var, L, Val}], Out, Args, _) -> + case lists:keysearch(Val, 2, Args) of + false -> + Key = list_to_atom(lists:concat(["A", length(Args) + 1])), + {regular, [{var, L, Key} | Out], [{Key, Val} | Args]}; + {value, {Key, _}} -> + {regular, [{var, L, Key} | Out], Args} + end; + +transl(nil, [Token], Out, Args, _) -> + {regular, [Token | Out], Args}; + +transl([H | T], [{var, L, Val}], Out, Args, DocRoot) -> + case lists:keysearch(Val, 2, Args) of + false -> + Key = list_to_atom(lists:concat(["A", length(Args) + 1])), + transl(H, T, [{var, L, Key} | Out], [{Key, Val} | Args], DocRoot); + {value, {Key, _}} -> + transl(H, T, [{var, L, Key} | Out], Args, DocRoot) + end; + +transl([H | T], [Token], Out, Args, DocRoot) -> + transl(H, T, [Token | Out], Args, DocRoot). + + +replace_block({block, Name, [nil, Str1]}, List) -> + case lists:keysearch(Name, 2, List) of + false -> + Str1; + {value, {_, _, [nil, Str2]}} -> + Str2 + end; +replace_block(Other, _) -> + Other. + + +inplace_block({block, _, [nil, Str]}) -> + Str; +inplace_block(Other) -> + Other. + + + diff --git a/src/erlydtl/erlydtl_parser.erl b/src/erlydtl/erlydtl_parser.erl new file mode 100644 index 0000000..1df8f70 --- /dev/null +++ b/src/erlydtl/erlydtl_parser.erl @@ -0,0 +1,189 @@ +-module(erlydtl_parser). +-export([parse/1, parse_and_scan/1, format_error/1]). +-file("src/erlydtl/erlydtl_parser.yrl", 63). + +block({_, _, [Name]}, Content) -> + {block, list_to_atom(Name), Content}. +-file("/Users/rsaccon/R11B/erlang/lib/parsetools-1.4.1.1/include/yeccpre.hrl", 0). +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id $ +%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The parser generator will insert appropriate declarations before this line.% + +parse(Tokens) -> + yeccpars0(Tokens, false). + +parse_and_scan({F, A}) -> % Fun or {M, F} + yeccpars0([], {F, A}); +parse_and_scan({M, F, A}) -> + yeccpars0([], {{M, F}, A}). + +format_error(Message) -> + case io_lib:deep_char_list(Message) of + true -> + Message; + _ -> + io_lib:write(Message) + end. + +% To be used in grammar files to throw an error message to the parser +% toplevel. Doesn't have to be exported! +-compile({nowarn_unused_function,{return_error,2}}). +return_error(Line, Message) -> + throw({error, {Line, ?MODULE, Message}}). + +yeccpars0(Tokens, MFA) -> + try yeccpars1(Tokens, MFA, 0, [], []) + catch + throw: {error, {_Line, ?MODULE, _M}} = Error -> + Error % probably from return_error/1 + end. + +% Don't change yeccpars1/6 too much, it is called recursively by yeccpars2/8! +yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, + Tokenizer); +yeccpars1([], {F, A}, State, States, Vstack) -> + case apply(F, A) of + {ok, Tokens, _Endline} -> + yeccpars1(Tokens, {F, A}, State, States, Vstack); + {eof, _Endline} -> + yeccpars1([], false, State, States, Vstack); + {error, Descriptor, _Endline} -> + {error, Descriptor} + end; +yeccpars1([], false, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false). + +% For internal use only. +yeccerror(Token) -> + {error, + {element(2, Token), ?MODULE, + ["syntax error before: ", yecctoken2string(Token)]}}. + +yecctoken2string({atom, _, A}) -> io_lib:write(A); +yecctoken2string({integer,_,N}) -> io_lib:write(N); +yecctoken2string({float,_,F}) -> io_lib:write(F); +yecctoken2string({char,_,C}) -> io_lib:write_char(C); +yecctoken2string({var,_,V}) -> io_lib:format('~s', [V]); +yecctoken2string({string,_,S}) -> io_lib:write_string(S); +yecctoken2string({reserved_symbol, _, A}) -> io_lib:format('~w', [A]); +yecctoken2string({_Cat, _, Val}) -> io_lib:format('~w', [Val]); +yecctoken2string({'dot', _}) -> io_lib:format('~w', ['.']); +yecctoken2string({'$end', _}) -> + []; +yecctoken2string({Other, _}) when is_atom(Other) -> + io_lib:format('~w', [Other]); +yecctoken2string(Other) -> + io_lib:write(Other). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +-file("src/erlydtl/erlydtl_parser.erl", 100). + +yeccpars2(0, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + __NewStack = yeccpars2_0_(__Stack), + yeccpars2(1, __Cat, [0 | __Ss], __NewStack, __T, __Ts, __Tzr); +yeccpars2(1, '$end', _, __Stack, _, _, _) -> + {ok, hd(__Stack)}; +yeccpars2(1, block, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [1 | __Ss], [__T | __Stack]); +yeccpars2(1, extends, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 4, [1 | __Ss], [__T | __Stack]); +yeccpars2(1, string, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 5, [1 | __Ss], [__T | __Stack]); +yeccpars2(1, var, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 6, [1 | __Ss], [__T | __Stack]); +yeccpars2(1, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(2, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + __NewStack = yeccpars2_2_(__Stack), + __Nss = lists:nthtail(1, __Ss), + yeccpars2(yeccgoto('Elements', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr); +yeccpars2(3, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + __NewStack = yeccpars2_3_(__Stack), + yeccpars2(7, __Cat, [3 | __Ss], __NewStack, __T, __Ts, __Tzr); +yeccpars2(4, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr); +yeccpars2(5, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr); +yeccpars2(6, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars2(yeccgoto('Element', hd(__Ss)), __Cat, __Ss, __Stack, __T, __Ts, __Tzr); +yeccpars2(7, block, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [7 | __Ss], [__T | __Stack]); +yeccpars2(7, endblock, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 8, [7 | __Ss], [__T | __Stack]); +yeccpars2(7, extends, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 4, [7 | __Ss], [__T | __Stack]); +yeccpars2(7, string, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 5, [7 | __Ss], [__T | __Stack]); +yeccpars2(7, var, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 6, [7 | __Ss], [__T | __Stack]); +yeccpars2(7, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(8, __Cat, __Ss, __Stack, __T, __Ts, __Tzr) -> + __NewStack = yeccpars2_8_(__Stack), + __Nss = lists:nthtail(2, __Ss), + yeccpars2(yeccgoto('Element', hd(__Nss)), __Cat, __Nss, __NewStack, __T, __Ts, __Tzr); +yeccpars2(__Other, _, _, _, _, _, _) -> + erlang:error({yecc_bug,"1.1",{missing_state_in_action_table, __Other}}). + +yeccgoto('Element', 1) -> + 2; +yeccgoto('Element', 7) -> + 2; +yeccgoto('Elements', 0) -> + 1; +yeccgoto('Elements', 3) -> + 7; +yeccgoto(__Symbol, __State) -> + erlang:error({yecc_bug,"1.1",{__Symbol, __State, missing_in_goto_table}}). + +-compile({inline,{yeccpars2_0_,1}}). +-file("src/erlydtl/erlydtl_parser.yrl", 51). +yeccpars2_0_(__Stack) -> + [begin + nil + end | __Stack]. + +-compile({inline,{yeccpars2_2_,1}}). +-file("src/erlydtl/erlydtl_parser.yrl", 52). +yeccpars2_2_([__2,__1 | __Stack]) -> + [begin + [ __1 , __2 ] + end | __Stack]. + +-compile({inline,{yeccpars2_3_,1}}). +-file("src/erlydtl/erlydtl_parser.yrl", 51). +yeccpars2_3_(__Stack) -> + [begin + nil + end | __Stack]. + +-compile({inline,{yeccpars2_8_,1}}). +-file("src/erlydtl/erlydtl_parser.yrl", 57). +yeccpars2_8_([__3,__2,__1 | __Stack]) -> + [begin + block ( __1 , __2 ) + end | __Stack]. + + +-file("src/erlydtl/erlydtl_parser.yrl", 66). diff --git a/src/erlydtl/erlydtl_parser.yrl b/src/erlydtl/erlydtl_parser.yrl new file mode 100755 index 0000000..fb7f165 --- /dev/null +++ b/src/erlydtl/erlydtl_parser.yrl @@ -0,0 +1,66 @@ +%%%------------------------------------------------------------------- +%%% File: erlydtl_parser.erl +%%% @author Roberto Saccon [http://rsaccon.com] +%%% @copyright 2007 Roberto Saccon, Tait Larson +%%% @doc Template language grammar +%%% @reference See http://erlydtl.googlecode.com for more information +%%% @end +%%% +%%% The MIT License +%%% +%%% Copyright (c) 2007 Roberto Saccon +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in +%%% all copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%%% THE SOFTWARE. +%%% +%%% @since 2007-11-11 by Roberto Saccon +%%%------------------------------------------------------------------- + + +Nonterminals + Elements + Element. + +Terminals + var + extends + block + endblock + string. + +Rootsymbol + Elements. + + +%% ------------------------------------------------------------------- +%% Rules +%% ------------------------------------------------------------------- + +Elements -> '$empty' : nil. +Elements -> Elements Element : ['$1', '$2']. + +Element -> string : '$1'. +Element -> var : '$1'. +Element -> extends : '$1'. +Element -> block Elements endblock : block('$1', '$2'). + + +Erlang code. + +block({_, _, [Name]}, Content) -> + {block, list_to_atom(Name), Content}. \ No newline at end of file diff --git a/src/erlydtl/erlydtl_scanner.erl b/src/erlydtl/erlydtl_scanner.erl new file mode 100755 index 0000000..0b0b6c7 --- /dev/null +++ b/src/erlydtl/erlydtl_scanner.erl @@ -0,0 +1,210 @@ +%%%------------------------------------------------------------------- +%%% File: erlydtl_scanner.erl +%%% @author Roberto Saccon [http://rsaccon.com] +%%% @copyright 2007 Roberto Saccon +%%% @doc Template language scanner +%%% @reference See http://erlydtl.googlecode.com for more information +%%% @end +%%% +%%% The MIT License +%%% +%%% Copyright (c) 2007 Roberto Saccon +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in +%%% all copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%%% THE SOFTWARE. +%%% +%%% @since 2007-11-11 by Roberto Saccon +%%%------------------------------------------------------------------- +-module(erlydtl_scanner). +-author('rsaccon@gmail.com'). + +%% API +-export([scan/1]). + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% @spec scan(T::template()) -> {ok, S::tokens()} | {error, Reason} +%% @type template() = string() | binary(). Template to parse +%% @type tokens() = [tuple()]. +%% @doc Scan the template string T and return the a token list or +%% an error. +%% @end +%%-------------------------------------------------------------------- + +scan(Template) -> + scan(Template, [], 1). + +scan([], Scanned, _Line) -> + Tokens = fold_strings(lists:reverse(Scanned), [], []), + {ok, Tokens}; + +scan([$<, $\!, $-, $-, ${, ${ | T], Scanned, Line) -> + Rules = [until(fun is_var_end/1), + until(fun is_html_comment_end/1)], + Scan = scan2(Rules), + case Scan(T) of + {ok, Token, LinesScanned, Rest} -> + scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned); + {error, Reason} -> + {error, {var, Line, Reason}} + end; + +scan([${, ${ | T], Scanned, Line) -> + Rules = [until(fun is_var_end/1)], + Scan = scan2(Rules), + case Scan(T) of + {ok, Token, LinesScanned, Rest} -> + scan(Rest, [{var, Line, Token} | Scanned], Line + LinesScanned); + {error, Reason} -> + {error, {var, Line, Reason}} + end; + +scan([$<, $\!, $-, $-, ${, $\% | T], Scanned, Line) -> + Rules = [until(fun is_tag_end/1), + until(fun is_html_comment_end/1)], + Scan = scan2(Rules), + case Scan(T) of + {ok, Token, LinesScanned, Rest} -> + scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned); + {error, Reason} -> + {error, {tag, Line, Reason}} + end; + +scan([${, $\% | T], Scanned, Line) -> + Rules = [until(fun is_tag_end/1)], + Scan = scan2(Rules), + case Scan(T) of + {ok, Token, LinesScanned, Rest} -> + scan(Rest, [{tag, Line, Token} | Scanned], Line + LinesScanned); + {error, Reason} -> + {error, {tag, Line, Reason}} + end; + +scan([${, $# | T], Scanned, Line) -> + Rules = [until(fun is_comment_end/1)], + Scan = scan2(Rules), + case Scan(T) of + {ok, _Token, LinesScanned, Rest} -> + scan(Rest, Scanned, Line + LinesScanned); + {error, Reason} -> + {error, {var, Line, Reason}} + end; + +scan([H | T], Scanned, Line) when [H] == "\r" andalso hd(T) == "\n" -> + scan(tl(T), ["\r\n" | Scanned], Line+1); + +scan([H | T], Scanned, Line) when [H] == "\r" orelse [H] == "\n" -> + scan(T, [H | Scanned], Line+1); + +scan([H | T], Scanned, Line) -> + scan(T, [H | Scanned], Line). + + +%%-------------------------------------------------------------------- +%% Internal Functions +%%-------------------------------------------------------------------- + +scan2(Rules) -> + fun(Tmpl) -> + scan2(Rules, Tmpl, [], 0) + end. + + +scan2([], Tmpl, SoFar, Line) -> + {ok, lists:reverse(SoFar), Line, Tmpl}; + +scan2([Rule | T], Tmpl, SoFar, Line) -> + case Rule(Tmpl) of + {error, Reason} -> + {error, Reason}; + {ok, Rest, LinesScanned} -> + scan2(T, Rest, SoFar, Line + LinesScanned); + {ok, Tok, LinesScanned, Rest} -> + scan2(T, Rest, [Tok | SoFar], Line + LinesScanned) + end. + +fold_strings([], Folded, []) -> + lists:reverse(Folded); + +fold_strings([], Folded, Acc) -> + S = {string, 1, lists:reverse(Acc)}, + lists:reverse([S | Folded]); + +fold_strings([H | T], Folded, []) when is_tuple(H) -> + fold_strings(T, [translate_token(H) | Folded], []); + +fold_strings([H | T], Folded, Acc) when is_tuple(H) -> + S = {string, 1, lists:reverse(Acc)}, + fold_strings(T, [translate_token(H), S | Folded], []); + +fold_strings([H | T], Folded, Acc) -> + fold_strings(T, Folded, [H | Acc]). + + +translate_token({var, Line, [[S] | _]}) -> + {var, Line, S}; + +translate_token({tag, Line, [[H | T] | _]}) -> + {list_to_atom(H), Line, T}; + +translate_token(Token) -> + io:format("TRACE ~p:~p unrecognized token: ~p~n",[?MODULE, ?LINE, Token]), + Token. + + +until(P) -> + fun (Tmpl) -> + until(P, Tmpl, 0, []) + end. + +until(_P, [], _Line, _Scanned) -> + {error, end_not_found}; + +until(P, [H|T], Line, Scanned) when [H]=="\r" andalso hd(T)=="\n" -> + until(P, tl(T), Line+1, Scanned); + +until(P, [H|T], Line, Scanned) when [H]=="\n" orelse [H]== "\r" -> + until(P, T, Line+1, Scanned); + +until(P, [H|T]=Tmpl, Line, Scanned) -> + case P(Tmpl) of + {true, R} -> + Scanned1 = string:strip(lists:reverse(Scanned)), + Scanned2 = string:tokens(Scanned1, " "), + {ok, Scanned2, Line, R}; + _ -> + until(P, T, Line, [H | Scanned]) + end. + + +is_var_end([$}, $} | T]) -> {true, T}; +is_var_end(_) -> false. + + +is_tag_end([$\%, $} | T]) -> {true, T}; +is_tag_end(_) -> false. + + +is_comment_end([$#, $} | T]) -> {true, T}; +is_comment_end(_) -> false. + + +is_html_comment_end([$-, $-, $> | T]) -> {true, T}; +is_html_comment_end(_) -> false. diff --git a/src/erlydtl/erlydtl_tools.erl b/src/erlydtl/erlydtl_tools.erl new file mode 100644 index 0000000..8b5f47e --- /dev/null +++ b/src/erlydtl/erlydtl_tools.erl @@ -0,0 +1,125 @@ +%%%------------------------------------------------------------------- +%%% File: erlydtl_tools.erl +%%% @author Roberto Saccon [http://rsaccon.com] +%%% @copyright 2007 Roberto Saccon +%%% @doc +%%% Utility for creating parser based on grammar +%%% @end +%%% +%%% The MIT License +%%% +%%% Copyright (c) 2007 Roberto Saccon +%%% +%%% Permission is hereby granted, free of charge, to any person obtaining a copy +%%% of this software and associated documentation files (the "Software"), to deal +%%% in the Software without restriction, including without limitation the rights +%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +%%% copies of the Software, and to permit persons to whom the Software is +%%% furnished to do so, subject to the following conditions: +%%% +%%% The above copyright notice and this permission notice shall be included in +%%% all copies or substantial portions of the Software. +%%% +%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +%%% THE SOFTWARE. +%%% +%%% @since 2007-11-17 by Roberto Saccon +%%%------------------------------------------------------------------- +-module(erlydtl_tools). +-author('rsaccon@gmail.com'). + +%% API +-export([create_parser/0, create_module/2, reload/2, write_beam/3]). + +%% -------------------------------------------------------------------- +%% Definitions +%% -------------------------------------------------------------------- +-ifdef(debug). +-define(PRINT_ERR_WARNS, [report_warnings, report_errors]). +-else. +-define(PRINT_ERR_WARNS, []). +-endif. + + +%%==================================================================== +%% API +%%==================================================================== +%%-------------------------------------------------------------------- +%% @spec +%% @doc +%% @end +%%-------------------------------------------------------------------- +create_parser() -> + create_parser("src/erlydtl/erlydtl_parser", "ebin"). + + +%%-------------------------------------------------------------------- +%% @spec (Ast::tuple(), Name::atom()) -> any() +%% @doc Translate Abstract Syntax Tree to Abstract Module Code +%% @end +%%-------------------------------------------------------------------- +create_module(Ast, ModuleName) when is_list(Ast) -> + Tail = lists:reverse([{eof, 1} | lists:reverse(lists:flatten(Ast))]), + add_module_header(Tail, ModuleName); +create_module(Ast, ModuleName) -> + Tail = [Ast, {eof, 1}], + add_module_header(Tail, ModuleName). + + + +%%-------------------------------------------------------------------- +%% @spec (ModuleName::string(), Bin,::binary()) -> Ok::atom() | Error::atom() +%% @doc reloads byte code +%% @end +%%-------------------------------------------------------------------- +reload(Module, Bin) -> + code:purge(Module), + SrcName = atom_to_list(Module) ++ ".erl", + case code:load_binary(Module, SrcName, Bin) of + {module, _} -> ok; + _ -> error + end. + + +%%-------------------------------------------------------------------- +%% @spec (ModuleName::string(), Bin,::binary(), Dir::string()) -> any() +%% @doc writes byte code to beam file +%% @end +%%-------------------------------------------------------------------- +write_beam(ModuleName, Bin, Dir) -> + File = filename:join([Dir, atom_to_list(ModuleName) ++ ".beam"]), + file:write_file(File, Bin). + + +%%==================================================================== +%% Internal functions +%%==================================================================== + +create_parser(Path, Outdir) -> + case yecc:file(Path) of + {ok, _} -> + compile_reload(Path, Outdir); + Err -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, Path ++ ": yecc failed"]), + Err + end. + +compile_reload(Path, Outdir) -> + case compile:file(Path, ?PRINT_ERR_WARNS ++ [{outdir, Outdir}]) of + {ok, Bin} -> + code:purge(Bin), + code:load_file(Bin); + Err -> + io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, Path ++ ": compilation failed"]), + Err + end. + + +add_module_header(Tail, ModuleName) -> + Tail2 = [{attribute, 1, compile, export_all} | Tail], + [{attribute, 1, module, list_to_atom(ModuleName)} | Tail2]. \ No newline at end of file