mirror of
				https://github.com/livebook-dev/livebook.git
				synced 2025-10-31 07:46:18 +08:00 
			
		
		
		
	Use unambiguous mapping between erlang and elixir variable names (#2556)
This commit is contained in:
		
							parent
							
								
									1cac107402
								
							
						
					
					
						commit
						6d994a5542
					
				
					 2 changed files with 74 additions and 2 deletions
				
			
		|  | @ -808,17 +808,47 @@ defmodule Livebook.Runtime.Evaluator do | ||||||
|   defp elixir_to_erlang_var(name) do |   defp elixir_to_erlang_var(name) do | ||||||
|     name |     name | ||||||
|     |> :erlang.atom_to_binary() |     |> :erlang.atom_to_binary() | ||||||
|     |> Macro.camelize() |     |> toggle_var_case() | ||||||
|     |> :erlang.binary_to_atom() |     |> :erlang.binary_to_atom() | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   defp erlang_to_elixir_var(name) do |   defp erlang_to_elixir_var(name) do | ||||||
|     name |     name | ||||||
|     |> :erlang.atom_to_binary() |     |> :erlang.atom_to_binary() | ||||||
|     |> Macro.underscore() |     |> toggle_var_case() | ||||||
|     |> :erlang.binary_to_atom() |     |> :erlang.binary_to_atom() | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   # Unambiguously maps variable names from camel case to underscore | ||||||
|  |   # case, and vice-versa. The mapping is defined as follows: | ||||||
|  |   # | ||||||
|  |   #   1. The first character case is changed | ||||||
|  |   # | ||||||
|  |   #   2. Underscore followed by lower character maps to upper character, | ||||||
|  |   #      and vice-versa | ||||||
|  |   # | ||||||
|  |   defp toggle_var_case(<<h, t::binary>>) do | ||||||
|  |     do_toggle_var_case(<<toggle_char_case(h)>>, t) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   defp do_toggle_var_case(acc, <<?_, h, t::binary>>) when h >= ?a and h <= ?z do | ||||||
|  |     do_toggle_var_case(<<acc::binary, toggle_char_case(h)>>, t) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   defp do_toggle_var_case(acc, <<h, t::binary>>) when h >= ?A and h <= ?Z do | ||||||
|  |     do_toggle_var_case(<<acc::binary, ?_, toggle_char_case(h)>>, t) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   defp do_toggle_var_case(acc, <<h, t::binary>>) do | ||||||
|  |     do_toggle_var_case(<<acc::binary, h>>, t) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   defp do_toggle_var_case(acc, <<>>), do: acc | ||||||
|  | 
 | ||||||
|  |   defp toggle_char_case(char) when char >= ?a and char <= ?z, do: char - 32 | ||||||
|  |   defp toggle_char_case(char) when char >= ?A and char <= ?Z, do: char + 32 | ||||||
|  |   defp toggle_char_case(char), do: char | ||||||
|  | 
 | ||||||
|   defp filter_erlang_code_markers(code_markers) do |   defp filter_erlang_code_markers(code_markers) do | ||||||
|     Enum.reject(code_markers, &(&1.line == 0)) |     Enum.reject(code_markers, &(&1.line == 0)) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -1268,6 +1268,48 @@ defmodule Livebook.Runtime.EvaluatorTest do | ||||||
|       assert [{:z, 1}, {:y, 1}, {:x, 1}] == binding |       assert [{:z, 1}, {:y, 1}, {:x, 1}] == binding | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     test "uses unambiguous camelization for erlang/elixir bindings", %{evaluator: evaluator} do | ||||||
|  |       Evaluator.evaluate_code(evaluator, :erlang, "{JSON, JsOn, JsON} = {1, 2, 3}.", :code_1, []) | ||||||
|  | 
 | ||||||
|  |       assert_receive {:runtime_evaluation_response, :code_1, terminal_text(_), metadata()} | ||||||
|  | 
 | ||||||
|  |       Evaluator.evaluate_code( | ||||||
|  |         evaluator, | ||||||
|  |         :elixir, | ||||||
|  |         """ | ||||||
|  |         assertion1 = {j_s_o_n, js_on, js_o_n} == {1, 2, 3} | ||||||
|  |         {j_s_o_n, js_on, js_o_n} = {11, 12, 13} | ||||||
|  |         """, | ||||||
|  |         :code_2, | ||||||
|  |         [:code_1] | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       assert_receive {:runtime_evaluation_response, :code_2, terminal_text(_), metadata()} | ||||||
|  | 
 | ||||||
|  |       Evaluator.evaluate_code( | ||||||
|  |         evaluator, | ||||||
|  |         :erlang, | ||||||
|  |         """ | ||||||
|  |         Assertion2 = {JSON, JsOn, JsON} =:= {11, 12, 13}. | ||||||
|  |         """, | ||||||
|  |         :code_3, | ||||||
|  |         [:code_2] | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       assert_receive {:runtime_evaluation_response, :code_3, terminal_text(_), metadata()} | ||||||
|  | 
 | ||||||
|  |       %{binding: binding} = | ||||||
|  |         Evaluator.get_evaluation_context(evaluator, [:code_3, :code_2, :code_1]) | ||||||
|  | 
 | ||||||
|  |       assert [ | ||||||
|  |                {:assertion2, true}, | ||||||
|  |                {:js_on, 12}, | ||||||
|  |                {:js_o_n, 13}, | ||||||
|  |                {:j_s_o_n, 11}, | ||||||
|  |                {:assertion1, true} | ||||||
|  |              ] == binding | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|     test "inspects erlang results using erlang format", %{evaluator: evaluator} do |     test "inspects erlang results using erlang format", %{evaluator: evaluator} do | ||||||
|       code = ~S"#{x=>1}." |       code = ~S"#{x=>1}." | ||||||
|       Evaluator.evaluate_code(evaluator, :erlang, code, :code_1, [], file: "file.ex") |       Evaluator.evaluate_code(evaluator, :erlang, code, :code_1, [], file: "file.ex") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue