Skip to content

Commit 112b416

Browse files
NSHkrNSHkr
authored andcommitted
* Refactored CFGGenerator to use Mox
** This is a compromise to slowly transition: ** The issue is that ExpressionProcessors now uses dependency injection via Application.get_env/3, ** but the main CFGGenerator and other parts of the system still directly call the concrete modules. ** This creates a mismatch. In this change we: Set the default Application environment values and fix the dependency injection pattern. For future refactoring that is done wholistically: Refactor the entire CFG generation pipeline to use dependency injection consistently.
1 parent 697fabb commit 112b416

File tree

15 files changed

+930
-93
lines changed

15 files changed

+930
-93
lines changed

config/test.exs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,19 @@ config :elixir_scope,
4646
interface: [
4747
iex_helpers: false, # Disable IEx helpers in tests
4848
query_timeout: 1000 # Quick timeout for tests
49-
]
49+
],
50+
51+
state_manager: ElixirScope.ASTRepository.Enhanced.CFGGenerator.StateManager,
52+
ast_utilities: ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities,
53+
ast_processor: ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessor
54+
55+
56+
57+
58+
59+
60+
61+
5062

5163
config :elixir_scope, :pattern_matcher,
5264
# Faster execution for tests

lib/elixir_scope/application.ex

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ defmodule ElixirScope.Application do
1515
def start(_type, _args) do
1616
Logger.info("Starting ElixirScope application...")
1717

