1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-27 06:40:14 +03:00
mal/impls/latex3/step2_eval.tex
Nicolas Boulenguez 00d168fdca latex3: new implementation
Self hosting fails at step4 because of exceeded TeX capacity.
2024-08-08 15:40:26 -05:00

174 lines
4.8 KiB
TeX

\documentclass{article}
\usepackage
% Uncomment this and \debug_on below when debugging.
% [enable-debug]
{expl3}
\usepackage{types}
\usepackage{printer}
\usepackage{reader}
\ExplSyntaxOn
% Slow but quite useful.
% \debug_on:n { all }
% Step 2
\cs_new:Nn \mal_eval_map:nN
{
% \iow_term:n {eval_map~ast=#1~env=#2}
\mal_map_new:
\prop_map_inline:cn { #1 }
{
\str_if_eq:nnF { ##1 } { __meta__ }
{
\seq_push:NV \l_mal_stack_seq \l_tmpa_tl
\mal_eval:nN { ##2 } #2
\seq_pop:NN \l_mal_stack_seq \l_tmpb_tl
\tl_if_head_eq_charcode:VNTF \l_tmpa_tl e
{ \prop_map_break: }
{
\prop_put:cnV \l_tmpb_tl { ##1 } \l_tmpa_tl
\tl_set_eq:NN \l_tmpa_tl \l_tmpb_tl
}
}
}
}
\cs_new:Nn \mal_eval_iterate_tl:nN
{
% The evaluated elements are appended to \l_tmpa_tl.
% \iow_term:n {eval_tl:~forms=#1~env=#2}
\tl_map_inline:nn { #1 }
{
\seq_push:NV \l_mal_stack_seq \l_tmpa_tl
\mal_eval:nN { ##1 } #2
\seq_pop:NN \l_mal_stack_seq \l_tmpb_tl
\tl_if_head_eq_charcode:VNTF \l_tmpa_tl e
{ \tl_map_break: }
{
\tl_set:Nx \l_tmpa_tl
{ \exp_not:V \l_tmpb_tl { \exp_not:V \l_tmpa_tl } }
}
}
}
\cs_generate_variant:Nn \mal_eval_iterate_tl:nN { oN }
% EVAL
\cs_new:Nn \mal_fn_apply:nn
{
% \iow_term:n {fn_apply:~func=#1~args=#2}
\tl_if_head_eq_charcode:nNTF { #1 } b
{ \use_none:nn #1 { #2 } }
{
\tl_set:Nx \l_tmpa_tl
{ e s \tl_to_str:n { can~only~apply~functions } }
}
% \iow_term:V \l_tmpa_tl
}
\cs_generate_variant:Nn \mal_fn_apply:nn { nx, Vo, VV, xx }
\cs_new:Nn \mal_eval_list:nN
{
% \iow_term:n {eval_mal_list~tl=#1~env=#2}
\tl_set:Nx \l_tmpa_tl { \tl_head:n {#1} }
\bool_case_true:nF
{
{ \tl_if_eq_p:NN \l_tmpa_tl \c_empty_tl }
{ \tl_set:Nn \l_tmpa_tl { l n } }
}
{
% \iow_term:n {eval_mal_list~apply_phase~tl=#1~env=#2}
\mal_eval:xN { \tl_head:n { #1 } } #2
\tl_if_head_eq_charcode:VNF \l_tmpa_tl e
{
\seq_push:NV \l_mal_stack_seq \l_tmpa_tl
\tl_clear:N \l_tmpa_tl
\mal_eval_iterate_tl:oN { \use_none:n #1 } #2
\seq_pop:NN \l_mal_stack_seq \l_tmpb_tl
\tl_if_head_eq_charcode:VNF \l_tmpa_tl e
{ \mal_fn_apply:VV \l_tmpb_tl \l_tmpa_tl }
}
}
}
\cs_generate_variant:Nn \mal_eval_list:nN { oN }
\cs_new:Nn \mal_eval:nN
{
% \iow_term:n {EVAL:~ast=#1~env=#2}
\exp_args:Nx \token_case_charcode:NnF { \tl_head:n {#1} }
{
l
{ \mal_eval_list:oN { \use_none:nn #1 } #2 }
y
{
\prop_get:NnNF #2 { #1 } \l_tmpa_tl
{
\tl_set:Nx \l_tmpa_tl
{ e s \use_none:n #1 \tl_to_str:n { ~not~found } }
}
}
v
{
\tl_set:Nn \l_tmpa_tl { v n }
\mal_eval_iterate_tl:oN { \use_none:nn #1 } #2
}
m
{ \mal_eval_map:nN { #1 } #2 }
}
{ \tl_set:Nn \l_tmpa_tl {#1} }
% \iow_term:n {EVAL:~ast=#1~returns}
% \iow_term:V \l_tmpa_tl
}
\cs_generate_variant:Nn \mal_eval:nN { oN, VN, xN }
% REPL
\prop_new:N \l_mal_repl_env_prop
\cs_new:Nn \mal_int_op:nnN
{
\tl_set:Nx \l_tmpa_tl
{ i \int_eval:n { \use_none:n #1 #3 \use_none:n #2 } }
}
\cs_new:Nn \mal_add:n { \mal_int_op:nnN #1 + }
\cs_new:Nn \mal_sub:n { \mal_int_op:nnN #1 - }
\cs_new:Nn \mal_mul:n { \mal_int_op:nnN #1 * }
\cs_new:Nn \mal_div:n { \mal_int_op:nnN #1 / }
\prop_put:Nnn \l_mal_repl_env_prop { y + } { b n \mal_add:n }
\prop_put:Nnn \l_mal_repl_env_prop { y - } { b n \mal_sub:n }
\prop_put:Nnn \l_mal_repl_env_prop { y * } { b n \mal_mul:n }
\prop_put:Nnn \l_mal_repl_env_prop { y / } { b n \mal_div:n }
\cs_new:Nn \repl_loop:
{
% \ior_str_get_term is able to display a prompt on the same line,
% but this would make ./run far more complex for little benefit.
\iow_term:n {user>~}
\ior_str_get_term:nN {} \l_tmpa_str
\str_if_eq:VnF \l_tmpa_str {MAL_LATEX3_END_OF_INPUT} % from ./run
{
% Ignore empty lines, the MAL self-hosting relies on this
% *not* triggering an error.
\str_if_eq:VnF \l_tmpa_str {}
{
\mal_read_str:
\tl_if_head_eq_charcode:VNF \l_tmpa_tl e
{ \mal_eval:VN \l_tmpa_tl \l_mal_repl_env_prop }
\iow_term:x { \mal_printer_pr_str:VN \l_tmpa_tl \c_true_bool }
}
\repl_loop:
}
}
% ./run removes the normal LaTeX output.
\iow_term:n {MAL_LATEX3_START_OF_OUTPUT}
\repl_loop:
\iow_term:n {MAL_LATEX3_END_OF_OUTPUT} % for ./run
\ExplSyntaxOff
\begin{document}
\end{document}