11defmodule ElixirScript.Translate.Function do
22 alias ESTree.Tools.Builder , as: J
33 alias ElixirScript.Translate.Clause
4+ alias ElixirScript.Translate.Forms.Pattern
5+ alias ElixirScript.Translate.Form
46
57 @ moduledoc """
68 Translates the given Elixir function AST into the
@@ -20,18 +22,108 @@ defmodule ElixirScript.Translate.Function do
2022
2123 def compile ( { { name , arity } , type , _ , clauses } , state ) do
2224 state = Map . put ( state , :function , { name , arity } )
25+ clauses = compile_clauses ( clauses , state )
26+
27+ arg_matches_declarator = J . variable_declarator (
28+ J . identifier ( "__arg_matches__" ) ,
29+ J . identifier ( "null" )
30+ )
31+
32+ arg_matches_declaration = J . variable_declaration ( [ arg_matches_declarator ] , :let )
2333
2434 declarator = J . variable_declarator (
2535 ElixirScript.Translator.Identifier . make_function_name ( name , arity ) ,
26- J . call_expression (
36+ J . function_expression (
37+ [ J . rest_element ( J . identifier ( "__function_args__" ) ) ] ,
38+ [ ] ,
39+ J . block_statement ( [
40+ arg_matches_declaration ,
41+ clauses ,
42+ J . throw_statement (
43+ J . call_expression (
44+ J . member_expression (
45+ patterns_ast ( ) ,
46+ J . identifier ( "MatchError" )
47+ ) ,
48+ [ J . identifier ( "__function_args__" ) ]
49+ )
50+ )
51+ ] )
52+ )
53+ )
54+
55+ J . variable_declaration ( [ declarator ] , :const )
56+ end
57+
58+ defp compile_clauses ( clauses , state ) do
59+ clauses
60+ |> Enum . map ( & compile_clause ( & 1 , state ) )
61+ |> Enum . map ( fn { patterns , params , guards , body } ->
62+ IO . inspect guards
63+ match_or_default_call = J . call_expression (
2764 J . member_expression (
2865 patterns_ast ( ) ,
29- J . identifier ( "defmatch" )
66+ J . identifier ( "match_or_default" )
67+ ) ,
68+ [ J . array_expression ( patterns ) , J . identifier ( "__function_args__" ) , guards ]
69+ )
70+
71+ J . if_statement (
72+ J . binary_expression (
73+ :!== ,
74+ J . assignment_expression ( := , J . identifier ( "__arg_matches__" ) , match_or_default_call ) ,
75+ J . identifier ( "null" )
3076 ) ,
31- Enum . map ( clauses , & Clause . compile ( & 1 , state ) )
77+ J . block_statement ( body )
3278 )
79+ end )
80+ |> Enum . reverse
81+ |> Enum . reduce ( nil , fn
82+ if_ast , nil ->
83+ if_ast
84+ if_ast , ast ->
85+ % { if_ast | alternate: ast }
86+ end )
87+ end
88+
89+ defp compile_clause ( { _ , args , guards , body } , state ) do
90+ { patterns , params } = Pattern . compile ( args , state )
91+ guard = Clause . compile_guard ( params , guards , state )
92+
93+ body = case body do
94+ nil ->
95+ J . identifier ( "null" )
96+ { :__block__ , _ , block_body } ->
97+ Enum . map ( block_body , & Form . compile ( & 1 , state ) )
98+ |> List . flatten
99+ b when is_list ( b ) ->
100+ Enum . map ( b , & Form . compile ( & 1 , state ) )
101+ |> List . flatten
102+ _ ->
103+ Form . compile ( body , state )
104+ end
105+
106+ body = Clause . return_last_statement ( body )
107+
108+ declarator = J . variable_declarator (
109+ J . array_expression ( params ) ,
110+ J . identifier ( "__arg_matches__" )
33111 )
34112
35- J . variable_declaration ( [ declarator ] , :const )
113+ declaration = J . variable_declaration ( [ declarator ] , :const )
114+
115+ body = [ declaration ] ++ body
116+ { patterns , params , guard , body }
117+ end
118+
119+ defp compile_clause ( { :-> , _ , [ [ { :when , _ , params } ] , body ] } , state ) do
120+ guards = List . last ( params )
121+ params = params |> Enum . reverse |> tl |> Enum . reverse
122+
123+ compile_clause ( { [ ] , params , guards , body } , state )
124+ end
125+
126+ defp compile_clause ( { :-> , _ , [ params , body ] } , state ) do
127+ compile_clause ( { [ ] , params , [ ] , body } , state )
36128 end
37129end
0 commit comments