18+
ensure_default_cfg_dependencies()
19+
1820
children = [
1921
# Core configuration and utilities (no dependencies)
2022
{ElixirScope.Config, []},
@@ -42,9 +44,26 @@ defmodule ElixirScope.Application do
4244
end
4345
end
4446

47+
defp ensure_default_cfg_dependencies do
48+
unless Application.get_env(:elixir_scope, :state_manager) do
49+
Application.put_env(:elixir_scope, :state_manager,
50+
ElixirScope.ASTRepository.Enhanced.CFGGenerator.StateManager)
51+
end
52+
53+
unless Application.get_env(:elixir_scope, :ast_utilities) do
54+
Application.put_env(:elixir_scope, :ast_utilities,
55+
ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities)
56+
end
57+
58+
unless Application.get_env(:elixir_scope, :ast_processor) do
59+
Application.put_env(:elixir_scope, :ast_processor,
60+
ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessor)
61+
end
62+
end
63+
4564
@impl true
4665
def stop(_state) do
4766
Logger.info("Stopping ElixirScope application...")
4867
:ok
4968
end
50-
end
69+
end

lib/elixir_scope/ast_repository/enhanced/cfg_generator/ast_processor.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessor do
33
Main AST processing functions for the CFG generator.
44
"""
55

6+
@behaviour ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessorBehaviour
7+
68
alias ElixirScope.ASTRepository.Enhanced.{CFGNode, CFGEdge, ScopeInfo}
79
alias ElixirScope.ASTRepository.Enhanced.CFGGenerator.{
810
StateManager, ASTUtilities, ControlFlowProcessors, ExpressionProcessors
@@ -11,10 +13,12 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessor do
1113
@doc """
1214
Processes a function body AST and returns CFG components.
1315
"""
16+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessorBehaviour
1417
def process_function_body({:def, meta, [head, [do: body]]}, state) do
1518
process_function_body({:defp, meta, [head, [do: body]]}, state)
1619
end
1720

21+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessorBehaviour
1822
def process_function_body({:defp, meta, [head, [do: body]]}, state) do
1923
line = ASTUtilities.get_line_number(meta)
2024

@@ -117,6 +121,7 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessor do
117121
@doc """
118122
Main AST node processing dispatcher.
119123
"""
124+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessorBehaviour
120125
def process_ast_node(ast, state) do
121126
case ast do
122127
# Block of statements - put this FIRST to ensure it matches before function call pattern
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTProcessorBehaviour do
2+
@moduledoc """
3+
Behaviour for main AST processing functions for the CFG generator.
4+
"""
5+
6+
alias ElixirScope.ASTRepository.Enhanced.{CFGNode, CFGEdge, ScopeInfo}
7+
alias ElixirScope.ASTRepository.Enhanced.CFGGenerator.State
8+
9+
@type nodes_map :: %{String.t() => CFGNode.t()}
10+
@type edges_list :: [CFGEdge.t()]
11+
@type exits_list :: [String.t()]
12+
@type scopes_map :: %{String.t() => ScopeInfo.t()}
13+
@type process_result :: {nodes_map(), edges_list(), exits_list(), scopes_map(), State.t()} | {:error, any()}
14+
15+
@doc """
16+
Processes a function body AST and returns CFG components.
17+
"""
18+
@callback process_function_body(function_ast :: term(), state :: State.t()) :: process_result()
19+
20+
@doc """
21+
Main AST node processing dispatcher.
22+
"""
23+
@callback process_ast_node(ast :: term(), state :: State.t()) :: process_result()
24+
end

lib/elixir_scope/ast_repository/enhanced/cfg_generator/ast_utilities.ex

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,28 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities do
33
Utility functions for working with AST nodes.
44
"""
55

6+
@behaviour ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
7+
68
@doc """
79
Extracts AST node ID from metadata.
810
"""
11+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
912
def get_ast_node_id(meta) do
1013
Keyword.get(meta, :ast_node_id)
1114
end
1215

1316
@doc """
1417
Extracts line number from metadata.
1518
"""
19+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
1620
def get_line_number(meta) do
1721
Keyword.get(meta, :line, 1)
1822
end
1923

2024
@doc """
2125
Extracts function parameters from function head.
2226
"""
27+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
2328
def extract_function_parameters({_name, _meta, args}) when is_list(args) do
2429
Enum.map(args, fn
2530
{var, _meta, nil} when is_atom(var) -> Atom.to_string(var)
@@ -32,6 +37,7 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities do
3237
@doc """
3338
Extracts variable names from a pattern.
3439
"""
40+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
3541
def extract_pattern_variables(pattern) do
3642
case pattern do
3743
{var, _meta, nil} when is_atom(var) -> [Atom.to_string(var)]
@@ -44,6 +50,7 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities do
4450
@doc """
4551
Calculates pattern matching probability (simplified).
4652
"""
53+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
4754
def calculate_pattern_probability(_pattern) do
4855
# Simplified probability - could be more sophisticated
4956
0.5
@@ -52,6 +59,7 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities do
5259
@doc """
5360
Determines the type of a literal value.
5461
"""
62+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
5563
def get_literal_type(literal) do
5664
cond do
5765
is_atom(literal) -> :atom
@@ -65,6 +73,7 @@ defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilities do
6573
@doc """
6674
Analyzes comprehension clauses to separate generators and filters.
6775
"""
76+
@impl ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour
6877
def analyze_comprehension_clauses(clauses) do
6978
Enum.reduce(clauses, {[], []}, fn clause, {generators, filters} ->
7079
case clause do
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
defmodule ElixirScope.ASTRepository.Enhanced.CFGGenerator.ASTUtilitiesBehaviour do
2+
@moduledoc """
3+
Behaviour for utility functions for working with AST nodes.
4+
"""
5+
6+
@type meta :: keyword()
7+
@type literal :: atom() | number() | binary() | list()
8+
@type pattern :: term()
9+
@type function_head :: {atom(), meta(), list() | nil}
10+
@type comprehension_clauses :: list(term())
11+
12+
@doc """
13+
Extracts AST node ID from metadata.
14+
"""
15+
@callback get_ast_node_id(meta :: meta()) :: String.t() | nil
16+
17+
@doc """
18+
Extracts line number from metadata.
19+
"""
20+
@callback get_line_number(meta :: meta()) :: non_neg_integer()
21+
22+
@doc """
23+
Extracts function parameters from function head.
24+
"""
25+
@callback extract_function_parameters(head :: function_head()) :: [String.t()]
26+
27+
@doc """
28+
Extracts variable names from a pattern.
29+
"""
30+
@callback extract_pattern_variables(pattern :: pattern()) :: [String.t()]
31+
32+
@doc """
33+
Calculates pattern matching probability (simplified).
34+
"""
35+
@callback calculate_pattern_probability(pattern :: pattern()) :: float()
36+
37+
@doc """
38+
Determines the type of a literal value.
39+
"""
40+
@callback get_literal_type(literal :: literal()) :: atom()
41+
42+
@doc """
43+
Analyzes comprehension clauses to separate generators and filters.
44+
"""
45+
@callback analyze_comprehension_clauses(clauses :: comprehension_clauses()) ::
46+
{generators :: list(term()), filters :: list(term())}
47+
end

0 commit comments

Comments
 (0)