@@ -2683,54 +2683,76 @@ defmodule Macro do
26832683 :unquoted_operator
26842684
26852685 true ->
2686- charlist = Atom . to_charlist ( atom )
2686+ classify_binary ( Atom . to_string ( atom ) , atom )
2687+ end
2688+ end
26872689
2688- if valid_alias? ( charlist ) do
2689- :alias
2690- else
2691- case :elixir_config . identifier_tokenizer ( ) . tokenize ( charlist ) do
2692- { kind , _acc , [ ] , _ , _ , special } ->
2693- cond do
2694- kind != :identifier or :lists . member ( :at , special ) ->
2695- :not_callable
2696-
2697- # identifier_tokenizer used to return errors for non-nfc, but
2698- # now it nfc-normalizes everything. However, lack of nfc is
2699- # still a good reason to quote an atom when printing.
2700- :lists . member ( :nfkc , special ) ->
2701- :other
2702-
2703- true ->
2704- :identifier
2705- end
2706-
2707- _ ->
2708- :other
2709- end
2690+ # ASCII identifiers and aliases are recognized on the binary to avoid building a
2691+ # charlist and running the (unicode aware) tokenizer, which dominates the cost of
2692+ # classifying keyword list, map and struct keys.
2693+ defp classify_binary ( << char , rest :: binary >> , atom )
2694+ when char >= ?a and char <= ?z
2695+ when char == ?_ do
2696+ if valid_identifier_rest? ( rest ) , do: :identifier , else: classify_with_tokenizer ( atom )
2697+ end
2698+
2699+ defp classify_binary ( "Elixir" <> rest , atom ) do
2700+ if valid_alias_piece? ( rest ) , do: :alias , else: classify_with_tokenizer ( atom )
2701+ end
2702+
2703+ defp classify_binary ( _binary , atom ) , do: classify_with_tokenizer ( atom )
2704+
2705+ defp classify_with_tokenizer ( atom ) do
2706+ case :elixir_config . identifier_tokenizer ( ) . tokenize ( Atom . to_charlist ( atom ) ) do
2707+ { kind , _acc , [ ] , _ , _ , special } ->
2708+ cond do
2709+ kind != :identifier or :lists . member ( :at , special ) ->
2710+ :not_callable
2711+
2712+ # identifier_tokenizer used to return errors for non-nfc, but
2713+ # now it nfc-normalizes everything. However, lack of nfc is
2714+ # still a good reason to quote an atom when printing.
2715+ :lists . member ( :nfkc , special ) ->
2716+ :other
2717+
2718+ true ->
2719+ :identifier
27102720 end
2721+
2722+ _ ->
2723+ :other
27112724 end
27122725 end
27132726
2714- defp valid_alias? ( [ ?E , ?l , ?i , ?x , ?i , ?r ] ++ rest ) , do: valid_alias_piece? ( rest )
2715- defp valid_alias? ( _other ) , do: false
2727+ defp valid_identifier_rest? ( << char , rest :: binary >> )
2728+ when char >= ?a and char <= ?z
2729+ when char >= ?A and char <= ?Z
2730+ when char >= ?0 and char <= ?9
2731+ when char == ?_ do
2732+ valid_identifier_rest? ( rest )
2733+ end
2734+
2735+ defp valid_identifier_rest? ( << char >> ) when char == ?? when char == ?! , do: true
2736+ defp valid_identifier_rest? ( << >> ) , do: true
2737+ defp valid_identifier_rest? ( _other ) , do: false
27162738
2717- defp valid_alias_piece? ( [ ?. , char | rest ] ) when char >= ?A and char <= ?Z ,
2718- do: valid_alias_piece? ( trim_leading_while_valid_identifier ( rest ) )
2739+ defp valid_alias_piece? ( << ?. , char , rest :: binary >> ) when char >= ?A and char <= ?Z ,
2740+ do: valid_alias_piece_rest? ( rest )
27192741
2720- defp valid_alias_piece? ( [ ] ) , do: true
2742+ defp valid_alias_piece? ( << >> ) , do: true
27212743 defp valid_alias_piece? ( _other ) , do: false
27222744
2723- defp trim_leading_while_valid_identifier ( [ char | rest ] )
2745+ # A helper returning the rest of the binary would build a sub binary per piece,
2746+ # so branch back into valid_alias_piece?/1 to keep the match context.
2747+ defp valid_alias_piece_rest? ( << char , rest :: binary >> )
27242748 when char >= ?a and char <= ?z
27252749 when char >= ?A and char <= ?Z
27262750 when char >= ?0 and char <= ?9
27272751 when char == ?_ do
2728- trim_leading_while_valid_identifier ( rest )
2752+ valid_alias_piece_rest? ( rest )
27292753 end
27302754
2731- defp trim_leading_while_valid_identifier ( other ) do
2732- other
2733- end
2755+ defp valid_alias_piece_rest? ( other ) , do: valid_alias_piece? ( other )
27342756
27352757 @ doc """
27362758 Default backend for `Kernel.dbg/2`.
0 commit comments